diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs
index 416ac6759..53d3341eb 100644
--- a/src/Discord.Net/DiscordClient.cs
+++ b/src/Discord.Net/DiscordClient.cs
@@ -95,7 +95,7 @@ namespace Discord
_api = new DiscordAPIClient(_config.LogLevel);
_dataSocket = new DataWebSocket(this);
_dataSocket.Connected += (s, e) => { if (_state == (int)DiscordClientState.Connecting) CompleteConnect(); };
- _dataSocket.Disconnected += async (s, e) => { RaiseDisconnected(e); if (e.WasUnexpected) await Connect(_token); /*await _dataSocket.Reconnect(_cancelToken);*/ };
+ _dataSocket.Disconnected += async (s, e) => { RaiseDisconnected(e); if (e.WasUnexpected) await Reconnect(_token); };
if (_config.EnableVoice)
{
_voiceSocket = new VoiceWebSocket(this);
@@ -553,7 +553,8 @@ namespace Discord
/// Connects to the Discord server with the provided token.
public async Task Connect(string token)
{
- await Disconnect().ConfigureAwait(false);
+ if (_state != (int)DiscordClientState.Disconnected)
+ await Disconnect().ConfigureAwait(false);
if (_config.LogLevel >= LogMessageSeverity.Verbose)
RaiseOnLog(LogMessageSeverity.Verbose, LogMessageSource.Authentication, $"Using cached token.");
@@ -564,7 +565,8 @@ namespace Discord
/// Returns a token for future connections.
public async Task Connect(string email, string password)
{
- await Disconnect().ConfigureAwait(false);
+ if (_state != (int)DiscordClientState.Disconnected)
+ await Disconnect().ConfigureAwait(false);
var response = await _api.Login(email, password).ConfigureAwait(false);
if (_config.LogLevel >= LogMessageSeverity.Verbose)
@@ -572,11 +574,15 @@ namespace Discord
return await ConnectInternal(response.Token).ConfigureAwait(false);
}
- private async Task ConnectInternal(string token)
+ private Task Reconnect(string token)
{
- if (_state != (int)DiscordClientState.Disconnected)
- throw new InvalidOperationException("Client is already connected or connecting to the server.");
+ if (_config.LogLevel >= LogMessageSeverity.Verbose)
+ RaiseOnLog(LogMessageSeverity.Verbose, LogMessageSource.Authentication, $"Using cached token.");
+ return ConnectInternal(token);
+ }
+ private async Task ConnectInternal(string token)
+ {
try
{
_disconnectedEvent.Reset();
@@ -618,14 +624,14 @@ namespace Discord
}
protected void CompleteConnect()
{
- _state = (int)WebSocketState.Connected;
+ _state = (int)DiscordClientState.Connected;
_connectedEvent.Set();
RaiseConnected();
}
/// Disconnects from the Discord server, canceling any pending requests.
public Task Disconnect() => DisconnectInternal(new Exception("Disconnect was requested by user."), isUnexpected: false);
- protected Task DisconnectInternal(Exception ex, bool isUnexpected = true, bool skipAwait = false)
+ protected Task DisconnectInternal(Exception ex = null, bool isUnexpected = true, bool skipAwait = false)
{
int oldState;
bool hasWriterLock;
@@ -644,7 +650,7 @@ namespace Discord
if (hasWriterLock)
{
_wasDisconnectUnexpected = isUnexpected;
- _disconnectReason = ExceptionDispatchInfo.Capture(ex);
+ _disconnectReason = ex != null ? ExceptionDispatchInfo.Capture(ex) : null;
_cancelTokenSource.Cancel();
}
@@ -662,12 +668,12 @@ namespace Discord
else
task = _cancelToken.Wait();
- try
- {
- await task.ConfigureAwait(false);
- }
+ try { await task.ConfigureAwait(false); }
catch (Exception ex) { await DisconnectInternal(ex, skipAwait: true).ConfigureAwait(false); }
+ //When the first task ends, make sure the rest do too
+ await DisconnectInternal(skipAwait: true);
+
bool wasUnexpected = _wasDisconnectUnexpected;
_wasDisconnectUnexpected = false;
@@ -680,8 +686,11 @@ namespace Discord
if (_config.EnableVoice)
await _voiceSocket.Disconnect().ConfigureAwait(false);
- Message ignored;
- while (_pendingMessages.TryDequeue(out ignored)) { }
+ if (_config.UseMessageQueue)
+ {
+ Message ignored;
+ while (_pendingMessages.TryDequeue(out ignored)) { }
+ }
_channels.Clear();
_members.Clear();
diff --git a/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs b/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs
index 38b64f8f5..86c7e80ce 100644
--- a/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs
+++ b/src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs
@@ -70,6 +70,29 @@ namespace Discord.Net.WebSockets
await Connect(host, cancelToken);
}
+ public async Task Reconnect(CancellationToken cancelToken)
+ {
+ try
+ {
+ await Task.Delay(_client.Config.ReconnectDelay, cancelToken).ConfigureAwait(false);
+ while (!cancelToken.IsCancellationRequested)
+ {
+ try
+ {
+ await Connect(_host, cancelToken).ConfigureAwait(false);
+ break;
+ }
+ catch (OperationCanceledException) { throw; }
+ catch (Exception ex)
+ {
+ RaiseOnLog(LogMessageSeverity.Error, $"DataSocket reconnect failed: {ex.GetBaseException().Message}");
+ //Net is down? We can keep trying to reconnect until the user runs Disconnect()
+ await Task.Delay(_client.Config.FailedReconnectDelay, cancelToken).ConfigureAwait(false);
+ }
+ }
+ }
+ catch (OperationCanceledException) { }
+ }
protected override Task[] Run()
{
diff --git a/src/Discord.Net/Net/WebSockets/WebSocket.cs b/src/Discord.Net/Net/WebSockets/WebSocket.cs
index 4644c396a..59acefdf5 100644
--- a/src/Discord.Net/Net/WebSockets/WebSocket.cs
+++ b/src/Discord.Net/Net/WebSockets/WebSocket.cs
@@ -69,29 +69,6 @@ namespace Discord.Net.WebSockets
};
}
- public async Task Reconnect(CancellationToken cancelToken)
- {
- try
- {
- await Task.Delay(_client.Config.ReconnectDelay, cancelToken).ConfigureAwait(false);
- while (!cancelToken.IsCancellationRequested)
- {
- try
- {
- await Connect(_host, cancelToken).ConfigureAwait(false);
- break;
- }
- catch (OperationCanceledException) { throw; }
- catch (Exception ex)
- {
- RaiseOnLog(LogMessageSeverity.Error, $"DataSocket reconnect failed: {ex.GetBaseException().Message}");
- //Net is down? We can keep trying to reconnect until the user runs Disconnect()
- await Task.Delay(_client.Config.FailedReconnectDelay, cancelToken).ConfigureAwait(false);
- }
- }
- }
- catch (OperationCanceledException) { }
- }
protected virtual async Task Connect(string host, CancellationToken cancelToken)
{
if (_state != (int)WebSocketState.Disconnected)
@@ -127,7 +104,7 @@ namespace Discord.Net.WebSockets
=> Connect(_host, _cancelToken);*/
public Task Disconnect() => DisconnectInternal(new Exception("Disconnect was requested by user."), isUnexpected: false);
- protected Task DisconnectInternal(Exception ex, bool isUnexpected = true, bool skipAwait = false)
+ protected Task DisconnectInternal(Exception ex = null, bool isUnexpected = true, bool skipAwait = false)
{
int oldState;
bool hasWriterLock;
@@ -146,7 +123,7 @@ namespace Discord.Net.WebSockets
if (hasWriterLock)
{
_wasDisconnectUnexpected = isUnexpected;
- _disconnectReason = ExceptionDispatchInfo.Capture(ex);
+ _disconnectReason = ex != null ? ExceptionDispatchInfo.Capture(ex) : null;
_cancelTokenSource.Cancel();
}
@@ -158,13 +135,17 @@ namespace Discord.Net.WebSockets
protected virtual async Task RunTasks()
{
- Task task = Task.WhenAll(Run());
+ Task[] tasks = Run();
+ Task firstTask = Task.WhenAny(tasks);
+ Task allTasks = Task.WhenAll(tasks);
- try
- {
- await task.ConfigureAwait(false);
- }
- catch (Exception ex) { await DisconnectInternal(ex, skipAwait: true).ConfigureAwait(false); }
+ try { await firstTask.ConfigureAwait(false); }
+ catch (Exception ex) { await DisconnectInternal(ex: ex, skipAwait: true).ConfigureAwait(false); }
+
+ //When the first task ends, make sure the rest do too
+ await DisconnectInternal(skipAwait: true);
+ try { await allTasks.ConfigureAwait(false); }
+ catch { }
bool wasUnexpected = _wasDisconnectUnexpected;
_wasDisconnectUnexpected = false;
@@ -207,7 +188,7 @@ namespace Discord.Net.WebSockets
{
while (!cancelToken.IsCancellationRequested)
{
- if (_heartbeatInterval > 0)
+ if (_state == (int)WebSocketState.Connected)
{
QueueMessage(GetKeepAlive());
await Task.Delay(_heartbeatInterval, cancelToken).ConfigureAwait(false);