diff --git a/src/Discord.Net/DiscordSocketClient.cs b/src/Discord.Net/DiscordSocketClient.cs
index d3ea71ffd..966c2aef8 100644
--- a/src/Discord.Net/DiscordSocketClient.cs
+++ b/src/Discord.Net/DiscordSocketClient.cs
@@ -35,6 +35,7 @@ namespace Discord
private int _unavailableGuilds;
private long _lastGuildAvailableTime;
private int _nextAudioId;
+ private bool _canReconnect;
/// Gets the shard if of this client.
public int ShardId { get; }
@@ -114,7 +115,7 @@ namespace Discord
protected override async Task OnLogoutAsync()
{
if (ConnectionState != ConnectionState.Disconnected)
- await DisconnectInternalAsync(null).ConfigureAwait(false);
+ await DisconnectInternalAsync(null, false).ConfigureAwait(false);
_voiceRegions = ImmutableDictionary.Create();
}
@@ -125,7 +126,7 @@ namespace Discord
await _connectionLock.WaitAsync().ConfigureAwait(false);
try
{
- await ConnectInternalAsync().ConfigureAwait(false);
+ await ConnectInternalAsync(false).ConfigureAwait(false);
}
finally { _connectionLock.Release(); }
@@ -136,17 +137,17 @@ namespace Discord
await _guildDownloadTask.ConfigureAwait(false);
}
}
- private async Task ConnectInternalAsync()
+ private async Task ConnectInternalAsync(bool isReconnecting)
{
if (LoginState != LoginState.LoggedIn)
throw new InvalidOperationException("You must log in before connecting.");
- if (_reconnectCancelToken != null && !_reconnectCancelToken.IsCancellationRequested)
+ if (!isReconnecting && _reconnectCancelToken != null && !_reconnectCancelToken.IsCancellationRequested)
_reconnectCancelToken.Cancel();
var state = ConnectionState;
if (state == ConnectionState.Connecting || state == ConnectionState.Connected)
- await DisconnectInternalAsync(null).ConfigureAwait(false);
+ await DisconnectInternalAsync(null, isReconnecting).ConfigureAwait(false);
ConnectionState = ConnectionState.Connecting;
await _gatewayLogger.InfoAsync("Connecting").ConfigureAwait(false);
@@ -164,12 +165,13 @@ namespace Discord
await ApiClient.SendIdentifyAsync().ConfigureAwait(false);
await _connectTask.Task.ConfigureAwait(false);
+ _canReconnect = true;
ConnectionState = ConnectionState.Connected;
await _gatewayLogger.InfoAsync("Connected").ConfigureAwait(false);
}
catch (Exception)
{
- await DisconnectInternalAsync(null).ConfigureAwait(false);
+ await DisconnectInternalAsync(null, isReconnecting).ConfigureAwait(false);
throw;
}
}
@@ -180,7 +182,7 @@ namespace Discord
await _connectionLock.WaitAsync().ConfigureAwait(false);
try
{
- await DisconnectInternalAsync(null).ConfigureAwait(false);
+ await DisconnectInternalAsync(null, false).ConfigureAwait(false);
}
finally { _connectionLock.Release(); }
}
@@ -190,14 +192,18 @@ namespace Discord
await _connectionLock.WaitAsync().ConfigureAwait(false);
try
{
- await DisconnectInternalAsync(ex).ConfigureAwait(false);
+ await DisconnectInternalAsync(ex, false).ConfigureAwait(false);
}
finally { _connectionLock.Release(); }
}
- private async Task DisconnectInternalAsync(Exception ex)
+ private async Task DisconnectInternalAsync(Exception ex, bool isReconnecting)
{
- if (_reconnectCancelToken != null && !_reconnectCancelToken.IsCancellationRequested)
- _reconnectCancelToken.Cancel();
+ if (!isReconnecting)
+ {
+ _canReconnect = false;
+ if (_reconnectCancelToken != null && !_reconnectCancelToken.IsCancellationRequested)
+ _reconnectCancelToken.Cancel();
+ }
ulong guildId;
@@ -242,7 +248,8 @@ namespace Discord
await _connectionLock.WaitAsync().ConfigureAwait(false);
try
{
- await DisconnectInternalAsync(null).ConfigureAwait(false);
+ if (!_canReconnect || _reconnectTask != null) return;
+ await DisconnectInternalAsync(null, true).ConfigureAwait(false);
_reconnectCancelToken = new CancellationTokenSource();
_reconnectTask = ReconnectInternalAsync(_reconnectCancelToken.Token);
}
@@ -253,34 +260,37 @@ namespace Discord
try
{
int nextReconnectDelay = 1000;
- while (!cancelToken.IsCancellationRequested)
+ while (true)
{
+ await Task.Delay(nextReconnectDelay, cancelToken).ConfigureAwait(false);
+ nextReconnectDelay *= 2;
+ if (nextReconnectDelay > 30000)
+ nextReconnectDelay = 30000;
+
+ await _connectionLock.WaitAsync().ConfigureAwait(false);
try
{
- await Task.Delay(nextReconnectDelay, cancelToken).ConfigureAwait(false);
- nextReconnectDelay *= 2;
- if (nextReconnectDelay > 30000)
- nextReconnectDelay = 30000;
-
- await _connectionLock.WaitAsync().ConfigureAwait(false);
- try
- {
- if (cancelToken.IsCancellationRequested) return;
- await ConnectInternalAsync().ConfigureAwait(false);
- }
- finally { _connectionLock.Release(); }
+ if (cancelToken.IsCancellationRequested) return;
+ await ConnectInternalAsync(true).ConfigureAwait(false);
+ _reconnectTask = null;
return;
}
catch (Exception ex)
{
await _gatewayLogger.WarningAsync("Reconnect failed", ex).ConfigureAwait(false);
}
+ finally { _connectionLock.Release(); }
}
}
- catch (OperationCanceledException) { }
- finally
+ catch (OperationCanceledException)
{
- _reconnectTask = null;
+ await _connectionLock.WaitAsync().ConfigureAwait(false);
+ try
+ {
+ await _gatewayLogger.DebugAsync("Reconnect cancelled").ConfigureAwait(false);
+ _reconnectTask = null;
+ }
+ finally { _connectionLock.Release(); }
}
}