Skip to main content

tf_rust_socketio/
payload.rs

1use bytes::Bytes;
2
3/// A type which represents a `payload` in the `socket.io` context.
4/// A payload could either be of the type `Payload::Binary`, which holds
5/// data in the [`Bytes`] type that represents the payload or of the type
6/// `Payload::String` which holds a [`std::string::String`]. The enum is
7/// used for both representing data that's send and data that's received.
8/// The optional `i32` field represents the ack ID if this payload
9/// requires acknowledgment from the server.
10#[derive(Debug, PartialEq, Eq, Clone)]
11pub enum Payload {
12    Binary(Bytes, Option<i32>),
13    Text(Vec<serde_json::Value>, Option<i32>),
14    #[deprecated = "Use `Payload::Text` instead. Continue existing behavior with: Payload::from(String)"]
15    /// String that is sent as JSON if this is a JSON string, or as a raw string if it isn't
16    String(String, Option<i32>),
17}
18
19impl Payload {
20    pub(crate) fn string_to_value(string: String) -> serde_json::Value {
21        if let Ok(value) = serde_json::from_str::<serde_json::Value>(&string) {
22            value
23        } else {
24            serde_json::Value::String(string)
25        }
26    }
27}
28
29impl From<&str> for Payload {
30    fn from(string: &str) -> Self {
31        Payload::from(string.to_owned())
32    }
33}
34
35impl Payload {
36    /// 创建一个带ack_id的payload
37    pub fn with_ack_id<T: Into<Self>>(payload: T, ack_id: i32) -> Self {
38        #[allow(deprecated)]
39        match payload.into() {
40            Payload::Binary(data, _) => Payload::Binary(data, Some(ack_id)),
41            Payload::Text(data, _) => Payload::Text(data, Some(ack_id)),
42            Payload::String(data, _) => Payload::String(data, Some(ack_id)),
43        }
44    }
45
46    /// 获取payload的ack_id
47    pub fn ack_id(&self) -> Option<i32> {
48        #[allow(deprecated)]
49        match self {
50            Payload::Binary(_, ack_id) => *ack_id,
51            Payload::Text(_, ack_id) => *ack_id,
52            Payload::String(_, ack_id) => *ack_id,
53        }
54    }
55
56    /// 设置payload的ack_id
57    pub fn set_ack_id(&mut self, ack_id: Option<i32>) {
58        #[allow(deprecated)]
59        match self {
60            Payload::Binary(_, id) => *id = ack_id,
61            Payload::Text(_, id) => *id = ack_id,
62            Payload::String(_, id) => *id = ack_id,
63        }
64    }
65
66    /// 获取payload的数据部分(不包含ack_id)
67    pub fn data(&self) -> PayloadData<'_> {
68        #[allow(deprecated)]
69        match self {
70            Payload::Binary(data, _) => PayloadData::Binary(data),
71            Payload::Text(data, _) => PayloadData::Text(data),
72            Payload::String(data, _) => PayloadData::String(data),
73        }
74    }
75}
76
77/// Payload的数据部分(不包含ack_id)
78#[derive(Debug, PartialEq, Eq, Clone)]
79pub enum PayloadData<'a> {
80    Binary(&'a Bytes),
81    Text(&'a Vec<serde_json::Value>),
82    String(&'a String),
83}
84
85impl From<String> for Payload {
86    fn from(string: String) -> Self {
87        Self::Text(vec![Payload::string_to_value(string)], None)
88    }
89}
90
91impl From<Vec<String>> for Payload {
92    fn from(arr: Vec<String>) -> Self {
93        Self::Text(
94            arr.into_iter().map(Payload::string_to_value).collect(),
95            None,
96        )
97    }
98}
99
100impl From<Vec<serde_json::Value>> for Payload {
101    fn from(values: Vec<serde_json::Value>) -> Self {
102        Self::Text(values, None)
103    }
104}
105
106impl From<serde_json::Value> for Payload {
107    fn from(value: serde_json::Value) -> Self {
108        Self::Text(vec![value], None)
109    }
110}
111
112impl From<Vec<u8>> for Payload {
113    fn from(val: Vec<u8>) -> Self {
114        Self::Binary(Bytes::from(val), None)
115    }
116}
117
118impl From<&'static [u8]> for Payload {
119    fn from(val: &'static [u8]) -> Self {
120        Self::Binary(Bytes::from_static(val), None)
121    }
122}
123
124impl From<Bytes> for Payload {
125    fn from(bytes: Bytes) -> Self {
126        Self::Binary(bytes, None)
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use serde_json::json;
133
134    use super::*;
135
136    #[test]
137    fn test_from_string() {
138        let sut = Payload::from("foo ™");
139
140        assert_eq!(
141            Payload::Text(vec![serde_json::Value::String(String::from("foo ™"))], None),
142            sut
143        );
144
145        let sut = Payload::from(String::from("foo ™"));
146        assert_eq!(
147            Payload::Text(vec![serde_json::Value::String(String::from("foo ™"))], None),
148            sut
149        );
150
151        let sut = Payload::from(json!("foo ™"));
152        assert_eq!(
153            Payload::Text(vec![serde_json::Value::String(String::from("foo ™"))], None),
154            sut
155        );
156    }
157
158    #[test]
159    fn test_from_multiple_strings() {
160        let input = vec![
161            "one".to_owned(),
162            "two".to_owned(),
163            json!(["foo", "bar"]).to_string(),
164        ];
165
166        assert_eq!(
167            Payload::Text(
168                vec![
169                    serde_json::Value::String(String::from("one")),
170                    serde_json::Value::String(String::from("two")),
171                    json!(["foo", "bar"])
172                ],
173                None
174            ),
175            Payload::from(input)
176        );
177    }
178
179    #[test]
180    fn test_from_multiple_json() {
181        let input = vec![json!({"foo": "bar"}), json!("foo"), json!(["foo", "bar"])];
182
183        assert_eq!(
184            Payload::Text(input.clone(), None),
185            Payload::from(input.clone())
186        );
187    }
188
189    #[test]
190    fn test_from_json() {
191        let json = json!({
192            "foo": "bar"
193        });
194        let sut = Payload::from(json.clone());
195
196        assert_eq!(Payload::Text(vec![json.clone()], None), sut);
197
198        // From JSON encoded string
199        let sut = Payload::from(json.to_string());
200
201        assert_eq!(Payload::Text(vec![json], None), sut);
202    }
203
204    #[test]
205    fn test_from_binary() {
206        let sut = Payload::from(vec![1, 2, 3]);
207        assert_eq!(Payload::Binary(Bytes::from_static(&[1, 2, 3]), None), sut);
208
209        let sut = Payload::from(&[1_u8, 2_u8, 3_u8][..]);
210        assert_eq!(Payload::Binary(Bytes::from_static(&[1, 2, 3]), None), sut);
211
212        let sut = Payload::from(Bytes::from_static(&[1, 2, 3]));
213        assert_eq!(Payload::Binary(Bytes::from_static(&[1, 2, 3]), None), sut);
214    }
215
216    #[test]
217    fn test_payload_with_ack_id() {
218        let payload = Payload::from("test");
219        let payload_with_ack = Payload::with_ack_id(payload, 123);
220
221        assert_eq!(payload_with_ack.ack_id(), Some(123));
222
223        match payload_with_ack {
224            Payload::Text(data, Some(ack_id)) => {
225                assert_eq!(data, vec![serde_json::Value::String("test".to_string())]);
226                assert_eq!(ack_id, 123);
227            }
228            _ => panic!("Expected Text payload with ack_id"),
229        }
230    }
231
232    #[test]
233    fn test_payload_set_ack_id() {
234        let mut payload = Payload::from(vec![1, 2, 3]);
235        assert_eq!(payload.ack_id(), None);
236
237        payload.set_ack_id(Some(456));
238        assert_eq!(payload.ack_id(), Some(456));
239
240        payload.set_ack_id(None);
241        assert_eq!(payload.ack_id(), None);
242    }
243
244    #[test]
245    fn test_payload_data() {
246        let payload = Payload::with_ack_id(json!("test"), 789);
247
248        match payload.data() {
249            PayloadData::Text(data) => {
250                assert_eq!(data, &vec![json!("test")]);
251            }
252            _ => panic!("Expected Text data"),
253        }
254
255        // Original payload still has ack_id
256        assert_eq!(payload.ack_id(), Some(789));
257    }
258}