Browse Source

Fixed reconnect crash

tags/docs-0.9
RogueException 9 years ago
parent
commit
de6ffed5c9
3 changed files with 60 additions and 47 deletions
  1. +24
    -15
      src/Discord.Net/DiscordClient.cs
  2. +23
    -0
      src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs
  3. +13
    -32
      src/Discord.Net/Net/WebSockets/WebSocket.cs

+ 24
- 15
src/Discord.Net/DiscordClient.cs View File

@@ -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
/// <summary> Connects to the Discord server with the provided token. </summary>
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> Returns a token for future connections. </returns>
public async Task<string> 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<string> 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<string> 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();
}

/// <summary> Disconnects from the Discord server, canceling any pending requests. </summary>
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();


+ 23
- 0
src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs View File

@@ -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()
{


+ 13
- 32
src/Discord.Net/Net/WebSockets/WebSocket.cs View File

@@ -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);


Loading…
Cancel
Save