rust_unity/
lib.rs

1extern crate rand;
2
3use rand::Rng;
4use std::ffi::{c_char, CStr, CString};
5use std::mem::transmute;
6
7use serde::{Deserialize as Deserialise, Serialize as Serialise};
8
9use twitcheventsub::*;
10
11pub struct TwitchEvents {
12  api: TwitchEventSubApi,
13}
14
15#[derive(Debug, Deserialise, Default)]
16pub struct UnitySubscriptions {
17  chat_message: bool,
18  user_update: bool,
19  follow: bool,
20  raid: bool,
21  update: bool,
22  new_subscription: bool,
23  subscription_end: bool,
24  gift_subscription: bool,
25  resubscription: bool,
26  cheer: bool,
27  points_custom_reward_redeem: bool,
28  points_auto_reward_redeem: bool,
29  poll_begin: bool,
30  poll_progress: bool,
31  poll_end: bool,
32  prediction_begin: bool,
33  prediction_progress: bool,
34  prediction_lock: bool,
35  prediction_end: bool,
36  goal_begin: bool,
37  goal_progress: bool,
38  goal_end: bool,
39  hype_train_begin: bool,
40  hype_train_progress: bool,
41  hype_train_end: bool,
42  shoutout_create: bool,
43  shoutout_receive: bool,
44  ban_timeout_user: bool,
45  delete_message: bool,
46  ad_break_begin: bool,
47}
48
49impl UnitySubscriptions {
50  pub fn new() -> UnitySubscriptions {
51    UnitySubscriptions {
52      user_update: false,
53      follow: true,
54      raid: true,
55      update: false,
56      new_subscription: true,
57      subscription_end: false,
58      gift_subscription: true,
59      resubscription: true,
60      cheer: true,
61      points_custom_reward_redeem: true,
62      points_auto_reward_redeem: true,
63      poll_begin: false,
64      poll_progress: false,
65      poll_end: false,
66      prediction_begin: false,
67      prediction_progress: false,
68      prediction_lock: false,
69      prediction_end: false,
70      goal_begin: false,
71      goal_progress: false,
72      goal_end: false,
73      hype_train_begin: false,
74      hype_train_progress: false,
75      hype_train_end: false,
76      shoutout_create: false,
77      shoutout_receive: false,
78      ban_timeout_user: false,
79      delete_message: false,
80      ad_break_begin: true,
81      chat_message: true,
82    }
83  }
84}
85
86#[no_mangle]
87pub extern "C" fn create_twitch_events(subscriptions: *const c_char) -> *mut TwitchEvents {
88  let keys = TwitchKeys::from_secrets_env().unwrap();
89  let subscriptions: UnitySubscriptions =
90    serde_json::from_str(unsafe { CStr::from_ptr(subscriptions) }.to_str().unwrap()).unwrap();
91
92  let mut twitch = TwitchEventSubApi::builder(keys.clone())
93    .set_redirect_url("http://localhost:3000")
94    .generate_new_token_if_insufficent_scope(true)
95    .generate_new_token_if_none(true)
96    .generate_access_token_on_expire(true)
97    .auto_save_load_created_tokens(".user_token.env", ".refresh_token.env");
98
99  if subscriptions.user_update {
100    twitch = twitch.add_subscription(Subscription::UserUpdate);
101  }
102  if subscriptions.follow {
103    twitch = twitch.add_subscription(Subscription::ChannelFollow);
104  }
105  if subscriptions.raid {
106    twitch = twitch.add_subscription(Subscription::ChannelRaid);
107  }
108  if subscriptions.update {
109    twitch = twitch.add_subscription(Subscription::ChannelUpdate);
110  }
111  if subscriptions.new_subscription {
112    twitch = twitch.add_subscription(Subscription::ChannelNewSubscription);
113  }
114  if subscriptions.subscription_end {
115    twitch = twitch.add_subscription(Subscription::ChannelSubscriptionEnd);
116  }
117  if subscriptions.gift_subscription {
118    twitch = twitch.add_subscription(Subscription::ChannelGiftSubscription);
119  }
120  if subscriptions.resubscription {
121    twitch = twitch.add_subscription(Subscription::ChannelResubscription);
122  }
123  if subscriptions.cheer {
124    twitch = twitch.add_subscription(Subscription::ChannelCheer);
125  }
126  if subscriptions.points_custom_reward_redeem {
127    twitch = twitch.add_subscription(Subscription::ChannelPointsCustomRewardRedeem);
128  }
129  if subscriptions.points_auto_reward_redeem {
130    twitch = twitch.add_subscription(Subscription::ChannelPointsAutoRewardRedeem);
131  }
132  if subscriptions.poll_begin {
133    twitch = twitch.add_subscription(Subscription::ChannelPollBegin);
134  }
135  if subscriptions.poll_progress {
136    twitch = twitch.add_subscription(Subscription::ChannelPollProgress);
137  }
138  if subscriptions.poll_end {
139    twitch = twitch.add_subscription(Subscription::ChannelPollEnd);
140  }
141  if subscriptions.prediction_begin {
142    twitch = twitch.add_subscription(Subscription::ChannelPredictionBegin);
143  }
144  if subscriptions.prediction_progress {
145    twitch = twitch.add_subscription(Subscription::ChannelPredictionProgress);
146  }
147  if subscriptions.prediction_lock {
148    twitch = twitch.add_subscription(Subscription::ChannelPredictionLock);
149  }
150  if subscriptions.prediction_end {
151    twitch = twitch.add_subscription(Subscription::ChannelPredictionEnd);
152  }
153  if subscriptions.goal_begin {
154    twitch = twitch.add_subscription(Subscription::ChannelGoalBegin);
155  }
156  if subscriptions.goal_progress {
157    twitch = twitch.add_subscription(Subscription::ChannelGoalProgress);
158  }
159  if subscriptions.goal_end {
160    twitch = twitch.add_subscription(Subscription::ChannelGoalEnd);
161  }
162  if subscriptions.hype_train_begin {
163    twitch = twitch.add_subscription(Subscription::ChannelHypeTrainBegin);
164  }
165  if subscriptions.hype_train_progress {
166    twitch = twitch.add_subscription(Subscription::ChannelHypeTrainProgress);
167  }
168  if subscriptions.hype_train_end {
169    twitch = twitch.add_subscription(Subscription::ChannelHypeTrainEnd);
170  }
171  if subscriptions.shoutout_create {
172    twitch = twitch.add_subscription(Subscription::ChannelShoutoutCreate);
173  }
174  if subscriptions.shoutout_receive {
175    twitch = twitch.add_subscription(Subscription::ChannelShoutoutReceive);
176  }
177  if subscriptions.ban_timeout_user {
178    twitch = twitch.add_subscription(Subscription::PermissionBanTimeoutUser);
179  }
180  if subscriptions.delete_message {
181    twitch = twitch.add_subscription(Subscription::PermissionDeleteMessage);
182  }
183  if subscriptions.ad_break_begin {
184    twitch = twitch.add_subscription(Subscription::AdBreakBegin);
185  }
186  if subscriptions.chat_message {
187    twitch = twitch.add_subscription(Subscription::ChatMessage);
188  }
189
190  let twitch = twitch.build().unwrap();
191
192  unsafe { transmute(Box::new(twitch)) }
193}
194
195#[repr(C)]
196pub struct EventData {
197  pub kind: CString,
198  pub json: CString,
199}
200
201impl EventData {
202  pub fn new() -> EventData {
203    EventData {
204      kind: CString::new("").unwrap(),
205      json: CString::new("").unwrap(),
206    }
207  }
208
209  pub fn kind(&self) -> CString {
210    self.kind.to_owned()
211  }
212
213  pub fn json(&self) -> CString {
214    self.json.to_owned()
215  }
216}
217
218#[no_mangle]
219pub extern "C" fn extract_type(event_data: *mut EventData) -> CString {
220  let event = unsafe { &mut *event_data };
221
222  event.kind()
223}
224
225#[no_mangle]
226pub extern "C" fn extract_json(event_data: *mut EventData) -> CString {
227  let event = unsafe { &mut *event_data };
228
229  event.json()
230}
231
232#[no_mangle]
233pub extern "C" fn get_event(twitch: *mut TwitchEvents) -> *mut EventData {
234  let twitch = unsafe { &mut *twitch };
235  let mut event = EventData::new();
236
237  for response in twitch.api.receive_all_messages(None) {
238    match response {
239      ResponseType::Event(event_a) => match event_a {
240        Event::ChatMessage(message_data) => {
241          println!("chat message recieved");
242          event.kind = CString::new(match message_data.message_type {
243            MessageType::PowerUpsGigantifiedEmote => "chat_message_powerup_gigantified_emote",
244            MessageType::PowerUpsMessageEffect => "chat_message_powerup_message_effect",
245            _ => "chat_message",
246          })
247          .unwrap();
248          event.json = CString::new(serde_json::to_string(&message_data).unwrap()).unwrap();
249        }
250        Event::PointsCustomRewardRedeem(custom_reward_redeem) => {
251          event.kind = CString::new("custom_point_reward_redeem").unwrap();
252          event.json = CString::new(serde_json::to_string(&custom_reward_redeem).unwrap()).unwrap();
253        }
254        Event::AdBreakBegin(ad_break_begin) => {
255          event.kind = CString::new("ad_break_start").unwrap();
256          event.json = CString::new(serde_json::to_string(&ad_break_begin).unwrap()).unwrap();
257        }
258        Event::Raid(raid) => {
259          event.kind = CString::new("raid").unwrap();
260          event.json = CString::new(serde_json::to_string(&raid).unwrap()).unwrap();
261        }
262        Event::Follow(follow) => {
263          event.kind = CString::new("follow").unwrap();
264          event.json = CString::new(serde_json::to_string(&follow).unwrap()).unwrap();
265        }
266        Event::NewSubscription(new_subscritpion) => {
267          event.kind = CString::new("new_subscription").unwrap();
268          event.json = CString::new(serde_json::to_string(&new_subscritpion).unwrap()).unwrap();
269        }
270        Event::GiftSubscription(gift) => {
271          event.kind = CString::new("subscription_gift").unwrap();
272          event.json = CString::new(serde_json::to_string(&gift).unwrap()).unwrap();
273        }
274        Event::Resubscription(resubscription) => {
275          event.kind = CString::new("resubscritpion").unwrap();
276          event.json = CString::new(serde_json::to_string(&resubscription).unwrap()).unwrap();
277        }
278        Event::Cheer(cheer) => {
279          event.kind = CString::new("cheer").unwrap();
280          event.json = CString::new(serde_json::to_string(&cheer).unwrap()).unwrap();
281        }
282        _ => {}
283      },
284
285      ResponseType::RawResponse(raw_string) => {
286        //event.kind = CString::new("RawResponse").unwrap();
287        //event.json = CString::new(raw_string).unwrap();
288      }
289      _ => {}
290    }
291  }
292
293  unsafe { transmute(Box::new(event)) }
294}
295
296#[no_mangle]
297pub extern "C" fn destroy_twitch_events(twitch_events: *mut TwitchEvents) {
298  let twitch: Box<TwitchEvents> = unsafe { transmute(twitch_events) };
299}