@@ -6,27 +6,79 @@ use axum::{
66 } ,
77 response:: IntoResponse ,
88} ;
9- use std:: time:: Duration ;
9+ use std:: { collections :: HashMap , sync :: Arc , time:: Duration } ;
1010use tokio:: {
1111 io:: { AsyncReadExt , AsyncWriteExt } ,
1212 net:: TcpStream ,
13+ sync:: Mutex ,
1314} ;
1415
15- pub ( crate ) async fn ws_handler (
16+ struct IdempotencyLockGuard {
17+ key : Option < String > ,
18+ locks : Arc < Mutex < HashMap < String , bool > > > ,
19+ }
20+
21+ impl IdempotencyLockGuard {
22+ async fn new (
23+ key : Option < String > ,
24+ locks : Arc < Mutex < HashMap < String , bool > > > ,
25+ ) -> Result < Self , String > {
26+ if let Some ( ref key) = key {
27+ let mut lock_map = locks. lock ( ) . await ;
28+ if lock_map. get ( key) . copied ( ) . unwrap_or ( false ) {
29+ return Err ( "Idempotency key already in use" . to_string ( ) ) ;
30+ }
31+ lock_map. insert ( key. clone ( ) , true ) ;
32+ }
33+ Ok ( Self { key, locks } )
34+ }
35+ }
36+
37+ impl Drop for IdempotencyLockGuard {
38+ fn drop ( & mut self ) {
39+ if let Some ( ref key) = self . key {
40+ if let Ok ( mut lock_map) = self . locks . try_lock ( ) {
41+ lock_map. insert ( key. clone ( ) , false ) ;
42+ // Log that the lock was successfully released if needed
43+ } else {
44+ // Log an error or handle the lock acquisition failure
45+ logger:: error ( "Failed to acquire lock to release idempotency key" ) ;
46+ }
47+ }
48+ }
49+ }
50+
51+ pub ( crate ) fn ws_handler (
1652 Path ( ( ip, port) ) : Path < ( String , String ) > ,
1753 ws : WebSocketUpgrade ,
1854 user_agent : Option < TypedHeader < headers:: UserAgent > > ,
55+ idempotency_key : Option < String > ,
56+ locks : Arc < Mutex < HashMap < String , bool > > > ,
1957) -> impl IntoResponse {
2058 logger:: info ( & format ! ( "ip: {ip}, port: {port}" ) ) ;
2159 if let Some ( TypedHeader ( user_agent) ) = user_agent {
2260 logger:: info ( & format ! ( "`{user_agent}` connected" ) ) ;
2361 }
2462
2563 ws. protocols ( [ "binary" ] )
26- . on_upgrade ( move |socket| handle_socket ( socket, ip, port) )
64+ . on_upgrade ( move |socket| handle_socket ( socket, ip, port, idempotency_key , locks ) )
2765}
2866
29- pub ( crate ) async fn handle_socket ( mut socket : WebSocket , host : String , port : String ) {
67+ pub ( crate ) async fn handle_socket (
68+ socket : WebSocket ,
69+ host : String ,
70+ port : String ,
71+ idempotency_key : Option < String > ,
72+ locks : Arc < Mutex < HashMap < String , bool > > > ,
73+ ) {
74+ let lock_guard = match IdempotencyLockGuard :: new ( idempotency_key, locks) . await {
75+ Ok ( guard) => guard,
76+ Err ( e) => {
77+ logger:: error ( & e) ;
78+ return ;
79+ }
80+ } ;
81+
3082 let server_stream = match connect_to_addr ( host, port, server_tcp_connect) {
3183 Ok ( s) => s,
3284 Err ( e) => {
0 commit comments