Allow server to see client disconnection before giving up on reconnecting

Antonio Scandurra created

Change summary

crates/call/src/room.rs | 71 +++++++++++++++++++++++-------------------
1 file changed, 39 insertions(+), 32 deletions(-)

Detailed changes

crates/call/src/room.rs 🔗

@@ -264,45 +264,52 @@ impl Room {
                     });
 
                 // Wait for client to re-establish a connection to the server.
-                let mut reconnection_timeout = cx.background().timer(RECONNECT_TIMEOUT).fuse();
-                let client_reconnection = async {
-                    loop {
-                        if let Some(status) = client_status.next().await {
-                            if status.is_connected() {
-                                return true;
+                {
+                    let mut reconnection_timeout = cx.background().timer(RECONNECT_TIMEOUT).fuse();
+                    let client_reconnection = async {
+                        let mut remaining_attempts = 3;
+                        while remaining_attempts > 0 {
+                            if let Some(status) = client_status.next().await {
+                                if status.is_connected() {
+                                    let rejoin_room = async {
+                                        let response =
+                                            client.request(proto::JoinRoom { id: room_id }).await?;
+                                        let room_proto =
+                                            response.room.ok_or_else(|| anyhow!("invalid room"))?;
+                                        this.upgrade(&cx)
+                                            .ok_or_else(|| anyhow!("room was dropped"))?
+                                            .update(&mut cx, |this, cx| {
+                                                this.status = RoomStatus::Online;
+                                                this.apply_room_update(room_proto, cx)
+                                            })?;
+                                        anyhow::Ok(())
+                                    };
+
+                                    if rejoin_room.await.is_ok() {
+                                        return true;
+                                    } else {
+                                        remaining_attempts -= 1;
+                                    }
+                                }
+                            } else {
+                                return false;
                             }
-                        } else {
-                            return false;
                         }
+                        false
                     }
-                }
-                .fuse();
-                futures::pin_mut!(client_reconnection);
-
-                futures::select_biased! {
-                    reconnected = client_reconnection => {
-                        if reconnected {
-                            // Client managed to reconnect to the server. Now attempt to join the room.
-                            let rejoin_room = async {
-                                let response = client.request(proto::JoinRoom { id: room_id }).await?;
-                                let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?;
-                                this.upgrade(&cx)
-                                    .ok_or_else(|| anyhow!("room was dropped"))?
-                                    .update(&mut cx, |this, cx| {
-                                        this.status = RoomStatus::Online;
-                                        this.apply_room_update(room_proto, cx)
-                                    })?;
-                                anyhow::Ok(())
-                            };
-
-                            // If we successfully joined the room, go back around the loop
-                            // waiting for future connection status changes.
-                            if rejoin_room.await.log_err().is_some() {
+                    .fuse();
+                    futures::pin_mut!(client_reconnection);
+
+                    futures::select_biased! {
+                        reconnected = client_reconnection => {
+                            if reconnected {
+                                // If we successfully joined the room, go back around the loop
+                                // waiting for future connection status changes.
                                 continue;
                             }
                         }
+                        _ = reconnection_timeout => {}
                     }
-                    _ = reconnection_timeout => {}
                 }
 
                 // The client failed to re-establish a connection to the server