aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Server.Implementations/HttpServer/WebSocketManager.cs31
-rw-r--r--Emby.Server.Implementations/Session/ISessionWebSocketListener.cs30
-rw-r--r--Emby.Server.Implementations/Session/SessionWebSocketListener.cs27
-rw-r--r--Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs2
-rw-r--r--Jellyfin.Api/WebSocketListeners/IActivityLogWebSocketListener.cs10
-rw-r--r--Jellyfin.Api/WebSocketListeners/IScheduledTasksWebSocketListener.cs10
-rw-r--r--Jellyfin.Api/WebSocketListeners/ISessionInfoWebSocketListener.cs10
-rw-r--r--Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs8
-rw-r--r--Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs2
-rw-r--r--Jellyfin.Server/CoreAppHost.cs13
-rw-r--r--Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs11
-rw-r--r--MediaBrowser.Controller/Net/IWebSocketManager.cs5
12 files changed, 95 insertions, 64 deletions
diff --git a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs
index 71ece80a7..5518fb95a 100644
--- a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs
+++ b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs
@@ -4,7 +4,9 @@ using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Threading.Tasks;
-using Jellyfin.Data.Events;
+using Emby.Server.Implementations.Session;
+using Jellyfin.Api.WebSocketListeners;
+using MediaBrowser.Controller;
using MediaBrowser.Controller.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
@@ -13,24 +15,21 @@ namespace Emby.Server.Implementations.HttpServer
{
public class WebSocketManager : IWebSocketManager
{
- private readonly Lazy<IEnumerable<IWebSocketListener>> _webSocketListeners;
+ private readonly IServerApplicationHost _appHost;
private readonly ILogger<WebSocketManager> _logger;
private readonly ILoggerFactory _loggerFactory;
-
private bool _disposed = false;
public WebSocketManager(
- Lazy<IEnumerable<IWebSocketListener>> webSocketListeners,
+ IServerApplicationHost appHost,
ILogger<WebSocketManager> logger,
ILoggerFactory loggerFactory)
{
- _webSocketListeners = webSocketListeners;
+ _appHost = appHost;
_logger = logger;
_loggerFactory = loggerFactory;
}
- public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
-
/// <inheritdoc />
public async Task WebSocketRequestHandler(HttpContext context)
{
@@ -39,6 +38,8 @@ namespace Emby.Server.Implementations.HttpServer
return;
}
+ var listener = _appHost.Resolve<ISessionWebSocketListener>();
+
try
{
_logger.LogInformation("WS {IP} request", context.Connection.RemoteIpAddress);
@@ -54,7 +55,7 @@ namespace Emby.Server.Implementations.HttpServer
OnReceive = ProcessWebSocketMessageReceived
};
- WebSocketConnected?.Invoke(this, new GenericEventArgs<IWebSocketConnection>(connection));
+ listener?.ProcessWebSocketConnected(connection);
await connection.ProcessAsync().ConfigureAwait(false);
_logger.LogInformation("WS {IP} closed", context.Connection.RemoteIpAddress);
@@ -80,16 +81,12 @@ namespace Emby.Server.Implementations.HttpServer
return Task.CompletedTask;
}
- IEnumerable<Task> GetTasks()
- {
- var listeners = _webSocketListeners.Value;
- foreach (var x in listeners)
- {
- yield return x.ProcessMessageAsync(result);
- }
- }
+ Parallel.Invoke(
+ () => _appHost.Resolve<IActivityLogWebSocketListener>(),
+ () => _appHost.Resolve<IScheduledTasksWebSocketListener>(),
+ () => _appHost.Resolve<ISessionInfoWebSocketListener>());
- return Task.WhenAll(GetTasks());
+ return Task.CompletedTask;
}
}
}
diff --git a/Emby.Server.Implementations/Session/ISessionWebSocketListener.cs b/Emby.Server.Implementations/Session/ISessionWebSocketListener.cs
new file mode 100644
index 000000000..9b0b28e6e
--- /dev/null
+++ b/Emby.Server.Implementations/Session/ISessionWebSocketListener.cs
@@ -0,0 +1,30 @@
+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);
+ }
+}
diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
index a5f847953..8f81ee194 100644
--- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
+++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
@@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Session
/// <summary>
/// Class SessionWebSocketListener.
/// </summary>
- public sealed class SessionWebSocketListener : IWebSocketListener, IDisposable
+ public sealed class SessionWebSocketListener : ISessionWebSocketListener, IDisposable
{
/// <summary>
/// The timeout in seconds after which a WebSocket is considered to be lost.
@@ -45,15 +45,13 @@ 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 accesing the KeepAlive cancellation token.
+ /// Lock used for accessing the KeepAlive cancellation token.
/// </summary>
private readonly object _keepAliveLock = new object();
@@ -63,7 +61,7 @@ namespace Emby.Server.Implementations.Session
private readonly HashSet<IWebSocketConnection> _webSockets = new HashSet<IWebSocketConnection>();
/// <summary>
- /// Lock used for accesing the WebSockets watchlist.
+ /// Lock used for accessing the WebSockets watchlist.
/// </summary>
private readonly object _webSocketsLock = new object();
@@ -73,32 +71,28 @@ 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,
- IWebSocketManager webSocketManager)
+ ILoggerFactory loggerFactory)
{
_logger = logger;
_sessionManager = sessionManager;
_loggerFactory = loggerFactory;
- _webSocketManager = webSocketManager;
-
- webSocketManager.WebSocketConnected += OnServerManagerWebSocketConnected;
}
- private async void OnServerManagerWebSocketConnected(object sender, GenericEventArgs<IWebSocketConnection> e)
+ /// <inheritdoc/>
+ public async void ProcessWebSocketConnected(IWebSocketConnection websocketConnection)
{
- var session = GetSession(e.Argument.QueryString, e.Argument.RemoteEndPoint.ToString());
+ var session = GetSession(websocketConnection.QueryString, websocketConnection.RemoteEndPoint.ToString());
if (session != null)
{
- EnsureController(session, e.Argument);
- await KeepAliveWebSocket(e.Argument).ConfigureAwait(false);
+ EnsureController(session, websocketConnection);
+ await KeepAliveWebSocket(websocketConnection).ConfigureAwait(false);
}
else
{
- _logger.LogWarning("Unable to determine session based on query string: {0}", e.Argument.QueryString);
+ _logger.LogWarning("Unable to determine session based on query string: {Querystring}", websocketConnection.QueryString);
}
}
@@ -122,7 +116,6 @@ namespace Emby.Server.Implementations.Session
/// <inheritdoc />
public void Dispose()
{
- _webSocketManager.WebSocketConnected -= OnServerManagerWebSocketConnected;
StopKeepAlive();
}
diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs
index 288e03fcf..3dc45b145 100644
--- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs
+++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs
@@ -11,7 +11,7 @@ namespace Jellyfin.Api.WebSocketListeners
/// <summary>
/// Class SessionInfoWebSocketListener.
/// </summary>
- public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener<ActivityLogEntry[], WebSocketListenerState>
+ public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener<ActivityLogEntry[], WebSocketListenerState>, IActivityLogWebSocketListener
{
/// <summary>
/// The _kernel.
diff --git a/Jellyfin.Api/WebSocketListeners/IActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/IActivityLogWebSocketListener.cs
new file mode 100644
index 000000000..b23022e71
--- /dev/null
+++ b/Jellyfin.Api/WebSocketListeners/IActivityLogWebSocketListener.cs
@@ -0,0 +1,10 @@
+#pragma warning disable CA1040 // Avoid empty interfaces
+namespace Jellyfin.Api.WebSocketListeners
+{
+ /// <summary>
+ /// Defines the <see cref="IActivityLogWebSocketListener" />.
+ /// </summary>
+ public interface IActivityLogWebSocketListener
+ {
+ }
+}
diff --git a/Jellyfin.Api/WebSocketListeners/IScheduledTasksWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/IScheduledTasksWebSocketListener.cs
new file mode 100644
index 000000000..425d61dfa
--- /dev/null
+++ b/Jellyfin.Api/WebSocketListeners/IScheduledTasksWebSocketListener.cs
@@ -0,0 +1,10 @@
+#pragma warning disable CA1040 // Avoid empty interfaces
+namespace Jellyfin.Api.WebSocketListeners
+{
+ /// <summary>
+ /// Defines the <see cref="IScheduledTasksWebSocketListener" />.
+ /// </summary>
+ public interface IScheduledTasksWebSocketListener
+ {
+ }
+}
diff --git a/Jellyfin.Api/WebSocketListeners/ISessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ISessionInfoWebSocketListener.cs
new file mode 100644
index 000000000..33636dc06
--- /dev/null
+++ b/Jellyfin.Api/WebSocketListeners/ISessionInfoWebSocketListener.cs
@@ -0,0 +1,10 @@
+#pragma warning disable CA1040 // Avoid empty interfaces
+namespace Jellyfin.Api.WebSocketListeners
+{
+ /// <summary>
+ /// Defines the <see cref="ISessionInfoWebSocketListener" />.
+ /// </summary>
+ public interface ISessionInfoWebSocketListener
+ {
+ }
+}
diff --git a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs
index 94df23e56..eafa9c71f 100644
--- a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs
+++ b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs
@@ -12,7 +12,7 @@ namespace Jellyfin.Api.WebSocketListeners
/// <summary>
/// Class ScheduledTasksWebSocketListener.
/// </summary>
- public class ScheduledTasksWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<TaskInfo>, WebSocketListenerState>
+ public class ScheduledTasksWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<TaskInfo>, WebSocketListenerState>, IScheduledTasksWebSocketListener
{
/// <summary>
/// Gets or sets the task manager.
@@ -66,19 +66,19 @@ namespace Jellyfin.Api.WebSocketListeners
private void OnTaskCompleted(object? sender, TaskCompletionEventArgs e)
{
- SendData(true);
+ SendData(true).GetAwaiter().GetResult();
e.Task.TaskProgress -= OnTaskProgress;
}
private void OnTaskExecuting(object? sender, GenericEventArgs<IScheduledTaskWorker> e)
{
- SendData(true);
+ SendData(true).GetAwaiter().GetResult();
e.Argument.TaskProgress += OnTaskProgress;
}
private void OnTaskProgress(object? sender, GenericEventArgs<double> e)
{
- SendData(false);
+ SendData(false).GetAwaiter().GetResult();
}
}
}
diff --git a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs
index d996ac69f..be701be45 100644
--- a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs
+++ b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs
@@ -11,7 +11,7 @@ namespace Jellyfin.Api.WebSocketListeners
/// <summary>
/// Class SessionInfoWebSocketListener.
/// </summary>
- public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<SessionInfo>, WebSocketListenerState>
+ public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<SessionInfo>, WebSocketListenerState>, ISessionInfoWebSocketListener
{
private readonly ISessionManager _sessionManager;
diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs
index 4b44537a5..100f3619a 100644
--- a/Jellyfin.Server/CoreAppHost.cs
+++ b/Jellyfin.Server/CoreAppHost.cs
@@ -11,7 +11,6 @@ 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;
@@ -82,14 +81,10 @@ namespace Jellyfin.Server
ServiceCollection.AddSingleton<IUserManager, UserManager>();
ServiceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>();
- 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>>));
+ ServiceCollection.AddScoped<IActivityLogWebSocketListener, ActivityLogWebSocketListener>();
+ ServiceCollection.AddScoped<IScheduledTasksWebSocketListener, ScheduledTasksWebSocketListener>();
+ ServiceCollection.AddScoped<ISessionInfoWebSocketListener, SessionInfoWebSocketListener>();
+ ServiceCollection.AddScoped<ISessionWebSocketListener, SessionWebSocketListener>();
base.RegisterServices();
}
diff --git a/Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs b/Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs
index 53f32bebd..ba0abfbdd 100644
--- a/Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs
+++ b/Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs
@@ -25,19 +25,10 @@ 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,
-#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
+ IWebSocketManager webSocketManager)
{
if (!httpContext.WebSockets.IsWebSocketRequest)
{
diff --git a/MediaBrowser.Controller/Net/IWebSocketManager.cs b/MediaBrowser.Controller/Net/IWebSocketManager.cs
index ce74173e7..d3f31de7c 100644
--- a/MediaBrowser.Controller/Net/IWebSocketManager.cs
+++ b/MediaBrowser.Controller/Net/IWebSocketManager.cs
@@ -12,11 +12,6 @@ namespace MediaBrowser.Controller.Net
public interface IWebSocketManager
{
/// <summary>
- /// Occurs when [web socket connected].
- /// </summary>
- event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
-
- /// <summary>
/// The HTTP request handler.
/// </summary>
/// <param name="context">The current HTTP context.</param>