1 /** 2 Implementations of packets sent over the Gateway websocket. 3 */ 4 module dcord.gateway.packets; 5 6 import std.stdio; 7 8 import dcord.types; 9 10 /// Enumeration of opcodes, stored as unsigned shorts 11 enum OPCode: ushort { 12 DISPATCH = 0, 13 HEARTBEAT = 1, 14 IDENTIFY = 2, 15 STATUS_UPDATE = 3, 16 VOICE_STATE_UPDATE = 4, 17 VOICE_SERVER_PING = 5, 18 RESUME = 6, 19 RECONNECT = 7, 20 REQUEST_GUILD_MEMBERS = 8, 21 INVALID_SESSION = 9, 22 HELLO = 10, 23 HEARTBEAT_ACK = 11, 24 GUILD_SYNC = 12, 25 } 26 27 interface Serializable { 28 VibeJSON serialize(); 29 } 30 31 interface Deserializable { 32 // doesn't need anything implemented 33 } 34 35 class BasePacket { 36 OPCode op; 37 VibeJSON data; 38 VibeJSON raw; 39 40 VibeJSON serialize(ushort op, VibeJSON data) { 41 return VibeJSON([ 42 "op": VibeJSON(op), 43 "d": data, 44 ]); 45 } 46 } 47 48 class HeartbeatPacket: BasePacket, Serializable { 49 uint seq; 50 51 this(uint seq) { 52 this.seq = seq; 53 } 54 55 override VibeJSON serialize() { 56 return super.serialize(OPCode.HEARTBEAT, VibeJSON(this.seq)); 57 } 58 } 59 60 class ResumePacket: BasePacket, Serializable { 61 string token; 62 string sessionID; 63 uint seq; 64 65 this(string token, string sessionID, uint seq) { 66 this.token = token; 67 this.sessionID = sessionID; 68 this.seq = seq; 69 } 70 71 override VibeJSON serialize() { 72 return super.serialize(OPCode.RESUME, VibeJSON([ 73 "token": VibeJSON(this.token), 74 "session_id": VibeJSON(this.sessionID), 75 "seq": VibeJSON(this.seq), 76 ])); 77 } 78 } 79 80 class VoiceStateUpdatePacket: BasePacket, Serializable { 81 Snowflake guildID; 82 Snowflake channelID; 83 bool self_mute; 84 bool self_deaf; 85 86 this(Snowflake guild_id, Snowflake channel_id, bool self_mute, bool self_deaf) { 87 this.guildID = guild_id; 88 this.channelID = channel_id; 89 this.self_mute = self_mute; 90 this.self_deaf = self_deaf; 91 } 92 93 override VibeJSON serialize() { 94 return super.serialize(OPCode.VOICE_STATE_UPDATE, VibeJSON([ 95 "self_mute": VibeJSON(this.self_mute), 96 "self_deaf": VibeJSON(this.self_deaf), 97 "guild_id": this.guildID ? VibeJSON(this.guildID) : VibeJSON(null), 98 "channel_id": this.channelID ? VibeJSON(this.channelID) : VibeJSON(null), 99 ])); 100 } 101 } 102 103 class IdentifyPacket: BasePacket, Serializable { 104 string token; 105 bool compress = true; 106 ushort largeThreshold = 250; 107 ushort[2] shard; 108 109 this(string token, ushort shard = 0, ushort numShards = 1) { 110 this.token = token; 111 this.shard = [shard, numShards]; 112 } 113 114 @property VibeJSON properties() { 115 return VibeJSON([ 116 "$os": VibeJSON("linux"), 117 "$browser": VibeJSON("dcord"), 118 "$device": VibeJSON("dcord"), 119 "$referrer": VibeJSON(""), 120 ]); 121 } 122 123 override VibeJSON serialize() { 124 return super.serialize(OPCode.IDENTIFY, VibeJSON([ 125 "token": VibeJSON(this.token), 126 "properties": this.properties, 127 "compress": VibeJSON(this.compress), 128 "large_threshold": VibeJSON(this.largeThreshold), 129 "shard": VibeJSON([VibeJSON(this.shard[0]), VibeJSON(this.shard[1])]), 130 ])); 131 } 132 } 133 134 class RequestGuildMembers: BasePacket, Serializable { 135 Snowflake guildID; 136 string query; 137 uint limit; 138 139 this(Snowflake guildID, string query="", uint limit=0) { 140 this.guildID = guildID; 141 this.query = query; 142 this.limit = limit; 143 } 144 145 override VibeJSON serialize() { 146 return super.serialize(OPCode.REQUEST_GUILD_MEMBERS, VibeJSON([ 147 "guild_id": VibeJSON(this.guildID.toString), 148 "query": VibeJSON(this.query), 149 "limit": VibeJSON(this.limit), 150 ])); 151 } 152 } 153 154 class StatusUpdate: BasePacket, Serializable { 155 /// The game for the presence update 156 Game game; 157 158 this(Game game) { 159 this.game = game; 160 } 161 162 override VibeJSON serialize() { 163 VibeJSON obj = VibeJSON.emptyObject; 164 obj["game"] = VibeJSON.emptyObject; 165 obj["since"] = 0; 166 obj["game"]["name"] = this.game.name; 167 obj["game"]["type"] = 0; 168 obj["status"] = "online"; 169 obj["afk"] = VibeJSON(false); 170 writeln(super.serialize(OPCode.STATUS_UPDATE, obj)); 171 return super.serialize(OPCode.STATUS_UPDATE, obj); 172 } 173 }