diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs index cad3c43849..b93b5326e6 100644 --- a/MediaBrowser.Api/SessionsService.cs +++ b/MediaBrowser.Api/SessionsService.cs @@ -325,49 +325,11 @@ namespace MediaBrowser.Api /// The request. public void Post(SendSystemCommand request) { - var task = SendSystemCommand(request); + var task = _sessionManager.SendSystemCommand(request.Id, request.Command, CancellationToken.None); Task.WaitAll(task); } - private async Task SendSystemCommand(SendSystemCommand request) - { - var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id); - - if (session == null) - { - throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id)); - } - - if (!session.SupportsRemoteControl) - { - throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id)); - } - - var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open); - - if (socket != null) - { - try - { - await socket.SendAsync(new WebSocketMessage - { - MessageType = "SystemCommand", - Data = request.Command.ToString() - - }, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.ErrorException("Error sending web socket message", ex); - } - } - else - { - throw new InvalidOperationException("The requested session does not have an open web socket."); - } - } - /// /// Posts the specified request. /// diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 80cf82da15..b5ad862bee 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -165,6 +165,7 @@ + diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index fba1d26e8b..f8f7ded2b7 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -1,7 +1,9 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Session; using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Controller.Session @@ -11,6 +13,12 @@ namespace MediaBrowser.Controller.Session /// public interface ISessionManager { + /// + /// Adds the parts. + /// + /// The remote controllers. + void AddParts(IEnumerable remoteControllers); + /// /// Occurs when [playback start]. /// @@ -72,5 +80,14 @@ namespace MediaBrowser.Controller.Session /// Task. /// Task OnPlaybackStopped(BaseItem item, long? positionTicks, Guid sessionId); + + /// + /// Sends the system command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + Task SendSystemCommand(Guid sessionId, SystemCommand command, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/Session/ISessionRemoteController.cs b/MediaBrowser.Controller/Session/ISessionRemoteController.cs new file mode 100644 index 0000000000..1f6faeb9c2 --- /dev/null +++ b/MediaBrowser.Controller/Session/ISessionRemoteController.cs @@ -0,0 +1,25 @@ +using MediaBrowser.Model.Session; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Session +{ + public interface ISessionRemoteController + { + /// + /// Supportses the specified session. + /// + /// The session. + /// true if XXXX, false otherwise + bool Supports(SessionInfo session); + + /// + /// Sends the system command. + /// + /// The session. + /// The command. + /// The cancellation token. + /// Task. + Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken); + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 9d2fc8c6b3..3c20217509 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -183,6 +183,7 @@ Code + diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 65ec02d128..5b0d957ae1 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Events; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -6,6 +7,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Session; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -75,6 +77,12 @@ namespace MediaBrowser.Server.Implementations.Session _userRepository = userRepository; } + private List _remoteControllers; + public void AddParts(IEnumerable remoteControllers) + { + _remoteControllers = remoteControllers.ToList(); + } + /// /// Gets all connections. /// @@ -122,7 +130,7 @@ namespace MediaBrowser.Server.Implementations.Session var activityDate = DateTime.UtcNow; var session = GetSessionInfo(clientType, appVersion, deviceId, deviceName, user); - + session.LastActivityDate = activityDate; if (user == null) @@ -233,7 +241,7 @@ namespace MediaBrowser.Server.Implementations.Session var key = item.GetUserDataKey(); var user = session.User; - + var data = _userDataRepository.GetUserData(user.Id, key); data.PlayCount++; @@ -321,7 +329,7 @@ namespace MediaBrowser.Server.Implementations.Session { throw new ArgumentOutOfRangeException("positionTicks"); } - + var session = Sessions.First(i => i.Id.Equals(sessionId)); RemoveNowPlayingItem(session, item); @@ -329,7 +337,7 @@ namespace MediaBrowser.Server.Implementations.Session var key = item.GetUserDataKey(); var user = session.User; - + var data = _userDataRepository.GetUserData(user.Id, key); if (positionTicks.HasValue) @@ -408,5 +416,54 @@ namespace MediaBrowser.Server.Implementations.Session data.PlaybackPositionTicks = positionTicks; } + + /// + /// Gets the session for remote control. + /// + /// The session id. + /// SessionInfo. + /// + private SessionInfo GetSessionForRemoteControl(Guid sessionId) + { + var session = Sessions.First(i => i.Id.Equals(sessionId)); + + if (session == null) + { + throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId)); + } + + if (!session.SupportsRemoteControl) + { + throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id)); + } + + return session; + } + + /// + /// Gets the controllers. + /// + /// The session. + /// IEnumerable{ISessionRemoteController}. + private IEnumerable GetControllers(SessionInfo session) + { + return _remoteControllers.Where(i => i.Supports(session)); + } + + /// + /// Sends the system command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + public Task SendSystemCommand(Guid sessionId, SystemCommand command, CancellationToken cancellationToken) + { + var session = GetSessionForRemoteControl(sessionId); + + var tasks = GetControllers(session).Select(i => i.SendSystemCommand(session, command, cancellationToken)); + + return Task.WhenAll(tasks); + } } } diff --git a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs new file mode 100644 index 0000000000..daa4c7d819 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs @@ -0,0 +1,52 @@ +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.Session; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Session +{ + public class WebSocketController : ISessionRemoteController + { + private readonly ILogger _logger; + + public WebSocketController(ILogger logger) + { + _logger = logger; + } + + public bool Supports(SessionInfo session) + { + return session.WebSockets.Any(i => i.State == WebSocketState.Open); + } + + public async Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken) + { + var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open); + + if (socket != null) + { + try + { + await socket.SendAsync(new WebSocketMessage + { + MessageType = "SystemCommand", + Data = command.ToString() + + }, cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error sending web socket message", ex); + } + } + else + { + throw new InvalidOperationException("The requested session does not have an open web socket."); + } + } + } +} diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 7a99693a67..e965166036 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -161,6 +161,7 @@ namespace MediaBrowser.ServerApplication private IMediaEncoder MediaEncoder { get; set; } private IIsoManager IsoManager { get; set; } + private ISessionManager SessionManager { get; set; } private ILocalizationManager LocalizationManager { get; set; } @@ -286,8 +287,8 @@ namespace MediaBrowser.ServerApplication RegisterSingleInstance(() => new LuceneSearchEngine(ApplicationPaths, LogManager, LibraryManager)); - var clientConnectionManager = new SessionManager(UserDataRepository, ServerConfigurationManager, Logger, UserRepository); - RegisterSingleInstance(clientConnectionManager); + SessionManager = new SessionManager(UserDataRepository, ServerConfigurationManager, Logger, UserRepository); + RegisterSingleInstance(SessionManager); HttpServer = await _httpServerCreationTask.ConfigureAwait(false); RegisterSingleInstance(HttpServer, false); @@ -477,6 +478,8 @@ namespace MediaBrowser.ServerApplication IsoManager.AddParts(GetExports()); + SessionManager.AddParts(GetExports()); + ImageProcessor.AddParts(GetExports()); }