Selaa lähdekoodia

Revert "Removed Lazy implementation."

cvium 4 vuotta sitten
vanhempi
sitoutus
1a0d8aef80

+ 17 - 14
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<IEnumerable<IWebSocketListener>> _webSocketListeners;
         private readonly ILogger<WebSocketManager> _logger;
         private readonly ILoggerFactory _loggerFactory;
+
         private bool _disposed = false;
 
         public WebSocketManager(
-            IServerApplicationHost appHost,
+            Lazy<IEnumerable<IWebSocketListener>> webSocketListeners,
             ILogger<WebSocketManager> logger,
             ILoggerFactory loggerFactory)
         {
-            _appHost = appHost;
+            _webSocketListeners = webSocketListeners;
             _logger = logger;
             _loggerFactory = loggerFactory;
         }
 
+        public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
+
         /// <inheritdoc />
         public async Task WebSocketRequestHandler(HttpContext context)
         {
@@ -38,8 +39,6 @@ namespace Emby.Server.Implementations.HttpServer
                 return;
             }
 
-            var listener = _appHost.Resolve<ISessionWebSocketListener>();
-
             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<IWebSocketConnection>(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<IActivityLogWebSocketListener>(),
-                () => _appHost.Resolve<IScheduledTasksWebSocketListener>(),
-                () => _appHost.Resolve<ISessionInfoWebSocketListener>());
+            IEnumerable<Task> GetTasks()
+            {
+                var listeners = _webSocketListeners.Value;
+                foreach (var x in listeners)
+                {
+                    yield return x.ProcessMessageAsync(result);
+                }
+            }
 
-            return Task.CompletedTask;
+            return Task.WhenAll(GetTasks());
         }
     }
 }

+ 0 - 30
Emby.Server.Implementations/Session/ISessionWebSocketListener.cs

@@ -1,30 +0,0 @@
-namespace Emby.Server.Implementations.Session
-{
-    using System.Threading.Tasks;
-    using Jellyfin.Data.Events;
-    using MediaBrowser.Controller.Net;
-
-    /// <summary>
-    /// Defines the <see cref="ISessionWebSocketListener" />.
-    /// </summary>
-    public interface ISessionWebSocketListener
-    {
-        /// <summary>
-        /// Runs processes due to a WebSocket connection event.
-        /// </summary>
-        /// <param name="websocketConnection">The <see cref="IWebSocketConnection"/> instance.</param>
-        void ProcessWebSocketConnected(IWebSocketConnection websocketConnection);
-
-        /// <summary>
-        /// Disposes the object.
-        /// </summary>
-        void Dispose();
-
-        /// <summary>
-        /// Processes a message.
-        /// </summary>
-        /// <param name="message">The <see cref="WebSocketMessageInfo"/>.</param>
-        /// <returns>A <see cref="Task"/>.</returns>
-        Task ProcessMessageAsync(WebSocketMessageInfo message);
-    }
-}

+ 17 - 10
Emby.Server.Implementations/Session/SessionWebSocketListener.cs

@@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Session
     /// <summary>
     /// Class SessionWebSocketListener.
     /// </summary>
-    public sealed class SessionWebSocketListener : ISessionWebSocketListener, IDisposable
+    public sealed class SessionWebSocketListener : IWebSocketListener, IDisposable
     {
         /// <summary>
         /// 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<SessionWebSocketListener> _logger;
         private readonly ILoggerFactory _loggerFactory;
 
+        private readonly IWebSocketManager _webSocketManager;
+
         /// <summary>
         /// The KeepAlive cancellation token.
         /// </summary>
         private CancellationTokenSource _keepAliveCancellationToken;
 
         /// <summary>
-        /// Lock used for accessing the KeepAlive cancellation token.
+        /// Lock used for accesing the KeepAlive cancellation token.
         /// </summary>
         private readonly object _keepAliveLock = new object();
 
@@ -61,7 +63,7 @@ namespace Emby.Server.Implementations.Session
         private readonly HashSet<IWebSocketConnection> _webSockets = new HashSet<IWebSocketConnection>();
 
         /// <summary>
-        /// Lock used for accessing the WebSockets watchlist.
+        /// Lock used for accesing the WebSockets watchlist.
         /// </summary>
         private readonly object _webSocketsLock = new object();
 
@@ -71,28 +73,32 @@ namespace Emby.Server.Implementations.Session
         /// <param name="logger">The logger.</param>
         /// <param name="sessionManager">The session manager.</param>
         /// <param name="loggerFactory">The logger factory.</param>
+        /// <param name="webSocketManager">The HTTP server.</param>
         public SessionWebSocketListener(
             ILogger<SessionWebSocketListener> logger,
             ISessionManager sessionManager,
-            ILoggerFactory loggerFactory)
+            ILoggerFactory loggerFactory,
+            IWebSocketManager webSocketManager)
         {
             _logger = logger;
             _sessionManager = sessionManager;
             _loggerFactory = loggerFactory;
+            _webSocketManager = webSocketManager;
+
+            webSocketManager.WebSocketConnected += OnServerManagerWebSocketConnected;
         }
 
-        /// <inheritdoc/>
-        public async void ProcessWebSocketConnected(IWebSocketConnection websocketConnection)
+        private async void OnServerManagerWebSocketConnected(object sender, GenericEventArgs<IWebSocketConnection> 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
         /// <inheritdoc />
         public void Dispose()
         {
+            _webSocketManager.WebSocketConnected -= OnServerManagerWebSocketConnected;
             StopKeepAlive();
         }
 

+ 1 - 1
Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs

@@ -11,7 +11,7 @@ namespace Jellyfin.Api.WebSocketListeners
     /// <summary>
     /// Class SessionInfoWebSocketListener.
     /// </summary>
-    public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener<ActivityLogEntry[], WebSocketListenerState>, IActivityLogWebSocketListener
+    public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener<ActivityLogEntry[], WebSocketListenerState>
     {
         /// <summary>
         /// The _kernel.

+ 0 - 10
Jellyfin.Api/WebSocketListeners/IActivityLogWebSocketListener.cs

@@ -1,10 +0,0 @@
-#pragma warning disable CA1040 // Avoid empty interfaces
-namespace Jellyfin.Api.WebSocketListeners
-{
-    /// <summary>
-    /// Defines the <see cref="IActivityLogWebSocketListener" />.
-    /// </summary>
-    public interface IActivityLogWebSocketListener
-    {
-    }
-}

+ 0 - 10
Jellyfin.Api/WebSocketListeners/IScheduledTasksWebSocketListener.cs

@@ -1,10 +0,0 @@
-#pragma warning disable CA1040 // Avoid empty interfaces
-namespace Jellyfin.Api.WebSocketListeners
-{
-    /// <summary>
-    /// Defines the <see cref="IScheduledTasksWebSocketListener" />.
-    /// </summary>
-    public interface IScheduledTasksWebSocketListener
-    {
-    }
-}

+ 0 - 10
Jellyfin.Api/WebSocketListeners/ISessionInfoWebSocketListener.cs

@@ -1,10 +0,0 @@
-#pragma warning disable CA1040 // Avoid empty interfaces
-namespace Jellyfin.Api.WebSocketListeners
-{
-    /// <summary>
-    /// Defines the <see cref="ISessionInfoWebSocketListener" />.
-    /// </summary>
-    public interface ISessionInfoWebSocketListener
-    {
-    }
-}

+ 4 - 4
Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs

@@ -12,7 +12,7 @@ namespace Jellyfin.Api.WebSocketListeners
     /// <summary>
     /// Class ScheduledTasksWebSocketListener.
     /// </summary>
-    public class ScheduledTasksWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<TaskInfo>, WebSocketListenerState>, IScheduledTasksWebSocketListener
+    public class ScheduledTasksWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<TaskInfo>, WebSocketListenerState>
     {
         /// <summary>
         /// 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<IScheduledTaskWorker> e)
         {
-            SendData(true).GetAwaiter().GetResult();
+            SendData(true);
             e.Argument.TaskProgress += OnTaskProgress;
         }
 
         private void OnTaskProgress(object? sender, GenericEventArgs<double> e)
         {
-            SendData(false).GetAwaiter().GetResult();
+            SendData(false);
         }
     }
 }

+ 1 - 1
Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs

@@ -11,7 +11,7 @@ namespace Jellyfin.Api.WebSocketListeners
     /// <summary>
     /// Class SessionInfoWebSocketListener.
     /// </summary>
-    public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<SessionInfo>, WebSocketListenerState>, ISessionInfoWebSocketListener
+    public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<SessionInfo>, WebSocketListenerState>
     {
         private readonly ISessionManager _sessionManager;
 

+ 9 - 4
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<IUserManager, UserManager>();
             ServiceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>();
 
-            ServiceCollection.AddScoped<IActivityLogWebSocketListener, ActivityLogWebSocketListener>();
-            ServiceCollection.AddScoped<IScheduledTasksWebSocketListener, ScheduledTasksWebSocketListener>();
-            ServiceCollection.AddScoped<ISessionInfoWebSocketListener, SessionInfoWebSocketListener>();
-            ServiceCollection.AddScoped<ISessionWebSocketListener, SessionWebSocketListener>();
+            ServiceCollection.AddScoped<IWebSocketListener, ActivityLogWebSocketListener>();
+            ServiceCollection.AddScoped<IWebSocketListener, ScheduledTasksWebSocketListener>();
+            ServiceCollection.AddScoped<IWebSocketListener, SessionInfoWebSocketListener>();
+            // This one has to be last as DI will select it for parameterization.
+            ServiceCollection.AddScoped<IWebSocketListener, SessionWebSocketListener>();
+
+            // TODO fix circular dependency on IWebSocketManager
+            ServiceCollection.AddScoped(serviceProvider => new Lazy<IEnumerable<IWebSocketListener>>(serviceProvider.GetRequiredService<IEnumerable<IWebSocketListener>>));
 
             base.RegisterServices();
         }

+ 10 - 1
Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs

@@ -25,10 +25,19 @@ namespace Jellyfin.Server.Middleware
         /// </summary>
         /// <param name="httpContext">The current HTTP context.</param>
         /// <param name="webSocketManager">The WebSocket connection manager.</param>
+        /// <param name="websocketListener">Session manager instance.</param>
         /// <returns>The async task.</returns>
         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)
             {

+ 5 - 0
MediaBrowser.Controller/Net/IWebSocketManager.cs

@@ -11,6 +11,11 @@ namespace MediaBrowser.Controller.Net
     /// </summary>
     public interface IWebSocketManager
     {
+        /// <summary>
+        /// Occurs when [web socket connected].
+        /// </summary>
+        event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
+
         /// <summary>
         /// The HTTP request handler.
         /// </summary>