| @@ -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); | |||||
| await _voiceSocket.SetChannel(_voiceServerId, channelId).ConfigureAwait(false); | |||||
| _dataSocket.SendJoinVoice(_voiceServerId, channelId); | _dataSocket.SendJoinVoice(_voiceServerId, channelId); | ||||
| CancellationTokenSource tokenSource = new CancellationTokenSource(); | |||||
| try | |||||
| { | |||||
| await Task.Run(() => _voiceSocket.WaitForConnection(tokenSource.Token)) | |||||
| .Timeout(_config.ConnectionTimeout, tokenSource) | |||||
| .ConfigureAwait(false); | |||||
| } | |||||
| catch (TimeoutException) | |||||
| { | |||||
| tokenSource.Cancel(); | |||||
| await _voiceSocket.Disconnect().ConfigureAwait(false); | |||||
| throw; | |||||
| } | |||||
| await _voiceSocket.WaitForConnection(_config.ConnectionTimeout); | |||||
| } | } | ||||
| /*async Task IDiscordVoiceClient.Disconnect() | /*async Task IDiscordVoiceClient.Disconnect() | ||||
| @@ -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 | ||||
| @@ -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(); | |||||
| } | |||||
| }); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -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)) | ||||
| @@ -79,12 +79,9 @@ namespace Discord.WebSockets | |||||
| }; | }; | ||||
| } | } | ||||
| protected virtual async Task Connect() | |||||
| protected async Task BeginConnect() | |||||
| { | { | ||||
| if (_state != (int)WebSocketState.Disconnected) | |||||
| throw new InvalidOperationException("Client is already connected or connecting to the server."); | |||||
| try | |||||
| 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(); | ||||