diff --git a/src/Discord.Net.Core/Net/WebSockets/IWebSocketClient.cs b/src/Discord.Net.Core/Net/WebSockets/IWebSocketClient.cs
index 14b41cce1..6791af354 100644
--- a/src/Discord.Net.Core/Net/WebSockets/IWebSocketClient.cs
+++ b/src/Discord.Net.Core/Net/WebSockets/IWebSocketClient.cs
@@ -14,7 +14,7 @@ namespace Discord.Net.WebSockets
void SetCancelToken(CancellationToken cancelToken);
Task ConnectAsync(string host);
- Task DisconnectAsync();
+ Task DisconnectAsync(int closeCode = 1000);
Task SendAsync(byte[] data, int index, int count, bool isText);
}
diff --git a/src/Discord.Net.Providers.WS4Net/WS4NetClient.cs b/src/Discord.Net.Providers.WS4Net/WS4NetClient.cs
index ef99c8045..50f19b778 100644
--- a/src/Discord.Net.Providers.WS4Net/WS4NetClient.cs
+++ b/src/Discord.Net.Providers.WS4Net/WS4NetClient.cs
@@ -40,7 +40,7 @@ namespace Discord.Net.Providers.WS4Net
{
if (disposing)
{
- DisconnectInternalAsync(true).GetAwaiter().GetResult();
+ DisconnectInternalAsync(isDisposing: true).GetAwaiter().GetResult();
_lock?.Dispose();
_cancelTokenSource?.Dispose();
}
@@ -92,19 +92,19 @@ namespace Discord.Net.Providers.WS4Net
_waitUntilConnect.Wait(_cancelToken);
}
- public async Task DisconnectAsync()
+ public async Task DisconnectAsync(int closeCode = 1000)
{
await _lock.WaitAsync().ConfigureAwait(false);
try
{
- await DisconnectInternalAsync().ConfigureAwait(false);
+ await DisconnectInternalAsync(closeCode: closeCode).ConfigureAwait(false);
}
finally
{
_lock.Release();
}
}
- private Task DisconnectInternalAsync(bool isDisposing = false)
+ private Task DisconnectInternalAsync(int closeCode = 1000, bool isDisposing = false)
{
_disconnectCancelTokenSource.Cancel();
if (_client == null)
@@ -112,7 +112,7 @@ namespace Discord.Net.Providers.WS4Net
if (_client.State == WebSocketState.Open)
{
- try { _client.Close(1000, ""); }
+ try { _client.Close(closeCode, ""); }
catch { }
}
diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs
index ff6d17240..3a46dcf21 100644
--- a/src/Discord.Net.Rest/DiscordRestApiClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs
@@ -47,7 +47,7 @@ namespace Discord.API
internal ulong? CurrentUserId { get; set; }
public RateLimitPrecision RateLimitPrecision { get; private set; }
internal bool UseSystemClock { get; set; }
-
+
internal JsonSerializer Serializer => _serializer;
/// Unknown OAuth token type.
@@ -164,7 +164,7 @@ namespace Discord.API
try { _loginCancelToken?.Cancel(false); }
catch { }
- await DisconnectInternalAsync().ConfigureAwait(false);
+ await DisconnectInternalAsync(null).ConfigureAwait(false);
await RequestQueue.ClearAsync().ConfigureAwait(false);
await RequestQueue.SetCancelTokenAsync(CancellationToken.None).ConfigureAwait(false);
@@ -175,7 +175,7 @@ namespace Discord.API
}
internal virtual Task ConnectInternalAsync() => Task.Delay(0);
- internal virtual Task DisconnectInternalAsync() => Task.Delay(0);
+ internal virtual Task DisconnectInternalAsync(Exception ex = null) => Task.Delay(0);
//Core
internal Task SendAsync(string method, Expression> endpointExpr, BucketIds ids,
@@ -1062,7 +1062,7 @@ namespace Discord.API
{
foreach (var roleId in args.RoleIds.Value)
Preconditions.NotEqual(roleId, 0, nameof(roleId));
- }
+ }
options = RequestOptions.CreateOrClone(options);
diff --git a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
index 9313f0711..ef97615e2 100644
--- a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
+++ b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
@@ -164,26 +164,17 @@ namespace Discord.API
}
}
- public async Task DisconnectAsync()
+ public async Task DisconnectAsync(Exception ex = null)
{
await _stateLock.WaitAsync().ConfigureAwait(false);
try
{
- await DisconnectInternalAsync().ConfigureAwait(false);
- }
- finally { _stateLock.Release(); }
- }
- public async Task DisconnectAsync(Exception ex)
- {
- await _stateLock.WaitAsync().ConfigureAwait(false);
- try
- {
- await DisconnectInternalAsync().ConfigureAwait(false);
+ await DisconnectInternalAsync(ex).ConfigureAwait(false);
}
finally { _stateLock.Release(); }
}
/// This client is not configured with WebSocket support.
- internal override async Task DisconnectInternalAsync()
+ internal override async Task DisconnectInternalAsync(Exception ex = null)
{
if (WebSocketClient == null)
throw new NotSupportedException("This client is not configured with WebSocket support.");
@@ -194,6 +185,9 @@ namespace Discord.API
try { _connectCancelToken?.Cancel(false); }
catch { }
+ if (ex is GatewayReconnectException)
+ await WebSocketClient.DisconnectAsync(4000);
+ else
await WebSocketClient.DisconnectAsync().ConfigureAwait(false);
ConnectionState = ConnectionState.Disconnected;
diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
index ed142d001..1819966b3 100644
--- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs
+++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
@@ -264,7 +264,7 @@ namespace Discord.WebSocket
{
await _gatewayLogger.DebugAsync("Disconnecting ApiClient").ConfigureAwait(false);
- await ApiClient.DisconnectAsync().ConfigureAwait(false);
+ await ApiClient.DisconnectAsync(ex).ConfigureAwait(false);
//Wait for tasks to complete
await _gatewayLogger.DebugAsync("Waiting for heartbeater").ConfigureAwait(false);
@@ -511,7 +511,7 @@ namespace Discord.WebSocket
case GatewayOpCode.Reconnect:
{
await _gatewayLogger.DebugAsync("Received Reconnect").ConfigureAwait(false);
- _connection.Error(new Exception("Server requested a reconnect"));
+ _connection.Error(new GatewayReconnectException("Server requested a reconnect"));
}
break;
case GatewayOpCode.Dispatch:
@@ -1689,7 +1689,7 @@ namespace Discord.WebSocket
{
if (ConnectionState == ConnectionState.Connected && (_guildDownloadTask?.IsCompleted ?? true))
{
- _connection.Error(new Exception("Server missed last heartbeat"));
+ _connection.Error(new GatewayReconnectException("Server missed last heartbeat"));
return;
}
}
diff --git a/src/Discord.Net.WebSocket/GatewayReconnectException.cs b/src/Discord.Net.WebSocket/GatewayReconnectException.cs
new file mode 100644
index 000000000..1a8024558
--- /dev/null
+++ b/src/Discord.Net.WebSocket/GatewayReconnectException.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Discord.WebSocket
+{
+ ///
+ /// An exception thrown when the gateway client has been requested to
+ /// reconnect.
+ ///
+ public class GatewayReconnectException : Exception
+ {
+ ///
+ /// Creates a new instance of the
+ /// type.
+ ///
+ ///
+ /// The reason why the gateway has been requested to reconnect.
+ ///
+ public GatewayReconnectException(string message)
+ : base(message)
+ { }
+ }
+}
diff --git a/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs b/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs
index 36a6fea4f..4723ae57a 100644
--- a/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs
+++ b/src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs
@@ -44,7 +44,7 @@ namespace Discord.Net.WebSockets
{
if (disposing)
{
- DisconnectInternalAsync(true).GetAwaiter().GetResult();
+ DisconnectInternalAsync(isDisposing: true).GetAwaiter().GetResult();
_disconnectTokenSource?.Dispose();
_cancelTokenSource?.Dispose();
_lock?.Dispose();
@@ -94,19 +94,19 @@ namespace Discord.Net.WebSockets
_task = RunAsync(_cancelToken);
}
- public async Task DisconnectAsync()
+ public async Task DisconnectAsync(int closeCode = 1000)
{
await _lock.WaitAsync().ConfigureAwait(false);
try
{
- await DisconnectInternalAsync().ConfigureAwait(false);
+ await DisconnectInternalAsync(closeCode: closeCode).ConfigureAwait(false);
}
finally
{
_lock.Release();
}
}
- private async Task DisconnectInternalAsync(bool isDisposing = false)
+ private async Task DisconnectInternalAsync(int closeCode = 1000, bool isDisposing = false)
{
try { _disconnectTokenSource.Cancel(false); }
catch { }
@@ -117,7 +117,8 @@ namespace Discord.Net.WebSockets
{
if (!isDisposing)
{
- try { await _client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", new CancellationToken()); }
+ var status = (WebSocketCloseStatus)closeCode;
+ try { await _client.CloseOutputAsync(status, "", new CancellationToken()); }
catch { }
}
try { _client.Dispose(); }
@@ -141,7 +142,7 @@ namespace Discord.Net.WebSockets
await _lock.WaitAsync().ConfigureAwait(false);
try
{
- await DisconnectInternalAsync(false);
+ await DisconnectInternalAsync(isDisposing: false);
}
finally
{