Added better WebSocket disconnect support

This commit is contained in:
Brandon Smith
2015-09-03 20:03:47 -03:00
parent 6343e8bfe9
commit 61644d1f77

View File

@@ -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) _wasDisconnectUnexpected = isUnexpected;
ex = new Exception("Disconnect requested by user.");
_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());
@@ -236,7 +250,15 @@ namespace Discord
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;
}
} }
} }