From 3fa6ba8d509075438e7c13aab5e4e7c6d3559b52 Mon Sep 17 00:00:00 2001 From: RogueException Date: Sun, 22 Nov 2015 00:57:39 -0400 Subject: [PATCH] Fixed pings, incoming message debugging and joining channels --- src/Discord.Net.Sessions/SessionsService.cs | 83 +++++++++++++++++++ src/Discord.Net/API/Voice.cs | 22 +---- src/Discord.Net/DiscordClient.Voice.cs | 2 +- src/Discord.Net/DiscordWSClient.cs | 2 +- .../Net/WebSockets/VoiceWebSocket.cs | 32 ++++--- 5 files changed, 106 insertions(+), 35 deletions(-) create mode 100644 src/Discord.Net.Sessions/SessionsService.cs diff --git a/src/Discord.Net.Sessions/SessionsService.cs b/src/Discord.Net.Sessions/SessionsService.cs new file mode 100644 index 000000000..1f366459d --- /dev/null +++ b/src/Discord.Net.Sessions/SessionsService.cs @@ -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 GetSessions(Server server) + => server.TextChannels.Where(x => x.Name != "" && x.Name[0] == '!'); + + public async Task 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 GetPermissionUsers(Channel channel) + { + return channel.PermissionOverwrites + .Where(x => x.TargetType == PermissionTarget.User && x.Allow.Text_ReadMessages) + .Select(x => x.TargetId); + }*/ + } +} diff --git a/src/Discord.Net/API/Voice.cs b/src/Discord.Net/API/Voice.cs index 84a20ed59..695f539b4 100644 --- a/src/Discord.Net/API/Voice.cs +++ b/src/Discord.Net/API/Voice.cs @@ -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 internal sealed class JoinVoiceCommand : WebSocketMessage { @@ -110,9 +92,9 @@ namespace Discord.API public SocketInfo SocketData = new SocketInfo(); } } - internal sealed class VoiceKeepAliveCommand : WebSocketMessage + internal sealed class VoiceKeepAliveCommand : WebSocketMessage { - public VoiceKeepAliveCommand() : base(3, null) { } + public VoiceKeepAliveCommand() : base(3, EpochTime.GetMilliseconds()) { } } internal sealed class IsTalkingCommand : WebSocketMessage { diff --git a/src/Discord.Net/DiscordClient.Voice.cs b/src/Discord.Net/DiscordClient.Voice.cs index d923c2d7e..cd05432f3 100644 --- a/src/Discord.Net/DiscordClient.Voice.cs +++ b/src/Discord.Net/DiscordClient.Voice.cs @@ -48,7 +48,7 @@ namespace Discord public async Task JoinVoiceServer(Channel 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); await client.JoinChannel(channel.Id).ConfigureAwait(false); diff --git a/src/Discord.Net/DiscordWSClient.cs b/src/Discord.Net/DiscordWSClient.cs index f3613db09..e46cc0cf3 100644 --- a/src/Discord.Net/DiscordWSClient.cs +++ b/src/Discord.Net/DiscordWSClient.cs @@ -282,7 +282,7 @@ namespace Discord 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."); } protected void RaiseEvent(string name, Action action) diff --git a/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs b/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs index b6a9a6446..394be9842 100644 --- a/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs +++ b/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs @@ -36,12 +36,14 @@ namespace Discord.Net.WebSockets private ushort _sequence; private long? _serverId, _channelId, _userId; private string _sessionId, _token, _encryptionMode; + private ulong _ping; private Thread _sendThread, _receiveThread; public long? CurrentServerId => _serverId; public long? CurrentChannelId => _channelId; public VoiceBuffer OutputBuffer => _sendBuffer; + public int Ping => (int)_ping; public VoiceWebSocket(DiscordWSClient client) : base(client) @@ -312,29 +314,30 @@ namespace Discord.Net.WebSockets } else voicePacket = new byte[MaxOpusSize + 12]; - + pingPacket = new byte[8]; pingPacket[0] = 0x80; //Flags; - pingPacket[1] = 0x78; //Payload Type - pingPacket[3] = 0x00; //Length - pingPacket[4] = 0x01; //Length (1*8 bytes) - pingPacket[5] = (byte)((_ssrc >> 24) & 0xFF); - pingPacket[6] = (byte)((_ssrc >> 16) & 0xFF); - pingPacket[7] = (byte)((_ssrc >> 8) & 0xFF); - pingPacket[8] = (byte)((_ssrc >> 0) & 0xFF); + pingPacket[1] = 0xC9; //Payload Type + pingPacket[2] = 0x00; //Length + pingPacket[3] = 0x01; //Length (1*8 bytes) + pingPacket[4] = (byte)((_ssrc >> 24) & 0xFF); + pingPacket[5] = (byte)((_ssrc >> 16) & 0xFF); + pingPacket[6] = (byte)((_ssrc >> 8) & 0xFF); + pingPacket[7] = (byte)((_ssrc >> 0) & 0xFF); if (_isEncrypted) { Buffer.BlockCopy(pingPacket, 0, nonce, 0, 8); int ret = Sodium.Encrypt(pingPacket, 8, encodedFrame, 0, nonce, _secretKey); if (ret != 0) throw new InvalidOperationException("Failed to encrypt ping packet"); - pingPacket = new byte[ret]; - Buffer.BlockCopy(encodedFrame, 0, pingPacket, 0, ret); + pingPacket = new byte[pingPacket.Length + 16]; + Buffer.BlockCopy(encodedFrame, 0, pingPacket, 0, pingPacket.Length); + Array.Clear(nonce, 0, nonce.Length); } int rtpPacketLength = 0; voicePacket[0] = 0x80; //Flags; - voicePacket[1] = 0xC9; //Payload Type + voicePacket[1] = 0x78; //Payload Type voicePacket[8] = (byte)((_ssrc >> 24) & 0xFF); voicePacket[9] = (byte)((_ssrc >> 16) & 0xFF); voicePacket[10] = (byte)((_ssrc >> 8) & 0xFF); @@ -385,7 +388,7 @@ namespace Discord.Net.WebSockets } if (currentTicks > nextPingTicks) { - _udp.Send(pingPacket, pingPacket.Length); + //_udp.Send(pingPacket, pingPacket.Length); nextPingTicks = currentTicks + 5 * Stopwatch.Frequency; } } @@ -412,6 +415,7 @@ namespace Discord.Net.WebSockets protected override async Task ProcessMessage(string json) { + await base.ProcessMessage(json).ConfigureAwait(false); var msg = JsonConvert.DeserializeObject(json); switch (msg.Operation) { @@ -454,7 +458,9 @@ namespace Discord.Net.WebSockets break; case 3: //PONG { - //var payload = (msg.Payload as JToken).ToObject(); + ulong time = EpochTime.GetMilliseconds(); + var payload = (ulong)(long)msg.Payload; + _ping = payload - time; //TODO: Use this to estimate latency } break;