소스 검색

support more kinds of remote control besides web socket

Luke Pulverenti 11 년 전
부모
커밋
c61cc4a304

+ 1 - 39
MediaBrowser.Api/SessionsService.cs

@@ -325,49 +325,11 @@ namespace MediaBrowser.Api
         /// <param name="request">The request.</param>
         /// <param name="request">The request.</param>
         public void Post(SendSystemCommand request)
         public void Post(SendSystemCommand request)
         {
         {
-            var task = SendSystemCommand(request);
+            var task = _sessionManager.SendSystemCommand(request.Id, request.Command, CancellationToken.None);
 
 
             Task.WaitAll(task);
             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<string>
-                    {
-                        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.");
-            }
-        }
-
         /// <summary>
         /// <summary>
         /// Posts the specified request.
         /// Posts the specified request.
         /// </summary>
         /// </summary>

+ 1 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -165,6 +165,7 @@
     <Compile Include="Kernel.cs" />
     <Compile Include="Kernel.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Providers\BaseMetadataProvider.cs" />
     <Compile Include="Providers\BaseMetadataProvider.cs" />
+    <Compile Include="Session\ISessionRemoteController.cs" />
     <Compile Include="Session\PlaybackInfo.cs" />
     <Compile Include="Session\PlaybackInfo.cs" />
     <Compile Include="Session\SessionInfo.cs" />
     <Compile Include="Session\SessionInfo.cs" />
     <Compile Include="Sorting\IBaseItemComparer.cs" />
     <Compile Include="Sorting\IBaseItemComparer.cs" />

+ 17 - 0
MediaBrowser.Controller/Session/ISessionManager.cs

@@ -1,7 +1,9 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Session;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
 namespace MediaBrowser.Controller.Session
 namespace MediaBrowser.Controller.Session
@@ -11,6 +13,12 @@ namespace MediaBrowser.Controller.Session
     /// </summary>
     /// </summary>
     public interface ISessionManager
     public interface ISessionManager
     {
     {
+        /// <summary>
+        /// Adds the parts.
+        /// </summary>
+        /// <param name="remoteControllers">The remote controllers.</param>
+        void AddParts(IEnumerable<ISessionRemoteController> remoteControllers);
+
         /// <summary>
         /// <summary>
         /// Occurs when [playback start].
         /// Occurs when [playback start].
         /// </summary>
         /// </summary>
@@ -72,5 +80,14 @@ namespace MediaBrowser.Controller.Session
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         /// <exception cref="System.ArgumentNullException"></exception>
         /// <exception cref="System.ArgumentNullException"></exception>
         Task OnPlaybackStopped(BaseItem item, long? positionTicks, Guid sessionId);
         Task OnPlaybackStopped(BaseItem item, long? positionTicks, Guid sessionId);
+
+        /// <summary>
+        /// Sends the system command.
+        /// </summary>
+        /// <param name="sessionId">The session id.</param>
+        /// <param name="command">The command.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        Task SendSystemCommand(Guid sessionId, SystemCommand command, CancellationToken cancellationToken);
     }
     }
 }
 }

+ 25 - 0
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
+    {
+        /// <summary>
+        /// Supportses the specified session.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
+        bool Supports(SessionInfo session);
+
+        /// <summary>
+        /// Sends the system command.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <param name="command">The command.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken);
+    }
+}

+ 1 - 0
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -183,6 +183,7 @@
       <SubType>Code</SubType>
       <SubType>Code</SubType>
     </Compile>
     </Compile>
     <Compile Include="Session\SessionWebSocketListener.cs" />
     <Compile Include="Session\SessionWebSocketListener.cs" />
+    <Compile Include="Session\WebSocketController.cs" />
     <Compile Include="Sorting\AlbumArtistComparer.cs" />
     <Compile Include="Sorting\AlbumArtistComparer.cs" />
     <Compile Include="Sorting\AlbumComparer.cs" />
     <Compile Include="Sorting\AlbumComparer.cs" />
     <Compile Include="Sorting\AlbumCountComparer.cs" />
     <Compile Include="Sorting\AlbumCountComparer.cs" />

+ 61 - 4
MediaBrowser.Server.Implementations/Session/SessionManager.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Audio;
@@ -6,6 +7,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Session;
 using System;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -75,6 +77,12 @@ namespace MediaBrowser.Server.Implementations.Session
             _userRepository = userRepository;
             _userRepository = userRepository;
         }
         }
 
 
+        private List<ISessionRemoteController> _remoteControllers;
+        public void AddParts(IEnumerable<ISessionRemoteController> remoteControllers)
+        {
+            _remoteControllers = remoteControllers.ToList();
+        }
+
         /// <summary>
         /// <summary>
         /// Gets all connections.
         /// Gets all connections.
         /// </summary>
         /// </summary>
@@ -122,7 +130,7 @@ namespace MediaBrowser.Server.Implementations.Session
             var activityDate = DateTime.UtcNow;
             var activityDate = DateTime.UtcNow;
 
 
             var session = GetSessionInfo(clientType, appVersion, deviceId, deviceName, user);
             var session = GetSessionInfo(clientType, appVersion, deviceId, deviceName, user);
-            
+
             session.LastActivityDate = activityDate;
             session.LastActivityDate = activityDate;
 
 
             if (user == null)
             if (user == null)
@@ -233,7 +241,7 @@ namespace MediaBrowser.Server.Implementations.Session
             var key = item.GetUserDataKey();
             var key = item.GetUserDataKey();
 
 
             var user = session.User;
             var user = session.User;
-            
+
             var data = _userDataRepository.GetUserData(user.Id, key);
             var data = _userDataRepository.GetUserData(user.Id, key);
 
 
             data.PlayCount++;
             data.PlayCount++;
@@ -321,7 +329,7 @@ namespace MediaBrowser.Server.Implementations.Session
             {
             {
                 throw new ArgumentOutOfRangeException("positionTicks");
                 throw new ArgumentOutOfRangeException("positionTicks");
             }
             }
-            
+
             var session = Sessions.First(i => i.Id.Equals(sessionId));
             var session = Sessions.First(i => i.Id.Equals(sessionId));
 
 
             RemoveNowPlayingItem(session, item);
             RemoveNowPlayingItem(session, item);
@@ -329,7 +337,7 @@ namespace MediaBrowser.Server.Implementations.Session
             var key = item.GetUserDataKey();
             var key = item.GetUserDataKey();
 
 
             var user = session.User;
             var user = session.User;
-            
+
             var data = _userDataRepository.GetUserData(user.Id, key);
             var data = _userDataRepository.GetUserData(user.Id, key);
 
 
             if (positionTicks.HasValue)
             if (positionTicks.HasValue)
@@ -408,5 +416,54 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
             data.PlaybackPositionTicks = positionTicks;
             data.PlaybackPositionTicks = positionTicks;
         }
         }
+
+        /// <summary>
+        /// Gets the session for remote control.
+        /// </summary>
+        /// <param name="sessionId">The session id.</param>
+        /// <returns>SessionInfo.</returns>
+        /// <exception cref="ResourceNotFoundException"></exception>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the controllers.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <returns>IEnumerable{ISessionRemoteController}.</returns>
+        private IEnumerable<ISessionRemoteController> GetControllers(SessionInfo session)
+        {
+            return _remoteControllers.Where(i => i.Supports(session));
+        }
+
+        /// <summary>
+        /// Sends the system command.
+        /// </summary>
+        /// <param name="sessionId">The session id.</param>
+        /// <param name="command">The command.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        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);
+        }
     }
     }
 }
 }

+ 52 - 0
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<string>
+                    {
+                        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.");
+            }
+        }
+    }
+}

+ 5 - 2
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -161,6 +161,7 @@ namespace MediaBrowser.ServerApplication
         private IMediaEncoder MediaEncoder { get; set; }
         private IMediaEncoder MediaEncoder { get; set; }
 
 
         private IIsoManager IsoManager { get; set; }
         private IIsoManager IsoManager { get; set; }
+        private ISessionManager SessionManager { get; set; }
 
 
         private ILocalizationManager LocalizationManager { get; set; }
         private ILocalizationManager LocalizationManager { get; set; }
 
 
@@ -286,8 +287,8 @@ namespace MediaBrowser.ServerApplication
 
 
             RegisterSingleInstance<ILibrarySearchEngine>(() => new LuceneSearchEngine(ApplicationPaths, LogManager, LibraryManager));
             RegisterSingleInstance<ILibrarySearchEngine>(() => new LuceneSearchEngine(ApplicationPaths, LogManager, LibraryManager));
 
 
-            var clientConnectionManager = new SessionManager(UserDataRepository, ServerConfigurationManager, Logger, UserRepository);
-            RegisterSingleInstance<ISessionManager>(clientConnectionManager);
+            SessionManager = new SessionManager(UserDataRepository, ServerConfigurationManager, Logger, UserRepository);
+            RegisterSingleInstance<ISessionManager>(SessionManager);
 
 
             HttpServer = await _httpServerCreationTask.ConfigureAwait(false);
             HttpServer = await _httpServerCreationTask.ConfigureAwait(false);
             RegisterSingleInstance(HttpServer, false);
             RegisterSingleInstance(HttpServer, false);
@@ -477,6 +478,8 @@ namespace MediaBrowser.ServerApplication
 
 
             IsoManager.AddParts(GetExports<IIsoMounter>());
             IsoManager.AddParts(GetExports<IIsoMounter>());
 
 
+            SessionManager.AddParts(GetExports<ISessionRemoteController>());
+            
             ImageProcessor.AddParts(GetExports<IImageEnhancer>());
             ImageProcessor.AddParts(GetExports<IImageEnhancer>());
         }
         }