1#![doc(alias = "raids")]
2use crate::{pubsub, types};
4use serde_derive::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
8#[serde(into = "String", try_from = "String")]
9pub struct Raid {
10 pub channel_id: u32,
12}
13
14impl_de_ser!(Raid, "raid", channel_id);
15
16impl pubsub::Topic for Raid {
17 #[cfg(feature = "twitch_oauth2")]
18 const SCOPE: twitch_oauth2::Validator = twitch_oauth2::validator![];
19
20 fn into_topic(self) -> pubsub::Topics { super::Topics::Raid(self) }
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
25#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
26#[non_exhaustive]
27pub struct RaidGoV2 {
28 pub creator_id: types::UserId,
30 pub force_raid_now_seconds: i64,
32 pub id: String,
34 pub source_id: types::UserId,
36 pub target_display_name: types::DisplayName,
38 pub target_id: types::UserId,
40 pub target_login: types::UserName,
42 pub target_profile_image: String,
44 pub transition_jitter_seconds: i64,
46 pub viewer_count: i64,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
52#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
53#[non_exhaustive]
54pub struct RaidUpdateV2 {
55 pub creator_id: types::UserId,
57 pub force_raid_now_seconds: i64,
59 pub id: String,
61 pub source_id: types::UserId,
63 pub target_display_name: types::DisplayName,
65 pub target_id: types::UserId,
67 pub target_login: types::UserName,
69 pub target_profile_image: String,
71 pub transition_jitter_seconds: i64,
73 pub viewer_count: i64,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
79#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
80#[non_exhaustive]
81pub struct RaidCancelV2 {
82 pub creator_id: types::UserId,
84 pub force_raid_now_seconds: i64,
86 pub id: String,
88 pub source_id: types::UserId,
90 pub target_display_name: types::DisplayName,
92 pub target_id: types::UserId,
94 pub target_login: types::UserName,
96 pub target_profile_image: String,
98 pub transition_jitter_seconds: i64,
100 pub viewer_count: i64,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
106#[serde(tag = "type", content = "raid")]
107#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
108#[non_exhaustive]
109pub enum RaidReply {
110 #[serde(rename = "raid_go_v2")]
112 RaidGoV2(RaidGoV2),
113 #[serde(rename = "raid_update_v2")]
115 RaidUpdateV2(RaidUpdateV2),
116 #[serde(rename = "raid_cancel_v2")]
118 RaidCancelV2(RaidCancelV2),
119}
120
121#[cfg(test)]
122mod tests {
123 use super::super::{Response, TopicData};
124 use super::*;
125
126 #[test]
127 fn raid() {
128 let message = r##"
129{
130 "type": "raid_go_v2",
131 "raid": {
132 "id": "7fbea6d0-1337-4c61-8c92-b7510e639010",
133 "creator_id": "27620241",
134 "source_id": "27620241",
135 "target_id": "1234",
136 "target_login": "tmi",
137 "target_display_name": "TMI",
138 "target_profile_image": "https://static-cdn.jtvnw.net/jtv_user_pictures/tmi-profile_image-deadbeef1234-70x70.jpeg",
139 "transition_jitter_seconds": 5,
140 "force_raid_now_seconds": 90,
141 "viewer_count": 5238
142 }
143}
144"##;
145
146 let source = format!(
147 r#"{{"type": "MESSAGE", "data": {{ "topic": "raid.27620241", "message": {message:?} }}}}"#
148 );
149 let actual = dbg!(Response::parse(&source).unwrap());
150 assert!(matches!(
151 actual,
152 Response::Message {
153 data: TopicData::Raid { .. },
154 }
155 ));
156 }
157
158 #[test]
159 fn raid_update() {
160 let message = r##"
161{
162 "type": "raid_update_v2",
163 "raid": {
164 "id": "7fbea6d0-4087-48e7-a395-c0ecd15ef551",
165 "creator_id": "123455",
166 "source_id": "123455",
167 "target_id": "123",
168 "target_login": "tmi",
169 "target_display_name": "tmi",
170 "target_profile_image": "https://static-cdn.jtvnw.net/jtv_user_pictures/deadbeef-profile_image-70x70.png",
171 "transition_jitter_seconds": 0,
172 "force_raid_now_seconds": 90,
173 "viewer_count": 143
174 }
175}
176"##;
177
178 let source = format!(
179 r#"{{"type": "MESSAGE", "data": {{ "topic": "raid.27620241", "message": {message:?} }}}}"#
180 );
181 let actual = dbg!(Response::parse(&source).unwrap());
182 assert!(matches!(
183 actual,
184 Response::Message {
185 data: TopicData::Raid { .. },
186 }
187 ));
188 }
189
190 #[test]
191 fn raid_cancel() {
192 let message = r##"
193{
194 "type": "raid_cancel_v2",
195 "raid": {
196 "id": "7fbea6d0-5b4b-4b8f-a79d-c9e94bf88bbf",
197 "creator_id": "123455",
198 "source_id": "123455",
199 "target_id": "123",
200 "target_login": "tmi",
201 "target_display_name": "TMI",
202 "target_profile_image": "https://static-cdn.jtvnw.net/jtv_user_pictures/deadbeef-profile_image-70x70.png",
203 "transition_jitter_seconds": 4,
204 "force_raid_now_seconds": 90,
205 "viewer_count": 4463
206 }
207}
208"##;
209
210 let source = format!(
211 r#"{{"type": "MESSAGE", "data": {{ "topic": "raid.27620241", "message": {message:?} }}}}"#
212 );
213 let actual = dbg!(Response::parse(&source).unwrap());
214 assert!(matches!(
215 actual,
216 Response::Message {
217 data: TopicData::Raid { .. },
218 }
219 ));
220 }
221
222 #[test]
223 fn check_deser() {
224 use std::convert::TryInto as _;
225 let s = "raid.1234";
226 assert_eq!(Raid { channel_id: 1234 }, s.to_string().try_into().unwrap());
227 }
228
229 #[test]
230 fn check_ser() {
231 let s = "raid.1234";
232 let right: String = Raid { channel_id: 1234 }.into();
233 assert_eq!(s.to_string(), right);
234 }
235}