@@ -35,6 +35,7 @@ namespace Discord
private int _unavailableGuilds;
private long _lastGuildAvailableTime;
private int _nextAudioId;
private bool _canReconnect;
/// <summary> Gets the shard if of this client. </summary>
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<string, VoiceRegion>();
}
@@ -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(); }
}
}