1use crate::*;
2use crate::{Deserialise, Serialise};
3
4macro_rules! from_string {
5 ($enum_name:ident { $($variant:ident),* }) => {
6 pub fn from_string(t: &str) -> Option<$enum_name> {
7 $(
8 if $enum_name::$variant.tag() == t {
9 return Some($enum_name::$variant);
10 }
11 )*
12 None
13 }
14 };
15}
16
17macro_rules! from_scope {
18 ($enum_name:ident { $($variant:ident),* }) => {
19 pub fn from_scope(t: &str) -> Option<$enum_name> {
20 $(
21 if $enum_name::$variant.required_scope().contains(&t) {
22 return Some($enum_name::$variant);
23 }
24 )*
25 None
26 }
27 };
28}
29
30#[derive(Clone, Debug, PartialEq)]
31pub enum Subscription {
32 UserUpdate,
33 ChannelFollow,
34 ChannelRaid,
35 ChannelUpdate,
36 ChannelNewSubscription,
37 ChannelSubscriptionEnd,
38 ChannelGiftSubscription,
39 ChannelResubscription,
40 ChannelCheer,
41 ChannelPointsCustomRewardRedeem,
42 ChannelPointsAutoRewardRedeem,
43 ChannelPollBegin,
44 ChannelPollProgress,
45 ChannelPollEnd,
46 ChannelPredictionBegin,
47 ChannelPredictionProgress,
48 ChannelPredictionLock,
49 ChannelPredictionEnd,
50 ChannelGoalBegin,
51 ChannelGoalProgress,
52 ChannelGoalEnd,
53 ChannelHypeTrainBegin,
54 ChannelHypeTrainProgress,
55 ChannelHypeTrainEnd,
56 ChannelShoutoutCreate,
57 ChannelShoutoutReceive,
58 ChannelMessageDeleted,
59 ChatMessage,
60 AdBreakBegin,
61 PermissionBanTimeoutUser,
62 PermissionDeleteMessage,
63 PermissionReadChatters,
64 PermissionReadModerator,
65 PermissionManageRewards,
66 PermissionSendAnnouncements,
67 PermissionIRCRead,
68 PermissionIRCWrite,
69 Custom((String, String, EventSubscription)),
70}
71
72#[derive(Serialise, Deserialise, Debug, Clone, PartialEq)]
73pub struct EventSubscription {
74 #[serde(rename = "type")]
75 pub kind: String,
76 pub version: String,
77 pub condition: Condition,
78 pub transport: Transport,
79}
80
81impl Subscription {
82 pub fn is_permission_subscription(&self) -> bool {
83 match self {
84 Subscription::PermissionBanTimeoutUser
85 | Subscription::PermissionDeleteMessage
86 | Subscription::PermissionReadChatters
87 | Subscription::PermissionReadModerator
88 | Subscription::PermissionManageRewards
89 | Subscription::PermissionSendAnnouncements
90 | Subscription::PermissionIRCRead
91 | Subscription::PermissionIRCWrite => true,
92 _ => false,
93 }
94 }
95
96 from_string!(Subscription {
97 UserUpdate,
98 ChannelFollow,
99 ChannelRaid,
100 ChannelUpdate,
101 ChannelNewSubscription,
102 ChannelSubscriptionEnd,
103 ChannelGiftSubscription,
104 ChannelResubscription,
105 ChannelCheer,
106 ChannelPointsCustomRewardRedeem,
107 ChannelPointsAutoRewardRedeem,
108 ChannelPollBegin,
109 ChannelPollProgress,
110 ChannelPollEnd,
111 ChannelPredictionBegin,
112 ChannelPredictionProgress,
113 ChannelPredictionLock,
114 ChannelPredictionEnd,
115 ChannelGoalBegin,
116 ChannelGoalProgress,
117 ChannelGoalEnd,
118 ChannelHypeTrainBegin,
119 ChannelHypeTrainProgress,
120 ChannelHypeTrainEnd,
121 ChannelShoutoutCreate,
122 ChannelShoutoutReceive,
123 ChannelMessageDeleted,
124 ChatMessage,
125 PermissionBanTimeoutUser,
126 PermissionDeleteMessage,
127 PermissionReadChatters,
128 PermissionReadModerator,
129 PermissionManageRewards,
130 PermissionSendAnnouncements,
131 PermissionIRCRead,
132 PermissionIRCWrite,
133 AdBreakBegin
134 });
135
136 from_scope!(Subscription {
137 UserUpdate,
138 ChannelFollow,
139 ChannelRaid,
140 ChannelUpdate,
141 ChannelNewSubscription,
142 ChannelSubscriptionEnd,
143 ChannelGiftSubscription,
144 ChannelResubscription,
145 ChannelCheer,
146 ChannelPointsCustomRewardRedeem,
147 ChannelPointsAutoRewardRedeem,
148 ChannelPollBegin,
149 ChannelPollProgress,
150 ChannelPollEnd,
151 ChannelPredictionBegin,
152 ChannelPredictionProgress,
153 ChannelPredictionLock,
154 ChannelPredictionEnd,
155 ChannelGoalBegin,
156 ChannelGoalProgress,
157 ChannelGoalEnd,
158 ChannelHypeTrainBegin,
159 ChannelHypeTrainProgress,
160 ChannelHypeTrainEnd,
161 ChannelShoutoutCreate,
162 ChannelShoutoutReceive,
163 ChannelMessageDeleted,
164 ChatMessage,
165 PermissionBanTimeoutUser,
166 PermissionDeleteMessage,
167 PermissionReadChatters,
168 PermissionReadModerator,
169 PermissionManageRewards,
170 PermissionSendAnnouncements,
171 PermissionIRCRead,
172 PermissionIRCWrite,
173 AdBreakBegin
174 });
175
176 fn details(&self) -> (String, String, String) {
177 let details = match self {
178 Subscription::UserUpdate => ("user.update", "", "1"),
179 Subscription::ChannelFollow => ("channel.follow", "moderator:read:followers", "2"),
180 Subscription::ChannelRaid => ("channel.raid", "", "1"),
181 Subscription::ChatMessage => (
182 "channel.chat.message",
183 "user:read:chat+user:write:chat",
184 "1",
185 ),
186 Subscription::ChannelPointsCustomRewardRedeem => (
187 "channel.channel_points_custom_reward_redemption.add",
188 "channel:read:redemptions",
189 "1",
190 ),
191 Subscription::AdBreakBegin => ("channel.ad_break.begin", "channel:read:ads", "1"),
192 Subscription::ChannelUpdate => ("channel.update", "", "2"),
193 Subscription::ChannelNewSubscription => {
194 ("channel.subscribe", "channel:read:subscriptions", "1")
195 }
196 Subscription::ChannelSubscriptionEnd => (
197 "channel.subscription.end",
198 "channel:read:subscriptions",
199 "1",
200 ),
201 Subscription::ChannelGiftSubscription => (
202 "channel.subscription.gift",
203 "channel:read:subscriptions",
204 "1",
205 ),
206 Subscription::ChannelResubscription => (
207 "channel.subscription.message",
208 "channel:read:subscriptions",
209 "1",
210 ),
211 Subscription::ChannelCheer => ("channel.cheer", "bits:read", "1"),
212 Subscription::ChannelPointsAutoRewardRedeem => (
213 "channel.channel_points_automatic_reward_redemption.add",
214 "channel:read:redemptions+channel:manage:redemptions",
215 "1",
216 ),
217 Subscription::ChannelPollBegin => (
218 "channel.poll.begin",
219 "channel:read:polls+channel:manage:polls",
220 "1",
221 ),
222 Subscription::ChannelPollProgress => (
223 "channel.poll.progress",
224 "channel:read:polls+channel:manage:polls",
225 "1",
226 ),
227 Subscription::ChannelPollEnd => (
228 "channel.poll.end",
229 "channel:read:polls+channel:manage:polls",
230 "1",
231 ),
232 Subscription::ChannelPredictionBegin => (
233 "channel.prediction.begin",
234 "channel:read:predictions+channel:manage:predictions",
235 "1",
236 ),
237 Subscription::ChannelPredictionProgress => (
238 "channel.prediction.progress",
239 "channel:read:predictions+channel:manage:predictions",
240 "1",
241 ),
242 Subscription::ChannelPredictionLock => (
243 "channel.prediction.lock",
244 "channel:read:predictions+channel:manage:predictions",
245 "1",
246 ),
247 Subscription::ChannelPredictionEnd => (
248 "channel.prediction.end",
249 "channel:read:predictions+channel:manage:predictions",
250 "1",
251 ),
252 Subscription::ChannelGoalBegin => ("channel.goal.begin", "channel:read:goals", "1"),
253 Subscription::ChannelGoalProgress => ("channel.goal.progress", "channel:read:goals", "1"),
254 Subscription::ChannelGoalEnd => ("channel.goal.end", "channel:read:goals", "1"),
255 Subscription::ChannelHypeTrainBegin => {
256 ("channel.hype_train.begin", "channel:read:hype_train", "1")
257 }
258 Subscription::ChannelHypeTrainProgress => (
259 "channel.hype_train.progress",
260 "channel:read:hype_train",
261 "1",
262 ),
263 Subscription::ChannelHypeTrainEnd => {
264 ("channel.hype_train.end", "channel:read:hype_train", "1")
265 }
266 Subscription::ChannelShoutoutCreate => (
267 "channel.shoutout.create",
268 "moderator:read:shoutouts+moderator:manage:shoutouts",
269 "1",
270 ),
271 Subscription::ChannelShoutoutReceive => (
272 "channel.shoutout.receive",
273 "moderator:read:shoutouts+moderator:manage:shoutouts",
274 "1",
275 ),
276 Subscription::ChannelMessageDeleted => ("channel.chat.message_delete", "user:read:chat", "1"),
277 Subscription::PermissionBanTimeoutUser => ("", "moderator:manage:banned_users", ""),
278 Subscription::PermissionDeleteMessage => ("", "moderator:manage:chat_messages", ""),
279 Subscription::PermissionReadChatters => ("", "moderator:read:chatters", ""),
280 Subscription::PermissionReadModerator => ("", "moderation:read", ""),
281 Subscription::PermissionManageRewards => ("", "channel:manage:redemptions", ""),
282 Subscription::PermissionSendAnnouncements => ("", "moderator:manage:announcements", ""),
283 Subscription::PermissionIRCRead => ("", "chat:read", ""),
284 Subscription::PermissionIRCWrite => ("", "chat:edit", ""),
285 Subscription::Custom((tag, scope, ..)) => (tag.as_str(), scope.as_str(), ""),
286 };
287
288 (
289 details.0.to_owned(),
290 details.1.to_owned(),
291 details.2.to_owned(),
292 )
293 }
294
295 pub fn tag(&self) -> String {
296 self.details().0
297 }
298
299 pub fn required_scope(&self) -> String {
300 self.details().1
301 }
302
303 pub fn version(&self) -> String {
304 self.details().2
305 }
306
307 pub fn construct_data<S: Into<String>, T: Into<String>>(
308 &self,
309 session_id: &str,
310 broadcaster_account_id: S,
311 token_user_id: T,
312 ) -> Option<EventSubscription> {
313 let transport = Transport::new(session_id);
314
315 if self.tag().is_empty() {
316 return None;
317 }
318
319 let broadcaster_account_id = broadcaster_account_id.into();
320 let user_id_in_access_token = token_user_id.into();
321
322 let event_subscription = EventSubscription::new(self, transport);
323 let condition = Condition::new().broadcaster_user_id(broadcaster_account_id.to_owned());
324
325 Some(match self {
326 Subscription::ChannelFollow => event_subscription
327 .condition(condition.moderator_user_id(user_id_in_access_token.to_owned())),
328 Subscription::ChannelRaid => event_subscription
329 .condition(condition.to_broadcaster_user_id(broadcaster_account_id.clone())),
330 Subscription::ChannelMessageDeleted
331 | Subscription::PermissionManageRewards
332 | Subscription::ChatMessage
333 | Subscription::UserUpdate => {
334 event_subscription.condition(condition.user_id(user_id_in_access_token.to_owned()))
335 }
336 Subscription::ChannelShoutoutReceive | Subscription::ChannelShoutoutCreate => {
337 event_subscription
338 .condition(condition.moderator_user_id(user_id_in_access_token.to_owned()))
339 }
340 Subscription::ChannelNewSubscription
341 | Subscription::ChannelSubscriptionEnd
342 | Subscription::ChannelGiftSubscription
343 | Subscription::ChannelResubscription
344 | Subscription::ChannelCheer
345 | Subscription::ChannelPollBegin
346 | Subscription::ChannelPollProgress
347 | Subscription::ChannelPollEnd
348 | Subscription::ChannelPredictionBegin
349 | Subscription::ChannelPredictionProgress
350 | Subscription::ChannelPredictionLock
351 | Subscription::ChannelPredictionEnd
352 | Subscription::ChannelHypeTrainBegin
353 | Subscription::ChannelHypeTrainProgress
354 | Subscription::ChannelHypeTrainEnd
355 | Subscription::ChannelPointsAutoRewardRedeem
356 | Subscription::ChannelUpdate
357 | Subscription::AdBreakBegin
358 | Subscription::ChannelPointsCustomRewardRedeem => event_subscription.condition(condition),
359 Subscription::Custom((_, _, event)) => event.to_owned().transport(Transport::new(session_id)),
360
361 _ => event_subscription,
362 })
363 }
364}
365
366impl EventSubscription {
367 pub fn new(event: &Subscription, transport: Transport) -> EventSubscription {
368 EventSubscription {
369 kind: event.tag(),
370 version: event.version(),
371 condition: Condition::new(),
372 transport,
373 }
374 }
375
376 pub fn transport(mut self, transport: Transport) -> EventSubscription {
377 self.transport = transport;
378 self
379 }
380
381 pub fn condition(mut self, condition: Condition) -> EventSubscription {
382 self.condition = condition;
383 self
384 }
385}
386
387#[derive(Serialise, Deserialise, Debug, Clone, Default, PartialEq)]
388pub struct Condition {
389 pub user_id: Option<String>,
390 pub moderator_user_id: Option<String>,
391 pub broadcaster_user_id: Option<String>,
392 pub reward_id: Option<String>,
393 pub from_broadcaster_user_id: Option<String>,
394 pub to_broadcaster_user_id: Option<String>,
395 #[serde(rename = "organization_id")]
396 pub organisation_id: Option<String>,
397 pub category_id: Option<String>,
398 pub campaign_id: Option<String>,
399 pub extension_client_id: Option<String>,
400}
401
402impl Condition {
403 pub fn new() -> Condition {
404 Condition {
405 ..Default::default()
406 }
407 }
408
409 pub fn user_id<S: Into<String>>(mut self, user_id: S) -> Condition {
410 self.user_id = Some(user_id.into());
411 self
412 }
413
414 pub fn moderator_user_id<S: Into<String>>(mut self, moderator_user_id: S) -> Condition {
415 self.moderator_user_id = Some(moderator_user_id.into());
416 self
417 }
418
419 pub fn broadcaster_user_id<S: Into<String>>(mut self, broadcaster_user_id: S) -> Condition {
420 self.broadcaster_user_id = Some(broadcaster_user_id.into());
421 self
422 }
423
424 pub fn reward_id<S: Into<String>>(mut self, reward_id: S) -> Condition {
425 self.reward_id = Some(reward_id.into());
426 self
427 }
428
429 pub fn from_broadcaster_user_id<S: Into<String>>(
430 mut self,
431 from_broadcaster_user_id: S,
432 ) -> Condition {
433 self.from_broadcaster_user_id = Some(from_broadcaster_user_id.into());
434 self
435 }
436
437 pub fn to_broadcaster_user_id<S: Into<String>>(mut self, to_broadcaster_user_id: S) -> Condition {
438 self.to_broadcaster_user_id = Some(to_broadcaster_user_id.into());
439 self
440 }
441}