@@ -95,6 +95,12 @@ impl PeerState {
95
95
None
96
96
}
97
97
}
98
+
99
+ fn is_empty ( & self ) -> bool {
100
+ self . pending_set_webhook_requests . is_empty ( )
101
+ && self . pending_list_webhooks_requests . is_empty ( )
102
+ && self . pending_remove_webhook_requests . is_empty ( )
103
+ }
98
104
}
99
105
100
106
/// Client-side handler for the LSPS5 (bLIP-55) webhook registration protocol.
@@ -389,8 +395,26 @@ where
389
395
}
390
396
} ;
391
397
self . with_peer_state ( * counterparty_node_id, handle_response) ;
398
+
399
+ self . check_and_remove_empty_peer_state ( counterparty_node_id) ;
400
+
392
401
result
393
402
}
403
+
404
+ fn check_and_remove_empty_peer_state ( & self , counterparty_node_id : & PublicKey ) {
405
+ let mut outer_state_lock = self . per_peer_state . write ( ) . unwrap ( ) ;
406
+ let should_remove =
407
+ if let Some ( peer_state_mutex) = outer_state_lock. get ( counterparty_node_id) {
408
+ let peer_state = peer_state_mutex. lock ( ) . unwrap ( ) ;
409
+ peer_state. is_empty ( )
410
+ } else {
411
+ false
412
+ } ;
413
+
414
+ if should_remove {
415
+ outer_state_lock. remove ( counterparty_node_id) ;
416
+ }
417
+ }
394
418
}
395
419
396
420
impl < ES : Deref > LSPSProtocolMessageHandler for LSPS5ClientHandler < ES >
@@ -515,36 +539,6 @@ mod tests {
515
539
}
516
540
}
517
541
518
- #[ test]
519
- fn test_handle_response_clears_pending_state ( ) {
520
- let ( client, _, _, peer, _) = setup_test_client ( ) ;
521
-
522
- let req_id = client
523
- . set_webhook ( peer, "test-app" . to_string ( ) , "https://example.com/hook" . to_string ( ) )
524
- . unwrap ( ) ;
525
-
526
- let response = LSPS5Response :: SetWebhook ( SetWebhookResponse {
527
- num_webhooks : 1 ,
528
- max_webhooks : 5 ,
529
- no_change : false ,
530
- } ) ;
531
- let response_msg = LSPS5Message :: Response ( req_id. clone ( ) , response) ;
532
-
533
- {
534
- let outer_state_lock = client. per_peer_state . read ( ) . unwrap ( ) ;
535
- let peer_state = outer_state_lock. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
536
- assert ! ( peer_state. pending_set_webhook_requests. contains_key( & req_id) ) ;
537
- }
538
-
539
- client. handle_message ( response_msg, & peer) . unwrap ( ) ;
540
-
541
- {
542
- let outer_state_lock = client. per_peer_state . read ( ) . unwrap ( ) ;
543
- let peer_state = outer_state_lock. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
544
- assert ! ( !peer_state. pending_set_webhook_requests. contains_key( & req_id) ) ;
545
- }
546
- }
547
-
548
542
#[ test]
549
543
fn test_unknown_request_id_handling ( ) {
550
544
let ( client, _message_queue, _, peer, _) = setup_test_client ( ) ;
@@ -612,4 +606,77 @@ mod tests {
612
606
. any( |( id, _) | id == & new_req_id) ) ;
613
607
}
614
608
}
609
+
610
+ #[ test]
611
+ fn test_peer_state_cleanup_and_recreation ( ) {
612
+ let ( client, _, _, peer, _) = setup_test_client ( ) ;
613
+
614
+ let set_webhook_req_id = client
615
+ . set_webhook ( peer, "test-app" . to_string ( ) , "https://example.com/hook" . to_string ( ) )
616
+ . unwrap ( ) ;
617
+
618
+ let list_webhooks_req_id = client. list_webhooks ( peer) ;
619
+
620
+ {
621
+ let state = client. per_peer_state . read ( ) . unwrap ( ) ;
622
+ assert ! ( state. contains_key( & peer) ) ;
623
+ let peer_state = state. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
624
+ assert ! ( peer_state
625
+ . pending_set_webhook_requests
626
+ . iter( )
627
+ . any( |( id, _) | id == & set_webhook_req_id) ) ;
628
+ assert ! ( peer_state. pending_list_webhooks_requests. contains( & list_webhooks_req_id) ) ;
629
+ }
630
+
631
+ let set_webhook_response = LSPS5Response :: SetWebhook ( SetWebhookResponse {
632
+ num_webhooks : 1 ,
633
+ max_webhooks : 5 ,
634
+ no_change : false ,
635
+ } ) ;
636
+ let response_msg = LSPS5Message :: Response ( set_webhook_req_id. clone ( ) , set_webhook_response) ;
637
+ // trigger cleanup but there is still a pending request
638
+ // so the peer state should not be removed
639
+ client. handle_message ( response_msg, & peer) . unwrap ( ) ;
640
+
641
+ {
642
+ let state = client. per_peer_state . read ( ) . unwrap ( ) ;
643
+ assert ! ( state. contains_key( & peer) ) ;
644
+ let peer_state = state. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
645
+ assert ! ( !peer_state
646
+ . pending_set_webhook_requests
647
+ . iter( )
648
+ . any( |( id, _) | id == & set_webhook_req_id) ) ;
649
+ assert ! ( peer_state. pending_list_webhooks_requests. contains( & list_webhooks_req_id) ) ;
650
+ }
651
+
652
+ let list_webhooks_response =
653
+ LSPS5Response :: ListWebhooks ( crate :: lsps5:: msgs:: ListWebhooksResponse {
654
+ app_names : vec ! [ ] ,
655
+ max_webhooks : 5 ,
656
+ } ) ;
657
+ let response_msg = LSPS5Message :: Response ( list_webhooks_req_id, list_webhooks_response) ;
658
+
659
+ // now the pending request is handled, so the peer state should be removed
660
+ client. handle_message ( response_msg, & peer) . unwrap ( ) ;
661
+
662
+ {
663
+ let state = client. per_peer_state . read ( ) . unwrap ( ) ;
664
+ assert ! ( !state. contains_key( & peer) ) ;
665
+ }
666
+
667
+ // check that it's possible to recreate the peer state by sending a new request
668
+ let new_req_id = client
669
+ . set_webhook ( peer, "test-app-2" . to_string ( ) , "https://example.com/hook2" . to_string ( ) )
670
+ . unwrap ( ) ;
671
+
672
+ {
673
+ let state = client. per_peer_state . read ( ) . unwrap ( ) ;
674
+ assert ! ( state. contains_key( & peer) ) ;
675
+ let peer_state = state. get ( & peer) . unwrap ( ) . lock ( ) . unwrap ( ) ;
676
+ assert ! ( peer_state
677
+ . pending_set_webhook_requests
678
+ . iter( )
679
+ . any( |( id, _) | id == & new_req_id) ) ;
680
+ }
681
+ }
615
682
}
0 commit comments