Skip to main content

chat_system/
channel_type.rs

1//! Channel/platform type definitions and capabilities.
2
3use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::str::FromStr;
6
7/// Supported inbound message delivery modes.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub enum InboundMode {
10    None,
11    Polling,
12    GatewayLoop,
13    SocketMode,
14    Webhook,
15}
16
17/// Capabilities of a particular channel type.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
19pub struct ChannelCapabilities {
20    pub inbound_mode: InboundMode,
21    pub supports_outbound: bool,
22    pub supports_streaming: bool,
23    pub supports_interactive: bool,
24    pub supports_threads: bool,
25    pub supports_voice_ingest: bool,
26    pub supports_pairing: bool,
27    pub supports_otp: bool,
28    pub supports_reactions: bool,
29    pub supports_location: bool,
30    /// Whether the platform supports editing sent messages.
31    pub supports_editing: bool,
32    /// Whether the platform supports deleting sent messages.
33    pub supports_deletion: bool,
34    /// Whether the platform supports file/media uploads.
35    pub supports_file_upload: bool,
36    /// Maximum message length in characters (0 = unknown/unlimited).
37    pub max_message_length: usize,
38}
39
40/// Descriptor combining a channel type with its display name and capabilities.
41#[derive(Debug, Clone, Copy)]
42pub struct ChannelDescriptor {
43    pub channel_type: ChannelType,
44    pub display_name: &'static str,
45    pub capabilities: ChannelCapabilities,
46}
47
48/// All supported chat platform / channel types.
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
50#[serde(rename_all = "lowercase")]
51pub enum ChannelType {
52    Telegram,
53    Whatsapp,
54    #[serde(rename = "msteams")]
55    MsTeams,
56    Discord,
57    Slack,
58    Irc,
59    Matrix,
60    Signal,
61    GoogleChat,
62    IMessage,
63    Console,
64    Webhook,
65}
66
67impl ChannelType {
68    pub const ALL: &'static [ChannelType] = &[
69        ChannelType::Telegram,
70        ChannelType::Whatsapp,
71        ChannelType::MsTeams,
72        ChannelType::Discord,
73        ChannelType::Slack,
74        ChannelType::Irc,
75        ChannelType::Matrix,
76        ChannelType::Signal,
77        ChannelType::GoogleChat,
78        ChannelType::IMessage,
79        ChannelType::Console,
80        ChannelType::Webhook,
81    ];
82
83    pub fn as_str(&self) -> &'static str {
84        match self {
85            ChannelType::Telegram => "telegram",
86            ChannelType::Whatsapp => "whatsapp",
87            ChannelType::MsTeams => "msteams",
88            ChannelType::Discord => "discord",
89            ChannelType::Slack => "slack",
90            ChannelType::Irc => "irc",
91            ChannelType::Matrix => "matrix",
92            ChannelType::Signal => "signal",
93            ChannelType::GoogleChat => "googlechat",
94            ChannelType::IMessage => "imessage",
95            ChannelType::Console => "console",
96            ChannelType::Webhook => "webhook",
97        }
98    }
99
100    pub fn display_name(&self) -> &'static str {
101        match self {
102            ChannelType::Telegram => "Telegram",
103            ChannelType::Whatsapp => "WhatsApp",
104            ChannelType::MsTeams => "Microsoft Teams",
105            ChannelType::Discord => "Discord",
106            ChannelType::Slack => "Slack",
107            ChannelType::Irc => "IRC",
108            ChannelType::Matrix => "Matrix",
109            ChannelType::Signal => "Signal",
110            ChannelType::GoogleChat => "Google Chat",
111            ChannelType::IMessage => "iMessage",
112            ChannelType::Console => "Console",
113            ChannelType::Webhook => "Webhook",
114        }
115    }
116
117    pub fn descriptor(&self) -> ChannelDescriptor {
118        let caps = match self {
119            ChannelType::Telegram => ChannelCapabilities {
120                inbound_mode: InboundMode::Polling,
121                supports_outbound: true,
122                supports_streaming: true,
123                supports_interactive: false,
124                supports_threads: false,
125                supports_voice_ingest: true,
126                supports_pairing: false,
127                supports_otp: true,
128                supports_reactions: true,
129                supports_location: true,
130                supports_editing: true,
131                supports_deletion: true,
132                supports_file_upload: true,
133                max_message_length: 4096,
134            },
135            ChannelType::Whatsapp => ChannelCapabilities {
136                inbound_mode: InboundMode::GatewayLoop,
137                supports_outbound: true,
138                supports_streaming: true,
139                supports_interactive: false,
140                supports_threads: false,
141                supports_voice_ingest: true,
142                supports_pairing: true,
143                supports_otp: true,
144                supports_reactions: true,
145                supports_location: false,
146                supports_editing: true,
147                supports_deletion: true,
148                supports_file_upload: true,
149                max_message_length: 65536,
150            },
151            ChannelType::MsTeams => ChannelCapabilities {
152                inbound_mode: InboundMode::Webhook,
153                supports_outbound: true,
154                supports_streaming: true,
155                supports_interactive: false,
156                supports_threads: false,
157                supports_voice_ingest: false,
158                supports_pairing: false,
159                supports_otp: false,
160                supports_reactions: true,
161                supports_location: true,
162                supports_editing: true,
163                supports_deletion: true,
164                supports_file_upload: true,
165                max_message_length: 28000,
166            },
167            ChannelType::Discord => ChannelCapabilities {
168                inbound_mode: InboundMode::GatewayLoop,
169                supports_outbound: true,
170                supports_streaming: true,
171                supports_interactive: true,
172                supports_threads: true,
173                supports_voice_ingest: false,
174                supports_pairing: false,
175                supports_otp: false,
176                supports_reactions: true,
177                supports_location: true,
178                supports_editing: true,
179                supports_deletion: true,
180                supports_file_upload: true,
181                max_message_length: 2000,
182            },
183            ChannelType::Slack => ChannelCapabilities {
184                inbound_mode: InboundMode::SocketMode,
185                supports_outbound: true,
186                supports_streaming: true,
187                supports_interactive: true,
188                supports_threads: true,
189                supports_voice_ingest: false,
190                supports_pairing: false,
191                supports_otp: false,
192                supports_reactions: true,
193                supports_location: false,
194                supports_editing: true,
195                supports_deletion: true,
196                supports_file_upload: true,
197                max_message_length: 40000,
198            },
199            ChannelType::Irc => ChannelCapabilities {
200                inbound_mode: InboundMode::GatewayLoop,
201                supports_outbound: true,
202                supports_streaming: false,
203                supports_interactive: false,
204                supports_threads: false,
205                supports_voice_ingest: false,
206                supports_pairing: false,
207                supports_otp: false,
208                supports_reactions: false,
209                supports_location: false,
210                supports_editing: false,
211                supports_deletion: false,
212                supports_file_upload: false,
213                max_message_length: 512,
214            },
215            ChannelType::Matrix => ChannelCapabilities {
216                inbound_mode: InboundMode::GatewayLoop,
217                supports_outbound: true,
218                supports_streaming: true,
219                supports_interactive: false,
220                supports_threads: true,
221                supports_voice_ingest: false,
222                supports_pairing: false,
223                supports_otp: false,
224                supports_reactions: true,
225                supports_location: false,
226                supports_editing: true,
227                supports_deletion: true,
228                supports_file_upload: true,
229                max_message_length: 65536,
230            },
231            ChannelType::Signal => ChannelCapabilities {
232                inbound_mode: InboundMode::GatewayLoop,
233                supports_outbound: true,
234                supports_streaming: false,
235                supports_interactive: false,
236                supports_threads: false,
237                supports_voice_ingest: true,
238                supports_pairing: false,
239                supports_otp: false,
240                supports_reactions: true,
241                supports_location: false,
242                supports_editing: false,
243                supports_deletion: true,
244                supports_file_upload: true,
245                max_message_length: 0,
246            },
247            ChannelType::GoogleChat => ChannelCapabilities {
248                inbound_mode: InboundMode::Webhook,
249                supports_outbound: true,
250                supports_streaming: false,
251                supports_interactive: false,
252                supports_threads: false,
253                supports_voice_ingest: false,
254                supports_pairing: false,
255                supports_otp: false,
256                supports_reactions: true,
257                supports_location: false,
258                supports_editing: true,
259                supports_deletion: true,
260                supports_file_upload: true,
261                max_message_length: 4096,
262            },
263            ChannelType::IMessage => ChannelCapabilities {
264                inbound_mode: InboundMode::Polling,
265                supports_outbound: true,
266                supports_streaming: false,
267                supports_interactive: false,
268                supports_threads: false,
269                supports_voice_ingest: false,
270                supports_pairing: false,
271                supports_otp: false,
272                supports_reactions: true,
273                supports_location: false,
274                supports_editing: false,
275                supports_deletion: false,
276                supports_file_upload: true,
277                max_message_length: 0,
278            },
279            ChannelType::Console => ChannelCapabilities {
280                inbound_mode: InboundMode::None,
281                supports_outbound: true,
282                supports_streaming: false,
283                supports_interactive: false,
284                supports_threads: false,
285                supports_voice_ingest: false,
286                supports_pairing: false,
287                supports_otp: false,
288                supports_reactions: false,
289                supports_location: false,
290                supports_editing: false,
291                supports_deletion: false,
292                supports_file_upload: false,
293                max_message_length: 0,
294            },
295            ChannelType::Webhook => ChannelCapabilities {
296                inbound_mode: InboundMode::None,
297                supports_outbound: true,
298                supports_streaming: false,
299                supports_interactive: false,
300                supports_threads: false,
301                supports_voice_ingest: false,
302                supports_pairing: false,
303                supports_otp: false,
304                supports_reactions: false,
305                supports_location: false,
306                supports_editing: false,
307                supports_deletion: false,
308                supports_file_upload: false,
309                max_message_length: 0,
310            },
311        };
312        ChannelDescriptor {
313            channel_type: *self,
314            display_name: self.display_name(),
315            capabilities: caps,
316        }
317    }
318}
319
320impl fmt::Display for ChannelType {
321    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322        f.write_str(self.as_str())
323    }
324}
325
326impl FromStr for ChannelType {
327    type Err = anyhow::Error;
328
329    fn from_str(s: &str) -> Result<Self, Self::Err> {
330        match s.to_lowercase().as_str() {
331            "telegram" => Ok(ChannelType::Telegram),
332            "whatsapp" => Ok(ChannelType::Whatsapp),
333            "msteams" | "teams" | "microsoft teams" => Ok(ChannelType::MsTeams),
334            "discord" => Ok(ChannelType::Discord),
335            "slack" => Ok(ChannelType::Slack),
336            "irc" => Ok(ChannelType::Irc),
337            "matrix" => Ok(ChannelType::Matrix),
338            "signal" => Ok(ChannelType::Signal),
339            "googlechat" | "google chat" => Ok(ChannelType::GoogleChat),
340            "imessage" => Ok(ChannelType::IMessage),
341            "console" => Ok(ChannelType::Console),
342            "webhook" => Ok(ChannelType::Webhook),
343            other => Err(anyhow::anyhow!("unknown channel type: {}", other)),
344        }
345    }
346}