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}