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");