Improved voice socket error handling

This commit is contained in:
RogueException
2015-10-12 03:39:54 -03:00
parent 2d3aeab64f
commit 7c024ecda8
5 changed files with 58 additions and 37 deletions

View File

@@ -24,22 +24,10 @@ namespace Discord
if (channelId == null) throw new ArgumentNullException(nameof(channelId)); if (channelId == null) throw new ArgumentNullException(nameof(channelId));
await _voiceSocket.Disconnect().ConfigureAwait(false); await _voiceSocket.Disconnect().ConfigureAwait(false);
_voiceSocket.SetChannel(_voiceServerId, channelId);
_dataSocket.SendJoinVoice(_voiceServerId, channelId);
CancellationTokenSource tokenSource = new CancellationTokenSource(); await _voiceSocket.SetChannel(_voiceServerId, channelId).ConfigureAwait(false);
try _dataSocket.SendJoinVoice(_voiceServerId, channelId);
{ await _voiceSocket.WaitForConnection(_config.ConnectionTimeout);
await Task.Run(() => _voiceSocket.WaitForConnection(tokenSource.Token))
.Timeout(_config.ConnectionTimeout, tokenSource)
.ConfigureAwait(false);
}
catch (TimeoutException)
{
tokenSource.Cancel();
await _voiceSocket.Disconnect().ConfigureAwait(false);
throw;
}
} }
/*async Task IDiscordVoiceClient.Disconnect() /*async Task IDiscordVoiceClient.Disconnect()

View File

@@ -19,7 +19,8 @@ namespace Discord.WebSockets.Data
public async Task Login(string token) public async Task Login(string token)
{ {
await Connect().ConfigureAwait(false); await BeginConnect().ConfigureAwait(false);
await Start().ConfigureAwait(false);
LoginCommand msg = new LoginCommand(); LoginCommand msg = new LoginCommand();
msg.Payload.Token = token; msg.Payload.Token = token;
@@ -29,7 +30,9 @@ namespace Discord.WebSockets.Data
private async Task Redirect(string server) private async Task Redirect(string server)
{ {
await DisconnectInternal(isUnexpected: false).ConfigureAwait(false); await DisconnectInternal(isUnexpected: false).ConfigureAwait(false);
await Connect().ConfigureAwait(false);
await BeginConnect().ConfigureAwait(false);
await Start().ConfigureAwait(false);
var resumeMsg = new ResumeCommand(); var resumeMsg = new ResumeCommand();
resumeMsg.Payload.SessionId = _sessionId; resumeMsg.Payload.SessionId = _sessionId;
@@ -87,7 +90,7 @@ namespace Discord.WebSockets.Data
} }
RaiseReceivedEvent(msg.Type, token); RaiseReceivedEvent(msg.Type, token);
if (msg.Type == "READY" || msg.Type == "RESUMED") if (msg.Type == "READY" || msg.Type == "RESUMED")
CompleteConnect(); EndConnect();
} }
break; break;
case 7: //Redirect case 7: //Redirect

View File

@@ -61,14 +61,16 @@ namespace Discord.WebSockets.Voice
_encoder = new OpusEncoder(48000, 1, 20, Opus.Application.Audio); _encoder = new OpusEncoder(48000, 1, 20, Opus.Application.Audio);
} }
public void SetChannel(string serverId, string channelId) public Task SetChannel(string serverId, string channelId)
{ {
_serverId = serverId; _serverId = serverId;
_channelId = channelId; _channelId = channelId;
return base.BeginConnect();
} }
public async Task Login(string userId, string sessionId, string token, CancellationToken cancelToken) public async Task Login(string userId, string sessionId, string token, CancellationToken cancelToken)
{ {
if ((WebSocketState)_state != WebSocketState.Disconnected) if ((WebSocketState)_state == WebSocketState.Connected)
{ {
//Adjust the host and tell the system to reconnect //Adjust the host and tell the system to reconnect
await DisconnectInternal(new Exception("Server transfer occurred."), isUnexpected: false); await DisconnectInternal(new Exception("Server transfer occurred."), isUnexpected: false);
@@ -79,7 +81,7 @@ namespace Discord.WebSockets.Voice
_sessionId = sessionId; _sessionId = sessionId;
_token = token; _token = token;
await Connect().ConfigureAwait(false); await Start().ConfigureAwait(false);
} }
public async Task Reconnect() public async Task Reconnect()
{ {
@@ -91,7 +93,7 @@ namespace Discord.WebSockets.Voice
{ {
try try
{ {
await Connect().ConfigureAwait(false); await Start().ConfigureAwait(false);
break; break;
} }
catch (OperationCanceledException) { throw; } catch (OperationCanceledException) { throw; }
@@ -245,7 +247,7 @@ namespace Discord.WebSockets.Voice
int port = packet[68] | packet[69] << 8; int port = packet[68] | packet[69] << 8;
string ip = Encoding.ASCII.GetString(packet, 4, 70 - 6).TrimEnd('\0'); string ip = Encoding.ASCII.GetString(packet, 4, 70 - 6).TrimEnd('\0');
CompleteConnect(); EndConnect();
var login2 = new Login2Command(); var login2 = new Login2Command();
login2.Payload.Protocol = "udp"; login2.Payload.Protocol = "udp";
@@ -599,9 +601,20 @@ namespace Discord.WebSockets.Voice
{ {
_sendQueueEmptyWait.Wait(_cancelToken); _sendQueueEmptyWait.Wait(_cancelToken);
} }
public void WaitForConnection(CancellationToken cancelToken) public Task WaitForConnection(int timeout)
{ {
_connectedEvent.Wait(cancelToken); return Task.Run(() =>
{
try
{
if (!_connectedEvent.Wait(timeout, _cancelToken))
throw new TimeoutException();
}
catch (OperationCanceledException ex)
{
ThrowError();
}
});
} }
} }
} }

View File

@@ -41,14 +41,14 @@ namespace Discord.WebSockets
_webSocket.OnError += async (s, e) => _webSocket.OnError += async (s, e) =>
{ {
_parent.RaiseOnLog(LogMessageSeverity.Error, $"Websocket Error: {e.Message}"); _parent.RaiseOnLog(LogMessageSeverity.Error, $"Websocket Error: {e.Message}");
await _parent.DisconnectInternal(e.Exception, isUnexpected: true, skipAwait: true); await _parent.DisconnectInternal(e.Exception, skipAwait: true);
}; };
_webSocket.OnClose += async (s, e) => _webSocket.OnClose += async (s, e) =>
{ {
string code = e.WasClean ? e.Code.ToString() : "Unexpected"; string code = e.WasClean ? e.Code.ToString() : "Unexpected";
string reason = e.Reason != "" ? e.Reason : "No Reason"; string reason = e.Reason != "" ? e.Reason : "No Reason";
Exception ex = new Exception($"Got Close Message ({code}): {reason}"); Exception ex = new Exception($"Got Close Message ({code}): {reason}");
await _parent.DisconnectInternal(ex, isUnexpected: !e.WasClean, skipAwait: true); await _parent.DisconnectInternal(ex, skipAwait: true);
}; };
_webSocket.Log.Output = (e, m) => { }; //Dont let websocket-sharp print to console _webSocket.Log.Output = (e, m) => { }; //Dont let websocket-sharp print to console
_webSocket.Connect(); _webSocket.Connect();
@@ -59,7 +59,12 @@ namespace Discord.WebSockets
{ {
string ignored; string ignored;
while (_sendQueue.TryDequeue(out ignored)) { } while (_sendQueue.TryDequeue(out ignored)) { }
_webSocket.Close();
var socket = _webSocket;
_webSocket = null;
if (socket != null)
socket.Close();
return TaskHelper.CompletedTask; return TaskHelper.CompletedTask;
} }
@@ -77,7 +82,7 @@ namespace Discord.WebSockets
{ {
try try
{ {
while (_webSocket.IsAlive && !cancelToken.IsCancellationRequested) while (!cancelToken.IsCancellationRequested)
{ {
string json; string json;
while (_sendQueue.TryDequeue(out json)) while (_sendQueue.TryDequeue(out json))

View File

@@ -79,12 +79,9 @@ namespace Discord.WebSockets
}; };
} }
protected virtual async Task Connect() protected async Task BeginConnect()
{ {
if (_state != (int)WebSocketState.Disconnected) try
throw new InvalidOperationException("Client is already connected or connecting to the server.");
try
{ {
await Disconnect().ConfigureAwait(false); await Disconnect().ConfigureAwait(false);
@@ -93,19 +90,34 @@ namespace Discord.WebSockets
_cancelTokenSource = new CancellationTokenSource(); _cancelTokenSource = new CancellationTokenSource();
_cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_cancelTokenSource.Token, ParentCancelToken.Value).Token; _cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_cancelTokenSource.Token, ParentCancelToken.Value).Token;
_state = (int)WebSocketState.Connecting;
}
catch (Exception ex)
{
await DisconnectInternal(ex, isUnexpected: false).ConfigureAwait(false);
throw;
}
}
protected virtual async Task Start()
{
try
{
if (_state != (int)WebSocketState.Connecting)
throw new InvalidOperationException("Socket is in the wrong state.");
_lastHeartbeat = DateTime.UtcNow; _lastHeartbeat = DateTime.UtcNow;
await _engine.Connect(Host, _cancelToken).ConfigureAwait(false); await _engine.Connect(Host, _cancelToken).ConfigureAwait(false);
_state = (int)WebSocketState.Connecting;
_runTask = RunTasks(); _runTask = RunTasks();
} }
catch (Exception ex) catch (Exception ex)
{ {
await DisconnectInternal(ex, isUnexpected: false).ConfigureAwait(false); await DisconnectInternal(ex, isUnexpected: false).ConfigureAwait(false);
throw; //Dont handle this exception internally, send up it upwards throw;
} }
} }
protected void CompleteConnect() protected void EndConnect()
{ {
_state = (int)WebSocketState.Connected; _state = (int)WebSocketState.Connected;
_connectedEvent.Set(); _connectedEvent.Set();