diff --git a/src/Discord.Net/API/WebSockets.cs b/src/Discord.Net/API/WebSockets.cs index 246bd2c6a..b253d380c 100644 --- a/src/Discord.Net/API/WebSockets.cs +++ b/src/Discord.Net/API/WebSockets.cs @@ -56,7 +56,11 @@ namespace Discord.API public int Version = 3; [JsonProperty("properties")] public Dictionary Properties = new Dictionary(); - } + [JsonProperty("large_threshold", NullValueHandling = NullValueHandling.Ignore)] + public int? LargeThreshold; + [JsonProperty("compress", NullValueHandling = NullValueHandling.Ignore)] + public bool? Compress; + } } internal sealed class ResumeCommand : WebSocketMessage { diff --git a/src/Discord.Net/Net/WebSockets/DataWebSocket.cs b/src/Discord.Net/Net/WebSockets/DataWebSocket.cs index 10ac57b22..a09dd016c 100644 --- a/src/Discord.Net/Net/WebSockets/DataWebSocket.cs +++ b/src/Discord.Net/Net/WebSockets/DataWebSocket.cs @@ -26,6 +26,8 @@ namespace Discord.Net.WebSockets LoginCommand msg = new LoginCommand(); msg.Payload.Token = token; msg.Payload.Properties["$device"] = "Discord.Net"; + //msg.Payload.LargeThreshold = 50; + msg.Payload.Compress = true; QueueMessage(msg); } private async Task Redirect(string server) @@ -67,6 +69,7 @@ namespace Discord.Net.WebSockets protected override async Task ProcessMessage(string json) { + await base.ProcessMessage(json); var msg = JsonConvert.DeserializeObject(json); if (msg.Sequence.HasValue) _lastSeq = msg.Sequence.Value; diff --git a/src/Discord.Net/Net/WebSockets/IWebSocketEngine.cs b/src/Discord.Net/Net/WebSockets/IWebSocketEngine.cs index 5ee746542..6fb868c21 100644 --- a/src/Discord.Net/Net/WebSockets/IWebSocketEngine.cs +++ b/src/Discord.Net/Net/WebSockets/IWebSocketEngine.cs @@ -5,15 +5,21 @@ using System.Threading.Tasks; namespace Discord.Net.WebSockets { - internal class WebSocketMessageEventArgs : EventArgs + internal class WebSocketBinaryMessageEventArgs : EventArgs + { + public readonly byte[] Data; + public WebSocketBinaryMessageEventArgs(byte[] data) { Data = data; } + } + internal class WebSocketTextMessageEventArgs : EventArgs { public readonly string Message; - public WebSocketMessageEventArgs(string msg) { Message = msg; } + public WebSocketTextMessageEventArgs(string msg) { Message = msg; } } internal interface IWebSocketEngine { - event EventHandler ProcessMessage; + event EventHandler BinaryMessage; + event EventHandler TextMessage; Task Connect(string host, CancellationToken cancelToken); Task Disconnect(); diff --git a/src/Discord.Net/Net/WebSockets/WebSocket.cs b/src/Discord.Net/Net/WebSockets/WebSocket.cs index c6b1a77f0..0b72cc064 100644 --- a/src/Discord.Net/Net/WebSockets/WebSocket.cs +++ b/src/Discord.Net/Net/WebSockets/WebSocket.cs @@ -1,6 +1,8 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.IO; +using System.IO.Compression; using System.Linq; using System.Runtime.ExceptionServices; using System.Threading; @@ -51,13 +53,23 @@ namespace Discord.Net.WebSockets _connectedEvent = new ManualResetEventSlim(false); _engine = new WebSocketSharpEngine(this, client.Config); - _engine.ProcessMessage += async (s, e) => + _engine.BinaryMessage += async (s, e) => + { + using (var compressed = new MemoryStream(e.Data, 2, e.Data.Length - 2)) + using (var decompressed = new MemoryStream()) + { + using (var zlib = new DeflateStream(compressed, CompressionMode.Decompress)) + await zlib.CopyToAsync(decompressed); + decompressed.Position = 0; + using (var reader = new StreamReader(decompressed)) + await ProcessMessage(await reader.ReadToEndAsync()); + } + }; + _engine.TextMessage += async (s, e) => { - if (_logLevel >= LogMessageSeverity.Debug) - RaiseOnLog(LogMessageSeverity.Debug, $"In: {e.Message}"); await ProcessMessage(e.Message); }; - } + } protected async Task BeginConnect() { @@ -185,7 +197,12 @@ namespace Discord.Net.WebSockets RaiseDisconnected(wasDisconnectUnexpected, _disconnectReason?.SourceException); } - protected abstract Task ProcessMessage(string json); + protected virtual Task ProcessMessage(string json) + { + if (_logLevel >= LogMessageSeverity.Debug) + RaiseOnLog(LogMessageSeverity.Debug, $"In: {json}"); + return TaskHelper.CompletedTask; + } protected abstract object GetKeepAlive(); protected void QueueMessage(object message) diff --git a/src/Discord.Net/Net/WebSockets/WebSocketSharpEngine.cs b/src/Discord.Net/Net/WebSockets/WebSocketSharpEngine.cs index 7841f4e4b..86cffca47 100644 --- a/src/Discord.Net/Net/WebSockets/WebSocketSharpEngine.cs +++ b/src/Discord.Net/Net/WebSockets/WebSocketSharpEngine.cs @@ -15,11 +15,17 @@ namespace Discord.Net.WebSockets private readonly WebSocket _parent; private WSSharpNWebSocket _webSocket; - public event EventHandler ProcessMessage; - private void RaiseProcessMessage(string msg) + public event EventHandler BinaryMessage; + public event EventHandler TextMessage; + private void RaiseBinaryMessage(byte[] data) { - if (ProcessMessage != null) - ProcessMessage(this, new WebSocketMessageEventArgs(msg)); + if (BinaryMessage != null) + BinaryMessage(this, new WebSocketBinaryMessageEventArgs(data)); + } + private void RaiseTextMessage(string msg) + { + if (TextMessage != null) + TextMessage(this, new WebSocketTextMessageEventArgs(msg)); } internal WebSocketSharpEngine(WebSocket parent, DiscordWSClientConfig config) @@ -34,9 +40,15 @@ namespace Discord.Net.WebSockets _webSocket = new WSSharpNWebSocket(host); _webSocket.EmitOnPing = false; _webSocket.EnableRedirection = true; - _webSocket.Compression = WebSocketSharp.CompressionMethod.None; + _webSocket.Compression = WebSocketSharp.CompressionMethod.Deflate; _webSocket.SetProxy(_config.ProxyUrl, _config.ProxyCredentials?.UserName, _config.ProxyCredentials?.Password); - _webSocket.OnMessage += (s, e) => RaiseProcessMessage(e.Data); + _webSocket.OnMessage += (s, e) => + { + if (e.Type == WebSocketSharp.Opcode.Binary) + RaiseBinaryMessage(e.RawData); + else if (e.Type == WebSocketSharp.Opcode.Text) + RaiseTextMessage(e.Data); + }; _webSocket.OnError += async (s, e) => { _parent.RaiseOnLog(LogMessageSeverity.Error, e.Exception.GetBaseException().Message);