#pragma warning disable CS1591 using System; using System.Collections.Generic; using System.Linq; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Net; using MediaBrowser.Model.Session; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Session { public sealed class WebSocketController : ISessionController, IAsyncDisposable, IDisposable { private readonly ILogger _logger; private readonly ISessionManager _sessionManager; private readonly SessionInfo _session; private readonly List _sockets; private bool _disposed = false; public WebSocketController( ILogger logger, SessionInfo session, ISessionManager sessionManager) { _logger = logger; _session = session; _sessionManager = sessionManager; _sockets = new List(); } private bool HasOpenSockets => GetActiveSockets().Any(); /// public bool SupportsMediaControl => HasOpenSockets; /// public bool IsSessionActive => HasOpenSockets; private IEnumerable GetActiveSockets() => _sockets.Where(i => i.State == WebSocketState.Open); public void AddWebSocket(IWebSocketConnection connection) { _logger.LogDebug("Adding websocket to session {Session}", _session.Id); _sockets.Add(connection); connection.Closed += OnConnectionClosed; } private async void OnConnectionClosed(object? sender, EventArgs e) { var connection = sender as IWebSocketConnection ?? throw new ArgumentException($"{nameof(sender)} is not of type {nameof(IWebSocketConnection)}", nameof(sender)); _logger.LogDebug("Removing websocket from session {Session}", _session.Id); _sockets.Remove(connection); connection.Closed -= OnConnectionClosed; await _sessionManager.CloseIfNeededAsync(_session).ConfigureAwait(false); } /// public Task SendMessage( SessionMessageType name, Guid messageId, T data, CancellationToken cancellationToken) { var socket = GetActiveSockets() .OrderByDescending(i => i.LastActivityDate) .FirstOrDefault(); if (socket is null) { return Task.CompletedTask; } return socket.SendAsync( new WebSocketMessage { Data = data, MessageType = name, MessageId = messageId }, cancellationToken); } /// public void Dispose() { if (_disposed) { return; } foreach (var socket in _sockets) { socket.Closed -= OnConnectionClosed; socket.Dispose(); } _disposed = true; } public async ValueTask DisposeAsync() { if (_disposed) { return; } foreach (var socket in _sockets) { socket.Closed -= OnConnectionClosed; await socket.DisposeAsync().ConfigureAwait(false); } _disposed = true; } } }