diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index fd7653a32d..7f620d666d 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -12,6 +12,7 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net.WebSocketMessages; using MediaBrowser.Controller.Net.WebSocketMessages.Outbound; using MediaBrowser.Model.Session; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.HttpServer @@ -43,14 +44,17 @@ namespace Emby.Server.Implementations.HttpServer /// /// The logger. /// The socket. + /// The authorization information. /// The remote end point. public WebSocketConnection( ILogger logger, WebSocket socket, + AuthorizationInfo authorizationInfo, IPAddress? remoteEndPoint) { _logger = logger; _socket = socket; + AuthorizationInfo = authorizationInfo; RemoteEndPoint = remoteEndPoint; _jsonOptions = JsonDefaults.Options; @@ -60,30 +64,22 @@ namespace Emby.Server.Implementations.HttpServer /// public event EventHandler? Closed; - /// - /// Gets the remote end point. - /// + /// + public AuthorizationInfo AuthorizationInfo { get; } + + /// public IPAddress? RemoteEndPoint { get; } - /// - /// Gets or sets the receive action. - /// - /// The receive action. + /// public Func? OnReceive { get; set; } - /// - /// Gets the last activity date. - /// - /// The last activity date. + /// public DateTime LastActivityDate { get; private set; } /// public DateTime LastKeepAliveDate { get; set; } - /// - /// Gets the state. - /// - /// The state. + /// public WebSocketState State => _socket.State; /// @@ -101,7 +97,7 @@ namespace Emby.Server.Implementations.HttpServer } /// - public async Task ProcessAsync(CancellationToken cancellationToken = default) + public async Task ReceiveAsync(CancellationToken cancellationToken = default) { var pipe = new Pipe(); var writer = pipe.Writer; diff --git a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs index ecfb242f6f..52f14b0b10 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs @@ -51,6 +51,7 @@ namespace Emby.Server.Implementations.HttpServer using var connection = new WebSocketConnection( _loggerFactory.CreateLogger(), webSocket, + authorizationInfo, context.GetNormalizedRemoteIP()) { OnReceive = ProcessWebSocketMessageReceived @@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.HttpServer await Task.WhenAll(tasks).ConfigureAwait(false); - await connection.ProcessAsync().ConfigureAwait(false); + await connection.ReceiveAsync().ConfigureAwait(false); _logger.LogInformation("WS {IP} closed", context.Connection.RemoteIpAddress); } catch (Exception ex) // Otherwise ASP.Net will ignore the exception diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs index 4a5e0ecd4f..33d391f296 100644 --- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs @@ -1,6 +1,8 @@ using System; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Session; @@ -9,7 +11,7 @@ using Microsoft.Extensions.Logging; namespace Jellyfin.Api.WebSocketListeners; /// -/// Class SessionInfoWebSocketListener. +/// Class ActivityLogWebSocketListener. /// public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener { @@ -56,6 +58,16 @@ public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener e) { await SendData(true).ConfigureAwait(false); diff --git a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs index 0d8bf205c9..0d614ba4f2 100644 --- a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Jellyfin.Data.Enums; +using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; @@ -66,6 +68,16 @@ public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener /// The message. - private void Start(WebSocketMessageInfo message) + protected void Start(WebSocketMessageInfo message) { var vals = message.Data.Split(','); diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index 79f0846b4a..bba5a6b851 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Net; using System.Net.WebSockets; @@ -9,6 +7,9 @@ using MediaBrowser.Controller.Net.WebSocketMessages; namespace MediaBrowser.Controller.Net { + /// + /// Interface for WebSocket connections. + /// public interface IWebSocketConnection : IAsyncDisposable, IDisposable { /// @@ -40,6 +41,11 @@ namespace MediaBrowser.Controller.Net /// The state. WebSocketState State { get; } + /// + /// Gets the authorization information. + /// + public AuthorizationInfo AuthorizationInfo { get; } + /// /// Gets the remote end point. /// @@ -65,6 +71,11 @@ namespace MediaBrowser.Controller.Net /// The message is null. Task SendAsync(OutboundWebSocketMessage message, CancellationToken cancellationToken); - Task ProcessAsync(CancellationToken cancellationToken = default); + /// + /// Receives a message asynchronously. + /// + /// The cancellation token. + /// Task. + Task ReceiveAsync(CancellationToken cancellationToken = default); } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs b/tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs index f016118192..22667ee82d 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/HttpServer/WebSocketConnectionTests.cs @@ -13,7 +13,7 @@ namespace Jellyfin.Server.Implementations.Tests.HttpServer [Fact] public void DeserializeWebSocketMessage_SingleSegment_Success() { - var con = new WebSocketConnection(new NullLogger(), null!, null!); + var con = new WebSocketConnection(new NullLogger(), null!, null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/ForceKeepAlive.json"); con.DeserializeWebSocketMessage(new ReadOnlySequence(bytes), out var bytesConsumed); Assert.Equal(109, bytesConsumed); @@ -23,7 +23,7 @@ namespace Jellyfin.Server.Implementations.Tests.HttpServer public void DeserializeWebSocketMessage_MultipleSegments_Success() { const int SplitPos = 64; - var con = new WebSocketConnection(new NullLogger(), null!, null!); + var con = new WebSocketConnection(new NullLogger(), null!, null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/ForceKeepAlive.json"); var seg1 = new BufferSegment(new Memory(bytes, 0, SplitPos)); var seg2 = seg1.Append(new Memory(bytes, SplitPos, bytes.Length - SplitPos)); @@ -34,7 +34,7 @@ namespace Jellyfin.Server.Implementations.Tests.HttpServer [Fact] public void DeserializeWebSocketMessage_ValidPartial_Success() { - var con = new WebSocketConnection(new NullLogger(), null!, null!); + var con = new WebSocketConnection(new NullLogger(), null!, null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/ValidPartial.json"); con.DeserializeWebSocketMessage(new ReadOnlySequence(bytes), out var bytesConsumed); Assert.Equal(109, bytesConsumed); @@ -43,7 +43,7 @@ namespace Jellyfin.Server.Implementations.Tests.HttpServer [Fact] public void DeserializeWebSocketMessage_Partial_ThrowJsonException() { - var con = new WebSocketConnection(new NullLogger(), null!, null!); + var con = new WebSocketConnection(new NullLogger(), null!, null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/Partial.json"); Assert.Throws(() => con.DeserializeWebSocketMessage(new ReadOnlySequence(bytes), out var bytesConsumed)); }