diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index f83da566b2..34dc027f18 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -101,14 +101,14 @@ namespace Emby.Server.Implementations.HttpServer var pipe = new Pipe(); var writer = pipe.Writer; - ValueWebSocketReceiveResult receiveresult; + ValueWebSocketReceiveResult receiveResult; do { // Allocate at least 512 bytes from the PipeWriter Memory memory = writer.GetMemory(512); try { - receiveresult = await _socket.ReceiveAsync(memory, cancellationToken).ConfigureAwait(false); + receiveResult = await _socket.ReceiveAsync(memory, cancellationToken).ConfigureAwait(false); } catch (WebSocketException ex) { @@ -116,7 +116,7 @@ namespace Emby.Server.Implementations.HttpServer break; } - int bytesRead = receiveresult.Count; + int bytesRead = receiveResult.Count; if (bytesRead == 0) { break; @@ -135,13 +135,13 @@ namespace Emby.Server.Implementations.HttpServer LastActivityDate = DateTime.UtcNow; - if (receiveresult.EndOfMessage) + if (receiveResult.EndOfMessage) { await ProcessInternal(pipe.Reader).ConfigureAwait(false); } } while ((_socket.State == WebSocketState.Open || _socket.State == WebSocketState.Connecting) - && receiveresult.MessageType != WebSocketMessageType.Close); + && receiveResult.MessageType != WebSocketMessageType.Close); Closed?.Invoke(this, EventArgs.Empty); diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index b3c93a904a..aba51de8f5 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -33,11 +33,6 @@ namespace Emby.Server.Implementations.Session /// private const float ForceKeepAliveFactor = 0.75f; - /// - /// Lock used for accessing the KeepAlive cancellation token. - /// - private readonly object _keepAliveLock = new object(); - /// /// The WebSocket watchlist. /// @@ -55,7 +50,7 @@ namespace Emby.Server.Implementations.Session /// /// The KeepAlive cancellation token. /// - private CancellationTokenSource? _keepAliveCancellationToken; + private System.Timers.Timer _keepAlive; /// /// Initializes a new instance of the class. @@ -71,12 +66,34 @@ namespace Emby.Server.Implementations.Session _logger = logger; _sessionManager = sessionManager; _loggerFactory = loggerFactory; + _keepAlive = new System.Timers.Timer(TimeSpan.FromSeconds(WebSocketLostTimeout * IntervalFactor)) + { + AutoReset = true, + Enabled = false + }; + _keepAlive.Elapsed += KeepAliveSockets; } /// public void Dispose() { - StopKeepAlive(); + if (_keepAlive is not null) + { + _keepAlive.Stop(); + _keepAlive.Elapsed -= KeepAliveSockets; + _keepAlive.Dispose(); + _keepAlive = null!; + } + + lock (_webSocketsLock) + { + foreach (var webSocket in _webSockets) + { + webSocket.Closed -= OnWebSocketClosed; + } + + _webSockets.Clear(); + } } /// @@ -164,7 +181,7 @@ namespace Emby.Server.Implementations.Session webSocket.Closed += OnWebSocketClosed; webSocket.LastKeepAliveDate = DateTime.UtcNow; - StartKeepAlive(); + _keepAlive.Start(); } // Notify WebSocket about timeout @@ -186,66 +203,26 @@ namespace Emby.Server.Implementations.Session { lock (_webSocketsLock) { - if (!_webSockets.Remove(webSocket)) + if (_webSockets.Remove(webSocket)) { - _logger.LogWarning("WebSocket {0} not on watchlist.", webSocket); + webSocket.Closed -= OnWebSocketClosed; } else { - webSocket.Closed -= OnWebSocketClosed; + _logger.LogWarning("WebSocket {0} not on watchlist.", webSocket); } - } - } - /// - /// Starts the KeepAlive watcher. - /// - private void StartKeepAlive() - { - lock (_keepAliveLock) - { - if (_keepAliveCancellationToken is null) + if (_webSockets.Count == 0) { - _keepAliveCancellationToken = new CancellationTokenSource(); - // Start KeepAlive watcher - _ = RepeatAsyncCallbackEvery( - KeepAliveSockets, - TimeSpan.FromSeconds(WebSocketLostTimeout * IntervalFactor), - _keepAliveCancellationToken.Token); + _keepAlive.Stop(); } } } - /// - /// Stops the KeepAlive watcher. - /// - private void StopKeepAlive() - { - lock (_keepAliveLock) - { - if (_keepAliveCancellationToken is not null) - { - _keepAliveCancellationToken.Cancel(); - _keepAliveCancellationToken.Dispose(); - _keepAliveCancellationToken = null; - } - } - - lock (_webSocketsLock) - { - foreach (var webSocket in _webSockets) - { - webSocket.Closed -= OnWebSocketClosed; - } - - _webSockets.Clear(); - } - } - /// /// Checks status of KeepAlive of WebSockets. /// - private async Task KeepAliveSockets() + private async void KeepAliveSockets(object? o, EventArgs? e) { List inactive; List lost; @@ -291,11 +268,6 @@ namespace Emby.Server.Implementations.Session RemoveWebSocket(webSocket); } } - - if (_webSockets.Count == 0) - { - StopKeepAlive(); - } } } @@ -310,29 +282,5 @@ namespace Emby.Server.Implementations.Session new ForceKeepAliveMessage(WebSocketLostTimeout), CancellationToken.None); } - - /// - /// Runs a given async callback once every specified interval time, until cancelled. - /// - /// The async callback. - /// The interval time. - /// The cancellation token. - /// Task. - private async Task RepeatAsyncCallbackEvery(Func callback, TimeSpan interval, CancellationToken cancellationToken) - { - while (!cancellationToken.IsCancellationRequested) - { - await callback().ConfigureAwait(false); - - try - { - await Task.Delay(interval, cancellationToken).ConfigureAwait(false); - } - catch (TaskCanceledException) - { - return; - } - } - } } }