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 Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Session { public sealed class WebSocketController : ISessionController, IDisposable { private readonly ILogger _logger; private readonly ISessionManager _sessionManager; private readonly SessionInfo _session; private 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 void OnConnectionClosed(object sender, EventArgs e) { _logger.LogDebug("Removing websocket from session {Session}", _session.Id); var connection = (IWebSocketConnection)sender; _sockets.Remove(connection); _sessionManager.CloseIfNeeded(_session); connection.Dispose(); } /// public Task SendMessage( string name, Guid messageId, T data, CancellationToken cancellationToken) { var socket = GetActiveSockets() .OrderByDescending(i => i.LastActivityDate) .FirstOrDefault(); if (socket == 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; } } }