@@ -6,27 +6,79 @@ use axum::{
6
6
} ,
7
7
response:: IntoResponse ,
8
8
} ;
9
- use std:: time:: Duration ;
9
+ use std:: { collections :: HashMap , sync :: Arc , time:: Duration } ;
10
10
use tokio:: {
11
11
io:: { AsyncReadExt , AsyncWriteExt } ,
12
12
net:: TcpStream ,
13
+ sync:: Mutex ,
13
14
} ;
14
15
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 (
16
52
Path ( ( ip, port) ) : Path < ( String , String ) > ,
17
53
ws : WebSocketUpgrade ,
18
54
user_agent : Option < TypedHeader < headers:: UserAgent > > ,
55
+ idempotency_key : Option < String > ,
56
+ locks : Arc < Mutex < HashMap < String , bool > > > ,
19
57
) -> impl IntoResponse {
20
58
logger:: info ( & format ! ( "ip: {ip}, port: {port}" ) ) ;
21
59
if let Some ( TypedHeader ( user_agent) ) = user_agent {
22
60
logger:: info ( & format ! ( "`{user_agent}` connected" ) ) ;
23
61
}
24
62
25
63
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 ) )
27
65
}
28
66
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
+
30
82
let server_stream = match connect_to_addr ( host, port, server_tcp_connect) {
31
83
Ok ( s) => s,
32
84
Err ( e) => {
0 commit comments