Browse Source

Added cleanup and doc to websockets

tags/docs-0.9
RogueException 9 years ago
parent
commit
567fb0ffa6
4 changed files with 94 additions and 72 deletions
  1. +24
    -8
      src/Discord.Net.Audio/API/Messages/VoiceSocket.cs
  2. +41
    -41
      src/Discord.Net.Audio/Net/WebSockets/VoiceWebSocket.cs
  3. +10
    -4
      src/Discord.Net/API/Messages/GatewaySocket.cs
  4. +19
    -19
      src/Discord.Net/Net/WebSockets/GatewayWebSocket.cs

+ 24
- 8
src/Discord.Net.Audio/API/Messages/VoiceSocket.cs View File

@@ -7,10 +7,26 @@ using Newtonsoft.Json;


namespace Discord.API namespace Discord.API
{ {
public enum VoiceOpCodes : byte
{
/// <summary> Client --> Server - Used to associate a connection with a token. </summary>
Identify = 0,
/// <summary> Client --> Server - Used to specify configuration. </summary>
SelectProtocol = 1,
/// <summary> Client <-- Server - Used to notify that the voice connection was successful and informs the client of available protocols. </summary>
Ready = 2,
/// <summary> Client <-> Server - Used to keep the connection alive and measure latency. </summary>
Heartbeat = 3,
/// <summary> Client <-- Server - Used to provide an encryption key to the client. </summary>
SessionDescription = 4,
/// <summary> Client <-> Server - Used to inform that a certain user is speaking. </summary>
Speaking = 5
}

//Commands //Commands
internal sealed class VoiceLoginCommand : WebSocketMessage<VoiceLoginCommand.Data>
internal sealed class IdentifyCommand : WebSocketMessage<IdentifyCommand.Data>
{ {
public VoiceLoginCommand() : base(0) { }
public IdentifyCommand() : base((int)VoiceOpCodes.Identify) { }
public class Data public class Data
{ {
[JsonProperty("server_id")] [JsonProperty("server_id")]
@@ -25,9 +41,9 @@ namespace Discord.API
public string Token; public string Token;
} }
} }
internal sealed class VoiceLogin2Command : WebSocketMessage<VoiceLogin2Command.Data>
internal sealed class SelectProtocolCommand : WebSocketMessage<SelectProtocolCommand.Data>
{ {
public VoiceLogin2Command() : base(1) { }
public SelectProtocolCommand() : base((int)VoiceOpCodes.SelectProtocol) { }
public class Data public class Data
{ {
public class SocketInfo public class SocketInfo
@@ -45,13 +61,13 @@ namespace Discord.API
public SocketInfo SocketData = new SocketInfo(); public SocketInfo SocketData = new SocketInfo();
} }
} }
internal sealed class VoiceKeepAliveCommand : WebSocketMessage<long>
internal sealed class HeartbeatCommand : WebSocketMessage<long>
{ {
public VoiceKeepAliveCommand() : base(3, EpochTime.GetMilliseconds()) { }
public HeartbeatCommand() : base((int)VoiceOpCodes.Heartbeat, EpochTime.GetMilliseconds()) { }
} }
internal sealed class IsTalkingCommand : WebSocketMessage<IsTalkingCommand.Data>
internal sealed class SpeakingCommand : WebSocketMessage<SpeakingCommand.Data>
{ {
public IsTalkingCommand() : base(5) { }
public SpeakingCommand() : base((int)VoiceOpCodes.Speaking) { }
public class Data public class Data
{ {
[JsonProperty("delay")] [JsonProperty("delay")]


+ 41
- 41
src/Discord.Net.Audio/Net/WebSockets/VoiceWebSocket.cs View File

@@ -17,16 +17,6 @@ namespace Discord.Net.WebSockets
{ {
public partial class VoiceWebSocket : WebSocket 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 int MaxOpusSize = 4000;
private const string EncryptedMode = "xsalsa20_poly1305"; private const string EncryptedMode = "xsalsa20_poly1305";
private const string UnencryptedMode = "plain"; private const string UnencryptedMode = "plain";
@@ -114,12 +104,7 @@ namespace Discord.Net.WebSockets
{ {
_udp = new UdpClient(new IPEndPoint(IPAddress.Any, 0)); _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<Task> tasks = new List<Task>(); List<Task> tasks = new List<Task>();
if ((_audioConfig.Mode & AudioMode.Outgoing) != 0) if ((_audioConfig.Mode & AudioMode.Outgoing) != 0)
@@ -224,15 +209,10 @@ namespace Discord.Net.WebSockets
if (packetLength != 70) if (packetLength != 70)
return; return;


int port = packet[68] | packet[69] << 8;
string ip = Encoding.UTF8.GetString(packet, 4, 70 - 6).TrimEnd('\0'); 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) if ((_audioConfig.Mode & AudioMode.Incoming) == 0)
return; return;
} }
@@ -441,10 +421,10 @@ namespace Discord.Net.WebSockets
{ {
await base.ProcessMessage(json).ConfigureAwait(false); await base.ProcessMessage(json).ConfigureAwait(false);
var msg = JsonConvert.DeserializeObject<WebSocketMessage>(json); var msg = JsonConvert.DeserializeObject<WebSocketMessage>(json);
var opCode = (OpCodes)msg.Operation;
var opCode = (VoiceOpCodes)msg.Operation;
switch (opCode) switch (opCode)
{ {
case OpCodes.Ready:
case VoiceOpCodes.Ready:
{ {
if (_state != (int)WebSocketState.Connected) if (_state != (int)WebSocketState.Connected)
{ {
@@ -481,7 +461,7 @@ namespace Discord.Net.WebSockets
} }
} }
break; break;
case OpCodes.Heartbeat:
case VoiceOpCodes.Heartbeat:
{ {
long time = EpochTime.GetMilliseconds(); long time = EpochTime.GetMilliseconds();
var payload = (long)msg.Payload; var payload = (long)msg.Payload;
@@ -489,7 +469,7 @@ namespace Discord.Net.WebSockets
//TODO: Use this to estimate latency //TODO: Use this to estimate latency
} }
break; break;
case OpCodes.SessionDescription:
case VoiceOpCodes.SessionDescription:
{ {
var payload = (msg.Payload as JToken).ToObject<JoinServerEvent>(_serializer); var payload = (msg.Payload as JToken).ToObject<JoinServerEvent>(_serializer);
_secretKey = payload.SecretKey; _secretKey = payload.SecretKey;
@@ -497,7 +477,7 @@ namespace Discord.Net.WebSockets
EndConnect(); EndConnect();
} }
break; break;
case OpCodes.Speaking:
case VoiceOpCodes.Speaking:
{ {
var payload = (msg.Payload as JToken).ToObject<IsTalkingEvent>(_serializer); var payload = (msg.Payload as JToken).ToObject<IsTalkingEvent>(_serializer);
RaiseIsSpeaking(payload.UserId, payload.IsSpeaking); RaiseIsSpeaking(payload.UserId, payload.IsSpeaking);
@@ -519,19 +499,6 @@ namespace Discord.Net.WebSockets
_sendBuffer.Clear(_cancelToken); _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() public void WaitForQueue()
{ {
_sendBuffer.Wait(_cancelToken); _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());
}
} }
} }

+ 10
- 4
src/Discord.Net/API/Messages/GatewaySocket.cs View File

@@ -11,14 +11,23 @@ namespace Discord.API
{ {
public enum GatewayOpCodes : byte public enum GatewayOpCodes : byte
{ {
/// <summary> Client <-- Server - Used to send most events. </summary>
Dispatch = 0, Dispatch = 0,
/// <summary> Client <-> Server - Used to keep the connection alive and measure latency. </summary>
Heartbeat = 1, Heartbeat = 1,
/// <summary> Client --> Server - Used to associate a connection with a token and specify configuration. </summary>
Identify = 2, Identify = 2,
/// <summary> Client --> Server - Used to update client's status and current game id. </summary>
StatusUpdate = 3, StatusUpdate = 3,
/// <summary> Client --> Server - Used to join a particular voice channel. </summary>
VoiceStateUpdate = 4, VoiceStateUpdate = 4,
//VoiceServerPing = 5, (Unused?)
/// <summary> Client --> Server - Used to ensure the server's voice server is alive. Only send this if voice connection fails or suddenly drops. </summary>
VoiceServerPing = 5,
/// <summary> Client --> Server - Used to resume a connection after a redirect occurs. </summary>
Resume = 6, Resume = 6,
/// <summary> Client <-- Server - Used to notify a client that they must reconnect to another gateway. </summary>
Redirect = 7, Redirect = 7,
/// <summary> Client --> Server - Used to request all members that were withheld by large_threshold </summary>
RequestGuildMembers = 8 RequestGuildMembers = 8
} }


@@ -92,8 +101,6 @@ namespace Discord.API
} }
} }



//Commands
internal sealed class JoinVoiceCommand : WebSocketMessage<JoinVoiceCommand.Data> internal sealed class JoinVoiceCommand : WebSocketMessage<JoinVoiceCommand.Data>
{ {
public JoinVoiceCommand() : base((int)GatewayOpCodes.VoiceStateUpdate) { } public JoinVoiceCommand() : base((int)GatewayOpCodes.VoiceStateUpdate) { }
@@ -112,7 +119,6 @@ namespace Discord.API
} }
} }


//Events
internal sealed class ResumeCommand : WebSocketMessage<ResumeCommand.Data> internal sealed class ResumeCommand : WebSocketMessage<ResumeCommand.Data>
{ {
public ResumeCommand() : base((int)GatewayOpCodes.Resume) { } public ResumeCommand() : base((int)GatewayOpCodes.Resume) { }


+ 19
- 19
src/Discord.Net/Net/WebSockets/GatewayWebSocket.cs View File

@@ -109,7 +109,7 @@ namespace Discord.Net.WebSockets


public void SendIdentify(string token) public void SendIdentify(string token)
{ {
IdentifyCommand msg = new IdentifyCommand();
var msg = new IdentifyCommand();
msg.Payload.Token = token; msg.Payload.Token = token;
msg.Payload.Properties["$device"] = "Discord.Net"; msg.Payload.Properties["$device"] = "Discord.Net";
if (_config.UseLargeThreshold) if (_config.UseLargeThreshold)
@@ -120,10 +120,10 @@ namespace Discord.Net.WebSockets


public void SendResume() 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() public override void SendHeartbeat()
@@ -133,31 +133,31 @@ namespace Discord.Net.WebSockets


public void SendStatusUpdate(long? idleSince, int? gameId) 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) 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) 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) 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);
} }
} }
} }

Loading…
Cancel
Save