浏览代码

Fix Websocket OpenApi (#9935)

* Further split inbound and outbound messages

* Fix datatype for inbound start messages

* fixes from review
Cody Robibero 1 年之前
父节点
当前提交
b5bbb98175
共有 50 个文件被更改,包括 165 次插入126 次删除
  1. 14 2
      Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
  2. 2 2
      Emby.Server.Implementations/Session/WebSocketController.cs
  3. 2 2
      MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
  4. 0 1
      MediaBrowser.Controller/Net/IWebSocketConnection.cs
  5. 0 6
      MediaBrowser.Controller/Net/WebSocketMessage.cs
  6. 0 2
      MediaBrowser.Controller/Net/WebSocketMessageInfo.cs
  7. 5 5
      MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStartMessage.cs
  8. 1 12
      MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStopMessage.cs
  9. 14 0
      MediaBrowser.Controller/Net/WebSocketMessages/Inbound/InboundKeepAliveMessage.cs
  10. 4 5
      MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStartMessage.cs
  11. 1 12
      MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStopMessage.cs
  12. 4 4
      MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStartMessage.cs
  13. 1 11
      MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStopMessage.cs
  14. 3 4
      MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessage.cs
  15. 26 0
      MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessageOfT.cs
  16. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ActivityLogEntryMessage.cs
  17. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ForceKeepAliveMessage.cs
  18. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/GeneralCommandMessage.cs
  19. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/LibraryChangedMessage.cs
  20. 14 0
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/OutboundKeepAliveMessage.cs
  21. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlayMessage.cs
  22. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlaystateMessage.cs
  23. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCancelledMessage.cs
  24. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCompletedMessage.cs
  25. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationFailedMessage.cs
  26. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallingMessage.cs
  27. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginUninstalledMessage.cs
  28. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RefreshProgressMessage.cs
  29. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RestartRequiredMessage.cs
  30. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTaskEndedMessage.cs
  31. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTasksInfoMessage.cs
  32. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCancelledMessage.cs
  33. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCreatedMessage.cs
  34. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerRestartingMessage.cs
  35. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerShuttingDownMessage.cs
  36. 3 2
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SessionsMessage.cs
  37. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayCommandMessage.cs
  38. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandMessage.cs
  39. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupInfoMessage.cs
  40. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage.cs
  41. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage.cs
  42. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfStringMessage.cs
  43. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCancelledMessage.cs
  44. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCreatedMessage.cs
  45. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDataChangedMessage.cs
  46. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDeletedMessage.cs
  47. 1 1
      MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserUpdatedMessage.cs
  48. 8 3
      MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessage.cs
  49. 33 0
      MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessageOfT.cs
  50. 0 23
      MediaBrowser.Controller/Net/WebSocketMessages/Shared/KeepAliveMessage.cs

+ 14 - 2
Emby.Server.Implementations/HttpServer/WebSocketConnection.cs

@@ -9,7 +9,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using Jellyfin.Extensions.Json;
 using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Net;
+using MediaBrowser.Controller.Net.WebSocketMessages;
 using MediaBrowser.Model.Session;
 using Microsoft.Extensions.Logging;
 
@@ -85,6 +85,18 @@ namespace Emby.Server.Implementations.HttpServer
         /// <value>The state.</value>
         public WebSocketState State => _socket.State;
 
+        /// <summary>
+        /// Sends a message asynchronously.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        public Task SendAsync(WebSocketMessage message, CancellationToken cancellationToken)
+        {
+            var json = JsonSerializer.SerializeToUtf8Bytes(message, _jsonOptions);
+            return _socket.SendAsync(json, WebSocketMessageType.Text, true, cancellationToken);
+        }
+
         /// <summary>
         /// Sends a message asynchronously.
         /// </summary>
@@ -224,7 +236,7 @@ namespace Emby.Server.Implementations.HttpServer
         {
             LastKeepAliveDate = DateTime.UtcNow;
             return SendAsync(
-                new WebSocketMessage<string>
+                new OutboundWebSocketMessage
                 {
                     MessageId = Guid.NewGuid(),
                     MessageType = SessionMessageType.KeepAlive

+ 2 - 2
Emby.Server.Implementations/Session/WebSocketController.cs

@@ -7,8 +7,8 @@ using System.Net.WebSockets;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Net.WebSocketMessages;
 using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Session;
 using Microsoft.Extensions.Logging;
 
@@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.Session
             }
 
             return socket.SendAsync(
-                new WebSocketMessage<T>
+                new OutboundWebSocketMessage<T>
                 {
                     Data = data,
                     MessageType = name,

+ 2 - 2
MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs

@@ -9,7 +9,7 @@ using System.Linq;
 using System.Net.WebSockets;
 using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
+using MediaBrowser.Controller.Net.WebSocketMessages;
 using MediaBrowser.Model.Session;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.Logging;
@@ -169,7 +169,7 @@ namespace MediaBrowser.Controller.Net
                 if (data is not null)
                 {
                     await connection.SendAsync(
-                        new WebSocketMessage<TReturnDataType>
+                        new OutboundWebSocketMessage<TReturnDataType>
                         {
                             MessageId = Guid.NewGuid(),
                             MessageType = Type,

+ 0 - 1
MediaBrowser.Controller/Net/IWebSocketConnection.cs

@@ -5,7 +5,6 @@ using System.Net;
 using System.Net.WebSockets;
 using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
 
 namespace MediaBrowser.Controller.Net
 {

+ 0 - 6
MediaBrowser.Controller/Net/WebSocketMessage.cs

@@ -1,4 +1,3 @@
-using System;
 using System.Text.Json.Serialization;
 using MediaBrowser.Model.Session;
 
@@ -15,11 +14,6 @@ public abstract class WebSocketMessage
     /// </summary>
     public virtual SessionMessageType MessageType { get; set; }
 
-    /// <summary>
-    /// Gets or sets the message id.
-    /// </summary>
-    public Guid MessageId { get; set; }
-
     /// <summary>
     /// Gets or sets the server id.
     /// </summary>

+ 0 - 2
MediaBrowser.Controller/Net/WebSocketMessageInfo.cs

@@ -1,7 +1,5 @@
 #nullable disable
 
-using MediaBrowser.Model.Net;
-
 namespace MediaBrowser.Controller.Net
 {
     /// <summary>

+ 5 - 5
MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStartMessage.cs

@@ -1,20 +1,20 @@
-using System.Collections.Generic;
 using System.ComponentModel;
-using MediaBrowser.Model.Activity;
 using MediaBrowser.Model.Session;
 
 namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
 
 /// <summary>
 /// Activity log entry start message.
+/// Data is the timing data encoded as "$initialDelay,$interval" in ms.
 /// </summary>
-public class ActivityLogEntryStartMessage : WebSocketMessage<IReadOnlyCollection<ActivityLogEntry>>, IInboundWebSocketMessage
+public class ActivityLogEntryStartMessage : InboundWebSocketMessage<string>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="ActivityLogEntryStartMessage"/> class.
+    /// Data is the timing data encoded as "$initialDelay,$interval" in ms.
     /// </summary>
-    /// <param name="data">Collection of activity log entries.</param>
-    public ActivityLogEntryStartMessage(IReadOnlyCollection<ActivityLogEntry> data)
+    /// <param name="data">The timing data encoded as "$initialDelay,$interval".</param>
+    public ActivityLogEntryStartMessage(string data)
         : base(data)
     {
     }

+ 1 - 12
MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStopMessage.cs

@@ -1,6 +1,4 @@
-using System.Collections.Generic;
 using System.ComponentModel;
-using MediaBrowser.Model.Activity;
 using MediaBrowser.Model.Session;
 
 namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
@@ -8,17 +6,8 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
 /// <summary>
 /// Activity log entry stop message.
 /// </summary>
-public class ActivityLogEntryStopMessage : WebSocketMessage<IReadOnlyCollection<ActivityLogEntry>>, IInboundWebSocketMessage
+public class ActivityLogEntryStopMessage : InboundWebSocketMessage
 {
-    /// <summary>
-    /// Initializes a new instance of the <see cref="ActivityLogEntryStopMessage"/> class.
-    /// </summary>
-    /// <param name="data">Collection of activity log entries.</param>
-    public ActivityLogEntryStopMessage(IReadOnlyCollection<ActivityLogEntry> data)
-        : base(data)
-    {
-    }
-
     /// <inheritdoc />
     [DefaultValue(SessionMessageType.ActivityLogEntryStop)]
     public override SessionMessageType MessageType => SessionMessageType.ActivityLogEntryStop;

+ 14 - 0
MediaBrowser.Controller/Net/WebSocketMessages/Inbound/InboundKeepAliveMessage.cs

@@ -0,0 +1,14 @@
+using System.ComponentModel;
+using MediaBrowser.Model.Session;
+
+namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
+
+/// <summary>
+/// Keep alive websocket messages.
+/// </summary>
+public class InboundKeepAliveMessage : InboundWebSocketMessage
+{
+    /// <inheritdoc />
+    [DefaultValue(SessionMessageType.KeepAlive)]
+    public override SessionMessageType MessageType => SessionMessageType.KeepAlive;
+}

+ 4 - 5
MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStartMessage.cs

@@ -1,20 +1,19 @@
-using System.Collections.Generic;
 using System.ComponentModel;
 using MediaBrowser.Model.Session;
-using MediaBrowser.Model.Tasks;
 
 namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
 
 /// <summary>
 /// Scheduled tasks info start message.
+/// Data is the timing data encoded as "$initialDelay,$interval" in ms.
 /// </summary>
-public class ScheduledTasksInfoStartMessage : WebSocketMessage<IReadOnlyCollection<TaskInfo>>, IInboundWebSocketMessage
+public class ScheduledTasksInfoStartMessage : InboundWebSocketMessage<string>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="ScheduledTasksInfoStartMessage"/> class.
     /// </summary>
-    /// <param name="data">Collection of task info.</param>
-    public ScheduledTasksInfoStartMessage(IReadOnlyCollection<TaskInfo> data)
+    /// <param name="data">The timing data encoded as $initialDelay,$interval.</param>
+    public ScheduledTasksInfoStartMessage(string data)
         : base(data)
     {
     }

+ 1 - 12
MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStopMessage.cs

@@ -1,24 +1,13 @@
-using System.Collections.Generic;
 using System.ComponentModel;
 using MediaBrowser.Model.Session;
-using MediaBrowser.Model.Tasks;
 
 namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
 
 /// <summary>
 /// Scheduled tasks info stop message.
 /// </summary>
-public class ScheduledTasksInfoStopMessage : WebSocketMessage<IReadOnlyCollection<TaskInfo>>, IInboundWebSocketMessage
+public class ScheduledTasksInfoStopMessage : InboundWebSocketMessage
 {
-    /// <summary>
-    /// Initializes a new instance of the <see cref="ScheduledTasksInfoStopMessage"/> class.
-    /// </summary>
-    /// <param name="data">Collection of task info.</param>
-    public ScheduledTasksInfoStopMessage(IReadOnlyCollection<TaskInfo> data)
-        : base(data)
-    {
-    }
-
     /// <inheritdoc />
     [DefaultValue(SessionMessageType.ScheduledTasksInfoStop)]
     public override SessionMessageType MessageType => SessionMessageType.ScheduledTasksInfoStop;

+ 4 - 4
MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStartMessage.cs

@@ -1,19 +1,19 @@
 using System.ComponentModel;
-using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Session;
 
 namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
 
 /// <summary>
 /// Sessions start message.
+/// Data is the timing data encoded as "$initialDelay,$interval" in ms.
 /// </summary>
-public class SessionsStartMessage : WebSocketMessage<SessionInfo>, IInboundWebSocketMessage
+public class SessionsStartMessage : InboundWebSocketMessage<string>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="SessionsStartMessage"/> class.
     /// </summary>
-    /// <param name="data">Session info.</param>
-    public SessionsStartMessage(SessionInfo data)
+    /// <param name="data">The timing data encoded as $initialDelay,$interval.</param>
+    public SessionsStartMessage(string data)
         : base(data)
     {
     }

+ 1 - 11
MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStopMessage.cs

@@ -1,5 +1,4 @@
 using System.ComponentModel;
-using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Session;
 
 namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
@@ -7,17 +6,8 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
 /// <summary>
 /// Sessions stop message.
 /// </summary>
-public class SessionsStopMessage : WebSocketMessage<SessionInfo>, IInboundWebSocketMessage
+public class SessionsStopMessage : InboundWebSocketMessage
 {
-    /// <summary>
-    /// Initializes a new instance of the <see cref="SessionsStopMessage"/> class.
-    /// </summary>
-    /// <param name="data">Session info.</param>
-    public SessionsStopMessage(SessionInfo data)
-        : base(data)
-    {
-    }
-
     /// <inheritdoc />
     [DefaultValue(SessionMessageType.SessionsStop)]
     public override SessionMessageType MessageType => SessionMessageType.SessionsStop;

+ 3 - 4
MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessage.cs

@@ -1,9 +1,8 @@
-namespace MediaBrowser.Controller.Net.WebSocketMessages;
+namespace MediaBrowser.Controller.Net.WebSocketMessages;
 
 /// <summary>
-/// Class representing the list of outbound websocket message types.
-/// Only used in openapi generation.
+/// Inbound websocket message.
 /// </summary>
-public class InboundWebSocketMessage : WebSocketMessage
+public class InboundWebSocketMessage : WebSocketMessage, IInboundWebSocketMessage
 {
 }

+ 26 - 0
MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessageOfT.cs

@@ -0,0 +1,26 @@
+#pragma warning disable SA1649 // File name must equal class name.
+
+namespace MediaBrowser.Controller.Net.WebSocketMessages;
+
+/// <summary>
+/// Inbound websocket message with data.
+/// </summary>
+/// <typeparam name="T">The data type.</typeparam>
+public class InboundWebSocketMessage<T> : WebSocketMessage<T>, IInboundWebSocketMessage
+{
+    /// <summary>
+    /// Initializes a new instance of the <see cref="InboundWebSocketMessage{T}"/> class.
+    /// </summary>
+    public InboundWebSocketMessage()
+    {
+    }
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="InboundWebSocketMessage{T}"/> class.
+    /// </summary>
+    /// <param name="data">The data to send.</param>
+    protected InboundWebSocketMessage(T data)
+    {
+        Data = data;
+    }
+}

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ActivityLogEntryMessage.cs

@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Activity log created message.
 /// </summary>
-public class ActivityLogEntryMessage : WebSocketMessage<IReadOnlyList<ActivityLogEntry>>, IOutboundWebSocketMessage
+public class ActivityLogEntryMessage : OutboundWebSocketMessage<IReadOnlyList<ActivityLogEntry>>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="ActivityLogEntryMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ForceKeepAliveMessage.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Force keep alive websocket messages.
 /// </summary>
-public class ForceKeepAliveMessage : WebSocketMessage<int>, IOutboundWebSocketMessage
+public class ForceKeepAliveMessage : OutboundWebSocketMessage<int>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="ForceKeepAliveMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/GeneralCommandMessage.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// General command websocket message.
 /// </summary>
-public class GeneralCommandMessage : WebSocketMessage<GeneralCommand>, IOutboundWebSocketMessage
+public class GeneralCommandMessage : OutboundWebSocketMessage<GeneralCommand>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="GeneralCommandMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/LibraryChangedMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Library changed message.
 /// </summary>
-public class LibraryChangedMessage : WebSocketMessage<LibraryUpdateInfo>, IOutboundWebSocketMessage
+public class LibraryChangedMessage : OutboundWebSocketMessage<LibraryUpdateInfo>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="LibraryChangedMessage"/> class.

+ 14 - 0
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/OutboundKeepAliveMessage.cs

@@ -0,0 +1,14 @@
+using System.ComponentModel;
+using MediaBrowser.Model.Session;
+
+namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
+
+/// <summary>
+/// Keep alive websocket messages.
+/// </summary>
+public class OutboundKeepAliveMessage : OutboundWebSocketMessage
+{
+    /// <inheritdoc />
+    [DefaultValue(SessionMessageType.KeepAlive)]
+    public override SessionMessageType MessageType => SessionMessageType.KeepAlive;
+}

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlayMessage.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Play command websocket message.
 /// </summary>
-public class PlayMessage : WebSocketMessage<PlayRequest>, IOutboundWebSocketMessage
+public class PlayMessage : OutboundWebSocketMessage<PlayRequest>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="PlayMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlaystateMessage.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Playstate message.
 /// </summary>
-public class PlaystateMessage : WebSocketMessage<PlaystateRequest>, IOutboundWebSocketMessage
+public class PlaystateMessage : OutboundWebSocketMessage<PlaystateRequest>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="PlaystateMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCancelledMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Plugin installation cancelled message.
 /// </summary>
-public class PluginInstallationCancelledMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage
+public class PluginInstallationCancelledMessage : OutboundWebSocketMessage<InstallationInfo>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="PluginInstallationCancelledMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCompletedMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Plugin installation completed message.
 /// </summary>
-public class PluginInstallationCompletedMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage
+public class PluginInstallationCompletedMessage : OutboundWebSocketMessage<InstallationInfo>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="PluginInstallationCompletedMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationFailedMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Plugin installation failed message.
 /// </summary>
-public class PluginInstallationFailedMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage
+public class PluginInstallationFailedMessage : OutboundWebSocketMessage<InstallationInfo>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="PluginInstallationFailedMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallingMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Package installing message.
 /// </summary>
-public class PluginInstallingMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage
+public class PluginInstallingMessage : OutboundWebSocketMessage<InstallationInfo>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="PluginInstallingMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginUninstalledMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Plugin uninstalled message.
 /// </summary>
-public class PluginUninstalledMessage : WebSocketMessage<PluginInfo>, IOutboundWebSocketMessage
+public class PluginUninstalledMessage : OutboundWebSocketMessage<PluginInfo>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="PluginUninstalledMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RefreshProgressMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Refresh progress message.
 /// </summary>
-public class RefreshProgressMessage : WebSocketMessage<Dictionary<string, string>>, IOutboundWebSocketMessage
+public class RefreshProgressMessage : OutboundWebSocketMessage<Dictionary<string, string>>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="RefreshProgressMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RestartRequiredMessage.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Restart required.
 /// </summary>
-public class RestartRequiredMessage : WebSocketMessage, IOutboundWebSocketMessage
+public class RestartRequiredMessage : OutboundWebSocketMessage
 {
     /// <inheritdoc />
     [DefaultValue(SessionMessageType.RestartRequired)]

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTaskEndedMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Scheduled task ended message.
 /// </summary>
-public class ScheduledTaskEndedMessage : WebSocketMessage<TaskResult>, IOutboundWebSocketMessage
+public class ScheduledTaskEndedMessage : OutboundWebSocketMessage<TaskResult>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="ScheduledTaskEndedMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTasksInfoMessage.cs

@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Scheduled tasks info message.
 /// </summary>
-public class ScheduledTasksInfoMessage : WebSocketMessage<IReadOnlyList<TaskInfo>>, IOutboundWebSocketMessage
+public class ScheduledTasksInfoMessage : OutboundWebSocketMessage<IReadOnlyList<TaskInfo>>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="ScheduledTasksInfoMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCancelledMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Series timer cancelled message.
 /// </summary>
-public class SeriesTimerCancelledMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage
+public class SeriesTimerCancelledMessage : OutboundWebSocketMessage<TimerEventInfo>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="SeriesTimerCancelledMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCreatedMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Series timer created message.
 /// </summary>
-public class SeriesTimerCreatedMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage
+public class SeriesTimerCreatedMessage : OutboundWebSocketMessage<TimerEventInfo>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="SeriesTimerCreatedMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerRestartingMessage.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Server restarting down message.
 /// </summary>
-public class ServerRestartingMessage : WebSocketMessage, IOutboundWebSocketMessage
+public class ServerRestartingMessage : OutboundWebSocketMessage
 {
     /// <inheritdoc />
     [DefaultValue(SessionMessageType.ServerRestarting)]

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerShuttingDownMessage.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Server shutting down message.
 /// </summary>
-public class ServerShuttingDownMessage : WebSocketMessage, IOutboundWebSocketMessage
+public class ServerShuttingDownMessage : OutboundWebSocketMessage
 {
     /// <inheritdoc />
     [DefaultValue(SessionMessageType.ServerShuttingDown)]

+ 3 - 2
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SessionsMessage.cs

@@ -1,3 +1,4 @@
+using System.Collections.Generic;
 using System.ComponentModel;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Session;
@@ -7,13 +8,13 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Sessions message.
 /// </summary>
-public class SessionsMessage : WebSocketMessage<SessionInfo>, IOutboundWebSocketMessage
+public class SessionsMessage : OutboundWebSocketMessage<IReadOnlyList<SessionInfo>>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="SessionsMessage"/> class.
     /// </summary>
     /// <param name="data">Session info.</param>
-    public SessionsMessage(SessionInfo data)
+    public SessionsMessage(IReadOnlyList<SessionInfo> data)
         : base(data)
     {
     }

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayCommandMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Sync play command.
 /// </summary>
-public class SyncPlayCommandMessage : WebSocketMessage<SendCommand>, IOutboundWebSocketMessage
+public class SyncPlayCommandMessage : OutboundWebSocketMessage<SendCommand>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="SyncPlayCommandMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Untyped sync play command.
 /// </summary>
-public class SyncPlayGroupUpdateCommandMessage : WebSocketMessage<GroupUpdate>, IOutboundWebSocketMessage
+public class SyncPlayGroupUpdateCommandMessage : OutboundWebSocketMessage<GroupUpdate>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupInfoMessage.cs

@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// Sync play group update command with group info.
 /// GroupUpdateTypes: GroupJoined.
 /// </summary>
-public class SyncPlayGroupUpdateCommandOfGroupInfoMessage : WebSocketMessage<GroupUpdate<GroupInfoDto>>, IOutboundWebSocketMessage
+public class SyncPlayGroupUpdateCommandOfGroupInfoMessage : OutboundWebSocketMessage<GroupUpdate<GroupInfoDto>>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfGroupInfoMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage.cs

@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// Sync play group update command with group state update.
 /// GroupUpdateTypes: StateUpdate.
 /// </summary>
-public class SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage : WebSocketMessage<GroupUpdate<GroupStateUpdate>>, IOutboundWebSocketMessage
+public class SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage : OutboundWebSocketMessage<GroupUpdate<GroupStateUpdate>>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage.cs

@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// Sync play group update command with play queue update.
 /// GroupUpdateTypes: PlayQueue.
 /// </summary>
-public class SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage : WebSocketMessage<GroupUpdate<PlayQueueUpdate>>, IOutboundWebSocketMessage
+public class SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage : OutboundWebSocketMessage<GroupUpdate<PlayQueueUpdate>>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfStringMessage.cs

@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// Sync play group update command with string.
 /// GroupUpdateTypes: GroupDoesNotExist (error), LibraryAccessDenied (error), NotInGroup (error), GroupLeft (groupId), UserJoined (username), UserLeft (username).
 /// </summary>
-public class SyncPlayGroupUpdateCommandOfStringMessage : WebSocketMessage<GroupUpdate<string>>, IOutboundWebSocketMessage
+public class SyncPlayGroupUpdateCommandOfStringMessage : OutboundWebSocketMessage<GroupUpdate<string>>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfStringMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCancelledMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Timer cancelled message.
 /// </summary>
-public class TimerCancelledMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage
+public class TimerCancelledMessage : OutboundWebSocketMessage<TimerEventInfo>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="TimerCancelledMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCreatedMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// Timer created message.
 /// </summary>
-public class TimerCreatedMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage
+public class TimerCreatedMessage : OutboundWebSocketMessage<TimerEventInfo>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="TimerCreatedMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDataChangedMessage.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// User data changed message.
 /// </summary>
-public class UserDataChangedMessage : WebSocketMessage<UserDataChangeInfo>, IOutboundWebSocketMessage
+public class UserDataChangedMessage : OutboundWebSocketMessage<UserDataChangeInfo>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="UserDataChangedMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDeletedMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// User deleted message.
 /// </summary>
-public class UserDeletedMessage : WebSocketMessage<Guid>, IOutboundWebSocketMessage
+public class UserDeletedMessage : OutboundWebSocketMessage<Guid>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="UserDeletedMessage"/> class.

+ 1 - 1
MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserUpdatedMessage.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
 /// <summary>
 /// User updated message.
 /// </summary>
-public class UserUpdatedMessage : WebSocketMessage<UserDto>, IOutboundWebSocketMessage
+public class UserUpdatedMessage : OutboundWebSocketMessage<UserDto>
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="UserUpdatedMessage"/> class.

+ 8 - 3
MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessage.cs

@@ -1,9 +1,14 @@
+using System;
+
 namespace MediaBrowser.Controller.Net.WebSocketMessages;
 
 /// <summary>
-/// Class representing the list of outbound websocket message types.
-/// Only used in openapi generation.
+/// Outbound websocket message.
 /// </summary>
-public class OutboundWebSocketMessage : WebSocketMessage
+public class OutboundWebSocketMessage : WebSocketMessage, IOutboundWebSocketMessage
 {
+    /// <summary>
+    /// Gets or sets the message id.
+    /// </summary>
+    public Guid MessageId { get; set; }
 }

+ 33 - 0
MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessageOfT.cs

@@ -0,0 +1,33 @@
+#pragma warning disable SA1649 // File name must equal class name.
+
+using System;
+
+namespace MediaBrowser.Controller.Net.WebSocketMessages;
+
+/// <summary>
+/// Outbound websocket message with data.
+/// </summary>
+/// <typeparam name="T">The data type.</typeparam>
+public class OutboundWebSocketMessage<T> : WebSocketMessage<T>, IOutboundWebSocketMessage
+{
+    /// <summary>
+    /// Initializes a new instance of the <see cref="OutboundWebSocketMessage{T}"/> class.
+    /// </summary>
+    public OutboundWebSocketMessage()
+    {
+    }
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="OutboundWebSocketMessage{T}"/> class.
+    /// </summary>
+    /// <param name="data">The data to send.</param>
+    protected OutboundWebSocketMessage(T data)
+    {
+        Data = data;
+    }
+
+    /// <summary>
+    /// Gets or sets the message id.
+    /// </summary>
+    public Guid MessageId { get; set; }
+}

+ 0 - 23
MediaBrowser.Controller/Net/WebSocketMessages/Shared/KeepAliveMessage.cs

@@ -1,23 +0,0 @@
-using System.ComponentModel;
-using MediaBrowser.Model.Session;
-
-namespace MediaBrowser.Controller.Net.WebSocketMessages.Shared;
-
-/// <summary>
-/// Keep alive websocket messages.
-/// </summary>
-public class KeepAliveMessage : WebSocketMessage<int>, IInboundWebSocketMessage, IOutboundWebSocketMessage
-{
-    /// <summary>
-    /// Initializes a new instance of the <see cref="KeepAliveMessage"/> class.
-    /// </summary>
-    /// <param name="data">The seconds to keep alive for.</param>
-    public KeepAliveMessage(int data)
-        : base(data)
-    {
-    }
-
-    /// <inheritdoc />
-    [DefaultValue(SessionMessageType.KeepAlive)]
-    public override SessionMessageType MessageType => SessionMessageType.KeepAlive;
-}