Repository: 1c3t3a/rust-socketio (language: rust)

Issue:
Multiple payload still broke
https://github.com/1c3t3a/rust-socketio/pull/392/files#diff-dd5d6ff18628a21723847133d6e54ab531454037b62be81d2c42109d333aeab9L481

https://github.com/1c3t3a/rust-socketio/pull/392/files#diff-58d0f04893e736959d245d946a723085fd60d5b9fd211a5e3eac8c2a4b8821f6L315

https://github.com/1c3t3a/rust-socketio/pull/392/files#diff-58d0f04893e736959d245d946a723085fd60d5b9fd211a5e3eac8c2a4b8821f6L347


Discussion / hints:

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index eee14527..f082b771 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -705,9 +705,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
 
 [[package]]
 name = "form_urlencoded"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
 dependencies = [
  "percent-encoding",
 ]
@@ -1034,9 +1034,9 @@ dependencies = [
 
 [[package]]
 name = "idna"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
 dependencies = [
  "unicode-bidi",
  "unicode-normalization",
@@ -1455,9 +1455,9 @@ dependencies = [
 
 [[package]]
 name = "percent-encoding"
-version = "2.3.0"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pin-project-lite"
@@ -2313,9 +2313,9 @@ checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
 
 [[package]]
 name = "url"
-version = "2.4.1"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
+checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
 dependencies = [
  "form_urlencoded",
  "idna",
diff --git a/ci/socket-io.js b/ci/socket-io.js
index f1996cdb..37649712 100644
--- a/ci/socket-io.js
+++ b/ci/socket-io.js
@@ -43,6 +43,10 @@ var callback = client => {
     client.emit('This is the first argument', 'This is the second argument', {
         argCount: 3
     });
+    client.emit('on_abc_event', '', {
+        abc: 0,
+        some_other: 'value',
+    });
 };
 io.on('connection', callback);
 io.of('/admin').on('connection', callback);
diff --git a/engineio/src/packet.rs b/engineio/src/packet.rs
index 010ed930..9238428f 100644
--- a/engineio/src/packet.rs
+++ b/engineio/src/packet.rs
@@ -1,4 +1,3 @@
-extern crate base64;
 use base64::{engine::general_purpose, Engine as _};
 use bytes::{BufMut, Bytes, BytesMut};
 use serde::{Deserialize, Serialize};
diff --git a/socketio/src/asynchronous/client/client.rs b/socketio/src/asynchronous/client/client.rs
index bece41e7..67feb7db 100644
--- a/socketio/src/asynchronous/client/client.rs
+++ b/socketio/src/asynchronous/client/client.rs
@@ -461,29 +461,26 @@ impl Client {
         };
 
         // a socketio message always comes in one of the following two flavors (both JSON):
-        // 1: `["event", "msg"]`
+        // 1: `["event", "msg", ...]`
         // 2: `["msg"]`
         // in case 2, the message is ment for the default message event, in case 1 the event
         // is specified
         if let Ok(Value::Array(contents)) = serde_json::from_str::<Value>(data) {
-            let (event, data) = if contents.len() > 1 {
-                // case 1
-                let event = match contents.first() {
-                    Some(Value::String(ev)) => Event::from(ev.as_str()),
-                    _ => Event::Message,
-                };
-
-                (event, contents.get(1).ok_or(Error::IncompletePacket())?)
-            } else {
-                // case 2
-                (
-                    Event::Message,
-                    contents.first().ok_or(Error::IncompletePacket())?,
-                )
+            let (event, payloads) = match contents.len() {
+                0 => return Err(Error::IncompletePacket()),
+                // Incorrect packet, ignore it
+                1 => (Event::Message, contents.as_slice()),
+                // it's a message event
+                _ => match contents.first() {
+                    Some(Value::String(ev)) => (Event::from(ev.as_str()), &contents[1..]),
+                    // get rest(1..) of them as data, not just take the 2nd element
+                    _ => (Event::Message, contents.as_slice()),
+                    // take them all as data
+                },
             };
 
             // call the correct callback
-            self.callback(&event, data.to_string()).await?;
+            self.callback(&event, payloads.to_vec()).await?;
         }
 
         Ok(())
@@ -1067,6 +1064,33 @@ mod test {
             )
         );
 
+        let packet: Option<Packet> = Some(socket_stream.next().await.unwrap()?);
+
+        assert!(packet.is_some());
+
+        let packet = packet.unwrap();
+        assert_eq!(
+            packet,
+            Packet::new(
+                PacketId::Event,
+                nsp.clone(),
+                Some(
+                    serde_json::json!([
+                        "on_abc_event",
+                        "",
+                        {
+                        "abc": 0,
+                        "some_other": "value",
+                        }
+                    ])
+                    .to_string()
+                ),
+                None,
+                0,
+                None,
+            )
+        );
+
         let cb = |message: Payload, _| {
             async {
                 println!("Yehaa! My ack got acked?");
diff --git a/socketio/src/client/raw_client.rs b/socketio/src/client/raw_client.rs
index b8299139..0686683f 100644
--- a/socketio/src/client/raw_client.rs
+++ b/socketio/src/client/raw_client.rs
@@ -288,14 +288,13 @@ impl RawClient {
                 }
 
                 if let Some(ref attachments) = socket_packet.attachments {
-                    if let Some(payload) = attachments.get(0) {
+                    if let Some(payload) = attachments.first() {
                         ack.callback.deref_mut()(Payload::Binary(payload.to_owned()), self.clone());
                     }
                 }
-            } else {
-                // Do something with timed out acks?
             }
-
+            // nope, just ignore it, the official implment just remove the ack id when timeout
+            // https://github.com/socketio/socket.io-client/blob/main/lib/socket.ts#L467-L495
             false
         });
 
@@ -312,7 +311,7 @@ impl RawClient {
         };
 
         if let Some(attachments) = &packet.attachments {
-            if let Some(binary_payload) = attachments.get(0) {
+            if let Some(binary_payload) = attachments.first() {
                 self.callback(&event, Payload::Binary(binary_payload.to_owned()))?;
             }
         }
@@ -327,29 +326,25 @@ impl RawClient {
         };
 
         // a socketio message always comes in one of the following two flavors (both JSON):
-        // 1: `["event", "msg"]`
+        // 1: `["event", "msg", ...]`
         // 2: `["msg"]`
         // in case 2, the message is ment for the default message event, in case 1 the event
         // is specified
         if let Ok(Value::Array(contents)) = serde_json::from_str::<Value>(data) {
-            let (event, data) = if contents.len() > 1 {
-                // case 1
-                let event = match contents.first() {
-                    Some(Value::String(ev)) => Event::from(ev.as_str()),
-                    _ => Event::Message,
-                };
-
-                (event, contents.get(1).ok_or(Error::IncompletePacket())?)
-            } else {
-                // case 2
-                (
-                    Event::Message,
-                    contents.first().ok_or(Error::IncompletePacket())?,
-                )
+            let (event, payloads) = match contents.len() {
+                0 => return Err(Error::IncompletePacket()),
+                1 => (Event::Message, contents.as_slice()),
+                // get rest of data if first is a event
+                _ => match contents.first() {
+                    Some(Value::String(ev)) => (Event::from(ev.as_str()), &contents[1..]),
+                    // get rest(1..) of them as data, not just take the 2nd element
+                    _ => (Event::Message, contents.as_slice()),
+                    // take them all as data
+                },
             };
 
             // call the correct callback
-            self.callback(&event, data.to_string())?;
+            self.callback(&event, payloads.to_vec())?;
         }
 
         Ok(())
@@ -751,6 +746,33 @@ mod test {
             )
         );
 
+        let packet: Option<Packet> = iter.next();
+
+        assert!(packet.is_some());
+
+        let packet = packet.unwrap();
+        assert_eq!(
+            packet,
+            Packet::new(
+                PacketId::Event,
+                nsp.clone(),
+                Some(
+                    serde_json::json!([
+                        "on_abc_event",
+                        "",
+                        {
+                        "abc": 0,
+                        "some_other": "value",
+                        }
+                    ])
+                    .to_string()
+                ),
+                None,
+                0,
+                None,
+            )
+        );
+
         assert!(socket
             .emit_with_ack(
                 "test",


Test patch: