From cb88b69a7f61ddc61001a6848460bd2a5c36c7e7 Mon Sep 17 00:00:00 2001 From: RogueException Date: Thu, 27 Aug 2015 17:38:24 -0300 Subject: [PATCH] Added XHRRawOutput, XHRTiming and VoiceInput debug types --- src/Discord.Net.Net45/Discord.Net.csproj | 3 + src/Discord.Net/DiscordClient.Events.cs | 5 +- src/Discord.Net/DiscordClient.cs | 11 ++-- src/Discord.Net/DiscordDataSocket.cs | 8 +-- src/Discord.Net/DiscordVoiceSocket.cs | 46 ++++++++++----- src/Discord.Net/DiscordWebSocket.cs | 12 ++-- .../Helpers/JsonHttpClient.Events.cs | 14 +++++ src/Discord.Net/Helpers/JsonHttpClient.cs | 56 ++++++++++--------- 8 files changed, 103 insertions(+), 52 deletions(-) create mode 100644 src/Discord.Net/Helpers/JsonHttpClient.Events.cs diff --git a/src/Discord.Net.Net45/Discord.Net.csproj b/src/Discord.Net.Net45/Discord.Net.csproj index 61efa7cbe..ea99530de 100644 --- a/src/Discord.Net.Net45/Discord.Net.csproj +++ b/src/Discord.Net.Net45/Discord.Net.csproj @@ -110,6 +110,9 @@ Helpers\JsonHttpClient.cs + + Helpers\JsonHttpClient.Events.cs + HttpException.cs diff --git a/src/Discord.Net/DiscordClient.Events.cs b/src/Discord.Net/DiscordClient.Events.cs index 9a264b1e5..0e2078556 100644 --- a/src/Discord.Net/DiscordClient.Events.cs +++ b/src/Discord.Net/DiscordClient.Events.cs @@ -10,7 +10,10 @@ namespace Discord WebSocketRawInput, //TODO: Make Http instanced and add a rawoutput event WebSocketUnknownOpCode, WebSocketUnknownEvent, - VoiceOutput + XHRRawOutput, + XHRTiming, + VoiceInput, + VoiceOutput, } public sealed class LogMessageEventArgs : EventArgs { diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs index 44ba6d75f..2b771fe46 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordClient.cs @@ -90,8 +90,6 @@ namespace Discord _blockEvent = new ManualResetEventSlim(true); _config = config ?? new DiscordClientConfig(); _rand = new Random(); - _http = new JsonHttpClient(); - _api = new DiscordAPI(_http); _serializer = new JsonSerializer(); #if TEST_RESPONSES @@ -367,7 +365,12 @@ namespace Discord } ); - _webSocket = new DiscordDataSocket(this, _config.ConnectionTimeout, _config.WebSocketInterval); + _http = new JsonHttpClient(config.EnableDebug); + _api = new DiscordAPI(_http); + if (_config.EnableDebug) + _http.OnDebugMessage += (s, e) => RaiseOnDebugMessage(e.Type, e.Message); + + _webSocket = new DiscordDataSocket(this, config.ConnectionTimeout, config.WebSocketInterval, config.EnableDebug); _webSocket.Connected += (s, e) => RaiseConnected(); _webSocket.Disconnected += async (s, e) => { @@ -406,7 +409,7 @@ namespace Discord #if !DNXCORE50 if (_config.EnableVoice) { - _voiceWebSocket = new DiscordVoiceSocket(this, _config.VoiceConnectionTimeout, _config.WebSocketInterval); + _voiceWebSocket = new DiscordVoiceSocket(this, _config.VoiceConnectionTimeout, _config.WebSocketInterval, config.EnableDebug); _voiceWebSocket.Connected += (s, e) => RaiseVoiceConnected(); _voiceWebSocket.Disconnected += async (s, e) => { diff --git a/src/Discord.Net/DiscordDataSocket.cs b/src/Discord.Net/DiscordDataSocket.cs index 7de5eefb6..605c71683 100644 --- a/src/Discord.Net/DiscordDataSocket.cs +++ b/src/Discord.Net/DiscordDataSocket.cs @@ -1,5 +1,4 @@ using Discord.API.Models; -using Discord.Helpers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; @@ -13,8 +12,8 @@ namespace Discord { private readonly ManualResetEventSlim _connectWaitOnLogin, _connectWaitOnLogin2; - public DiscordDataSocket(DiscordClient client, int timeout, int interval) - : base(client, timeout, interval) + public DiscordDataSocket(DiscordClient client, int timeout, int interval, bool isDebug) + : base(client, timeout, interval, isDebug) { _connectWaitOnLogin = new ManualResetEventSlim(false); _connectWaitOnLogin2 = new ManualResetEventSlim(false); @@ -72,7 +71,8 @@ namespace Discord } break; default: - RaiseOnDebugMessage(DebugMessageType.WebSocketUnknownOpCode, "Unknown DataSocket op: " + msg.Operation); + if (_isDebug) + RaiseOnDebugMessage(DebugMessageType.WebSocketUnknownOpCode, "Unknown DataSocket op: " + msg.Operation); break; } #if DNXCORE diff --git a/src/Discord.Net/DiscordVoiceSocket.cs b/src/Discord.Net/DiscordVoiceSocket.cs index d66849ac9..f8411b0bc 100644 --- a/src/Discord.Net/DiscordVoiceSocket.cs +++ b/src/Discord.Net/DiscordVoiceSocket.cs @@ -49,8 +49,8 @@ namespace Discord #endif #endif - public DiscordVoiceSocket(DiscordClient client, int timeout, int interval) - : base(client, timeout, interval) + public DiscordVoiceSocket(DiscordClient client, int timeout, int interval, bool isDebug) + : base(client, timeout, interval, isDebug) { _connectWaitOnLogin = new ManualResetEventSlim(false); #if !DNXCORE50 @@ -287,7 +287,8 @@ namespace Discord break; #endif default: - RaiseOnDebugMessage(DebugMessageType.WebSocketUnknownOpCode, "Unknown VoiceSocket op: " + msg.Operation); + if (_isDebug) + RaiseOnDebugMessage(DebugMessageType.WebSocketUnknownOpCode, "Unknown VoiceSocket op: " + msg.Operation); break; } #if DNXCORE50 @@ -322,25 +323,42 @@ namespace Discord else { //Parse RTP Data - /*if (length < 12) - throw new Exception($"Unexpected message length. Expected >= 12, got {length}."); + if (length < 12) + { + if (_isDebug) + RaiseOnDebugMessage(DebugMessageType.VoiceInput, $"Unexpected message length. Expected >= 12, got {length}."); + return; + } byte flags = buffer[0]; if (flags != 0x80) - throw new Exception("Unexpected Flags"); + { + if (_isDebug) + RaiseOnDebugMessage(DebugMessageType.VoiceInput, $"Unexpected Flags: {flags}"); + return; + } byte payloadType = buffer[1]; if (payloadType != 0x78) - throw new Exception("Unexpected Payload Type"); + { + if (_isDebug) + RaiseOnDebugMessage(DebugMessageType.VoiceInput, $"Unexpected Payload Type: {flags}"); + return; + } - ushort sequenceNumber = (ushort)((buffer[2] << 8) | buffer[3]); - uint timestamp = (uint)((buffer[4] << 24) | (buffer[5] << 16) | - (buffer[6] << 8) | (buffer[7] << 0)); - uint ssrc = (uint)((buffer[8] << 24) | (buffer[9] << 16) | - (buffer[10] << 8) | (buffer[11] << 0)); + ushort sequenceNumber = (ushort)((buffer[2] << 8) | + buffer[3] << 0); + uint timestamp = (uint)((buffer[4] << 24) | + (buffer[5] << 16) | + (buffer[6] << 8) | + (buffer[7] << 0)); + uint ssrc = (uint)((buffer[8] << 24) | + (buffer[9] << 16) | + (buffer[10] << 8) | + (buffer[11] << 0)); //Decrypt - if (_mode == "xsalsa20_poly1305") + /*if (_mode == "xsalsa20_poly1305") { if (length < 36) //12 + 24 throw new Exception($"Unexpected message length. Expected >= 36, got {length}."); @@ -362,6 +380,8 @@ namespace Discord buffer = newBuffer; }*/ + if (_isDebug) + RaiseOnDebugMessage(DebugMessageType.VoiceInput, $"Received {buffer.Length - 12} bytes."); //TODO: Use Voice Data } } diff --git a/src/Discord.Net/DiscordWebSocket.cs b/src/Discord.Net/DiscordWebSocket.cs index 2c4c81c54..e2b666f49 100644 --- a/src/Discord.Net/DiscordWebSocket.cs +++ b/src/Discord.Net/DiscordWebSocket.cs @@ -14,22 +14,24 @@ namespace Discord private const int SendChunkSize = 4096; protected readonly DiscordClient _client; - protected volatile CancellationTokenSource _disconnectToken; - protected int _timeout, _heartbeatInterval; protected readonly int _sendInterval; - protected string _host; + protected readonly bool _isDebug; + private readonly ConcurrentQueue _sendQueue; + protected volatile CancellationTokenSource _disconnectToken; private volatile ClientWebSocket _webSocket; private volatile Task _tasks; - private ConcurrentQueue _sendQueue; + protected string _host; + protected int _timeout, _heartbeatInterval; private DateTime _lastHeartbeat; private bool _isConnected; - public DiscordWebSocket(DiscordClient client, int timeout, int interval) + public DiscordWebSocket(DiscordClient client, int timeout, int interval, bool isDebug) { _client = client; _timeout = timeout; _sendInterval = interval; + _isDebug = isDebug; _sendQueue = new ConcurrentQueue(); } diff --git a/src/Discord.Net/Helpers/JsonHttpClient.Events.cs b/src/Discord.Net/Helpers/JsonHttpClient.Events.cs new file mode 100644 index 000000000..02c9afd99 --- /dev/null +++ b/src/Discord.Net/Helpers/JsonHttpClient.Events.cs @@ -0,0 +1,14 @@ +using System; + +namespace Discord.Helpers +{ + internal partial class JsonHttpClient + { + public event EventHandler OnDebugMessage; + protected void RaiseOnDebugMessage(DebugMessageType type, string message) + { + if (OnDebugMessage != null) + OnDebugMessage(this, new LogMessageEventArgs(type, message)); + } + } +} diff --git a/src/Discord.Net/Helpers/JsonHttpClient.cs b/src/Discord.Net/Helpers/JsonHttpClient.cs index 688fc7a32..093e7f9b0 100644 --- a/src/Discord.Net/Helpers/JsonHttpClient.cs +++ b/src/Discord.Net/Helpers/JsonHttpClient.cs @@ -1,7 +1,6 @@ using Discord.API; using Newtonsoft.Json; using System; -using System.Diagnostics; using System.IO; using System.Globalization; using System.Net.Http; @@ -9,24 +8,22 @@ using System.Net; using System.Reflection; using System.Text; using System.Threading.Tasks; +using System.Diagnostics; namespace Discord.Helpers { - internal class JsonHttpClient + internal partial class JsonHttpClient { -#if TEST_RESPONSES - private const bool _isDebug = true; -#else - private const bool _isDebug = false; -#endif + private bool _isDebug; private readonly HttpClient _client; private readonly HttpMethod _patch; #if TEST_RESPONSES private readonly JsonSerializerSettings _settings; #endif - public JsonHttpClient() + public JsonHttpClient(bool isDebug) { + _isDebug = isDebug; _patch = new HttpMethod("PATCH"); //Not sure why this isn't a default... _client = new HttpClient(new HttpClientHandler @@ -131,8 +128,8 @@ namespace Discord.Helpers private async Task Send(HttpMethod method, string path, HttpContent content) { string responseJson = await SendRequest(method, path, content, true); - if (path.StartsWith(Endpoints.BaseApi)) - CheckEmptyResponse(responseJson); + if (path.StartsWith(Endpoints.BaseApi) && !string.IsNullOrEmpty(responseJson)) + throw new Exception("API check failed: Response is not empty."); return responseJson; } #else @@ -142,9 +139,25 @@ namespace Discord.Helpers private async Task SendRequest(HttpMethod method, string path, HttpContent content, bool hasResponse) { -#if TEST_RESPONSES - Stopwatch stopwatch = Stopwatch.StartNew(); -#endif + Stopwatch stopwatch = null; + if (_isDebug) + { + if (content != null) + { + if (content is StringContent) + { + string json = await (content as StringContent).ReadAsStringAsync(); + RaiseOnDebugMessage(DebugMessageType.XHRRawOutput, $"{method} {path}: {json}"); + } + else + { + byte[] bytes = await content.ReadAsByteArrayAsync(); + RaiseOnDebugMessage(DebugMessageType.XHRRawOutput, $"{method} {path}: {bytes.Length} bytes"); + } + } + stopwatch = Stopwatch.StartNew(); + } + string result; using (HttpRequestMessage msg = new HttpRequestMessage(method, path)) { @@ -168,21 +181,14 @@ namespace Discord.Helpers } } -#if TEST_RESPONSES - stopwatch.Stop(); - Debug.WriteLine($"{method} {path}: {Math.Round(stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond, 2)}ms"); -#endif + if (_isDebug) + { + stopwatch.Stop(); + RaiseOnDebugMessage(DebugMessageType.XHRTiming, $"{method} {path}: {Math.Round(stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond, 2)}ms"); + } return result; } -#if TEST_RESPONSES - private void CheckEmptyResponse(string json) - { - if (!string.IsNullOrEmpty(json)) - throw new Exception("API check failed: Response is not empty."); - } -#endif - private StringContent AsJson(object obj) { return new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");