@@ -11,7 +11,7 @@ use claudette::room::{ParticipantInfo, Vote};
1111use serde_json:: json;
1212
1313use crate :: handler:: ConnectionCtx ;
14- use crate :: ws:: { ServerState , Writer , send_message } ;
14+ use crate :: ws:: { ServerState , Writer , try_send_message } ;
1515
1616/// Register a participant against a room, spawn their per-connection event
1717/// forwarder, and return a snapshot of the room's current state so the
@@ -76,14 +76,16 @@ pub async fn handle_join_session(
7676 let writer = Arc :: clone ( writer) ;
7777 let mut rx = room. subscribe ( ) ;
7878 let chat_session_id_for_forwarder = chat_session_id. to_string ( ) ;
79- tokio:: spawn ( async move {
79+ let forwarder = tokio:: spawn ( async move {
8080 loop {
8181 match rx. recv ( ) . await {
8282 Ok ( evt) => {
83- send_message ( & writer, & evt. 0 ) . await ;
83+ if try_send_message ( & writer, & evt. 0 ) . await . is_err ( ) {
84+ break ;
85+ }
8486 }
8587 Err ( tokio:: sync:: broadcast:: error:: RecvError :: Lagged ( _) ) => {
86- let _ = send_message (
88+ if try_send_message (
8789 & writer,
8890 & json ! ( {
8991 "event" : "resync-required" ,
@@ -92,12 +94,20 @@ pub async fn handle_join_session(
9294 } ,
9395 } ) ,
9496 )
95- . await ;
97+ . await
98+ . is_err ( )
99+ {
100+ break ;
101+ }
96102 }
97103 Err ( tokio:: sync:: broadcast:: error:: RecvError :: Closed ) => break ,
98104 }
99105 }
100106 } ) ;
107+ ctx. room_forwarders
108+ . lock ( )
109+ . await
110+ . insert ( chat_session_id. to_string ( ) , forwarder) ;
101111 }
102112
103113 // Snapshot for late joiners: full chat history + current participants +
@@ -129,6 +139,9 @@ pub async fn handle_leave_session(
129139 } ;
130140 let removed = ctx. joined_sessions . lock ( ) . await . remove ( chat_session_id) ;
131141 if removed {
142+ if let Some ( handle) = ctx. room_forwarders . lock ( ) . await . remove ( chat_session_id) {
143+ handle. abort ( ) ;
144+ }
132145 room. remove_participant ( & ctx. participant_id ) . await ;
133146 room. publish ( json ! ( {
134147 "event" : "participants-changed" ,
@@ -192,6 +205,16 @@ pub async fn handle_vote_plan_approval(
192205/// resulting roster updates. Called from the WS connection-close path.
193206pub async fn drop_all_joined_sessions ( state : & Arc < ServerState > , ctx : & ConnectionCtx ) {
194207 let session_ids: Vec < String > = ctx. joined_sessions . lock ( ) . await . drain ( ) . collect ( ) ;
208+ let forwarders: Vec < tokio:: task:: JoinHandle < ( ) > > = ctx
209+ . room_forwarders
210+ . lock ( )
211+ . await
212+ . drain ( )
213+ . map ( |( _, h) | h)
214+ . collect ( ) ;
215+ for handle in forwarders {
216+ handle. abort ( ) ;
217+ }
195218 for session_id in session_ids {
196219 let Some ( room) = state. rooms . get ( & session_id) . await else {
197220 continue ;
0 commit comments