From 567fb0ffa627f0a5771b43912ff7ffb3415a28b1 Mon Sep 17 00:00:00 2001 From: RogueException Date: Sun, 6 Dec 2015 22:23:06 -0400 Subject: [PATCH] Added cleanup and doc to websockets --- .../API/Messages/VoiceSocket.cs | 32 ++++++-- .../Net/WebSockets/VoiceWebSocket.cs | 82 +++++++++---------- src/Discord.Net/API/Messages/GatewaySocket.cs | 14 +++- .../Net/WebSockets/GatewayWebSocket.cs | 38 ++++----- 4 files changed, 94 insertions(+), 72 deletions(-) diff --git a/src/Discord.Net.Audio/API/Messages/VoiceSocket.cs b/src/Discord.Net.Audio/API/Messages/VoiceSocket.cs index 262a97ec0..bf6d57ca3 100644 --- a/src/Discord.Net.Audio/API/Messages/VoiceSocket.cs +++ b/src/Discord.Net.Audio/API/Messages/VoiceSocket.cs @@ -7,10 +7,26 @@ using Newtonsoft.Json; namespace Discord.API { + public enum VoiceOpCodes : byte + { + /// Client --> Server - Used to associate a connection with a token. + Identify = 0, + /// Client --> Server - Used to specify configuration. + SelectProtocol = 1, + /// Client <-- Server - Used to notify that the voice connection was successful and informs the client of available protocols. + Ready = 2, + /// Client <-> Server - Used to keep the connection alive and measure latency. + Heartbeat = 3, + /// Client <-- Server - Used to provide an encryption key to the client. + SessionDescription = 4, + /// Client <-> Server - Used to inform that a certain user is speaking. + Speaking = 5 + } + //Commands - internal sealed class VoiceLoginCommand : WebSocketMessage + internal sealed class IdentifyCommand : WebSocketMessage { - public VoiceLoginCommand() : base(0) { } + public IdentifyCommand() : base((int)VoiceOpCodes.Identify) { } public class Data { [JsonProperty("server_id")] @@ -25,9 +41,9 @@ namespace Discord.API public string Token; } } - internal sealed class VoiceLogin2Command : WebSocketMessage + internal sealed class SelectProtocolCommand : WebSocketMessage { - public VoiceLogin2Command() : base(1) { } + public SelectProtocolCommand() : base((int)VoiceOpCodes.SelectProtocol) { } public class Data { public class SocketInfo @@ -45,13 +61,13 @@ namespace Discord.API public SocketInfo SocketData = new SocketInfo(); } } - internal sealed class VoiceKeepAliveCommand : WebSocketMessage + internal sealed class HeartbeatCommand : WebSocketMessage { - public VoiceKeepAliveCommand() : base(3, EpochTime.GetMilliseconds()) { } + public HeartbeatCommand() : base((int)VoiceOpCodes.Heartbeat, EpochTime.GetMilliseconds()) { } } - internal sealed class IsTalkingCommand : WebSocketMessage + internal sealed class SpeakingCommand : WebSocketMessage { - public IsTalkingCommand() : base(5) { } + public SpeakingCommand() : base((int)VoiceOpCodes.Speaking) { } public class Data { [JsonProperty("delay")] diff --git a/src/Discord.Net.Audio/Net/WebSockets/VoiceWebSocket.cs b/src/Discord.Net.Audio/Net/WebSockets/VoiceWebSocket.cs index 88a3dbe76..0a44f773b 100644 --- a/src/Discord.Net.Audio/Net/WebSockets/VoiceWebSocket.cs +++ b/src/Discord.Net.Audio/Net/WebSockets/VoiceWebSocket.cs @@ -17,16 +17,6 @@ namespace Discord.Net.WebSockets { public partial class VoiceWebSocket : WebSocket { - public enum OpCodes : byte - { - Identify = 0, - SelectProtocol = 1, - Ready = 2, - Heartbeat = 3, - SessionDescription = 4, - Speaking = 5 - } - private const int MaxOpusSize = 4000; private const string EncryptedMode = "xsalsa20_poly1305"; private const string UnencryptedMode = "plain"; @@ -114,12 +104,7 @@ namespace Discord.Net.WebSockets { _udp = new UdpClient(new IPEndPoint(IPAddress.Any, 0)); - VoiceLoginCommand msg = new VoiceLoginCommand(); - msg.Payload.ServerId = _serverId.Value; - msg.Payload.SessionId = _sessionId; - msg.Payload.Token = _token; - msg.Payload.UserId = _userId.Value; - QueueMessage(msg); + SendIdentify(); List tasks = new List(); if ((_audioConfig.Mode & AudioMode.Outgoing) != 0) @@ -224,15 +209,10 @@ namespace Discord.Net.WebSockets if (packetLength != 70) return; - int port = packet[68] | packet[69] << 8; string ip = Encoding.UTF8.GetString(packet, 4, 70 - 6).TrimEnd('\0'); + int port = packet[68] | packet[69] << 8; - var login2 = new VoiceLogin2Command(); - login2.Payload.Protocol = "udp"; - login2.Payload.SocketData.Address = ip; - login2.Payload.SocketData.Mode = _encryptionMode; - login2.Payload.SocketData.Port = port; - QueueMessage(login2); + SendSelectProtocol(ip, port); if ((_audioConfig.Mode & AudioMode.Incoming) == 0) return; } @@ -441,10 +421,10 @@ namespace Discord.Net.WebSockets { await base.ProcessMessage(json).ConfigureAwait(false); var msg = JsonConvert.DeserializeObject(json); - var opCode = (OpCodes)msg.Operation; + var opCode = (VoiceOpCodes)msg.Operation; switch (opCode) { - case OpCodes.Ready: + case VoiceOpCodes.Ready: { if (_state != (int)WebSocketState.Connected) { @@ -481,7 +461,7 @@ namespace Discord.Net.WebSockets } } break; - case OpCodes.Heartbeat: + case VoiceOpCodes.Heartbeat: { long time = EpochTime.GetMilliseconds(); var payload = (long)msg.Payload; @@ -489,7 +469,7 @@ namespace Discord.Net.WebSockets //TODO: Use this to estimate latency } break; - case OpCodes.SessionDescription: + case VoiceOpCodes.SessionDescription: { var payload = (msg.Payload as JToken).ToObject(_serializer); _secretKey = payload.SecretKey; @@ -497,7 +477,7 @@ namespace Discord.Net.WebSockets EndConnect(); } break; - case OpCodes.Speaking: + case VoiceOpCodes.Speaking: { var payload = (msg.Payload as JToken).ToObject(_serializer); RaiseIsSpeaking(payload.UserId, payload.IsSpeaking); @@ -519,19 +499,6 @@ namespace Discord.Net.WebSockets _sendBuffer.Clear(_cancelToken); } - private void SendIsTalking(bool value) - { - var isTalking = new IsTalkingCommand(); - isTalking.Payload.IsSpeaking = value; - isTalking.Payload.Delay = 0; - QueueMessage(isTalking); - } - - public override void SendHeartbeat() - { - QueueMessage(new VoiceKeepAliveCommand()); - } - public void WaitForQueue() { _sendBuffer.Wait(_cancelToken); @@ -551,5 +518,38 @@ namespace Discord.Net.WebSockets } }); } + + public void SendIdentify() + { + var msg = new IdentifyCommand(); + msg.Payload.ServerId = _serverId.Value; + msg.Payload.SessionId = _sessionId; + msg.Payload.Token = _token; + msg.Payload.UserId = _userId.Value; + QueueMessage(msg); + } + + public void SendSelectProtocol(string externalIp, int externalPort) + { + var msg = new SelectProtocolCommand(); + msg.Payload.Protocol = "udp"; + msg.Payload.SocketData.Address = externalIp; + msg.Payload.SocketData.Mode = _encryptionMode; + msg.Payload.SocketData.Port = externalPort; + QueueMessage(msg); + } + + public void SendIsTalking(bool value) + { + var isTalking = new SpeakingCommand(); + isTalking.Payload.IsSpeaking = value; + isTalking.Payload.Delay = 0; + QueueMessage(isTalking); + } + + public override void SendHeartbeat() + { + QueueMessage(new HeartbeatCommand()); + } } } \ No newline at end of file diff --git a/src/Discord.Net/API/Messages/GatewaySocket.cs b/src/Discord.Net/API/Messages/GatewaySocket.cs index 18895da48..d84fbc761 100644 --- a/src/Discord.Net/API/Messages/GatewaySocket.cs +++ b/src/Discord.Net/API/Messages/GatewaySocket.cs @@ -11,14 +11,23 @@ namespace Discord.API { public enum GatewayOpCodes : byte { + /// Client <-- Server - Used to send most events. Dispatch = 0, + /// Client <-> Server - Used to keep the connection alive and measure latency. Heartbeat = 1, + /// Client --> Server - Used to associate a connection with a token and specify configuration. Identify = 2, + /// Client --> Server - Used to update client's status and current game id. StatusUpdate = 3, + /// Client --> Server - Used to join a particular voice channel. VoiceStateUpdate = 4, - //VoiceServerPing = 5, (Unused?) + /// Client --> Server - Used to ensure the server's voice server is alive. Only send this if voice connection fails or suddenly drops. + VoiceServerPing = 5, + /// Client --> Server - Used to resume a connection after a redirect occurs. Resume = 6, + /// Client <-- Server - Used to notify a client that they must reconnect to another gateway. Redirect = 7, + /// Client --> Server - Used to request all members that were withheld by large_threshold RequestGuildMembers = 8 } @@ -92,8 +101,6 @@ namespace Discord.API } } - - //Commands internal sealed class JoinVoiceCommand : WebSocketMessage { public JoinVoiceCommand() : base((int)GatewayOpCodes.VoiceStateUpdate) { } @@ -112,7 +119,6 @@ namespace Discord.API } } - //Events internal sealed class ResumeCommand : WebSocketMessage { public ResumeCommand() : base((int)GatewayOpCodes.Resume) { } diff --git a/src/Discord.Net/Net/WebSockets/GatewayWebSocket.cs b/src/Discord.Net/Net/WebSockets/GatewayWebSocket.cs index 8e0a52a50..b6c292268 100644 --- a/src/Discord.Net/Net/WebSockets/GatewayWebSocket.cs +++ b/src/Discord.Net/Net/WebSockets/GatewayWebSocket.cs @@ -109,7 +109,7 @@ namespace Discord.Net.WebSockets public void SendIdentify(string token) { - IdentifyCommand msg = new IdentifyCommand(); + var msg = new IdentifyCommand(); msg.Payload.Token = token; msg.Payload.Properties["$device"] = "Discord.Net"; if (_config.UseLargeThreshold) @@ -120,10 +120,10 @@ namespace Discord.Net.WebSockets public void SendResume() { - var resumeMsg = new ResumeCommand(); - resumeMsg.Payload.SessionId = _sessionId; - resumeMsg.Payload.Sequence = _lastSeq; - QueueMessage(resumeMsg); + var msg = new ResumeCommand(); + msg.Payload.SessionId = _sessionId; + msg.Payload.Sequence = _lastSeq; + QueueMessage(msg); } public override void SendHeartbeat() @@ -133,31 +133,31 @@ namespace Discord.Net.WebSockets public void SendStatusUpdate(long? idleSince, int? gameId) { - var updateStatus = new StatusUpdateCommand(); - updateStatus.Payload.IdleSince = idleSince; - updateStatus.Payload.GameId = gameId; - QueueMessage(updateStatus); + var msg = new StatusUpdateCommand(); + msg.Payload.IdleSince = idleSince; + msg.Payload.GameId = gameId; + QueueMessage(msg); } public void SendJoinVoice(long serverId, long channelId) { - var joinVoice = new JoinVoiceCommand(); - joinVoice.Payload.ServerId = serverId; - joinVoice.Payload.ChannelId = channelId; - QueueMessage(joinVoice); + var msg = new JoinVoiceCommand(); + msg.Payload.ServerId = serverId; + msg.Payload.ChannelId = channelId; + QueueMessage(msg); } public void SendLeaveVoice(long serverId) { - var leaveVoice = new JoinVoiceCommand(); - leaveVoice.Payload.ServerId = serverId; - QueueMessage(leaveVoice); + var msg = new JoinVoiceCommand(); + msg.Payload.ServerId = serverId; + QueueMessage(msg); } public void SendRequestUsers(long serverId, string query = "", int limit = 0) { - var getOfflineUsers = new GetUsersCommand(); - getOfflineUsers.Payload.ServerId = serverId; - QueueMessage(getOfflineUsers); + var msg = new GetUsersCommand(); + msg.Payload.ServerId = serverId; + QueueMessage(msg); } } }