diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index e27a8975b7..3d36a50454 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -889,6 +889,11 @@ namespace Emby.Dlna.PlayTo return Task.CompletedTask; } + public void CloseAllWebSockets(CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + private class StreamParams { private MediaSourceInfo _mediaSource; diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index b87f1bc226..2c5ec81ada 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -231,6 +231,15 @@ namespace Emby.Server.Implementations.HttpServer CancellationToken.None); } + /// + /// Gracefully closes the socket. + /// + /// The cancellation token. + public void CloseSocket(CancellationToken cancellationToken) + { + _socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "System Shutdown", cancellationToken); + } + /// public void Dispose() { diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index e2fa93a380..0d2d0e5176 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1363,9 +1363,26 @@ namespace Emby.Server.Implementations.Session { CheckDisposed(); + CloseAllWebSockets(cancellationToken); + return SendMessageToSessions(Sessions, SessionMessageType.ServerShuttingDown, string.Empty, cancellationToken); } + /// + /// Gracefully closes all web sockets in all sessions. + /// + /// The cancellation token. + private void CloseAllWebSockets(CancellationToken cancellationToken) + { + foreach (var session in Sessions) + { + foreach (var sessionController in session.SessionControllers) + { + sessionController.CloseAllWebSockets(cancellationToken); + } + } + } + /// /// Sends the server restart notification. /// diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs index 9fa92a53a1..16312ffb81 100644 --- a/Emby.Server.Implementations/Session/WebSocketController.cs +++ b/Emby.Server.Implementations/Session/WebSocketController.cs @@ -88,6 +88,18 @@ namespace Emby.Server.Implementations.Session cancellationToken); } + /// + /// Gracefully closes all web sockets. + /// + /// The cancellation token. + public void CloseAllWebSockets(CancellationToken cancellationToken) + { + foreach (var socket in _sockets) + { + socket.CloseSocket(cancellationToken); + } + } + /// public void Dispose() { diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index 2c6483ae28..c53199de6b 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -58,5 +58,11 @@ namespace MediaBrowser.Controller.Net Task SendAsync(WebSocketMessage message, CancellationToken cancellationToken); Task ProcessAsync(CancellationToken cancellationToken = default); + + /// + /// Gracefully closes the socket. + /// + /// The cancellation token. + void CloseSocket(CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Session/ISessionController.cs b/MediaBrowser.Controller/Session/ISessionController.cs index b38ee11462..3db79076da 100644 --- a/MediaBrowser.Controller/Session/ISessionController.cs +++ b/MediaBrowser.Controller/Session/ISessionController.cs @@ -33,5 +33,11 @@ namespace MediaBrowser.Controller.Session /// CancellationToken for operation. /// A task. Task SendMessage(SessionMessageType name, Guid messageId, T data, CancellationToken cancellationToken); + + /// + /// Gracefully closes all web sockets. + /// + /// The cancellation token. + void CloseAllWebSockets(CancellationToken cancellationToken); } }