2020-01-13 12:03:49 -07:00
#pragma warning disable CS1591
2019-01-13 12:54:44 -07:00
using System ;
2013-10-02 18:22:50 -07:00
using System.Collections.Generic ;
2013-09-24 08:42:30 -07:00
using System.Linq ;
2019-01-13 12:22:24 -07:00
using System.Net.WebSockets ;
2013-09-24 08:42:30 -07:00
using System.Threading ;
using System.Threading.Tasks ;
2019-01-13 12:22:24 -07:00
using MediaBrowser.Controller.Net ;
2023-06-29 04:44:36 -07:00
using MediaBrowser.Controller.Net.WebSocketMessages ;
2019-01-13 12:22:24 -07:00
using MediaBrowser.Controller.Session ;
2020-09-25 00:25:59 -07:00
using MediaBrowser.Model.Session ;
2019-01-13 12:22:24 -07:00
using Microsoft.Extensions.Logging ;
2013-09-24 08:42:30 -07:00
2016-11-03 16:35:19 -07:00
namespace Emby.Server.Implementations.Session
2013-09-24 08:42:30 -07:00
{
2022-07-24 09:35:46 -07:00
public sealed class WebSocketController : ISessionController , IAsyncDisposable , IDisposable
2013-09-24 08:42:30 -07:00
{
2020-06-05 17:15:56 -07:00
private readonly ILogger < WebSocketController > _logger ;
2014-05-17 11:37:40 -07:00
private readonly ISessionManager _sessionManager ;
2019-12-17 15:15:02 -07:00
private readonly SessionInfo _session ;
2014-05-17 11:37:40 -07:00
2020-05-01 16:30:04 -07:00
private readonly List < IWebSocketConnection > _sockets ;
2019-12-17 15:15:02 -07:00
private bool _disposed = false ;
public WebSocketController (
ILogger < WebSocketController > logger ,
SessionInfo session ,
ISessionManager sessionManager )
2013-09-24 08:42:30 -07:00
{
2014-05-16 21:24:10 -07:00
_logger = logger ;
2019-12-17 15:15:02 -07:00
_session = session ;
2014-05-17 11:37:40 -07:00
_sessionManager = sessionManager ;
2019-12-17 15:15:02 -07:00
_sockets = new List < IWebSocketConnection > ( ) ;
2013-09-24 08:42:30 -07:00
}
2019-01-06 13:50:43 -07:00
private bool HasOpenSockets = > GetActiveSockets ( ) . Any ( ) ;
2015-03-21 09:10:02 -07:00
2019-12-17 15:15:02 -07:00
/// <inheritdoc />
2019-01-06 13:50:43 -07:00
public bool SupportsMediaControl = > HasOpenSockets ;
2015-03-21 09:10:02 -07:00
2019-12-17 15:15:02 -07:00
/// <inheritdoc />
2019-01-06 13:50:43 -07:00
public bool IsSessionActive = > HasOpenSockets ;
2013-10-02 18:22:50 -07:00
2014-05-16 21:24:10 -07:00
private IEnumerable < IWebSocketConnection > GetActiveSockets ( )
2019-12-17 15:15:02 -07:00
= > _sockets . Where ( i = > i . State = = WebSocketState . Open ) ;
2014-05-16 21:24:10 -07:00
2014-05-17 11:37:40 -07:00
public void AddWebSocket ( IWebSocketConnection connection )
{
2019-12-17 15:15:02 -07:00
_logger . LogDebug ( "Adding websocket to session {Session}" , _session . Id ) ;
_sockets . Add ( connection ) ;
2014-05-17 11:37:40 -07:00
2019-12-17 15:15:02 -07:00
connection . Closed + = OnConnectionClosed ;
2014-05-17 11:37:40 -07:00
}
2022-05-29 07:49:50 -07:00
private async void OnConnectionClosed ( object? sender , EventArgs e )
2014-05-17 11:37:40 -07:00
{
2020-11-13 18:04:06 -07:00
var connection = sender as IWebSocketConnection ? ? throw new ArgumentException ( $"{nameof(sender)} is not of type {nameof(IWebSocketConnection)}" , nameof ( sender ) ) ;
2019-12-26 12:57:46 -07:00
_logger . LogDebug ( "Removing websocket from session {Session}" , _session . Id ) ;
2019-12-17 15:15:02 -07:00
_sockets . Remove ( connection ) ;
2019-12-26 12:57:46 -07:00
connection . Closed - = OnConnectionClosed ;
2022-05-29 07:49:50 -07:00
await _sessionManager . CloseIfNeededAsync ( _session ) . ConfigureAwait ( false ) ;
2014-05-17 11:37:40 -07:00
}
2019-12-17 15:15:02 -07:00
/// <inheritdoc />
public Task SendMessage < T > (
2020-09-25 00:25:59 -07:00
SessionMessageType name ,
2019-12-17 15:15:02 -07:00
Guid messageId ,
T data ,
CancellationToken cancellationToken )
2014-05-16 21:24:10 -07:00
{
2023-04-01 14:00:51 -07:00
var socket = GetActiveSockets ( ) . MaxBy ( i = > i . LastActivityDate ) ;
2013-09-24 12:54:42 -07:00
2022-12-05 07:00:20 -07:00
if ( socket is null )
2013-09-24 08:42:30 -07:00
{
2018-09-12 10:26:21 -07:00
return Task . CompletedTask ;
2013-09-24 08:42:30 -07:00
}
2013-09-24 12:54:42 -07:00
2020-01-13 12:03:49 -07:00
return socket . SendAsync (
2023-06-29 04:44:36 -07:00
new OutboundWebSocketMessage < T >
2020-01-13 12:03:49 -07:00
{
Data = data ,
MessageType = name ,
MessageId = messageId
} ,
cancellationToken ) ;
2015-01-12 20:46:44 -07:00
}
2019-12-17 15:15:02 -07:00
/// <inheritdoc />
2014-05-17 14:23:48 -07:00
public void Dispose ( )
{
2019-12-17 15:15:02 -07:00
if ( _disposed )
2014-05-17 14:23:48 -07:00
{
2019-12-17 15:15:02 -07:00
return ;
2014-05-17 14:23:48 -07:00
}
2019-12-17 15:15:02 -07:00
foreach ( var socket in _sockets )
{
socket . Closed - = OnConnectionClosed ;
2022-07-24 09:35:46 -07:00
socket . Dispose ( ) ;
}
_disposed = true ;
}
public async ValueTask DisposeAsync ( )
{
if ( _disposed )
{
return ;
}
foreach ( var socket in _sockets )
{
socket . Closed - = OnConnectionClosed ;
await socket . DisposeAsync ( ) . ConfigureAwait ( false ) ;
2019-12-17 15:15:02 -07:00
}
_disposed = true ;
2014-05-17 14:23:48 -07:00
}
2013-09-24 08:42:30 -07:00
}
}