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 }