Browse Source

[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
tags/2.3.0
Monica S GitHub 5 years ago
parent
commit
ed869bd78b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 48 additions and 31 deletions
  1. +1
    -1
      src/Discord.Net.Core/Net/WebSockets/IWebSocketClient.cs
  2. +5
    -5
      src/Discord.Net.Providers.WS4Net/WS4NetClient.cs
  3. +4
    -4
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  4. +6
    -12
      src/Discord.Net.WebSocket/DiscordSocketApiClient.cs
  5. +3
    -3
      src/Discord.Net.WebSocket/DiscordSocketClient.cs
  6. +22
    -0
      src/Discord.Net.WebSocket/GatewayReconnectException.cs
  7. +7
    -6
      src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs

+ 1
- 1
src/Discord.Net.Core/Net/WebSockets/IWebSocketClient.cs View File

@@ -14,7 +14,7 @@ namespace Discord.Net.WebSockets
void SetCancelToken(CancellationToken cancelToken); void SetCancelToken(CancellationToken cancelToken);


Task ConnectAsync(string host); Task ConnectAsync(string host);
Task DisconnectAsync();
Task DisconnectAsync(int closeCode = 1000);


Task SendAsync(byte[] data, int index, int count, bool isText); Task SendAsync(byte[] data, int index, int count, bool isText);
} }


+ 5
- 5
src/Discord.Net.Providers.WS4Net/WS4NetClient.cs View File

@@ -40,7 +40,7 @@ namespace Discord.Net.Providers.WS4Net
{ {
if (disposing) if (disposing)
{ {
DisconnectInternalAsync(true).GetAwaiter().GetResult();
DisconnectInternalAsync(isDisposing: true).GetAwaiter().GetResult();
_lock?.Dispose(); _lock?.Dispose();
_cancelTokenSource?.Dispose(); _cancelTokenSource?.Dispose();
} }
@@ -92,19 +92,19 @@ namespace Discord.Net.Providers.WS4Net
_waitUntilConnect.Wait(_cancelToken); _waitUntilConnect.Wait(_cancelToken);
} }


public async Task DisconnectAsync()
public async Task DisconnectAsync(int closeCode = 1000)
{ {
await _lock.WaitAsync().ConfigureAwait(false); await _lock.WaitAsync().ConfigureAwait(false);
try try
{ {
await DisconnectInternalAsync().ConfigureAwait(false);
await DisconnectInternalAsync(closeCode: closeCode).ConfigureAwait(false);
} }
finally finally
{ {
_lock.Release(); _lock.Release();
} }
} }
private Task DisconnectInternalAsync(bool isDisposing = false)
private Task DisconnectInternalAsync(int closeCode = 1000, bool isDisposing = false)
{ {
_disconnectCancelTokenSource.Cancel(); _disconnectCancelTokenSource.Cancel();
if (_client == null) if (_client == null)
@@ -112,7 +112,7 @@ namespace Discord.Net.Providers.WS4Net


if (_client.State == WebSocketState.Open) if (_client.State == WebSocketState.Open)
{ {
try { _client.Close(1000, ""); }
try { _client.Close(closeCode, ""); }
catch { } catch { }
} }




+ 4
- 4
src/Discord.Net.Rest/DiscordRestApiClient.cs View File

@@ -47,7 +47,7 @@ namespace Discord.API
internal ulong? CurrentUserId { get; set; } internal ulong? CurrentUserId { get; set; }
public RateLimitPrecision RateLimitPrecision { get; private set; } public RateLimitPrecision RateLimitPrecision { get; private set; }
internal bool UseSystemClock { get; set; } internal bool UseSystemClock { get; set; }
internal JsonSerializer Serializer => _serializer; internal JsonSerializer Serializer => _serializer;


/// <exception cref="ArgumentException">Unknown OAuth token type.</exception> /// <exception cref="ArgumentException">Unknown OAuth token type.</exception>
@@ -164,7 +164,7 @@ namespace Discord.API
try { _loginCancelToken?.Cancel(false); } try { _loginCancelToken?.Cancel(false); }
catch { } catch { }


await DisconnectInternalAsync().ConfigureAwait(false);
await DisconnectInternalAsync(null).ConfigureAwait(false);
await RequestQueue.ClearAsync().ConfigureAwait(false); await RequestQueue.ClearAsync().ConfigureAwait(false);


await RequestQueue.SetCancelTokenAsync(CancellationToken.None).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 ConnectInternalAsync() => Task.Delay(0);
internal virtual Task DisconnectInternalAsync() => Task.Delay(0);
internal virtual Task DisconnectInternalAsync(Exception ex = null) => Task.Delay(0);


//Core //Core
internal Task SendAsync(string method, Expression<Func<string>> endpointExpr, BucketIds ids, 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) foreach (var roleId in args.RoleIds.Value)
Preconditions.NotEqual(roleId, 0, nameof(roleId)); Preconditions.NotEqual(roleId, 0, nameof(roleId));
}
}


options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);




+ 6
- 12
src/Discord.Net.WebSocket/DiscordSocketApiClient.cs View File

@@ -164,26 +164,17 @@ namespace Discord.API
} }
} }


public async Task DisconnectAsync()
public async Task DisconnectAsync(Exception ex = null)
{ {
await _stateLock.WaitAsync().ConfigureAwait(false); await _stateLock.WaitAsync().ConfigureAwait(false);
try 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(); } finally { _stateLock.Release(); }
} }
/// <exception cref="NotSupportedException">This client is not configured with WebSocket support.</exception> /// <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) if (WebSocketClient == null)
throw new NotSupportedException("This client is not configured with WebSocket support."); throw new NotSupportedException("This client is not configured with WebSocket support.");
@@ -194,6 +185,9 @@ namespace Discord.API
try { _connectCancelToken?.Cancel(false); } try { _connectCancelToken?.Cancel(false); }
catch { } catch { }


if (ex is GatewayReconnectException)
await WebSocketClient.DisconnectAsync(4000);
else
await WebSocketClient.DisconnectAsync().ConfigureAwait(false); await WebSocketClient.DisconnectAsync().ConfigureAwait(false);


ConnectionState = ConnectionState.Disconnected; ConnectionState = ConnectionState.Disconnected;


+ 3
- 3
src/Discord.Net.WebSocket/DiscordSocketClient.cs View File

@@ -264,7 +264,7 @@ namespace Discord.WebSocket
{ {


await _gatewayLogger.DebugAsync("Disconnecting ApiClient").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Disconnecting ApiClient").ConfigureAwait(false);
await ApiClient.DisconnectAsync().ConfigureAwait(false);
await ApiClient.DisconnectAsync(ex).ConfigureAwait(false);


//Wait for tasks to complete //Wait for tasks to complete
await _gatewayLogger.DebugAsync("Waiting for heartbeater").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Waiting for heartbeater").ConfigureAwait(false);
@@ -511,7 +511,7 @@ namespace Discord.WebSocket
case GatewayOpCode.Reconnect: case GatewayOpCode.Reconnect:
{ {
await _gatewayLogger.DebugAsync("Received Reconnect").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Reconnect").ConfigureAwait(false);
_connection.Error(new Exception("Server requested a reconnect"));
_connection.Error(new GatewayReconnectException("Server requested a reconnect"));
} }
break; break;
case GatewayOpCode.Dispatch: case GatewayOpCode.Dispatch:
@@ -1689,7 +1689,7 @@ namespace Discord.WebSocket
{ {
if (ConnectionState == ConnectionState.Connected && (_guildDownloadTask?.IsCompleted ?? true)) if (ConnectionState == ConnectionState.Connected && (_guildDownloadTask?.IsCompleted ?? true))
{ {
_connection.Error(new Exception("Server missed last heartbeat"));
_connection.Error(new GatewayReconnectException("Server missed last heartbeat"));
return; return;
} }
} }


+ 22
- 0
src/Discord.Net.WebSocket/GatewayReconnectException.cs View 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)
{ }
}
}

+ 7
- 6
src/Discord.Net.WebSocket/Net/DefaultWebSocketClient.cs View File

@@ -44,7 +44,7 @@ namespace Discord.Net.WebSockets
{ {
if (disposing) if (disposing)
{ {
DisconnectInternalAsync(true).GetAwaiter().GetResult();
DisconnectInternalAsync(isDisposing: true).GetAwaiter().GetResult();
_disconnectTokenSource?.Dispose(); _disconnectTokenSource?.Dispose();
_cancelTokenSource?.Dispose(); _cancelTokenSource?.Dispose();
_lock?.Dispose(); _lock?.Dispose();
@@ -94,19 +94,19 @@ namespace Discord.Net.WebSockets
_task = RunAsync(_cancelToken); _task = RunAsync(_cancelToken);
} }


public async Task DisconnectAsync()
public async Task DisconnectAsync(int closeCode = 1000)
{ {
await _lock.WaitAsync().ConfigureAwait(false); await _lock.WaitAsync().ConfigureAwait(false);
try try
{ {
await DisconnectInternalAsync().ConfigureAwait(false);
await DisconnectInternalAsync(closeCode: closeCode).ConfigureAwait(false);
} }
finally finally
{ {
_lock.Release(); _lock.Release();
} }
} }
private async Task DisconnectInternalAsync(bool isDisposing = false)
private async Task DisconnectInternalAsync(int closeCode = 1000, bool isDisposing = false)
{ {
try { _disconnectTokenSource.Cancel(false); } try { _disconnectTokenSource.Cancel(false); }
catch { } catch { }
@@ -117,7 +117,8 @@ namespace Discord.Net.WebSockets
{ {
if (!isDisposing) if (!isDisposing)
{ {
try { await _client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", new CancellationToken()); }
var status = (WebSocketCloseStatus)closeCode;
try { await _client.CloseOutputAsync(status, "", new CancellationToken()); }
catch { } catch { }
} }
try { _client.Dispose(); } try { _client.Dispose(); }
@@ -141,7 +142,7 @@ namespace Discord.Net.WebSockets
await _lock.WaitAsync().ConfigureAwait(false); await _lock.WaitAsync().ConfigureAwait(false);
try try
{ {
await DisconnectInternalAsync(false);
await DisconnectInternalAsync(isDisposing: false);
} }
finally finally
{ {


Loading…
Cancel
Save