twitch_irc/message/commands/
roomstate.rs1use crate::message::commands::IRCMessageParseExt;
2use crate::message::{IRCMessage, ServerMessageParseError};
3use std::convert::TryFrom;
4use std::time::Duration;
5
6#[cfg(feature = "with-serde")]
7use {serde::Deserialize, serde::Serialize};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
17#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
18pub struct RoomStateMessage {
19 pub channel_login: String,
21 pub channel_id: String,
23
24 pub emote_only: Option<bool>,
32
33 pub followers_only: Option<FollowersOnlyMode>,
38
39 pub r9k: Option<bool>,
44
45 pub slow_mode: Option<Duration>,
55
56 pub subscribers_only: Option<bool>,
61
62 pub source: IRCMessage,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
68#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
69pub enum FollowersOnlyMode {
70 Disabled,
73
74 Enabled(Duration),
85}
86
87impl TryFrom<IRCMessage> for RoomStateMessage {
88 type Error = ServerMessageParseError;
89
90 fn try_from(source: IRCMessage) -> Result<RoomStateMessage, ServerMessageParseError> {
91 if source.command != "ROOMSTATE" {
92 return Err(ServerMessageParseError::MismatchedCommand(Box::new(source)));
93 }
94
95 Ok(RoomStateMessage {
106 channel_login: source.try_get_channel_login()?.to_owned(),
107 channel_id: source.try_get_nonempty_tag_value("room-id")?.to_owned(),
108 emote_only: source.try_get_optional_bool("emote-only")?,
109 followers_only: source
110 .try_get_optional_number::<i64>("followers-only")?
111 .map(|n| match n {
112 n if n >= 0 => FollowersOnlyMode::Enabled(Duration::from_secs((n * 60) as u64)),
113 _ => FollowersOnlyMode::Disabled,
114 }),
115 r9k: source.try_get_optional_bool("r9k")?,
116 slow_mode: source
117 .try_get_optional_number::<u64>("slow")?
118 .map(Duration::from_secs),
119 subscribers_only: source.try_get_optional_bool("subs-only")?,
120 source,
121 })
122 }
123}
124
125impl From<RoomStateMessage> for IRCMessage {
126 fn from(msg: RoomStateMessage) -> IRCMessage {
127 msg.source
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use crate::message::commands::roomstate::FollowersOnlyMode;
134 use crate::message::{IRCMessage, RoomStateMessage};
135 use std::convert::TryFrom;
136 use std::time::Duration;
137
138 #[test]
139 pub fn test_basic_full() {
140 let src = "@emote-only=0;followers-only=-1;r9k=0;rituals=0;room-id=40286300;slow=0;subs-only=0 :tmi.twitch.tv ROOMSTATE #randers";
141 let irc_message = IRCMessage::parse(src).unwrap();
142 let msg = RoomStateMessage::try_from(irc_message.clone()).unwrap();
143
144 assert_eq!(
145 msg,
146 RoomStateMessage {
147 channel_login: "randers".to_owned(),
148 channel_id: "40286300".to_owned(),
149 emote_only: Some(false),
150 followers_only: Some(FollowersOnlyMode::Disabled),
151 r9k: Some(false),
152 slow_mode: Some(Duration::from_secs(0)),
153 subscribers_only: Some(false),
154 source: irc_message
155 }
156 );
157 }
158
159 #[test]
160 pub fn test_basic_full2() {
161 let src = "@emote-only=1;followers-only=0;r9k=1;rituals=0;room-id=40286300;slow=5;subs-only=1 :tmi.twitch.tv ROOMSTATE #randers";
162 let irc_message = IRCMessage::parse(src).unwrap();
163 let msg = RoomStateMessage::try_from(irc_message.clone()).unwrap();
164
165 assert_eq!(
166 msg,
167 RoomStateMessage {
168 channel_login: "randers".to_owned(),
169 channel_id: "40286300".to_owned(),
170 emote_only: Some(true),
171 followers_only: Some(FollowersOnlyMode::Enabled(Duration::from_secs(0))),
172 r9k: Some(true),
173 slow_mode: Some(Duration::from_secs(5)),
174 subscribers_only: Some(true),
175 source: irc_message
176 }
177 );
178 }
179
180 #[test]
181 pub fn test_followers_non_zero() {
182 let src = "@emote-only=1;followers-only=10;r9k=1;rituals=0;room-id=40286300;slow=5;subs-only=1 :tmi.twitch.tv ROOMSTATE #randers";
183 let irc_message = IRCMessage::parse(src).unwrap();
184 let msg = RoomStateMessage::try_from(irc_message).unwrap();
185
186 assert_eq!(
187 msg.followers_only,
188 Some(FollowersOnlyMode::Enabled(Duration::from_secs(10 * 60))) );
190 }
191
192 #[test]
193 pub fn test_partial_1() {
194 let src = "@room-id=40286300;slow=5 :tmi.twitch.tv ROOMSTATE #randers";
195 let irc_message = IRCMessage::parse(src).unwrap();
196 let msg = RoomStateMessage::try_from(irc_message.clone()).unwrap();
197
198 assert_eq!(
199 msg,
200 RoomStateMessage {
201 channel_login: "randers".to_owned(),
202 channel_id: "40286300".to_owned(),
203 emote_only: None,
204 followers_only: None,
205 r9k: None,
206 slow_mode: Some(Duration::from_secs(5)),
207 subscribers_only: None,
208 source: irc_message
209 }
210 );
211 }
212
213 #[test]
214 pub fn test_partial_2() {
215 let src = "@emote-only=1;room-id=40286300 :tmi.twitch.tv ROOMSTATE #randers";
216 let irc_message = IRCMessage::parse(src).unwrap();
217 let msg = RoomStateMessage::try_from(irc_message.clone()).unwrap();
218
219 assert_eq!(
220 msg,
221 RoomStateMessage {
222 channel_login: "randers".to_owned(),
223 channel_id: "40286300".to_owned(),
224 emote_only: Some(true),
225 followers_only: None,
226 r9k: None,
227 slow_mode: None,
228 subscribers_only: None,
229 source: irc_message
230 }
231 );
232 }
233}