1 module dscord.gateway.events;
2 
3 import std.algorithm,
4        std.string,
5        std.stdio,
6        std.datetime,
7        std.array,
8        std.conv;
9 
10 import dscord.gateway.client,
11        dscord.gateway.packets,
12        dscord.types.all;
13 
14 /**
15   A wrapper type for delegates that can be attached to an event, and run after
16   all listeners are executed. This can be used to ensure an event has fully passed
17   through all listeners, or to avoid having function/stack pointers within plugin
18   code (which allows for dynamically reloading the plugin).
19 */
20 alias EventDeferredFunc = void delegate();
21 
22 /**
23   Base template for events from discord. Handles basic initilization, and some
24   deferred-function code.
25 */
26 mixin template Event() {
27   Client client;
28 
29   /**
30     Array of functions to be ran when this event has completed its pass through
31     the any listeners, and is ready to be destroyed.
32   */
33   EventDeferredFunc[] deferred;
34 
35   this(Client c, ref JSON obj) {
36     debug {
37       auto sw = StopWatch(AutoStart.yes);
38       c.log.tracef("Starting create event for %s", this.toString);
39     }
40 
41     this.client = c;
42     this.load(obj);
43 
44     debug {
45       this.client.log.tracef("Create event for %s took %sms", this.toString,
46         sw.peek().to!("msecs", real));
47     }
48   }
49 
50   /**
51     Used to defer a functions execution until after this event has passed through
52     all listeners, and is ready to be destroyed.
53   */
54   void defer(EventDeferredFunc f) {
55     this.deferred ~= f;
56   }
57 
58   /**
59     Calls all deferred functions.
60   */
61   void resolveDeferreds() {
62     foreach (ref f; this.deferred) {
63       f();
64     }
65   }
66 }
67 
68 /**
69   Sent when we initially connect, contains base state and connection information.
70 */
71 class Ready {
72   mixin Event;
73 
74   ushort     ver;
75   uint       heartbeatInterval;
76   string     sessionID;
77   User       me;
78   Guild[]    guilds;
79   Channel[]  dms;
80 
81   void load(ref JSON obj) {
82     obj.keySwitch!("v", "heartbeat_interval", "session_id", "user", "guilds")(
83       { this.ver = obj.read!ushort; },
84       { this.heartbeatInterval = obj.read!uint; },
85       { this.sessionID = obj.read!string; },
86       { this.me = new User(this.client, obj); },
87       { loadMany!Guild(this.client, obj, (g) { this.guilds ~= g; }); },
88     );
89   }
90 }
91 
92 /**
93   Sent when we've completed a reconnect/resume sequence.
94 */
95 class Resumed {
96   mixin Event;
97 
98   void load(ref JSON obj) {}
99 }
100 
101 /**
102   Sent when a channel is created.
103 */
104 class ChannelCreate {
105   mixin Event;
106 
107   Channel  channel;
108 
109   void load(ref JSON obj) {
110     this.channel = new Channel(this.client, obj);
111   }
112 }
113 
114 /**
115   Sent when a channel is updated.
116 */
117 class ChannelUpdate {
118   mixin Event;
119 
120   Channel  channel;
121 
122   void load(ref JSON obj) {
123     this.channel = new Channel(this.client, obj);
124   }
125 }
126 
127 /**
128   Sent when a channel is deleted.
129 */
130 class ChannelDelete {
131   mixin Event;
132 
133   Channel  channel;
134 
135   void load(ref JSON obj) {
136     this.channel = new Channel(this.client, obj);
137   }
138 }
139 
140 /**
141   Sent when a guild is created (often on startup).
142 */
143 class GuildCreate {
144   mixin Event;
145 
146   Guild  guild;
147 
148   void load(ref JSON obj) {
149     this.guild = new Guild(this.client, obj);
150   }
151 }
152 
153 /**
154   Sent when a guild is updated
155 */
156 class GuildUpdate {
157   mixin Event;
158 
159   Guild  guild;
160 
161   void load(ref JSON obj) {
162     this.guild = new Guild(this.client, obj);
163   }
164 }
165 
166 /**
167   Sent when a guild is deleted (or becomes unavailable)
168 */
169 class GuildDelete {
170   mixin Event;
171 
172   Snowflake  guildID;
173   bool       unavailable;
174 
175   void load(ref JSON obj) {
176     obj.keySwitch!("guild_id", "unavailable")(
177       { this.guildID = readSnowflake(obj); },
178       { this.unavailable = obj.read!bool; },
179     );
180   }
181 }
182 
183 /**
184   Sent when a guild ban is added.
185 */
186 class GuildBanAdd {
187   mixin Event;
188 
189   User  user;
190 
191   void load(ref JSON obj) {
192     this.user = new User(this.client, obj);
193   }
194 }
195 
196 /**
197   Sent when a guild ban is removed.
198 */
199 class GuildBanRemove {
200   mixin Event;
201 
202   User  user;
203 
204   void load(ref JSON obj) {
205     this.user = new User(this.client, obj);
206   }
207 }
208 
209 /**
210   Sent when a guilds emojis are updated.
211 */
212 class GuildEmojisUpdate {
213   mixin Event;
214 
215   void load(ref JSON obj) {}
216 }
217 
218 /**
219   Sent when a guilds integrations are updated.
220 */
221 class GuildIntegrationsUpdate {
222   mixin Event;
223 
224   void load(ref JSON obj) {}
225 }
226 
227 /**
228   Sent when a member is added to a guild.
229 */
230 class GuildMemberAdd {
231   mixin Event;
232 
233   GuildMember  member;
234 
235   void load(ref JSON obj) {
236     this.member = new GuildMember(this.client, obj);
237   }
238 }
239 
240 /**
241   Sent when a member is removed from a guild.
242 */
243 class GuildMemberRemove {
244   mixin Event;
245 
246   Snowflake  guildID;
247   User       user;
248 
249   void load(ref JSON obj) {
250     obj.keySwitch!("guild_id", "user")(
251       { this.guildID = readSnowflake(obj); },
252       { this.user = new User(this.client, obj); },
253     );
254   }
255 }
256 
257 /**
258   Sent when a guild member is updated.
259 */
260 class GuildMemberUpdate {
261   mixin Event;
262 
263   Snowflake    guildID;
264   User         user;
265   Snowflake[]  roles;
266 
267   void load(ref JSON obj) {
268     obj.keySwitch!("guild_id", "user", "roles")(
269       { this.guildID = readSnowflake(obj); },
270       { this.user = new User(this.client, obj); },
271       { this.roles = obj.read!(string[]).map!((c) => c.to!Snowflake).array; },
272     );
273   }
274 }
275 
276 /**
277   Sent when a guild role is created.
278 */
279 class GuildRoleCreate {
280   mixin Event;
281 
282   Snowflake  guildID;
283   Role       role;
284 
285   void load(ref JSON obj) {
286     obj.keySwitch!("guild_id", "role")(
287       { this.guildID = readSnowflake(obj); },
288       { this.role = new Role(this.client, obj); },
289     );
290   }
291 }
292 
293 /**
294   Sent when a guild role is updated.
295 */
296 class GuildRoleUpdate {
297   mixin Event;
298 
299   Snowflake  guildID;
300   Role       role;
301 
302   void load(ref JSON obj) {
303     obj.keySwitch!("guild_id", "role")(
304       { this.guildID = readSnowflake(obj); },
305       { this.role = new Role(this.client, obj); },
306     );
307   }
308 }
309 
310 /**
311   Sent when a guild role is deleted.
312 */
313 class GuildRoleDelete {
314   mixin Event;
315 
316   Snowflake  guildID;
317   Role       role;
318 
319   void load(ref JSON obj) {
320     obj.keySwitch!("guild_id", "role")(
321       { this.guildID = readSnowflake(obj); },
322       { this.role = new Role(this.client, obj); },
323     );
324   }
325 }
326 
327 /**
328   Sent when a message is created.
329 */
330 class MessageCreate {
331   mixin Event;
332 
333   Message  message;
334 
335   void load(ref JSON obj) {
336     this.message = new Message(this.client, obj);
337   }
338 }
339 
340 /**
341   Sent when a message is updated.
342 */
343 class MessageUpdate {
344   mixin Event;
345 
346   Message  message;
347 
348   void load(ref JSON obj) {
349     this.message = new Message(this.client, obj);
350   }
351 }
352 
353 /**
354   Sent when a message is deleted.
355 */
356 class MessageDelete {
357   mixin Event;
358 
359   Snowflake  id;
360   Snowflake  channelID;
361 
362   void load(ref JSON obj) {
363     obj.keySwitch!("id", "channel_id")(
364       { this.id = readSnowflake(obj); },
365       { this.channelID = readSnowflake(obj); },
366     );
367   }
368 }
369 
370 /**
371   Sent when a users presence is updated.
372 */
373 class PresenceUpdate {
374   mixin Event;
375 
376   User         user;
377   Snowflake    guildID;
378   Snowflake[]  roles;
379   string       game;
380   string       status;
381 
382   void load(ref JSON obj) {
383     obj.keySwitch!("user", "guild_id", "roles", "game", "status")(
384       { this.user = new User(this.client, obj); },
385       { this.guildID = readSnowflake(obj); },
386       { this.roles = obj.read!(string[]).map!((c) => c.to!Snowflake).array; },
387       { this.game = obj.read!string; },
388       { this.status = obj.read!string; },
389     );
390   }
391 }
392 
393 /**
394   Sent when a user starts typing.
395 */
396 class TypingStart {
397   mixin Event;
398 
399   Snowflake  channelID;
400   Snowflake  userID;
401   ulong      timestamp;
402 
403   void load(ref JSON obj) {
404     obj.keySwitch!("channel_id", "user_id", "timestamp")(
405       { this.channelID = readSnowflake(obj); },
406       { this.userID = readSnowflake(obj); },
407       { this.timestamp = obj.read!ulong; },
408     );
409   }
410 }
411 
412 /**
413   Sent when this users settings are updated.
414 */
415 class UserSettingsUpdate {
416   mixin Event;
417 
418   void load(ref JSON obj) {};
419 }
420 
421 /**
422   Sent when this user is updated.
423 */
424 class UserUpdate {
425   mixin Event;
426 
427   void load(ref JSON obj) {};
428 }
429 
430 /**
431   Sent when a voice state is updated.
432 */
433 class VoiceStateUpdate {
434   mixin Event;
435 
436   VoiceState  state;
437 
438   void load(ref JSON obj) {
439     this.state = new VoiceState(this.client, obj);
440   }
441 }
442 
443 /**
444   Sent when a voice server is updated.
445 */
446 class VoiceServerUpdate {
447   mixin Event;
448 
449   string     token;
450   string     endpoint;
451   Snowflake  guildID;
452 
453   void load(ref JSON obj) {
454     obj.keySwitch!("token", "endpoint", "guild_id")(
455       { this.token = obj.read!string; },
456       { this.endpoint = obj.read!string; },
457       { this.guildID = readSnowflake(obj); },
458     );
459   }
460 }