@@ -56,7 +56,11 @@ namespace Discord.API | |||
public int Version = 3; | |||
[JsonProperty("properties")] | |||
public Dictionary<string, string> Properties = new Dictionary<string, string>(); | |||
} | |||
[JsonProperty("large_threshold", NullValueHandling = NullValueHandling.Ignore)] | |||
public int? LargeThreshold; | |||
[JsonProperty("compress", NullValueHandling = NullValueHandling.Ignore)] | |||
public bool? Compress; | |||
} | |||
} | |||
internal sealed class ResumeCommand : WebSocketMessage<ResumeCommand.Data> | |||
{ | |||
@@ -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<WebSocketMessage>(json); | |||
if (msg.Sequence.HasValue) | |||
_lastSeq = msg.Sequence.Value; | |||
@@ -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<WebSocketMessageEventArgs> ProcessMessage; | |||
event EventHandler<WebSocketBinaryMessageEventArgs> BinaryMessage; | |||
event EventHandler<WebSocketTextMessageEventArgs> TextMessage; | |||
Task Connect(string host, CancellationToken cancelToken); | |||
Task Disconnect(); | |||
@@ -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) | |||
@@ -15,11 +15,17 @@ namespace Discord.Net.WebSockets | |||
private readonly WebSocket _parent; | |||
private WSSharpNWebSocket _webSocket; | |||
public event EventHandler<WebSocketMessageEventArgs> ProcessMessage; | |||
private void RaiseProcessMessage(string msg) | |||
public event EventHandler<WebSocketBinaryMessageEventArgs> BinaryMessage; | |||
public event EventHandler<WebSocketTextMessageEventArgs> 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); | |||