From e6be52e83bb286e0a652ab1464dfbaf856ea55de Mon Sep 17 00:00:00 2001 From: Brandon Smith Date: Tue, 1 Sep 2015 19:17:54 -0300 Subject: [PATCH] Use better exceptions during websocket errors --- src/Discord.Net/DiscordDataSocket.cs | 2 +- src/Discord.Net/DiscordVoiceSocket.cs | 20 ++++++----- src/Discord.Net/DiscordWebSocket.cs | 49 +++++++++++++++++++-------- 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/Discord.Net/DiscordDataSocket.cs b/src/Discord.Net/DiscordDataSocket.cs index 7631860ab..3525568ca 100644 --- a/src/Discord.Net/DiscordDataSocket.cs +++ b/src/Discord.Net/DiscordDataSocket.cs @@ -42,7 +42,7 @@ namespace Discord } catch (OperationCanceledException) { - throw new InvalidOperationException("Bad Token"); + throw _disconnectReason; } try { _connectWaitOnLogin2.Wait(cancelToken); } //Waiting on READY handler catch (OperationCanceledException) { return; } diff --git a/src/Discord.Net/DiscordVoiceSocket.cs b/src/Discord.Net/DiscordVoiceSocket.cs index cef90cdb9..53ffb1b1d 100644 --- a/src/Discord.Net/DiscordVoiceSocket.cs +++ b/src/Discord.Net/DiscordVoiceSocket.cs @@ -109,7 +109,7 @@ namespace Discord } catch (OperationCanceledException) { - throw new InvalidOperationException("Bad Token"); + throw _disconnectReason; } SetConnected(); @@ -129,8 +129,9 @@ namespace Discord ProcessUdpMessage(result); } } - catch { } - finally { cancelSource.Cancel(); } + catch (OperationCanceledException) { } + catch (Exception ex) { DisconnectInternal(ex); } + finally { DisconnectInternal(); } } #if USE_THREAD @@ -156,7 +157,7 @@ namespace Discord uint timestamp = 0; double nextTicks = 0.0; double ticksPerMillisecond = Stopwatch.Frequency / 1000.0; - double ticksPerFrame = ticksPerMillisecond * _encoder.FrameLength; + double ticksPerFrame = ticksPerMillisecond * _encoder.FrameLength; double spinLockThreshold = 1.5 * ticksPerMillisecond; uint samplesPerFrame = (uint)_encoder.SamplesPerFrame; Stopwatch sw = Stopwatch.StartNew(); @@ -208,11 +209,12 @@ namespace Discord #endif } } - catch { } - finally { cancelSource.Cancel(); } - } + catch (OperationCanceledException) { } + catch (Exception ex) { DisconnectInternal(ex); } + finally { DisconnectInternal(); } + } #endif - //Closes the UDP socket when _disconnectToken is triggered, since UDPClient doesn't allow passing a canceltoken + //Closes the UDP socket when _disconnectToken is triggered, since UDPClient doesn't allow passing a canceltoken private async Task WatcherAsync() { var cancelToken = _disconnectToken.Token; @@ -220,7 +222,7 @@ namespace Discord { await Task.Delay(-1, cancelToken); } - catch (TaskCanceledException) { } + catch (OperationCanceledException) { } finally { _udp.Close(); } } diff --git a/src/Discord.Net/DiscordWebSocket.cs b/src/Discord.Net/DiscordWebSocket.cs index 1538ff508..f68d245a7 100644 --- a/src/Discord.Net/DiscordWebSocket.cs +++ b/src/Discord.Net/DiscordWebSocket.cs @@ -19,12 +19,13 @@ namespace Discord private readonly ConcurrentQueue _sendQueue; protected CancellationTokenSource _disconnectToken; + protected string _host; + protected int _timeout, _heartbeatInterval; + protected Exception _disconnectReason; private ClientWebSocket _webSocket; private DateTime _lastHeartbeat; private Task _task; - protected string _host; - protected int _timeout, _heartbeatInterval; - private bool _isConnected, _wasDisconnectedUnexpected; + private bool _isConnected, _wasDisconnectUnexpected; public DiscordWebSocket(DiscordClient client, int timeout, int interval, bool isDebug) { @@ -64,7 +65,7 @@ namespace Discord _disconnectToken.Dispose(); _disconnectToken = null; - _wasDisconnectedUnexpected = false; + _wasDisconnectUnexpected = false; //Clear send queue _heartbeatInterval = 0; @@ -77,7 +78,7 @@ namespace Discord if (_isConnected) { _isConnected = false; - RaiseDisconnected(_wasDisconnectedUnexpected); + RaiseDisconnected(_wasDisconnectUnexpected); } _task = null; @@ -89,10 +90,26 @@ namespace Discord { if (_task != null) { - try { _disconnectToken.Cancel(); } catch (NullReferenceException) { } + try { DisconnectInternal(new Exception("Disconnect requested by user.")); } catch (NullReferenceException) { } try { await _task; } catch (NullReferenceException) { } } } + + protected void DisconnectInternal() + { + _disconnectToken.Cancel(); + } + protected void DisconnectInternal(Exception ex) + { + if (_disconnectReason == null) + { + if (ex == null) + ex = new Exception("Disconnect requested by user."); + _disconnectReason = ex; + _disconnectToken.Cancel(); + } + } + protected virtual void OnConnect() { } protected virtual void OnDisconnect() { } @@ -131,17 +148,19 @@ namespace Discord if (result.MessageType == WebSocketMessageType.Close) { - _wasDisconnectedUnexpected = true; + _wasDisconnectUnexpected = true; + string msg = $"Got Close Message ({result.CloseStatus?.ToString() ?? "Unexpected"}, {result.CloseStatusDescription ?? "No Reason"})"; + RaiseOnDebugMessage(DebugMessageType.Connection, msg); + DisconnectInternal(new Exception(msg)); await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); - RaiseOnDebugMessage(DebugMessageType.Connection, $"Got Close Message ({result.CloseStatus?.ToString() ?? "Unexpected"}, {result.CloseStatusDescription ?? "No Reason"})"); - return; + return; } else builder.Append(Encoding.UTF8.GetString(buffer, 0, result.Count)); } while (!result.EndOfMessage); - + #if DEBUG System.Diagnostics.Debug.WriteLine(">>> " + builder.ToString()); #endif @@ -150,8 +169,9 @@ namespace Discord builder.Clear(); } } - catch { } - finally { cancelSource.Cancel(); } + catch (OperationCanceledException) { } + catch (Exception ex) { DisconnectInternal(ex); } + finally { DisconnectInternal(); } } private async Task SendAsync() { @@ -178,8 +198,9 @@ namespace Discord await Task.Delay(_sendInterval, cancelToken); } } - catch { } - finally { cancelSource.Cancel(); } + catch (OperationCanceledException) { } + catch (Exception ex) { DisconnectInternal(ex); } + finally { DisconnectInternal(); } } protected abstract Task ProcessMessage(string json);