From d5ea8ca3ad378fc7e0a18ad314e1dfce07003ab6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 3 Nov 2016 19:35:19 -0400 Subject: move classes to portable --- .../Session/WebSocketController.cs | 288 +++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 Emby.Server.Implementations/Session/WebSocketController.cs (limited to 'Emby.Server.Implementations/Session/WebSocketController.cs') diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs new file mode 100644 index 000000000..f0ff0b5dd --- /dev/null +++ b/Emby.Server.Implementations/Session/WebSocketController.cs @@ -0,0 +1,288 @@ +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.Session; +using MediaBrowser.Model.System; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Emby.Server.Implementations.Session +{ + public class WebSocketController : ISessionController, IDisposable + { + public SessionInfo Session { get; private set; } + public IReadOnlyList Sockets { get; private set; } + + private readonly ILogger _logger; + + private readonly ISessionManager _sessionManager; + + public WebSocketController(SessionInfo session, ILogger logger, ISessionManager sessionManager) + { + Session = session; + _logger = logger; + _sessionManager = sessionManager; + Sockets = new List(); + } + + private bool HasOpenSockets + { + get { return GetActiveSockets().Any(); } + } + + public bool SupportsMediaControl + { + get { return HasOpenSockets; } + } + + private bool _isActive; + private DateTime _lastActivityDate; + public bool IsSessionActive + { + get + { + if (HasOpenSockets) + { + return true; + } + + //return false; + return _isActive && (DateTime.UtcNow - _lastActivityDate).TotalMinutes <= 10; + } + } + + public void OnActivity() + { + _isActive = true; + _lastActivityDate = DateTime.UtcNow; + } + + private IEnumerable GetActiveSockets() + { + return Sockets + .OrderByDescending(i => i.LastActivityDate) + .Where(i => i.State == WebSocketState.Open); + } + + public void AddWebSocket(IWebSocketConnection connection) + { + var sockets = Sockets.ToList(); + sockets.Add(connection); + + Sockets = sockets; + + connection.Closed += connection_Closed; + } + + void connection_Closed(object sender, EventArgs e) + { + if (!GetActiveSockets().Any()) + { + _isActive = false; + + try + { + _sessionManager.ReportSessionEnded(Session.Id); + } + catch (Exception ex) + { + _logger.ErrorException("Error reporting session ended.", ex); + } + } + } + + private IWebSocketConnection GetActiveSocket() + { + var socket = GetActiveSockets() + .FirstOrDefault(); + + if (socket == null) + { + throw new InvalidOperationException("The requested session does not have an open web socket."); + } + + return socket; + } + + public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken) + { + return SendMessageInternal(new WebSocketMessage + { + MessageType = "Play", + Data = command + + }, cancellationToken); + } + + public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken) + { + return SendMessageInternal(new WebSocketMessage + { + MessageType = "Playstate", + Data = command + + }, cancellationToken); + } + + public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken) + { + return SendMessagesInternal(new WebSocketMessage + { + MessageType = "LibraryChanged", + Data = info + + }, cancellationToken); + } + + /// + /// Sends the restart required message. + /// + /// The information. + /// The cancellation token. + /// Task. + public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken) + { + return SendMessagesInternal(new WebSocketMessage + { + MessageType = "RestartRequired", + Data = info + + }, cancellationToken); + } + + + /// + /// Sends the user data change info. + /// + /// The info. + /// The cancellation token. + /// Task. + public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken) + { + return SendMessagesInternal(new WebSocketMessage + { + MessageType = "UserDataChanged", + Data = info + + }, cancellationToken); + } + + /// + /// Sends the server shutdown notification. + /// + /// The cancellation token. + /// Task. + public Task SendServerShutdownNotification(CancellationToken cancellationToken) + { + return SendMessagesInternal(new WebSocketMessage + { + MessageType = "ServerShuttingDown", + Data = string.Empty + + }, cancellationToken); + } + + /// + /// Sends the server restart notification. + /// + /// The cancellation token. + /// Task. + public Task SendServerRestartNotification(CancellationToken cancellationToken) + { + return SendMessagesInternal(new WebSocketMessage + { + MessageType = "ServerRestarting", + Data = string.Empty + + }, cancellationToken); + } + + public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken) + { + return SendMessageInternal(new WebSocketMessage + { + MessageType = "GeneralCommand", + Data = command + + }, cancellationToken); + } + + public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken) + { + return SendMessagesInternal(new WebSocketMessage + { + MessageType = "SessionEnded", + Data = sessionInfo + + }, cancellationToken); + } + + public Task SendPlaybackStartNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken) + { + return SendMessagesInternal(new WebSocketMessage + { + MessageType = "PlaybackStart", + Data = sessionInfo + + }, cancellationToken); + } + + public Task SendPlaybackStoppedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken) + { + return SendMessagesInternal(new WebSocketMessage + { + MessageType = "PlaybackStopped", + Data = sessionInfo + + }, cancellationToken); + } + + public Task SendMessage(string name, T data, CancellationToken cancellationToken) + { + return SendMessagesInternal(new WebSocketMessage + { + Data = data, + MessageType = name + + }, cancellationToken); + } + + private Task SendMessageInternal(WebSocketMessage message, CancellationToken cancellationToken) + { + var socket = GetActiveSocket(); + + return socket.SendAsync(message, cancellationToken); + } + + private Task SendMessagesInternal(WebSocketMessage message, CancellationToken cancellationToken) + { + var tasks = GetActiveSockets().Select(i => Task.Run(async () => + { + try + { + await i.SendAsync(message, cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error sending web socket message", ex); + } + + }, cancellationToken)); + + return Task.WhenAll(tasks); + } + + public void Dispose() + { + foreach (var socket in Sockets.ToList()) + { + socket.Closed -= connection_Closed; + } + } + } +} -- cgit v1.2.3