From 1a0d8aef80a066fdefec4d757d5dcba0dfe0a03c Mon Sep 17 00:00:00 2001 From: cvium Date: Sat, 28 Nov 2020 09:50:16 +0100 Subject: [PATCH] Revert "Removed Lazy implementation." --- .../HttpServer/WebSocketManager.cs | 31 ++++++++++--------- .../Session/ISessionWebSocketListener.cs | 30 ------------------ .../Session/SessionWebSocketListener.cs | 27 ++++++++++------ .../ActivityLogWebSocketListener.cs | 2 +- .../IActivityLogWebSocketListener.cs | 10 ------ .../IScheduledTasksWebSocketListener.cs | 10 ------ .../ISessionInfoWebSocketListener.cs | 10 ------ .../ScheduledTasksWebSocketListener.cs | 8 ++--- .../SessionInfoWebSocketListener.cs | 2 +- Jellyfin.Server/CoreAppHost.cs | 13 +++++--- .../Middleware/WebSocketHandlerMiddleware.cs | 11 ++++++- .../Net/IWebSocketManager.cs | 5 +++ 12 files changed, 64 insertions(+), 95 deletions(-) delete mode 100644 Emby.Server.Implementations/Session/ISessionWebSocketListener.cs delete mode 100644 Jellyfin.Api/WebSocketListeners/IActivityLogWebSocketListener.cs delete mode 100644 Jellyfin.Api/WebSocketListeners/IScheduledTasksWebSocketListener.cs delete mode 100644 Jellyfin.Api/WebSocketListeners/ISessionInfoWebSocketListener.cs diff --git a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs index 5518fb95aa..71ece80a75 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs @@ -4,9 +4,7 @@ using System; using System.Collections.Generic; using System.Net.WebSockets; using System.Threading.Tasks; -using Emby.Server.Implementations.Session; -using Jellyfin.Api.WebSocketListeners; -using MediaBrowser.Controller; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; @@ -15,21 +13,24 @@ namespace Emby.Server.Implementations.HttpServer { public class WebSocketManager : IWebSocketManager { - private readonly IServerApplicationHost _appHost; + private readonly Lazy> _webSocketListeners; private readonly ILogger _logger; private readonly ILoggerFactory _loggerFactory; + private bool _disposed = false; public WebSocketManager( - IServerApplicationHost appHost, + Lazy> webSocketListeners, ILogger logger, ILoggerFactory loggerFactory) { - _appHost = appHost; + _webSocketListeners = webSocketListeners; _logger = logger; _loggerFactory = loggerFactory; } + public event EventHandler> WebSocketConnected; + /// public async Task WebSocketRequestHandler(HttpContext context) { @@ -38,8 +39,6 @@ namespace Emby.Server.Implementations.HttpServer return; } - var listener = _appHost.Resolve(); - try { _logger.LogInformation("WS {IP} request", context.Connection.RemoteIpAddress); @@ -55,7 +54,7 @@ namespace Emby.Server.Implementations.HttpServer OnReceive = ProcessWebSocketMessageReceived }; - listener?.ProcessWebSocketConnected(connection); + WebSocketConnected?.Invoke(this, new GenericEventArgs(connection)); await connection.ProcessAsync().ConfigureAwait(false); _logger.LogInformation("WS {IP} closed", context.Connection.RemoteIpAddress); @@ -81,12 +80,16 @@ namespace Emby.Server.Implementations.HttpServer return Task.CompletedTask; } - Parallel.Invoke( - () => _appHost.Resolve(), - () => _appHost.Resolve(), - () => _appHost.Resolve()); + IEnumerable GetTasks() + { + var listeners = _webSocketListeners.Value; + foreach (var x in listeners) + { + yield return x.ProcessMessageAsync(result); + } + } - return Task.CompletedTask; + return Task.WhenAll(GetTasks()); } } } diff --git a/Emby.Server.Implementations/Session/ISessionWebSocketListener.cs b/Emby.Server.Implementations/Session/ISessionWebSocketListener.cs deleted file mode 100644 index 9b0b28e6ee..0000000000 --- a/Emby.Server.Implementations/Session/ISessionWebSocketListener.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Emby.Server.Implementations.Session -{ - using System.Threading.Tasks; - using Jellyfin.Data.Events; - using MediaBrowser.Controller.Net; - - /// - /// Defines the . - /// - public interface ISessionWebSocketListener - { - /// - /// Runs processes due to a WebSocket connection event. - /// - /// The instance. - void ProcessWebSocketConnected(IWebSocketConnection websocketConnection); - - /// - /// Disposes the object. - /// - void Dispose(); - - /// - /// Processes a message. - /// - /// The . - /// A . - Task ProcessMessageAsync(WebSocketMessageInfo message); - } -} diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 8f81ee1948..a5f8479537 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Session /// /// Class SessionWebSocketListener. /// - public sealed class SessionWebSocketListener : ISessionWebSocketListener, IDisposable + public sealed class SessionWebSocketListener : IWebSocketListener, IDisposable { /// /// The timeout in seconds after which a WebSocket is considered to be lost. @@ -45,13 +45,15 @@ namespace Emby.Server.Implementations.Session private readonly ILogger _logger; private readonly ILoggerFactory _loggerFactory; + private readonly IWebSocketManager _webSocketManager; + /// /// The KeepAlive cancellation token. /// private CancellationTokenSource _keepAliveCancellationToken; /// - /// Lock used for accessing the KeepAlive cancellation token. + /// Lock used for accesing the KeepAlive cancellation token. /// private readonly object _keepAliveLock = new object(); @@ -61,7 +63,7 @@ namespace Emby.Server.Implementations.Session private readonly HashSet _webSockets = new HashSet(); /// - /// Lock used for accessing the WebSockets watchlist. + /// Lock used for accesing the WebSockets watchlist. /// private readonly object _webSocketsLock = new object(); @@ -71,28 +73,32 @@ namespace Emby.Server.Implementations.Session /// The logger. /// The session manager. /// The logger factory. + /// The HTTP server. public SessionWebSocketListener( ILogger logger, ISessionManager sessionManager, - ILoggerFactory loggerFactory) + ILoggerFactory loggerFactory, + IWebSocketManager webSocketManager) { _logger = logger; _sessionManager = sessionManager; _loggerFactory = loggerFactory; + _webSocketManager = webSocketManager; + + webSocketManager.WebSocketConnected += OnServerManagerWebSocketConnected; } - /// - public async void ProcessWebSocketConnected(IWebSocketConnection websocketConnection) + private async void OnServerManagerWebSocketConnected(object sender, GenericEventArgs e) { - var session = GetSession(websocketConnection.QueryString, websocketConnection.RemoteEndPoint.ToString()); + var session = GetSession(e.Argument.QueryString, e.Argument.RemoteEndPoint.ToString()); if (session != null) { - EnsureController(session, websocketConnection); - await KeepAliveWebSocket(websocketConnection).ConfigureAwait(false); + EnsureController(session, e.Argument); + await KeepAliveWebSocket(e.Argument).ConfigureAwait(false); } else { - _logger.LogWarning("Unable to determine session based on query string: {Querystring}", websocketConnection.QueryString); + _logger.LogWarning("Unable to determine session based on query string: {0}", e.Argument.QueryString); } } @@ -116,6 +122,7 @@ namespace Emby.Server.Implementations.Session /// public void Dispose() { + _webSocketManager.WebSocketConnected -= OnServerManagerWebSocketConnected; StopKeepAlive(); } diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs index 3dc45b1459..288e03fcff 100644 --- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs @@ -11,7 +11,7 @@ namespace Jellyfin.Api.WebSocketListeners /// /// Class SessionInfoWebSocketListener. /// - public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener, IActivityLogWebSocketListener + public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener { /// /// The _kernel. diff --git a/Jellyfin.Api/WebSocketListeners/IActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/IActivityLogWebSocketListener.cs deleted file mode 100644 index b23022e71d..0000000000 --- a/Jellyfin.Api/WebSocketListeners/IActivityLogWebSocketListener.cs +++ /dev/null @@ -1,10 +0,0 @@ -#pragma warning disable CA1040 // Avoid empty interfaces -namespace Jellyfin.Api.WebSocketListeners -{ - /// - /// Defines the . - /// - public interface IActivityLogWebSocketListener - { - } -} diff --git a/Jellyfin.Api/WebSocketListeners/IScheduledTasksWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/IScheduledTasksWebSocketListener.cs deleted file mode 100644 index 425d61dfa4..0000000000 --- a/Jellyfin.Api/WebSocketListeners/IScheduledTasksWebSocketListener.cs +++ /dev/null @@ -1,10 +0,0 @@ -#pragma warning disable CA1040 // Avoid empty interfaces -namespace Jellyfin.Api.WebSocketListeners -{ - /// - /// Defines the . - /// - public interface IScheduledTasksWebSocketListener - { - } -} diff --git a/Jellyfin.Api/WebSocketListeners/ISessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ISessionInfoWebSocketListener.cs deleted file mode 100644 index 33636dc06d..0000000000 --- a/Jellyfin.Api/WebSocketListeners/ISessionInfoWebSocketListener.cs +++ /dev/null @@ -1,10 +0,0 @@ -#pragma warning disable CA1040 // Avoid empty interfaces -namespace Jellyfin.Api.WebSocketListeners -{ - /// - /// Defines the . - /// - public interface ISessionInfoWebSocketListener - { - } -} diff --git a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs index eafa9c71f0..94df23e569 100644 --- a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs @@ -12,7 +12,7 @@ namespace Jellyfin.Api.WebSocketListeners /// /// Class ScheduledTasksWebSocketListener. /// - public class ScheduledTasksWebSocketListener : BasePeriodicWebSocketListener, WebSocketListenerState>, IScheduledTasksWebSocketListener + public class ScheduledTasksWebSocketListener : BasePeriodicWebSocketListener, WebSocketListenerState> { /// /// Gets or sets the task manager. @@ -66,19 +66,19 @@ namespace Jellyfin.Api.WebSocketListeners private void OnTaskCompleted(object? sender, TaskCompletionEventArgs e) { - SendData(true).GetAwaiter().GetResult(); + SendData(true); e.Task.TaskProgress -= OnTaskProgress; } private void OnTaskExecuting(object? sender, GenericEventArgs e) { - SendData(true).GetAwaiter().GetResult(); + SendData(true); e.Argument.TaskProgress += OnTaskProgress; } private void OnTaskProgress(object? sender, GenericEventArgs e) { - SendData(false).GetAwaiter().GetResult(); + SendData(false); } } } diff --git a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs index be701be45e..d996ac69f9 100644 --- a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs @@ -11,7 +11,7 @@ namespace Jellyfin.Api.WebSocketListeners /// /// Class SessionInfoWebSocketListener. /// - public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener, WebSocketListenerState>, ISessionInfoWebSocketListener + public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener, WebSocketListenerState> { private readonly ISessionManager _sessionManager; diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 100f3619a6..4b44537a59 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -11,6 +11,7 @@ using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Activity; using Jellyfin.Server.Implementations.Events; using Jellyfin.Server.Implementations.Users; +using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.BaseItemManager; using MediaBrowser.Controller.Drawing; @@ -81,10 +82,14 @@ namespace Jellyfin.Server ServiceCollection.AddSingleton(); ServiceCollection.AddSingleton(); - ServiceCollection.AddScoped(); - ServiceCollection.AddScoped(); - ServiceCollection.AddScoped(); - ServiceCollection.AddScoped(); + ServiceCollection.AddScoped(); + ServiceCollection.AddScoped(); + ServiceCollection.AddScoped(); + // This one has to be last as DI will select it for parameterization. + ServiceCollection.AddScoped(); + + // TODO fix circular dependency on IWebSocketManager + ServiceCollection.AddScoped(serviceProvider => new Lazy>(serviceProvider.GetRequiredService>)); base.RegisterServices(); } diff --git a/Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs b/Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs index ba0abfbdd4..53f32bebd1 100644 --- a/Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs +++ b/Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs @@ -25,10 +25,19 @@ namespace Jellyfin.Server.Middleware /// /// The current HTTP context. /// The WebSocket connection manager. + /// Session manager instance. /// The async task. public async Task Invoke( HttpContext httpContext, - IWebSocketManager webSocketManager) + IWebSocketManager webSocketManager, +#pragma warning disable CA1801 +#pragma warning disable IDE0060 + // TODO: Workaround. see https://github.com/jellyfin/jellyfin/pull/3194 + // Do not remove this parameter. It uses DI to create a SessionWebSocketListener which is + // required for webSocketManager events. + IWebSocketListener websocketListener) +#pragma warning restore IDE0060 // Remove unused parameter +#pragma warning restore CA1801 { if (!httpContext.WebSockets.IsWebSocketRequest) { diff --git a/MediaBrowser.Controller/Net/IWebSocketManager.cs b/MediaBrowser.Controller/Net/IWebSocketManager.cs index d3f31de7c8..ce74173e70 100644 --- a/MediaBrowser.Controller/Net/IWebSocketManager.cs +++ b/MediaBrowser.Controller/Net/IWebSocketManager.cs @@ -11,6 +11,11 @@ namespace MediaBrowser.Controller.Net /// public interface IWebSocketManager { + /// + /// Occurs when [web socket connected]. + /// + event EventHandler> WebSocketConnected; + /// /// The HTTP request handler. ///