| @@ -1,6 +1,7 @@ | |||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| using System; | using System; | ||||
| using System.Collections.Concurrent; | using System.Collections.Concurrent; | ||||
| using System.ComponentModel; | |||||
| using System.Net.WebSockets; | using System.Net.WebSockets; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Threading; | using System.Threading; | ||||
| @@ -12,6 +13,7 @@ namespace Discord | |||||
| { | { | ||||
| private const int ReceiveChunkSize = 4096; | private const int ReceiveChunkSize = 4096; | ||||
| private const int SendChunkSize = 4096; | private const int SendChunkSize = 4096; | ||||
| private const int HR_TIMEOUT = -2147012894; | |||||
| protected readonly DiscordClient _client; | protected readonly DiscordClient _client; | ||||
| protected readonly int _sendInterval; | protected readonly int _sendInterval; | ||||
| @@ -90,7 +92,7 @@ namespace Discord | |||||
| { | { | ||||
| if (_task != null) | if (_task != null) | ||||
| { | { | ||||
| try { DisconnectInternal(new Exception("Disconnect requested by user.")); } catch (NullReferenceException) { } | |||||
| try { DisconnectInternal(new Exception("Disconnect requested by user."), false); } catch (NullReferenceException) { } | |||||
| try { await _task; } catch (NullReferenceException) { } | try { await _task; } catch (NullReferenceException) { } | ||||
| } | } | ||||
| } | } | ||||
| @@ -99,12 +101,11 @@ namespace Discord | |||||
| { | { | ||||
| _disconnectToken.Cancel(); | _disconnectToken.Cancel(); | ||||
| } | } | ||||
| protected void DisconnectInternal(Exception ex) | |||||
| protected void DisconnectInternal(Exception ex, bool isUnexpected = true) | |||||
| { | { | ||||
| if (_disconnectReason == null) | if (_disconnectReason == null) | ||||
| { | { | ||||
| if (ex == null) | |||||
| ex = new Exception("Disconnect requested by user."); | |||||
| _wasDisconnectUnexpected = isUnexpected; | |||||
| _disconnectReason = ex; | _disconnectReason = ex; | ||||
| _disconnectToken.Cancel(); | _disconnectToken.Cancel(); | ||||
| } | } | ||||
| @@ -141,14 +142,27 @@ namespace Discord | |||||
| { | { | ||||
| while (_webSocket.State == WebSocketState.Open && !cancelToken.IsCancellationRequested) | while (_webSocket.State == WebSocketState.Open && !cancelToken.IsCancellationRequested) | ||||
| { | { | ||||
| WebSocketReceiveResult result; | |||||
| WebSocketReceiveResult result = null; | |||||
| do | do | ||||
| { | { | ||||
| result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancelToken); | |||||
| if (_webSocket.State != WebSocketState.Open || cancelToken.IsCancellationRequested) | |||||
| return; | |||||
| try | |||||
| { | |||||
| result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancelToken); | |||||
| } | |||||
| catch (Win32Exception ex) | |||||
| when (ex.HResult == HR_TIMEOUT) | |||||
| { | |||||
| string msg = $"Connection timed out."; | |||||
| RaiseOnDebugMessage(DebugMessageType.Connection, msg); | |||||
| DisconnectInternal(new Exception(msg)); | |||||
| return; | |||||
| } | |||||
| if (result.MessageType == WebSocketMessageType.Close) | if (result.MessageType == WebSocketMessageType.Close) | ||||
| { | { | ||||
| _wasDisconnectUnexpected = true; | |||||
| string msg = $"Got Close Message ({result.CloseStatus?.ToString() ?? "Unexpected"}, {result.CloseStatusDescription ?? "No Reason"})"; | string msg = $"Got Close Message ({result.CloseStatus?.ToString() ?? "Unexpected"}, {result.CloseStatusDescription ?? "No Reason"})"; | ||||
| RaiseOnDebugMessage(DebugMessageType.Connection, msg); | RaiseOnDebugMessage(DebugMessageType.Connection, msg); | ||||
| DisconnectInternal(new Exception(msg)); | DisconnectInternal(new Exception(msg)); | ||||
| @@ -159,7 +173,7 @@ namespace Discord | |||||
| builder.Append(Encoding.UTF8.GetString(buffer, 0, result.Count)); | builder.Append(Encoding.UTF8.GetString(buffer, 0, result.Count)); | ||||
| } | } | ||||
| while (!result.EndOfMessage); | |||||
| while (result == null || !result.EndOfMessage); | |||||
| #if DEBUG | #if DEBUG | ||||
| System.Diagnostics.Debug.WriteLine(">>> " + builder.ToString()); | System.Diagnostics.Debug.WriteLine(">>> " + builder.ToString()); | ||||
| @@ -235,8 +249,16 @@ namespace Discord | |||||
| count = message.Length - (i * SendChunkSize); | count = message.Length - (i * SendChunkSize); | ||||
| else | else | ||||
| count = SendChunkSize; | count = SendChunkSize; | ||||
| await _webSocket.SendAsync(new ArraySegment<byte>(message, offset, count), WebSocketMessageType.Text, isLast, cancelToken); | |||||
| try | |||||
| { | |||||
| await _webSocket.SendAsync(new ArraySegment<byte>(message, offset, count), WebSocketMessageType.Text, isLast, cancelToken); | |||||
| } | |||||
| catch (Win32Exception ex) | |||||
| when (ex.HResult == HR_TIMEOUT) | |||||
| { | |||||
| return; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||