[apibrk] change: Specify WebSocket close code (#1500)
* API breaking change: Specify WebSocket close code Should fix #1479 and help overall with resuming sessions. * Also try to resume on missed heartbeats
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 { }
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <exception cref="ArgumentException">Unknown OAuth token type.</exception>
|
||||
@@ -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<Func<string>> 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);
|
||||
|
||||
|
||||
@@ -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(); }
|
||||
}
|
||||
/// <exception cref="NotSupportedException">This client is not configured with WebSocket support.</exception>
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
22
src/Discord.Net.WebSocket/GatewayReconnectException.cs
Normal file
22
src/Discord.Net.WebSocket/GatewayReconnectException.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace Discord.WebSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception thrown when the gateway client has been requested to
|
||||
/// reconnect.
|
||||
/// </summary>
|
||||
public class GatewayReconnectException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the
|
||||
/// <see cref="GatewayReconnectException"/> type.
|
||||
/// </summary>
|
||||
/// <param name="message">
|
||||
/// The reason why the gateway has been requested to reconnect.
|
||||
/// </param>
|
||||
public GatewayReconnectException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user