diff options
16 files changed, 198 insertions, 55 deletions
diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index fd7653a32..7f620d666 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 /// </summary> /// <param name="logger">The logger.</param> /// <param name="socket">The socket.</param> + /// <param name="authorizationInfo">The authorization information.</param> /// <param name="remoteEndPoint">The remote end point.</param> public WebSocketConnection( ILogger<WebSocketConnection> 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 /// <inheritdoc /> public event EventHandler<EventArgs>? Closed; - /// <summary> - /// Gets the remote end point. - /// </summary> + /// <inheritdoc /> + public AuthorizationInfo AuthorizationInfo { get; } + + /// <inheritdoc /> public IPAddress? RemoteEndPoint { get; } - /// <summary> - /// Gets or sets the receive action. - /// </summary> - /// <value>The receive action.</value> + /// <inheritdoc /> public Func<WebSocketMessageInfo, Task>? OnReceive { get; set; } - /// <summary> - /// Gets the last activity date. - /// </summary> - /// <value>The last activity date.</value> + /// <inheritdoc /> public DateTime LastActivityDate { get; private set; } /// <inheritdoc /> public DateTime LastKeepAliveDate { get; set; } - /// <summary> - /// Gets the state. - /// </summary> - /// <value>The state.</value> + /// <inheritdoc /> public WebSocketState State => _socket.State; /// <inheritdoc /> @@ -101,7 +97,7 @@ namespace Emby.Server.Implementations.HttpServer } /// <inheritdoc /> - 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 ecfb242f6..52f14b0b1 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<WebSocketConnection>(), 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/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 5f6dc93fb..03ff96b19 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -24,6 +24,7 @@ using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Authentication; using MediaBrowser.Controller.Events.Session; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; @@ -1462,7 +1463,7 @@ namespace Emby.Server.Implementations.Session if (user is null) { - await _eventManager.PublishAsync(new GenericEventArgs<AuthenticationRequest>(request)).ConfigureAwait(false); + await _eventManager.PublishAsync(new AuthenticationRequestEventArgs(request)).ConfigureAwait(false); throw new AuthenticationException("Invalid username or password entered."); } @@ -1498,7 +1499,7 @@ namespace Emby.Server.Implementations.Session ServerId = _appHost.SystemId }; - await _eventManager.PublishAsync(new GenericEventArgs<AuthenticationResult>(returnResult)).ConfigureAwait(false); + await _eventManager.PublishAsync(new AuthenticationResultEventArgs(returnResult)).ConfigureAwait(false); return returnResult; } diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs index 4a5e0ecd4..5b90d65d8 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; /// <summary> -/// Class SessionInfoWebSocketListener. +/// Class ActivityLogWebSocketListener. /// </summary> public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener<ActivityLogEntry[], WebSocketListenerState> { @@ -56,6 +58,20 @@ public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener<Activi base.Dispose(dispose); } + /// <summary> + /// Starts sending messages over an activity log web socket. + /// </summary> + /// <param name="message">The message.</param> + protected override void Start(WebSocketMessageInfo message) + { + if (!message.Connection.AuthorizationInfo.User.HasPermission(PermissionKind.IsAdministrator)) + { + throw new AuthenticationException("Only admin users can retrieve the activity log."); + } + + base.Start(message); + } + private async void OnEntryCreated(object? sender, GenericEventArgs<ActivityLogEntry> e) { await SendData(true).ConfigureAwait(false); diff --git a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs index 0d8bf205c..b403ff46d 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,20 @@ public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener<IEnume base.Dispose(dispose); } + /// <summary> + /// Starts sending messages over a session info web socket. + /// </summary> + /// <param name="message">The message.</param> + protected override void Start(WebSocketMessageInfo message) + { + if (!message.Connection.AuthorizationInfo.User.HasPermission(PermissionKind.IsAdministrator)) + { + throw new AuthenticationException("Only admin users can subscribe to session information."); + } + + base.Start(message); + } + private async void OnSessionManagerSessionActivity(object? sender, SessionEventArgs e) { await SendData(false).ConfigureAwait(false); diff --git a/Jellyfin.Networking/Extensions/NetworkExtensions.cs b/Jellyfin.Networking/Extensions/NetworkExtensions.cs index d55f78135..e45fa3bcb 100644 --- a/Jellyfin.Networking/Extensions/NetworkExtensions.cs +++ b/Jellyfin.Networking/Extensions/NetworkExtensions.cs @@ -104,7 +104,7 @@ public static partial class NetworkExtensions Span<byte> bytes = stackalloc byte[mask.AddressFamily == AddressFamily.InterNetwork ? Network.IPv4MaskBytes : Network.IPv6MaskBytes]; if (!mask.TryWriteBytes(bytes, out var bytesWritten)) { - Console.WriteLine("Unable to write address bytes, only {bytesWritten} bytes written."); + Console.WriteLine("Unable to write address bytes, only ${bytesWritten} bytes written."); } var zeroed = false; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs index f899b4497..b5f18d983 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs @@ -2,9 +2,8 @@ using System.Globalization; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using Jellyfin.Data.Events; using MediaBrowser.Controller.Events; -using MediaBrowser.Controller.Session; +using MediaBrowser.Controller.Events.Authentication; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Globalization; using Microsoft.Extensions.Logging; @@ -14,7 +13,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Security /// <summary> /// Creates an entry in the activity log when there is a failed login attempt. /// </summary> - public class AuthenticationFailedLogger : IEventConsumer<GenericEventArgs<AuthenticationRequest>> + public class AuthenticationFailedLogger : IEventConsumer<AuthenticationRequestEventArgs> { private readonly ILocalizationManager _localizationManager; private readonly IActivityManager _activityManager; @@ -31,13 +30,13 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Security } /// <inheritdoc /> - public async Task OnEvent(GenericEventArgs<AuthenticationRequest> eventArgs) + public async Task OnEvent(AuthenticationRequestEventArgs eventArgs) { await _activityManager.CreateAsync(new ActivityLog( string.Format( CultureInfo.InvariantCulture, _localizationManager.GetLocalizedString("FailedLoginAttemptWithUserName"), - eventArgs.Argument.Username), + eventArgs.Username), "AuthenticationFailed", Guid.Empty) { @@ -45,7 +44,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Security ShortOverview = string.Format( CultureInfo.InvariantCulture, _localizationManager.GetLocalizedString("LabelIpAddressValue"), - eventArgs.Argument.RemoteEndPoint), + eventArgs.RemoteEndPoint), }).ConfigureAwait(false); } } diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs index 8b0bd84c6..2ee5b4e88 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs @@ -2,8 +2,8 @@ using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Events; -using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Authentication; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Globalization; @@ -12,7 +12,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Security /// <summary> /// Creates an entry in the activity log when there is a successful login attempt. /// </summary> - public class AuthenticationSucceededLogger : IEventConsumer<GenericEventArgs<AuthenticationResult>> + public class AuthenticationSucceededLogger : IEventConsumer<AuthenticationResultEventArgs> { private readonly ILocalizationManager _localizationManager; private readonly IActivityManager _activityManager; @@ -29,20 +29,20 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Security } /// <inheritdoc /> - public async Task OnEvent(GenericEventArgs<AuthenticationResult> eventArgs) + public async Task OnEvent(AuthenticationResultEventArgs eventArgs) { await _activityManager.CreateAsync(new ActivityLog( string.Format( CultureInfo.InvariantCulture, _localizationManager.GetLocalizedString("AuthenticationSucceededWithUserName"), - eventArgs.Argument.User.Name), + eventArgs.User.Name), "AuthenticationSucceeded", - eventArgs.Argument.User.Id) + eventArgs.User.Id) { ShortOverview = string.Format( CultureInfo.InvariantCulture, _localizationManager.GetLocalizedString("LabelIpAddressValue"), - eventArgs.Argument.SessionInfo.RemoteEndPoint), + eventArgs.SessionInfo?.RemoteEndPoint), }).ConfigureAwait(false); } } diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs index aeb62e814..27726a57a 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs @@ -58,15 +58,18 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Session var user = eventArgs.Users[0]; await _activityManager.CreateAsync(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localizationManager.GetLocalizedString("UserStartedPlayingItemWithValues"), - user.Username, - GetItemName(eventArgs.MediaInfo), - eventArgs.DeviceName), - GetPlaybackNotificationType(eventArgs.MediaInfo.MediaType), - user.Id)) - .ConfigureAwait(false); + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserStartedPlayingItemWithValues"), + user.Username, + GetItemName(eventArgs.MediaInfo), + eventArgs.DeviceName), + GetPlaybackNotificationType(eventArgs.MediaInfo.MediaType), + user.Id) + { + ItemId = eventArgs.Item?.Id.ToString("N", CultureInfo.InvariantCulture), + }) + .ConfigureAwait(false); } private static string GetItemName(BaseItemDto item) diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs index dd7290fb8..6b16477aa 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs @@ -73,7 +73,10 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Session GetItemName(item), eventArgs.DeviceName), notificationType, - user.Id)) + user.Id) + { + ItemId = eventArgs.Item?.Id.ToString("N", CultureInfo.InvariantCulture), + }) .ConfigureAwait(false); } diff --git a/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs index 5d558189b..9a473de52 100644 --- a/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs +++ b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs @@ -8,12 +8,11 @@ using Jellyfin.Server.Implementations.Events.Consumers.System; using Jellyfin.Server.Implementations.Events.Consumers.Updates; using Jellyfin.Server.Implementations.Events.Consumers.Users; using MediaBrowser.Common.Updates; -using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Authentication; using MediaBrowser.Controller.Events.Session; using MediaBrowser.Controller.Events.Updates; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Subtitles; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.DependencyInjection; @@ -35,8 +34,8 @@ namespace Jellyfin.Server.Implementations.Events collection.AddScoped<IEventConsumer<SubtitleDownloadFailureEventArgs>, SubtitleDownloadFailureLogger>(); // Security consumers - collection.AddScoped<IEventConsumer<GenericEventArgs<AuthenticationRequest>>, AuthenticationFailedLogger>(); - collection.AddScoped<IEventConsumer<GenericEventArgs<AuthenticationResult>>, AuthenticationSucceededLogger>(); + collection.AddScoped<IEventConsumer<AuthenticationRequestEventArgs>, AuthenticationFailedLogger>(); + collection.AddScoped<IEventConsumer<AuthenticationResultEventArgs>, AuthenticationSucceededLogger>(); // Session consumers collection.AddScoped<IEventConsumer<PlaybackStartEventArgs>, PlaybackStartLogger>(); diff --git a/MediaBrowser.Controller/Events/Authentication/AuthenticationRequestEventArgs.cs b/MediaBrowser.Controller/Events/Authentication/AuthenticationRequestEventArgs.cs new file mode 100644 index 000000000..2143c6998 --- /dev/null +++ b/MediaBrowser.Controller/Events/Authentication/AuthenticationRequestEventArgs.cs @@ -0,0 +1,60 @@ +using System; +using MediaBrowser.Controller.Session; + +namespace MediaBrowser.Controller.Events.Authentication; + +/// <summary> +/// A class representing an authentication result event. +/// </summary> +public class AuthenticationRequestEventArgs : EventArgs +{ + /// <summary> + /// Initializes a new instance of the <see cref="AuthenticationRequestEventArgs"/> class. + /// </summary> + /// <param name="request">The <see cref="AuthenticationRequest"/>.</param> + public AuthenticationRequestEventArgs(AuthenticationRequest request) + { + Username = request.Username; + UserId = request.UserId; + App = request.App; + AppVersion = request.AppVersion; + DeviceId = request.DeviceId; + DeviceName = request.DeviceName; + RemoteEndPoint = request.RemoteEndPoint; + } + + /// <summary> + /// Gets or sets the user name. + /// </summary> + public string? Username { get; set; } + + /// <summary> + /// Gets or sets the user id. + /// </summary> + public Guid? UserId { get; set; } + + /// <summary> + /// Gets or sets the app. + /// </summary> + public string? App { get; set; } + + /// <summary> + /// Gets or sets the app version. + /// </summary> + public string? AppVersion { get; set; } + + /// <summary> + /// Gets or sets the device id. + /// </summary> + public string? DeviceId { get; set; } + + /// <summary> + /// Gets or sets the device name. + /// </summary> + public string? DeviceName { get; set; } + + /// <summary> + /// Gets or sets the remote endpoint. + /// </summary> + public string? RemoteEndPoint { get; set; } +} diff --git a/MediaBrowser.Controller/Events/Authentication/AuthenticationResultEventArgs.cs b/MediaBrowser.Controller/Events/Authentication/AuthenticationResultEventArgs.cs new file mode 100644 index 000000000..357ef9406 --- /dev/null +++ b/MediaBrowser.Controller/Events/Authentication/AuthenticationResultEventArgs.cs @@ -0,0 +1,38 @@ +using System; +using MediaBrowser.Controller.Authentication; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Dto; + +namespace MediaBrowser.Controller.Events.Authentication; + +/// <summary> +/// A class representing an authentication result event. +/// </summary> +public class AuthenticationResultEventArgs : EventArgs +{ + /// <summary> + /// Initializes a new instance of the <see cref="AuthenticationResultEventArgs"/> class. + /// </summary> + /// <param name="result">The <see cref="AuthenticationResult"/>.</param> + public AuthenticationResultEventArgs(AuthenticationResult result) + { + User = result.User; + SessionInfo = result.SessionInfo; + ServerId = result.ServerId; + } + + /// <summary> + /// Gets or sets the user. + /// </summary> + public UserDto User { get; set; } + + /// <summary> + /// Gets or sets the session information. + /// </summary> + public SessionInfo? SessionInfo { get; set; } + + /// <summary> + /// Gets or sets the server id. + /// </summary> + public string? ServerId { get; set; } +} diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 8f38d4976..e0942e490 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Net /// Starts sending messages over a web socket. /// </summary> /// <param name="message">The message.</param> - private void Start(WebSocketMessageInfo message) + protected virtual void Start(WebSocketMessageInfo message) { var vals = message.Data.Split(','); diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index 79f0846b4..bba5a6b85 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 { + /// <summary> + /// Interface for WebSocket connections. + /// </summary> public interface IWebSocketConnection : IAsyncDisposable, IDisposable { /// <summary> @@ -41,6 +42,11 @@ namespace MediaBrowser.Controller.Net WebSocketState State { get; } /// <summary> + /// Gets the authorization information. + /// </summary> + public AuthorizationInfo AuthorizationInfo { get; } + + /// <summary> /// Gets the remote end point. /// </summary> /// <value>The remote end point.</value> @@ -65,6 +71,11 @@ namespace MediaBrowser.Controller.Net /// <exception cref="ArgumentNullException">The message is null.</exception> Task SendAsync<T>(OutboundWebSocketMessage<T> message, CancellationToken cancellationToken); - Task ProcessAsync(CancellationToken cancellationToken = default); + /// <summary> + /// Receives a message asynchronously. + /// </summary> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + 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 f01611819..22667ee82 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<WebSocketConnection>(), null!, null!); + var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/ForceKeepAlive.json"); con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(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<WebSocketConnection>(), null!, null!); + var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/ForceKeepAlive.json"); var seg1 = new BufferSegment(new Memory<byte>(bytes, 0, SplitPos)); var seg2 = seg1.Append(new Memory<byte>(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<WebSocketConnection>(), null!, null!); + var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/ValidPartial.json"); con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(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<WebSocketConnection>(), null!, null!); + var con = new WebSocketConnection(new NullLogger<WebSocketConnection>(), null!, null!, null!); var bytes = File.ReadAllBytes("Test Data/HttpServer/Partial.json"); Assert.Throws<JsonException>(() => con.DeserializeWebSocketMessage(new ReadOnlySequence<byte>(bytes), out var bytesConsumed)); } |
