From 0540579505e3e1373fe975f81aa13076db91ec28 Mon Sep 17 00:00:00 2001 From: Tobias Kantusch Date: Sun, 22 Sep 2024 18:43:52 +0200 Subject: [PATCH] feat(socketio): send close reason when emitting Event::Close Previously, when we emitted an Event::Close, we didn't specify a reason for why this event was emitted. When implementing the close notification on unexpected transport closes, we started sending 'transport close' as the payload for the close event. We now decided to do this more consistently and added a close reason when emitting the Event::Close, so that the client better knows why this event was emitted. --- socketio/src/asynchronous/client/client.rs | 15 ++++++---- socketio/src/client/raw_client.rs | 6 ++-- socketio/src/event.rs | 35 ++++++++++++++++++++++ socketio/src/lib.rs | 2 +- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/socketio/src/asynchronous/client/client.rs b/socketio/src/asynchronous/client/client.rs index f2040c9d..da1d5f09 100644 --- a/socketio/src/asynchronous/client/client.rs +++ b/socketio/src/asynchronous/client/client.rs @@ -19,7 +19,7 @@ use crate::{ asynchronous::socket::Socket as InnerSocket, error::{Error, Result}, packet::{Packet, PacketId}, - Event, Payload, + CloseReason, Event, Payload, }; #[derive(Default)] @@ -168,7 +168,7 @@ impl Client { // We don't need to do that in the other cases, since proper server close // and manual client close are handled explicitly. if let Some(err) = client_clone - .callback(&Event::Close, "transport close") + .callback(&Event::Close, CloseReason::TransportClose.as_str()) .await .err() { @@ -524,7 +524,8 @@ impl Client { } PacketId::Disconnect => { *(self.disconnect_reason.write().await) = DisconnectReason::Server; - self.callback(&Event::Close, "").await?; + self.callback(&Event::Close, CloseReason::IOServerDisconnect.as_str()) + .await?; } PacketId::ConnectError => { self.callback( @@ -604,8 +605,7 @@ mod test { }, error::Result, packet::{Packet, PacketId}, - Event, - Payload, TransportType, + CloseReason, Event, Payload, TransportType, }; #[tokio::test] @@ -977,7 +977,10 @@ mod test { let rx_timeout = timeout(Duration::from_secs(1), rx.recv()).await; assert!(rx_timeout.is_ok()); - assert_eq!(rx_timeout.unwrap(), Some(Payload::from("transport close"))); + assert_eq!( + rx_timeout.unwrap(), + Some(Payload::from(CloseReason::TransportClose.as_str())) + ); Ok(()) } diff --git a/socketio/src/client/raw_client.rs b/socketio/src/client/raw_client.rs index 0686683f..865a9ec6 100644 --- a/socketio/src/client/raw_client.rs +++ b/socketio/src/client/raw_client.rs @@ -1,7 +1,7 @@ use super::callback::Callback; use crate::packet::{Packet, PacketId}; use crate::Error; -pub(crate) use crate::{event::Event, payload::Payload}; +pub(crate) use crate::{event::CloseReason, event::Event, payload::Payload}; use rand::{thread_rng, Rng}; use serde_json::Value; @@ -149,7 +149,7 @@ impl RawClient { let _ = self.socket.send(disconnect_packet); self.socket.disconnect()?; - let _ = self.callback(&Event::Close, ""); // trigger on_close + let _ = self.callback(&Event::Close, CloseReason::IOClientDisconnect.as_str()); // trigger on_close Ok(()) } @@ -372,7 +372,7 @@ impl RawClient { self.callback(&Event::Connect, "")?; } PacketId::Disconnect => { - self.callback(&Event::Close, "")?; + self.callback(&Event::Close, CloseReason::IOServerDisconnect.as_str())?; } PacketId::ConnectError => { self.callback( diff --git a/socketio/src/event.rs b/socketio/src/event.rs index 2d2ed1f9..ef1c65a8 100644 --- a/socketio/src/event.rs +++ b/socketio/src/event.rs @@ -57,3 +57,38 @@ impl Display for Event { f.write_str(self.as_str()) } } + +/// A `CloseReason` is the payload of the [`Event::Close`] and specifies the reason for +/// why it was fired. +/// These are aligned with the official Socket.IO disconnect reasons, see +/// https://socket.io/docs/v4/client-socket-instance/#disconnect +#[derive(Debug, PartialEq, PartialOrd, Clone, Eq, Hash)] +pub enum CloseReason { + IOServerDisconnect, + IOClientDisconnect, + TransportClose, +} + +impl CloseReason { + pub fn as_str(&self) -> &str { + match self { + // Inspired by https://github.com/socketio/socket.io/blob/d0fc72042068e7eaef448941add617f05e1ec236/packages/socket.io-client/lib/socket.ts#L865 + CloseReason::IOServerDisconnect => "io server disconnect", + // Inspired by https://github.com/socketio/socket.io/blob/d0fc72042068e7eaef448941add617f05e1ec236/packages/socket.io-client/lib/socket.ts#L911 + CloseReason::IOClientDisconnect => "io client disconnect", + CloseReason::TransportClose => "transport close", + } + } +} + +impl From for String { + fn from(event: CloseReason) -> Self { + Self::from(event.as_str()) + } +} + +impl Display for CloseReason { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.write_str(self.as_str()) + } +} diff --git a/socketio/src/lib.rs b/socketio/src/lib.rs index b913eb4d..1445cc82 100644 --- a/socketio/src/lib.rs +++ b/socketio/src/lib.rs @@ -191,7 +191,7 @@ pub mod asynchronous; pub use error::Error; -pub use {event::Event, payload::Payload}; +pub use {event::CloseReason, event::Event, payload::Payload}; pub use client::{ClientBuilder, RawClient, TransportType};