Added cleanup and doc to websockets
This commit is contained in:
@@ -7,10 +7,26 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace Discord.API
|
namespace Discord.API
|
||||||
{
|
{
|
||||||
//Commands
|
public enum VoiceOpCodes : byte
|
||||||
internal sealed class VoiceLoginCommand : WebSocketMessage<VoiceLoginCommand.Data>
|
|
||||||
{
|
{
|
||||||
public VoiceLoginCommand() : base(0) { }
|
/// <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
|
||||||
|
internal sealed class IdentifyCommand : WebSocketMessage<IdentifyCommand.Data>
|
||||||
|
{
|
||||||
|
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")]
|
||||||
|
|||||||
@@ -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();
|
SendIdentify();
|
||||||
msg.Payload.ServerId = _serverId.Value;
|
|
||||||
msg.Payload.SessionId = _sessionId;
|
|
||||||
msg.Payload.Token = _token;
|
|
||||||
msg.Payload.UserId = _userId.Value;
|
|
||||||
QueueMessage(msg);
|
|
||||||
|
|
||||||
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();
|
SendSelectProtocol(ip, port);
|
||||||
login2.Payload.Protocol = "udp";
|
|
||||||
login2.Payload.SocketData.Address = ip;
|
|
||||||
login2.Payload.SocketData.Mode = _encryptionMode;
|
|
||||||
login2.Payload.SocketData.Port = port;
|
|
||||||
QueueMessage(login2);
|
|
||||||
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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) { }
|
||||||
|
|||||||
@@ -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();
|
var msg = new ResumeCommand();
|
||||||
resumeMsg.Payload.SessionId = _sessionId;
|
msg.Payload.SessionId = _sessionId;
|
||||||
resumeMsg.Payload.Sequence = _lastSeq;
|
msg.Payload.Sequence = _lastSeq;
|
||||||
QueueMessage(resumeMsg);
|
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();
|
var msg = new StatusUpdateCommand();
|
||||||
updateStatus.Payload.IdleSince = idleSince;
|
msg.Payload.IdleSince = idleSince;
|
||||||
updateStatus.Payload.GameId = gameId;
|
msg.Payload.GameId = gameId;
|
||||||
QueueMessage(updateStatus);
|
QueueMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendJoinVoice(long serverId, long channelId)
|
public void SendJoinVoice(long serverId, long channelId)
|
||||||
{
|
{
|
||||||
var joinVoice = new JoinVoiceCommand();
|
var msg = new JoinVoiceCommand();
|
||||||
joinVoice.Payload.ServerId = serverId;
|
msg.Payload.ServerId = serverId;
|
||||||
joinVoice.Payload.ChannelId = channelId;
|
msg.Payload.ChannelId = channelId;
|
||||||
QueueMessage(joinVoice);
|
QueueMessage(msg);
|
||||||
}
|
}
|
||||||
public void SendLeaveVoice(long serverId)
|
public void SendLeaveVoice(long serverId)
|
||||||
{
|
{
|
||||||
var leaveVoice = new JoinVoiceCommand();
|
var msg = new JoinVoiceCommand();
|
||||||
leaveVoice.Payload.ServerId = serverId;
|
msg.Payload.ServerId = serverId;
|
||||||
QueueMessage(leaveVoice);
|
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();
|
var msg = new GetUsersCommand();
|
||||||
getOfflineUsers.Payload.ServerId = serverId;
|
msg.Payload.ServerId = serverId;
|
||||||
QueueMessage(getOfflineUsers);
|
QueueMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user