twitcheventsub_structs/
subscriptions.rs

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}