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