|
@@ -33,11 +33,6 @@ namespace Emby.Server.Implementations.Session
|
|
|
/// </summary>
|
|
|
private const float ForceKeepAliveFactor = 0.75f;
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// Lock used for accessing the KeepAlive cancellation token.
|
|
|
- /// </summary>
|
|
|
- private readonly object _keepAliveLock = new object();
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// The WebSocket watchlist.
|
|
|
/// </summary>
|
|
@@ -55,7 +50,7 @@ namespace Emby.Server.Implementations.Session
|
|
|
/// <summary>
|
|
|
/// The KeepAlive cancellation token.
|
|
|
/// </summary>
|
|
|
- private CancellationTokenSource? _keepAliveCancellationToken;
|
|
|
+ private System.Timers.Timer _keepAlive;
|
|
|
|
|
|
/// <summary>
|
|
|
/// Initializes a new instance of the <see cref="SessionWebSocketListener" /> 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;
|
|
|
}
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
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();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -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))
|
|
|
- {
|
|
|
- _logger.LogWarning("WebSocket {0} not on watchlist.", webSocket);
|
|
|
- }
|
|
|
- else
|
|
|
+ if (_webSockets.Remove(webSocket))
|
|
|
{
|
|
|
webSocket.Closed -= OnWebSocketClosed;
|
|
|
}
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Starts the KeepAlive watcher.
|
|
|
- /// </summary>
|
|
|
- private void StartKeepAlive()
|
|
|
- {
|
|
|
- lock (_keepAliveLock)
|
|
|
- {
|
|
|
- if (_keepAliveCancellationToken is null)
|
|
|
- {
|
|
|
- _keepAliveCancellationToken = new CancellationTokenSource();
|
|
|
- // Start KeepAlive watcher
|
|
|
- _ = RepeatAsyncCallbackEvery(
|
|
|
- KeepAliveSockets,
|
|
|
- TimeSpan.FromSeconds(WebSocketLostTimeout * IntervalFactor),
|
|
|
- _keepAliveCancellationToken.Token);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Stops the KeepAlive watcher.
|
|
|
- /// </summary>
|
|
|
- private void StopKeepAlive()
|
|
|
- {
|
|
|
- lock (_keepAliveLock)
|
|
|
- {
|
|
|
- if (_keepAliveCancellationToken is not null)
|
|
|
+ else
|
|
|
{
|
|
|
- _keepAliveCancellationToken.Cancel();
|
|
|
- _keepAliveCancellationToken.Dispose();
|
|
|
- _keepAliveCancellationToken = null;
|
|
|
+ _logger.LogWarning("WebSocket {0} not on watchlist.", webSocket);
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- lock (_webSocketsLock)
|
|
|
- {
|
|
|
- foreach (var webSocket in _webSockets)
|
|
|
+ if (_webSockets.Count == 0)
|
|
|
{
|
|
|
- webSocket.Closed -= OnWebSocketClosed;
|
|
|
+ _keepAlive.Stop();
|
|
|
}
|
|
|
-
|
|
|
- _webSockets.Clear();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// Checks status of KeepAlive of WebSockets.
|
|
|
/// </summary>
|
|
|
- private async Task KeepAliveSockets()
|
|
|
+ private async void KeepAliveSockets(object? o, EventArgs? e)
|
|
|
{
|
|
|
List<IWebSocketConnection> inactive;
|
|
|
List<IWebSocketConnection> 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);
|
|
|
}
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Runs a given async callback once every specified interval time, until cancelled.
|
|
|
- /// </summary>
|
|
|
- /// <param name="callback">The async callback.</param>
|
|
|
- /// <param name="interval">The interval time.</param>
|
|
|
- /// <param name="cancellationToken">The cancellation token.</param>
|
|
|
- /// <returns>Task.</returns>
|
|
|
- private async Task RepeatAsyncCallbackEvery(Func<Task> callback, TimeSpan interval, CancellationToken cancellationToken)
|
|
|
- {
|
|
|
- while (!cancellationToken.IsCancellationRequested)
|
|
|
- {
|
|
|
- await callback().ConfigureAwait(false);
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- await Task.Delay(interval, cancellationToken).ConfigureAwait(false);
|
|
|
- }
|
|
|
- catch (TaskCanceledException)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
}
|