Fixed pings, incoming message debugging and joining channels
This commit is contained in:
83
src/Discord.Net.Sessions/SessionsService.cs
Normal file
83
src/Discord.Net.Sessions/SessionsService.cs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Discord.Sessions
|
||||||
|
{
|
||||||
|
public class SessionsService : IService
|
||||||
|
{
|
||||||
|
private static readonly DualChannelPermissions _ownerPerm = new DualChannelPermissions() { ReadMessages = true, ManageChannel = true };
|
||||||
|
private static readonly DualChannelPermissions _memberPerm = new DualChannelPermissions() { ReadMessages = true };
|
||||||
|
private static readonly DualChannelPermissions _everyonePerm = new DualChannelPermissions() { ReadMessages = false };
|
||||||
|
|
||||||
|
private DiscordClient _client;
|
||||||
|
|
||||||
|
public void Install(DiscordClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Channel> GetSessions(Server server)
|
||||||
|
=> server.TextChannels.Where(x => x.Name != "" && x.Name[0] == '!');
|
||||||
|
|
||||||
|
public async Task<Channel> CreateSession(Server server, string name, bool includeVoice, User owner)
|
||||||
|
{
|
||||||
|
name = '!' + name;
|
||||||
|
Channel textChannel = await _client.CreateChannel(server, name, ChannelType.Text);
|
||||||
|
Channel voiceChannel = includeVoice ? await _client.CreateChannel(server, name, ChannelType.Voice) : null;
|
||||||
|
|
||||||
|
//Take away read from everyone
|
||||||
|
await _client.SetChannelPermissions(textChannel, server.EveryoneRole, _everyonePerm);
|
||||||
|
await _client.SetChannelPermissions(textChannel, owner, _ownerPerm);
|
||||||
|
|
||||||
|
return textChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DestroySession(Channel channel)
|
||||||
|
{
|
||||||
|
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
||||||
|
CheckSession(channel);
|
||||||
|
|
||||||
|
await _client.DeleteChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task JoinSession(Channel channel, User user)
|
||||||
|
{
|
||||||
|
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
||||||
|
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||||
|
CheckSession(channel);
|
||||||
|
|
||||||
|
return _client.SetChannelPermissions(channel, user, _memberPerm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LeaveSession(Channel channel, User user)
|
||||||
|
{
|
||||||
|
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
||||||
|
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||||
|
CheckSession(channel);
|
||||||
|
|
||||||
|
if (IsOwner(channel, user))
|
||||||
|
await DestroySession(channel);
|
||||||
|
else
|
||||||
|
await _client.RemoveChannelPermissions(channel, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsSession(Channel channel)
|
||||||
|
=> channel.Name == "" && channel.Name[0] == '!';
|
||||||
|
private void CheckSession(Channel channel)
|
||||||
|
{
|
||||||
|
if (!IsSession(channel))
|
||||||
|
throw new InvalidOperationException("The provided channel is not a session.");
|
||||||
|
}
|
||||||
|
private bool IsOwner(Channel channel, User user)
|
||||||
|
=> _client.GetChannelPermissions(channel, user).ManageMessages == true;
|
||||||
|
/*private IEnumerable<string> GetPermissionUsers(Channel channel)
|
||||||
|
{
|
||||||
|
return channel.PermissionOverwrites
|
||||||
|
.Where(x => x.TargetType == PermissionTarget.User && x.Allow.Text_ReadMessages)
|
||||||
|
.Select(x => x.TargetId);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,24 +23,6 @@ namespace Discord.API
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public class GetIceResponse
|
|
||||||
{
|
|
||||||
[JsonProperty("ttl")]
|
|
||||||
public string TTL;
|
|
||||||
[JsonProperty("servers")]
|
|
||||||
public ServerData[] Servers;
|
|
||||||
|
|
||||||
public sealed class ServerData
|
|
||||||
{
|
|
||||||
[JsonProperty("url")]
|
|
||||||
public string URL;
|
|
||||||
[JsonProperty("username")]
|
|
||||||
public string Username;
|
|
||||||
[JsonProperty("credential")]
|
|
||||||
public string Credential;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//Commands
|
//Commands
|
||||||
internal sealed class JoinVoiceCommand : WebSocketMessage<JoinVoiceCommand.Data>
|
internal sealed class JoinVoiceCommand : WebSocketMessage<JoinVoiceCommand.Data>
|
||||||
{
|
{
|
||||||
@@ -110,9 +92,9 @@ namespace Discord.API
|
|||||||
public SocketInfo SocketData = new SocketInfo();
|
public SocketInfo SocketData = new SocketInfo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal sealed class VoiceKeepAliveCommand : WebSocketMessage<object>
|
internal sealed class VoiceKeepAliveCommand : WebSocketMessage<ulong>
|
||||||
{
|
{
|
||||||
public VoiceKeepAliveCommand() : base(3, null) { }
|
public VoiceKeepAliveCommand() : base(3, EpochTime.GetMilliseconds()) { }
|
||||||
}
|
}
|
||||||
internal sealed class IsTalkingCommand : WebSocketMessage<IsTalkingCommand.Data>
|
internal sealed class IsTalkingCommand : WebSocketMessage<IsTalkingCommand.Data>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace Discord
|
|||||||
public async Task<IDiscordVoiceClient> JoinVoiceServer(Channel channel)
|
public async Task<IDiscordVoiceClient> JoinVoiceServer(Channel channel)
|
||||||
{
|
{
|
||||||
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
||||||
CheckReady(); //checkVoice is done inside the voice client
|
CheckReady(true); //checkVoice is done inside the voice client
|
||||||
|
|
||||||
var client = await CreateVoiceClient(channel.Server).ConfigureAwait(false);
|
var client = await CreateVoiceClient(channel.Server).ConfigureAwait(false);
|
||||||
await client.JoinChannel(channel.Id).ConfigureAwait(false);
|
await client.JoinChannel(channel.Id).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ namespace Discord
|
|||||||
throw new InvalidOperationException("The client is connecting.");
|
throw new InvalidOperationException("The client is connecting.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkVoice && !_config.EnableVoice)
|
if (checkVoice && _config.VoiceMode == DiscordVoiceMode.Disabled)
|
||||||
throw new InvalidOperationException("Voice is not enabled for this client.");
|
throw new InvalidOperationException("Voice is not enabled for this client.");
|
||||||
}
|
}
|
||||||
protected void RaiseEvent(string name, Action action)
|
protected void RaiseEvent(string name, Action action)
|
||||||
|
|||||||
@@ -36,12 +36,14 @@ namespace Discord.Net.WebSockets
|
|||||||
private ushort _sequence;
|
private ushort _sequence;
|
||||||
private long? _serverId, _channelId, _userId;
|
private long? _serverId, _channelId, _userId;
|
||||||
private string _sessionId, _token, _encryptionMode;
|
private string _sessionId, _token, _encryptionMode;
|
||||||
|
private ulong _ping;
|
||||||
|
|
||||||
private Thread _sendThread, _receiveThread;
|
private Thread _sendThread, _receiveThread;
|
||||||
|
|
||||||
public long? CurrentServerId => _serverId;
|
public long? CurrentServerId => _serverId;
|
||||||
public long? CurrentChannelId => _channelId;
|
public long? CurrentChannelId => _channelId;
|
||||||
public VoiceBuffer OutputBuffer => _sendBuffer;
|
public VoiceBuffer OutputBuffer => _sendBuffer;
|
||||||
|
public int Ping => (int)_ping;
|
||||||
|
|
||||||
public VoiceWebSocket(DiscordWSClient client)
|
public VoiceWebSocket(DiscordWSClient client)
|
||||||
: base(client)
|
: base(client)
|
||||||
@@ -315,26 +317,27 @@ namespace Discord.Net.WebSockets
|
|||||||
|
|
||||||
pingPacket = new byte[8];
|
pingPacket = new byte[8];
|
||||||
pingPacket[0] = 0x80; //Flags;
|
pingPacket[0] = 0x80; //Flags;
|
||||||
pingPacket[1] = 0x78; //Payload Type
|
pingPacket[1] = 0xC9; //Payload Type
|
||||||
pingPacket[3] = 0x00; //Length
|
pingPacket[2] = 0x00; //Length
|
||||||
pingPacket[4] = 0x01; //Length (1*8 bytes)
|
pingPacket[3] = 0x01; //Length (1*8 bytes)
|
||||||
pingPacket[5] = (byte)((_ssrc >> 24) & 0xFF);
|
pingPacket[4] = (byte)((_ssrc >> 24) & 0xFF);
|
||||||
pingPacket[6] = (byte)((_ssrc >> 16) & 0xFF);
|
pingPacket[5] = (byte)((_ssrc >> 16) & 0xFF);
|
||||||
pingPacket[7] = (byte)((_ssrc >> 8) & 0xFF);
|
pingPacket[6] = (byte)((_ssrc >> 8) & 0xFF);
|
||||||
pingPacket[8] = (byte)((_ssrc >> 0) & 0xFF);
|
pingPacket[7] = (byte)((_ssrc >> 0) & 0xFF);
|
||||||
if (_isEncrypted)
|
if (_isEncrypted)
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(pingPacket, 0, nonce, 0, 8);
|
Buffer.BlockCopy(pingPacket, 0, nonce, 0, 8);
|
||||||
int ret = Sodium.Encrypt(pingPacket, 8, encodedFrame, 0, nonce, _secretKey);
|
int ret = Sodium.Encrypt(pingPacket, 8, encodedFrame, 0, nonce, _secretKey);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
throw new InvalidOperationException("Failed to encrypt ping packet");
|
throw new InvalidOperationException("Failed to encrypt ping packet");
|
||||||
pingPacket = new byte[ret];
|
pingPacket = new byte[pingPacket.Length + 16];
|
||||||
Buffer.BlockCopy(encodedFrame, 0, pingPacket, 0, ret);
|
Buffer.BlockCopy(encodedFrame, 0, pingPacket, 0, pingPacket.Length);
|
||||||
|
Array.Clear(nonce, 0, nonce.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtpPacketLength = 0;
|
int rtpPacketLength = 0;
|
||||||
voicePacket[0] = 0x80; //Flags;
|
voicePacket[0] = 0x80; //Flags;
|
||||||
voicePacket[1] = 0xC9; //Payload Type
|
voicePacket[1] = 0x78; //Payload Type
|
||||||
voicePacket[8] = (byte)((_ssrc >> 24) & 0xFF);
|
voicePacket[8] = (byte)((_ssrc >> 24) & 0xFF);
|
||||||
voicePacket[9] = (byte)((_ssrc >> 16) & 0xFF);
|
voicePacket[9] = (byte)((_ssrc >> 16) & 0xFF);
|
||||||
voicePacket[10] = (byte)((_ssrc >> 8) & 0xFF);
|
voicePacket[10] = (byte)((_ssrc >> 8) & 0xFF);
|
||||||
@@ -385,7 +388,7 @@ namespace Discord.Net.WebSockets
|
|||||||
}
|
}
|
||||||
if (currentTicks > nextPingTicks)
|
if (currentTicks > nextPingTicks)
|
||||||
{
|
{
|
||||||
_udp.Send(pingPacket, pingPacket.Length);
|
//_udp.Send(pingPacket, pingPacket.Length);
|
||||||
nextPingTicks = currentTicks + 5 * Stopwatch.Frequency;
|
nextPingTicks = currentTicks + 5 * Stopwatch.Frequency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -412,6 +415,7 @@ namespace Discord.Net.WebSockets
|
|||||||
|
|
||||||
protected override async Task ProcessMessage(string json)
|
protected override async Task ProcessMessage(string json)
|
||||||
{
|
{
|
||||||
|
await base.ProcessMessage(json).ConfigureAwait(false);
|
||||||
var msg = JsonConvert.DeserializeObject<WebSocketMessage>(json);
|
var msg = JsonConvert.DeserializeObject<WebSocketMessage>(json);
|
||||||
switch (msg.Operation)
|
switch (msg.Operation)
|
||||||
{
|
{
|
||||||
@@ -454,7 +458,9 @@ namespace Discord.Net.WebSockets
|
|||||||
break;
|
break;
|
||||||
case 3: //PONG
|
case 3: //PONG
|
||||||
{
|
{
|
||||||
//var payload = (msg.Payload as JToken).ToObject<VoiceKeepAliveCommand>();
|
ulong time = EpochTime.GetMilliseconds();
|
||||||
|
var payload = (ulong)(long)msg.Payload;
|
||||||
|
_ping = payload - time;
|
||||||
//TODO: Use this to estimate latency
|
//TODO: Use this to estimate latency
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user