public async Task HeartbeatLoop(int heartbeatInterval) { receivedHeartbeatAck = true; while (State == WebSocketState.Open && !heartbeatCancellationSource.IsCancellationRequested) { if (!receivedHeartbeatAck) { log.LogWarning("[HeartbeatLoop] Connection timed out (did not receive ack for last heartbeat)."); OnTimedOut?.Invoke(this, EventArgs.Empty); break; } try { receivedHeartbeatAck = false; // Send heartbeat await SendHeartbeatPayload().ConfigureAwait(false); } catch (InvalidOperationException) { // Socket was closed between the loop check and sending the heartbeat break; } catch (DiscordWebSocketException dwex) { // Expected to be the socket closing while sending a heartbeat if (dwex.Error != DiscordWebSocketError.ConnectionClosed) { // Unexpected errors may not be the socket closing/aborting, so just log and loop around. log.LogError($"[HeartbeatLoop] Unexpected error occured while sending a heartbeat: {dwex}"); } else { break; } } try { // Wait heartbeat interval await Task.Delay(heartbeatInterval, heartbeatCancellationSource.Token) .ConfigureAwait(false); } catch (ObjectDisposedException) { // VoiceWebSocket was disposed between sending a heartbeat payload and beginning to wait break; } catch (OperationCanceledException) { // Socket is disconnecting break; } } }
private void UpdateConnectionTimeout(Boolean alive) { var newTimeoutTask = Task.Delay(TimeOutMilliseonds); newTimeoutTask.ContinueWith(_ => { // If this is the live task, swap it with null and continue with the timeout. if (Interlocked.CompareExchange(ref _timeoutTask, null, newTimeoutTask) != newTimeoutTask) { return; } // Has timed out. OnTimedOut?.Invoke(this); }); _timeoutTask = alive ? newTimeoutTask : null; }