twitch_message/messages/
twitch_message.rs

1#![allow(deprecated)]
2use crate::messages::*;
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
6#[allow(deprecated)]
7/// All possible Twitch messages created by this crate
8pub enum TwitchMessage<'a> {
9    /// State received after joining a channel or sending a [`Privmsg`](crate::encode::Privmsg)
10    UserState(UserState<'a>),
11    /// [`USERNOTICE`](https://dev.twitch.tv/docs/irc/commands/#usernotice). Sent when events like someone subscribing to the channel occurs.
12    UserNotice(UserNotice<'a>),
13    /// [`RECONNECT`](https://dev.twitch.tv/docs/irc/commands/#reconnect). is sent when the Twitch IRC server needs to terminate the connection.
14    Reconnect(Reconnect<'a>),
15    #[deprecated(
16        note = "hosting has been deprecated, see https://help.twitch.tv/s/article/how-to-use-host-mode?language=en_US"
17    )]
18    /// A HostTarget of the `/host` command
19    HostTarget(HostTarget<'a>),
20    /// [`ROOMSTATE`](https://dev.twitch.tv/docs/irc/commands/#roomstate). Sent when the bot joins a channel or when the channel’s chat settings change.
21    RoomState(RoomState<'a>),
22    /// A 001 IRC-styled Ready
23    IrcReady(IrcReady<'a>),
24    /// A user posts a message to the chat room.
25    Privmsg(Privmsg<'a>),
26    /// Sent when a `WHISPER` message is directed specifically to the connected user.
27    Whisper(Whisper<'a>),
28    /// [`NOTICE`](https://dev.twitch.tv/docs/irc/commands/#notice) Sent to indicate the outcome of an action like banning a user.
29    #[deprecated(
30        note = "twitch has deprecated chat commands through irc, see https://discuss.dev.twitch.tv/t/deprecation-of-chat-commands-through-irc/40486 "
31    )]
32    Notice(Notice<'a>),
33    /// Tests the presence of a connection. A [PING](Self) message results in a [PONG](crate::encode::Pong) reply.
34    Ping(Ping<'a>),
35    /// This command is a reply to the [PING](crate::encode::Ping) command
36    Pong(Pong<'a>),
37    /// A TMI-styled ready, sent after [`IrcReady`](super::IrcReady)
38    Ready(Ready<'a>),
39    /// [`GLOBALUSERSTATE`](https://dev.twitch.tv/docs/irc/commands/#globaluserstate) command. The Twitch IRC server sends this message after the bot authenticates with the server.
40    GlobalUserState(GlobalUserState<'a>),
41    /// [`CLEARMSG`](https://dev.twitch.tv/docs/irc/commands/#clearmsg) command. Sent when a bot or user with moderator privileges deletes a single message from the chat room.
42    ClearMsg(ClearMsg<'a>),
43    /// A capability signals extra functionality, received when requesting capabilities on server join
44    Capability(Capability<'a>),
45    /// [`CLEARCHAT`](https://dev.twitch.tv/docs/irc/commands/#clearchat) command. Sent when a bot or moderator removes all messages from the chat room or removes all messages for the specified user.
46    ClearChat(ClearChat<'a>),
47    /// A twitch chat message.
48    ///
49    /// This is a 'catchall' for when a message cannot be turned into a [`self::TwitchMessage`]
50    Message(Message<'a>),
51}
52
53impl<'a> From<UserState<'a>> for TwitchMessage<'a> {
54    #[inline]
55    fn from(ty: UserState<'a>) -> Self {
56        Self::UserState(ty)
57    }
58}
59
60impl<'a, 'b: 'a> From<&'b UserState<'a>> for TwitchMessage<'a> {
61    #[inline]
62    fn from(ty: &'b UserState<'a>) -> Self {
63        Self::UserState(ty.clone())
64    }
65}
66
67impl<'a> From<UserNotice<'a>> for TwitchMessage<'a> {
68    #[inline]
69    fn from(ty: UserNotice<'a>) -> Self {
70        Self::UserNotice(ty)
71    }
72}
73
74impl<'a, 'b: 'a> From<&'b UserNotice<'a>> for TwitchMessage<'a> {
75    #[inline]
76    fn from(ty: &'b UserNotice<'a>) -> Self {
77        Self::UserNotice(ty.clone())
78    }
79}
80
81impl<'a> From<Reconnect<'a>> for TwitchMessage<'a> {
82    #[inline]
83    fn from(ty: Reconnect<'a>) -> Self {
84        Self::Reconnect(ty)
85    }
86}
87
88impl<'a, 'b: 'a> From<&'b Reconnect<'a>> for TwitchMessage<'a> {
89    #[inline]
90    fn from(ty: &'b Reconnect<'a>) -> Self {
91        Self::Reconnect(ty.clone())
92    }
93}
94
95impl<'a> From<HostTarget<'a>> for TwitchMessage<'a> {
96    #[inline]
97    fn from(ty: HostTarget<'a>) -> Self {
98        Self::HostTarget(ty)
99    }
100}
101
102impl<'a, 'b: 'a> From<&'b HostTarget<'a>> for TwitchMessage<'a> {
103    #[inline]
104    fn from(ty: &'b HostTarget<'a>) -> Self {
105        Self::HostTarget(ty.clone())
106    }
107}
108
109impl<'a> From<RoomState<'a>> for TwitchMessage<'a> {
110    #[inline]
111    fn from(ty: RoomState<'a>) -> Self {
112        Self::RoomState(ty)
113    }
114}
115
116impl<'a, 'b: 'a> From<&'b RoomState<'a>> for TwitchMessage<'a> {
117    #[inline]
118    fn from(ty: &'b RoomState<'a>) -> Self {
119        Self::RoomState(ty.clone())
120    }
121}
122
123impl<'a> From<IrcReady<'a>> for TwitchMessage<'a> {
124    #[inline]
125    fn from(ty: IrcReady<'a>) -> Self {
126        Self::IrcReady(ty)
127    }
128}
129
130impl<'a, 'b: 'a> From<&'b IrcReady<'a>> for TwitchMessage<'a> {
131    #[inline]
132    fn from(ty: &'b IrcReady<'a>) -> Self {
133        Self::IrcReady(ty.clone())
134    }
135}
136
137impl<'a> From<Privmsg<'a>> for TwitchMessage<'a> {
138    #[inline]
139    fn from(ty: Privmsg<'a>) -> Self {
140        Self::Privmsg(ty)
141    }
142}
143
144impl<'a, 'b: 'a> From<&'b Privmsg<'a>> for TwitchMessage<'a> {
145    #[inline]
146    fn from(ty: &'b Privmsg<'a>) -> Self {
147        Self::Privmsg(ty.clone())
148    }
149}
150
151impl<'a> From<Whisper<'a>> for TwitchMessage<'a> {
152    #[inline]
153    fn from(ty: Whisper<'a>) -> Self {
154        Self::Whisper(ty)
155    }
156}
157
158impl<'a, 'b: 'a> From<&'b Whisper<'a>> for TwitchMessage<'a> {
159    #[inline]
160    fn from(ty: &'b Whisper<'a>) -> Self {
161        Self::Whisper(ty.clone())
162    }
163}
164
165impl<'a> From<Notice<'a>> for TwitchMessage<'a> {
166    #[inline]
167    fn from(ty: Notice<'a>) -> Self {
168        Self::Notice(ty)
169    }
170}
171
172impl<'a, 'b: 'a> From<&'b Notice<'a>> for TwitchMessage<'a> {
173    #[inline]
174    fn from(ty: &'b Notice<'a>) -> Self {
175        Self::Notice(ty.clone())
176    }
177}
178
179impl<'a> From<Ping<'a>> for TwitchMessage<'a> {
180    #[inline]
181    fn from(ty: Ping<'a>) -> Self {
182        Self::Ping(ty)
183    }
184}
185
186impl<'a, 'b: 'a> From<&'b Ping<'a>> for TwitchMessage<'a> {
187    #[inline]
188    fn from(ty: &'b Ping<'a>) -> Self {
189        Self::Ping(ty.clone())
190    }
191}
192
193impl<'a> From<Pong<'a>> for TwitchMessage<'a> {
194    #[inline]
195    fn from(ty: Pong<'a>) -> Self {
196        Self::Pong(ty)
197    }
198}
199
200impl<'a, 'b: 'a> From<&'b Pong<'a>> for TwitchMessage<'a> {
201    #[inline]
202    fn from(ty: &'b Pong<'a>) -> Self {
203        Self::Pong(ty.clone())
204    }
205}
206
207impl<'a> From<Ready<'a>> for TwitchMessage<'a> {
208    #[inline]
209    fn from(ty: Ready<'a>) -> Self {
210        Self::Ready(ty)
211    }
212}
213
214impl<'a, 'b: 'a> From<&'b Ready<'a>> for TwitchMessage<'a> {
215    #[inline]
216    fn from(ty: &'b Ready<'a>) -> Self {
217        Self::Ready(ty.clone())
218    }
219}
220
221impl<'a> From<GlobalUserState<'a>> for TwitchMessage<'a> {
222    #[inline]
223    fn from(ty: GlobalUserState<'a>) -> Self {
224        Self::GlobalUserState(ty)
225    }
226}
227
228impl<'a, 'b: 'a> From<&'b GlobalUserState<'a>> for TwitchMessage<'a> {
229    #[inline]
230    fn from(ty: &'b GlobalUserState<'a>) -> Self {
231        Self::GlobalUserState(ty.clone())
232    }
233}
234
235impl<'a> From<ClearMsg<'a>> for TwitchMessage<'a> {
236    #[inline]
237    fn from(ty: ClearMsg<'a>) -> Self {
238        Self::ClearMsg(ty)
239    }
240}
241
242impl<'a, 'b: 'a> From<&'b ClearMsg<'a>> for TwitchMessage<'a> {
243    #[inline]
244    fn from(ty: &'b ClearMsg<'a>) -> Self {
245        Self::ClearMsg(ty.clone())
246    }
247}
248
249impl<'a> From<Capability<'a>> for TwitchMessage<'a> {
250    #[inline]
251    fn from(ty: Capability<'a>) -> Self {
252        Self::Capability(ty)
253    }
254}
255
256impl<'a, 'b: 'a> From<&'b Capability<'a>> for TwitchMessage<'a> {
257    #[inline]
258    fn from(ty: &'b Capability<'a>) -> Self {
259        Self::Capability(ty.clone())
260    }
261}
262
263impl<'a> From<ClearChat<'a>> for TwitchMessage<'a> {
264    #[inline]
265    fn from(ty: ClearChat<'a>) -> Self {
266        Self::ClearChat(ty)
267    }
268}
269
270impl<'a, 'b: 'a> From<&'b ClearChat<'a>> for TwitchMessage<'a> {
271    #[inline]
272    fn from(ty: &'b ClearChat<'a>) -> Self {
273        Self::ClearChat(ty.clone())
274    }
275}
276
277impl<'a> From<Message<'a>> for TwitchMessage<'a> {
278    #[inline]
279    fn from(ty: Message<'a>) -> Self {
280        Self::Message(ty)
281    }
282}
283
284impl<'a, 'b: 'a> From<&'b Message<'a>> for TwitchMessage<'a> {
285    #[inline]
286    fn from(ty: &'b Message<'a>) -> Self {
287        Self::Message(ty.clone())
288    }
289}
290
291#[cfg(test)]
292mod tests {
293    use super::*;
294
295    #[test]
296    fn conversion() {
297        use std::borrow::Cow;
298
299        let inputs = [
300"@emote-only=0;followers-only=-1;r9k=0;room-id=23196011;slow=0;subs-only=0 :tmi.twitch.tv ROOMSTATE #museun\r\n",
301":tmi.twitch.tv RECONNECT\r\n",
302":tmi.twitch.tv 376 museun :>\r\n",
303"PONG :1234567890\r\n",
304"PING :1234567890\r\n",
305":tmi.twitch.tv 001 museun :Welcome, GLHF!\r\n",
306":tmi.twitch.tv HOSTTARGET #museun :shaken_bot 10\r\n",
307"@room-id=12345678;tmi-sent-ts=1642715695392 :tmi.twitch.tv CLEARCHAT #museun :shaken_bot\r\n",
308"@room-id=12345678;tmi-sent-ts=1642715695392 :tmi.twitch.tv CLEARMSG #museun :Kappa\r\n",
309":tmi.twitch.tv CAP * ACK :foobar\r\n",
310"@emote-only=0;followers-only=-1;r9k=0;room-id=23196011;slow=0;subs-only=0 :tmi.twitch.tv ROOMSTATE #museun\r\n",
311":museun!museun@museun.tmi.twitch.tv PRIVMSG #museun :hello world\r\n",
312"@room-id=12345678;tmi-sent-ts=1642715695392 :museun!museun@museun.tmi.twitch.tv WHISPER shaken_bot :this is a test\r\n",
313"@badge-info=;badges=premium/1;color=#008000;display-name=museun;emote-sets=0,19194,300374282,300597048,301337952,460515209,537206155,564265402,592920959,610186276;user-id=23196011;user-type= :tmi.twitch.tv GLOBALUSERSTATE\r\n"
314        ];
315
316        let expected = vec![
317            TwitchMessage::RoomState(RoomState {
318                tags: Tags::default(),
319                raw: Cow::default(),
320            }),
321            TwitchMessage::Reconnect(Reconnect {
322                raw: Cow::default(),
323            }),
324            TwitchMessage::Ready(Ready {
325                name: Cow::default(),
326                raw: Cow::default(),
327            }),
328            TwitchMessage::Pong(Pong {
329                token: Cow::default(),
330                raw: Cow::default(),
331            }),
332            TwitchMessage::Ping(Ping {
333                token: Cow::default(),
334                raw: Cow::default(),
335            }),
336            TwitchMessage::IrcReady(IrcReady {
337                name: Cow::default(),
338                raw: Cow::default(),
339            }),
340            TwitchMessage::HostTarget(HostTarget {
341                raw: Cow::default(),
342                hosting_channel: Cow::default(),
343                host_mode: HostMode::End { viewers: 0 },
344            }),
345            TwitchMessage::ClearChat(ClearChat {
346                raw: Cow::default(),
347                channel: Cow::default(),
348                target: ClearChatTarget::All,
349                tags: Tags::default(),
350            }),
351            TwitchMessage::ClearMsg(ClearMsg {
352                raw: Cow::default(),
353                channel: Cow::default(),
354                message: Cow::default(),
355                tags: Tags::default(),
356            }),
357            TwitchMessage::Capability(Capability {
358                acknowledged: false,
359                kind: Cow::default(),
360                raw: Cow::default(),
361            }),
362            TwitchMessage::RoomState(RoomState {
363                tags: Tags::default(),
364                raw: Cow::default(),
365            }),
366            TwitchMessage::Privmsg(Privmsg {
367                channel: Cow::default(),
368                sender: Cow::default(),
369                tags: Tags::default(),
370                data: Cow::default(),
371                raw: Cow::default(),
372            }),
373            TwitchMessage::Whisper(Whisper {
374                raw: Cow::default(),
375                from_user: Cow::default(),
376                to_user: Cow::default(),
377                data: Cow::default(),
378                tags: Tags::default(),
379            }),
380            TwitchMessage::GlobalUserState(GlobalUserState {
381                tags: Tags::default(),
382                raw: Cow::default(),
383            }),
384        ];
385
386        let expected = expected.iter().map(std::mem::discriminant);
387
388        for (input, discriminant) in inputs.into_iter().zip(expected) {
389            let res = crate::parse(input).unwrap();
390            assert!(res.remaining.is_empty());
391
392            let e = res.message.as_enum();
393            assert_eq!(std::mem::discriminant(&e), discriminant);
394
395            let e = res.message.into_enum();
396            assert_eq!(std::mem::discriminant(&e), discriminant)
397        }
398    }
399}