slack_rust/socket/
event.rs

1use crate::event_api::event::Event;
2use crate::payloads::interactive::{InteractivePayload, SlashPayload};
3use serde::{Deserialize, Serialize};
4use serde_with::skip_serializing_none;
5
6#[derive(Deserialize, Serialize, Debug, PartialEq)]
7#[serde(tag = "type")]
8pub enum SocketModeEvent {
9    #[serde(rename = "hello")]
10    HelloEvent(HelloEvent),
11    #[serde(rename = "disconnect")]
12    DisconnectEvent(DisconnectEvent),
13    #[serde(rename = "events_api")]
14    EventsAPI(EventsAPI),
15    #[serde(rename = "interactive")]
16    InteractiveEvent(InteractiveEvent),
17    #[serde(rename = "slash_commands")]
18    SlashCommandsEvent(SlashCommandsEvent),
19}
20
21impl SocketModeEvent {
22    pub fn event_type(&self) -> SocketModeEventType {
23        match self {
24            SocketModeEvent::HelloEvent(HelloEvent { .. }) => SocketModeEventType::Hello,
25            SocketModeEvent::DisconnectEvent(DisconnectEvent { .. }) => {
26                SocketModeEventType::Disconnect
27            }
28            SocketModeEvent::EventsAPI(EventsAPI { .. }) => SocketModeEventType::EventsAPI,
29            SocketModeEvent::InteractiveEvent(InteractiveEvent { .. }) => {
30                SocketModeEventType::Interactive
31            }
32            SocketModeEvent::SlashCommandsEvent(SlashCommandsEvent { .. }) => {
33                SocketModeEventType::SlashCommands
34            }
35        }
36    }
37}
38
39#[derive(Deserialize, Serialize, Debug, PartialEq)]
40#[serde(rename_all = "snake_case")]
41pub enum SocketModeEventType {
42    Hello,
43    Disconnect,
44    EventsAPI,
45    Interactive,
46    SlashCommands,
47}
48
49#[skip_serializing_none]
50#[derive(Deserialize, Serialize, Debug, Default, PartialEq)]
51pub struct DebugInfo {
52    pub host: Option<String>,
53    pub started: Option<String>,
54    pub build_number: Option<i32>,
55    pub approximate_connection_time: Option<i32>,
56}
57
58#[skip_serializing_none]
59#[derive(Deserialize, Serialize, Debug, PartialEq)]
60pub struct HelloEvent {
61    pub connection_info: Option<ConnectionInfo>,
62    pub num_connections: Option<i32>,
63    pub debug_info: Option<DebugInfo>,
64}
65
66#[skip_serializing_none]
67#[derive(Deserialize, Serialize, Debug, Default, PartialEq)]
68pub struct ConnectionInfo {
69    pub app_id: Option<String>,
70}
71
72#[skip_serializing_none]
73#[derive(Deserialize, Serialize, Debug, PartialEq)]
74pub struct DisconnectEvent {
75    pub reason: DisconnectReason,
76    pub debug_info: Option<DebugInfo>,
77}
78
79#[derive(Deserialize, Serialize, Debug, PartialEq)]
80#[serde(rename_all = "snake_case")]
81pub enum DisconnectReason {
82    LinkDisabled,
83    Warning,
84    RefreshRequested,
85}
86
87#[skip_serializing_none]
88#[derive(Deserialize, Serialize, Debug, PartialEq)]
89pub struct EventsAPI {
90    pub envelope_id: String,
91    pub accepts_response_payload: bool,
92    pub payload: Event,
93}
94
95#[skip_serializing_none]
96#[derive(Deserialize, Serialize, Debug, PartialEq)]
97pub struct InteractiveEvent {
98    pub envelope_id: String,
99    pub accepts_response_payload: bool,
100    pub payload: InteractivePayload,
101}
102
103#[skip_serializing_none]
104#[derive(Deserialize, Serialize, Debug, PartialEq)]
105pub struct SlashCommandsEvent {
106    pub envelope_id: String,
107    pub accepts_response_payload: bool,
108    pub payload: SlashPayload,
109}
110
111#[skip_serializing_none]
112#[derive(Deserialize, Serialize, Debug, PartialEq)]
113pub struct AcknowledgeMessage<'s> {
114    pub envelope_id: &'s str,
115}
116
117#[cfg(test)]
118mod test {
119    use super::*;
120    use crate::payloads::interactive::InteractiveEventType;
121
122    #[test]
123    fn deserialize_hello_event() {
124        let json = r##"{
125  "type": "hello",
126  "connection_info": {
127    "app_id": "app_id"
128  },
129  "num_connections": 1,
130  "debug_info": {
131    "host": "host"
132  }
133}"##;
134        let event = serde_json::from_str::<SocketModeEvent>(json).unwrap();
135        match event {
136            SocketModeEvent::HelloEvent(HelloEvent {
137                connection_info,
138                num_connections,
139                debug_info,
140            }) => {
141                assert_eq!(connection_info.unwrap().app_id.unwrap(), "app_id");
142                assert_eq!(num_connections.unwrap(), 1);
143                assert_eq!(debug_info.unwrap().host.unwrap(), "host");
144            }
145            _ => panic!("Event deserialize into incorrect variant"),
146        }
147    }
148
149    #[test]
150    fn deserialize_disconnect_event() {
151        let json = r##"{
152  "type": "disconnect",
153  "reason": "link_disabled",
154  "debug_info": {
155    "host": "wss-111.slack.com"
156  }
157}"##;
158        let event = serde_json::from_str::<SocketModeEvent>(json).unwrap();
159        match event {
160            SocketModeEvent::DisconnectEvent(DisconnectEvent { reason, debug_info }) => {
161                assert_eq!(reason, DisconnectReason::LinkDisabled);
162                assert_eq!(debug_info.unwrap().host.unwrap(), "wss-111.slack.com");
163            }
164            _ => panic!("Event deserialize into incorrect variant"),
165        }
166    }
167
168    #[test]
169    fn deserialize_events_api() {
170        let json = r##"{
171  "type": "events_api",
172  "envelope_id": "dbdd0ef3-1543-4f94-bfb4-133d0e6c1545",
173  "accepts_response_payload": false,
174  "payload": {
175    "type": "app_home_opened",
176    "user": "U061F7AUR",
177    "channel": "D0LAN2Q65",
178    "event_ts": "1515449522000016",
179    "tab": "home",
180    "view": {
181      "id": "VPASKP233"
182    }
183  }
184}"##;
185        let event = serde_json::from_str::<SocketModeEvent>(json).unwrap();
186        match event {
187            SocketModeEvent::EventsAPI(EventsAPI {
188                envelope_id,
189                accepts_response_payload,
190                payload,
191            }) => {
192                assert_eq!(envelope_id, "dbdd0ef3-1543-4f94-bfb4-133d0e6c1545");
193                assert!(!accepts_response_payload, "false");
194
195                match payload {
196                    Event::AppHomeOpened { user, .. } => {
197                        assert_eq!(user, "U061F7AUR");
198                    }
199                    _ => panic!("Payload deserialize into incorrect variant"),
200                }
201            }
202            _ => panic!("Event deserialize into incorrect variant"),
203        }
204    }
205
206    #[test]
207    fn deserialize_interactive_event() {
208        let json = r##"{
209  "type": "interactive",
210  "envelope_id": "dbdd0ef3-1543-4f94-bfb4-133d0e6c1545",
211  "accepts_response_payload": true,    
212  "payload": {
213    "type": "view_submission"
214  }
215}"##;
216        let event = serde_json::from_str::<SocketModeEvent>(json).unwrap();
217        match event {
218            SocketModeEvent::InteractiveEvent(InteractiveEvent {
219                envelope_id,
220                accepts_response_payload,
221                payload,
222            }) => {
223                assert_eq!(envelope_id, "dbdd0ef3-1543-4f94-bfb4-133d0e6c1545");
224                assert!(accepts_response_payload, "true");
225                assert_eq!(payload.type_filed, InteractiveEventType::ViewSubmission);
226            }
227            _ => panic!("Event deserialize into incorrect variant"),
228        }
229    }
230
231    #[test]
232    fn deserialize_slash_commands_event() {
233        let json = r##"{
234  "type": "slash_commands",
235  "envelope_id": "dbdd0ef3-1543-4f94-bfb4-133d0e6c1545",
236  "accepts_response_payload": true,
237  "payload": {
238    "token": "bHKJ2n9AW6Ju3MjciOHfbA1b"
239  }
240}"##;
241        let event = serde_json::from_str::<SocketModeEvent>(json).unwrap();
242        match event {
243            SocketModeEvent::SlashCommandsEvent(SlashCommandsEvent {
244                envelope_id,
245                accepts_response_payload,
246                payload,
247            }) => {
248                assert_eq!(envelope_id, "dbdd0ef3-1543-4f94-bfb4-133d0e6c1545");
249                assert!(accepts_response_payload, "true");
250                assert_eq!(payload.token.unwrap(), "bHKJ2n9AW6Ju3MjciOHfbA1b");
251            }
252            _ => panic!("Event deserialize into incorrect variant"),
253        }
254    }
255
256    #[test]
257    fn serialize_acknowledge_message() {
258        let json = serde_json::to_string_pretty(&AcknowledgeMessage {
259            envelope_id: "xxxxxxxxxxxxxxxxxxxxx",
260        })
261        .unwrap();
262
263        let expect = r##"{
264  "envelope_id": "xxxxxxxxxxxxxxxxxxxxx"
265}"##;
266
267        assert_eq!(expect, json);
268    }
269}