Skip to main content

pusher_rs/
events.rs

1use serde::{Serialize, Deserialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct Event {
6    pub event: String,
7    pub channel: Option<String>,
8    #[serde(with = "json_string")]
9    pub data: Value,
10}
11
12impl Event {
13    pub fn new(event: String, channel: Option<String>, data: Value) -> Self {
14        Self {
15            event,
16            channel,
17            data,
18        }
19    }
20
21    pub fn is_system_event(&self) -> bool {
22        self.event.starts_with("pusher:")
23    }
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct SystemEvent {
28    pub event: String,
29    pub channel: Option<String>,
30    pub data: SystemEventData,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(untagged)]
35pub enum SystemEventData {
36    ConnectionEstablished {
37        socket_id: String,
38        activity_timeout: u64,
39    },
40    SubscriptionSucceeded {
41        #[serde(default)]
42        presence: Option<PresenceData>,
43    },
44    MemberAdded {
45        user_id: String,
46        user_info: Value,
47    },
48    MemberRemoved {
49        user_id: String,
50    },
51    Error {
52        code: Option<u32>,
53        message: String,
54    },
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct PresenceData {
59    pub count: u32,
60    pub hash: std::collections::HashMap<String, Value>,
61    pub ids: Vec<String>,
62}
63
64impl SystemEvent {
65    pub fn new(event: String, channel: Option<String>, data: SystemEventData) -> Self {
66        Self {
67            event,
68            channel,
69            data,
70        }
71    }
72
73    pub fn connection_established(socket_id: String, activity_timeout: u64) -> Self {
74        Self::new(
75            "pusher:connection_established".to_string(),
76            None,
77            SystemEventData::ConnectionEstablished {
78                socket_id,
79                activity_timeout,
80            },
81        )
82    }
83
84    pub fn subscription_succeeded(channel: String, presence: Option<PresenceData>) -> Self {
85        Self::new(
86            "pusher:subscription_succeeded".to_string(),
87            Some(channel),
88            SystemEventData::SubscriptionSucceeded { presence },
89        )
90    }
91
92    pub fn member_added(channel: String, user_id: String, user_info: Value) -> Self {
93        Self::new(
94            "pusher:member_added".to_string(),
95            Some(channel),
96            SystemEventData::MemberAdded { user_id, user_info },
97        )
98    }
99
100    pub fn member_removed(channel: String, user_id: String) -> Self {
101        Self::new(
102            "pusher:member_removed".to_string(),
103            Some(channel),
104            SystemEventData::MemberRemoved { user_id },
105        )
106    }
107
108    pub fn error(code: Option<u32>, message: String) -> Self {
109        Self::new(
110            "pusher:error".to_string(),
111            None,
112            SystemEventData::Error { code, message },
113        )
114    }
115}
116
117mod json_string {
118    use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
119    use serde_json::Value;
120
121    pub fn serialize<S>(value: &Value, serializer: S) -> Result<S::Ok, S::Error>
122    where
123        S: Serializer,
124    {
125        value.to_string().serialize(serializer)
126    }
127
128    pub fn deserialize<'de, D>(deserializer: D) -> Result<Value, D::Error>
129    where
130        D: Deserializer<'de>,
131    {
132        let s = String::deserialize(deserializer)?;
133        serde_json::from_str(&s).map_err(D::Error::custom)
134    }
135}
136#[cfg(test)]
137mod tests {
138    use super::*;
139    use serde_json::json;
140
141    #[test]
142    fn test_event_serialization() {
143        let event = Event::new(
144            "test_event".to_string(),
145            Some("test_channel".to_string()),
146            json!({"message": "Hello, world!"}),
147        );
148
149        let serialized = serde_json::to_string(&event).unwrap();
150        let deserialized: Event = serde_json::from_str(&serialized).unwrap();
151
152        assert_eq!(event.event, deserialized.event);
153        assert_eq!(event.channel, deserialized.channel);
154        assert_eq!(event.data, deserialized.data);
155    }
156
157    #[test]
158    fn test_system_event_connection_established() {
159        let event = SystemEvent::connection_established("socket123".to_string(), 120);
160
161        assert_eq!(event.event, "pusher:connection_established");
162        assert_eq!(event.channel, None);
163
164        if let SystemEventData::ConnectionEstablished { socket_id, activity_timeout } = event.data {
165            assert_eq!(socket_id, "socket123");
166            assert_eq!(activity_timeout, 120);
167        } else {
168            panic!("Unexpected event data");
169        }
170    }
171
172    #[test]
173    fn test_system_event_subscription_succeeded() {
174        let presence_data = PresenceData {
175            count: 2,
176            hash: [
177                ("user1".to_string(), json!({"name": "Alice"})),
178                ("user2".to_string(), json!({"name": "Bob"})),
179            ].into_iter().collect(),
180            ids: vec!["user1".to_string(), "user2".to_string()],
181        };
182
183        let event = SystemEvent::subscription_succeeded("presence-channel".to_string(), Some(presence_data));
184
185        assert_eq!(event.event, "pusher:subscription_succeeded");
186        assert_eq!(event.channel, Some("presence-channel".to_string()));
187
188        if let SystemEventData::SubscriptionSucceeded { presence } = event.data {
189            assert!(presence.is_some());
190            let presence = presence.unwrap();
191            assert_eq!(presence.count, 2);
192            assert_eq!(presence.ids, vec!["user1", "user2"]);
193        } else {
194            panic!("Unexpected event data");
195        }
196    }
197
198    #[test]
199    fn test_system_event_member_added() {
200        let event = SystemEvent::member_added(
201            "presence-channel".to_string(),
202            "user3".to_string(),
203            json!({"name": "Charlie"}),
204        );
205
206        assert_eq!(event.event, "pusher:member_added");
207        assert_eq!(event.channel, Some("presence-channel".to_string()));
208
209        if let SystemEventData::MemberAdded { user_id, user_info } = event.data {
210            assert_eq!(user_id, "user3");
211            assert_eq!(user_info, json!({"name": "Charlie"}));
212        } else {
213            panic!("Unexpected event data");
214        }
215    }
216
217    #[test]
218    fn test_system_event_member_removed() {
219        let event = SystemEvent::member_removed("presence-channel".to_string(), "user2".to_string());
220
221        assert_eq!(event.event, "pusher:member_removed");
222        assert_eq!(event.channel, Some("presence-channel".to_string()));
223
224        if let SystemEventData::MemberRemoved { user_id } = event.data {
225            assert_eq!(user_id, "user2");
226        } else {
227            panic!("Unexpected event data");
228        }
229    }
230
231    #[test]
232    fn test_system_event_error() {
233        let event = SystemEvent::error(Some(4004), "Error message".to_string());
234
235        assert_eq!(event.event, "pusher:error");
236        assert_eq!(event.channel, None);
237
238        if let SystemEventData::Error { code, message } = event.data {
239            assert_eq!(code, Some(4004));
240            assert_eq!(message, "Error message");
241        } else {
242            panic!("Unexpected event data");
243        }
244    }
245}
246
247
248impl Event {
249    pub fn is_presence_event(&self) -> bool {
250        matches!(self.event.as_str(), "pusher:member_added" | "pusher:member_removed")
251    }
252
253    pub fn is_subscription_event(&self) -> bool {
254        self.event == "pusher:subscription_succeeded" || self.event == "pusher:subscription_error"
255    }
256
257    pub fn as_system_event(&self) -> Option<SystemEvent> {
258        if self.is_system_event() {
259            serde_json::from_value(serde_json::to_value(self).unwrap()).ok()
260        } else {
261            None
262        }
263    }
264}
265
266
267impl SystemEvent {
268    pub fn is_presence_event(&self) -> bool {
269        matches!(self.event.as_str(), "pusher:member_added" | "pusher:member_removed")
270    }
271
272    pub fn is_subscription_event(&self) -> bool {
273        self.event == "pusher:subscription_succeeded" || self.event == "pusher:subscription_error"
274    }
275
276    pub fn as_event(&self) -> Event {
277        Event {
278            event: self.event.clone(),
279            channel: self.channel.clone(),
280            data: serde_json::to_value(&self.data).unwrap(),
281        }
282    }
283}