diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations/Session')
| -rw-r--r-- | MediaBrowser.Server.Implementations/Session/SessionManager.cs | 164 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs | 78 |
2 files changed, 190 insertions, 52 deletions
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index a9488190c..5ea970426 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -202,7 +202,7 @@ namespace MediaBrowser.Server.Implementations.Session /// <summary> /// Logs the user activity. /// </summary> - /// <param name="clientType">Type of the client.</param> + /// <param name="appName">Type of the client.</param> /// <param name="appVersion">The app version.</param> /// <param name="deviceId">The device id.</param> /// <param name="deviceName">Name of the device.</param> @@ -211,16 +211,16 @@ namespace MediaBrowser.Server.Implementations.Session /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException">user</exception> /// <exception cref="System.UnauthorizedAccessException"></exception> - public async Task<SessionInfo> LogSessionActivity(string clientType, + public async Task<SessionInfo> LogSessionActivity(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user) { - if (string.IsNullOrEmpty(clientType)) + if (string.IsNullOrEmpty(appName)) { - throw new ArgumentNullException("clientType"); + throw new ArgumentNullException("appName"); } if (string.IsNullOrEmpty(appVersion)) { @@ -237,10 +237,7 @@ namespace MediaBrowser.Server.Implementations.Session var activityDate = DateTime.UtcNow; - var userId = user == null ? (Guid?)null : user.Id; - var username = user == null ? null : user.Name; - - var session = await GetSessionInfo(clientType, appVersion, deviceId, deviceName, remoteEndPoint, userId, username).ConfigureAwait(false); + var session = await GetSessionInfo(appName, appVersion, deviceId, deviceName, remoteEndPoint, user).ConfigureAwait(false); session.LastActivityDate = activityDate; @@ -281,7 +278,7 @@ namespace MediaBrowser.Server.Implementations.Session if (session != null) { - var key = GetSessionKey(session.Client, session.ApplicationVersion, session.DeviceId); + var key = GetSessionKey(session.Client, session.DeviceId); SessionInfo removed; @@ -317,7 +314,10 @@ namespace MediaBrowser.Server.Implementations.Session if (!string.Equals(info.ItemId, info.MediaSourceId) && !string.IsNullOrWhiteSpace(info.MediaSourceId)) { - runtimeTicks = _libraryManager.GetItemById(new Guid(info.MediaSourceId)).RunTimeTicks; + var runtimeItem = _libraryManager.GetItemById(new Guid(info.MediaSourceId)) ?? + _libraryManager.GetItemById(info.ItemId); + + runtimeTicks = runtimeItem.RunTimeTicks; } var current = session.NowPlayingItem; @@ -365,42 +365,44 @@ namespace MediaBrowser.Server.Implementations.Session } } - private string GetSessionKey(string clientType, string appVersion, string deviceId) + private string GetSessionKey(string appName, string deviceId) { - return clientType + deviceId; + return appName + deviceId; } /// <summary> /// Gets the connection. /// </summary> - /// <param name="clientType">Type of the client.</param> + /// <param name="appName">Type of the client.</param> /// <param name="appVersion">The app version.</param> /// <param name="deviceId">The device id.</param> /// <param name="deviceName">Name of the device.</param> /// <param name="remoteEndPoint">The remote end point.</param> - /// <param name="userId">The user identifier.</param> - /// <param name="username">The username.</param> + /// <param name="user">The user.</param> /// <returns>SessionInfo.</returns> - private async Task<SessionInfo> GetSessionInfo(string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint, Guid? userId, string username) + private async Task<SessionInfo> GetSessionInfo(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user) { - var key = GetSessionKey(clientType, appVersion, deviceId); + var key = GetSessionKey(appName, deviceId); await _sessionLock.WaitAsync(CancellationToken.None).ConfigureAwait(false); + var userId = user == null ? (Guid?)null : user.Id; + var username = user == null ? null : user.Name; + try { - SessionInfo connection; + SessionInfo sessionInfo; DeviceInfo device = null; - if (!_activeConnections.TryGetValue(key, out connection)) + if (!_activeConnections.TryGetValue(key, out sessionInfo)) { - var sessionInfo = new SessionInfo - { - Client = clientType, - DeviceId = deviceId, - ApplicationVersion = appVersion, - Id = Guid.NewGuid().ToString("N") - }; + sessionInfo = new SessionInfo + { + Client = appName, + DeviceId = deviceId, + ApplicationVersion = appVersion, + Id = key.GetMD5().ToString("N") + }; sessionInfo.DeviceName = deviceName; sessionInfo.UserId = userId; @@ -410,12 +412,11 @@ namespace MediaBrowser.Server.Implementations.Session OnSessionStarted(sessionInfo); _activeConnections.TryAdd(key, sessionInfo); - connection = sessionInfo; if (!string.IsNullOrEmpty(deviceId)) { var userIdString = userId.HasValue ? userId.Value.ToString("N") : null; - device = await _deviceManager.RegisterDevice(deviceId, deviceName, clientType, userIdString).ConfigureAwait(false); + device = await _deviceManager.RegisterDevice(deviceId, deviceName, appName, appVersion, userIdString).ConfigureAwait(false); } } @@ -426,24 +427,25 @@ namespace MediaBrowser.Server.Implementations.Session deviceName = device.CustomName; } - connection.DeviceName = deviceName; - connection.UserId = userId; - connection.UserName = username; - connection.RemoteEndPoint = remoteEndPoint; + sessionInfo.DeviceName = deviceName; + sessionInfo.UserId = userId; + sessionInfo.UserName = username; + sessionInfo.RemoteEndPoint = remoteEndPoint; + sessionInfo.ApplicationVersion = appVersion; if (!userId.HasValue) { - connection.AdditionalUsers.Clear(); + sessionInfo.AdditionalUsers.Clear(); } - if (connection.SessionController == null) + if (sessionInfo.SessionController == null) { - connection.SessionController = _sessionFactories - .Select(i => i.GetSessionController(connection)) + sessionInfo.SessionController = _sessionFactories + .Select(i => i.GetSessionController(sessionInfo)) .FirstOrDefault(i => i != null); } - return connection; + return sessionInfo; } finally { @@ -798,6 +800,19 @@ namespace MediaBrowser.Server.Implementations.Session return session; } + private SessionInfo GetSessionToRemoteControl(string sessionId) + { + // Accept either device id or session id + var session = Sessions.FirstOrDefault(i => string.Equals(i.Id, sessionId)); + + if (session == null) + { + throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId)); + } + + return session; + } + public Task SendMessageCommand(string controllingSessionId, string sessionId, MessageCommand command, CancellationToken cancellationToken) { var generalCommand = new GeneralCommand @@ -818,7 +833,7 @@ namespace MediaBrowser.Server.Implementations.Session public Task SendGeneralCommand(string controllingSessionId, string sessionId, GeneralCommand command, CancellationToken cancellationToken) { - var session = GetSession(sessionId); + var session = GetSessionToRemoteControl(sessionId); var controllingSession = GetSession(controllingSessionId); AssertCanControl(session, controllingSession); @@ -828,7 +843,7 @@ namespace MediaBrowser.Server.Implementations.Session public Task SendPlayCommand(string controllingSessionId, string sessionId, PlayRequest command, CancellationToken cancellationToken) { - var session = GetSession(sessionId); + var session = GetSessionToRemoteControl(sessionId); var user = session.UserId.HasValue ? _userManager.GetUserById(session.UserId.Value) : null; @@ -907,7 +922,7 @@ namespace MediaBrowser.Server.Implementations.Session return FilterToSingleMediaType(items) .OrderBy(i => i.SortName); } - + if (item.IsFolder) { var folder = (Folder)item; @@ -955,7 +970,7 @@ namespace MediaBrowser.Server.Implementations.Session public Task SendPlaystateCommand(string controllingSessionId, string sessionId, PlaystateRequest command, CancellationToken cancellationToken) { - var session = GetSession(sessionId); + var session = GetSessionToRemoteControl(sessionId); var controllingSession = GetSession(controllingSessionId); AssertCanControl(session, controllingSession); @@ -1327,8 +1342,7 @@ namespace MediaBrowser.Server.Implementations.Session ClientCapabilities capabilities, bool saveCapabilities) { - session.PlayableMediaTypes = capabilities.PlayableMediaTypes; - session.SupportedCommands = capabilities.SupportedCommands; + session.Capabilities = capabilities; if (!string.IsNullOrWhiteSpace(capabilities.MessageCallbackUrl)) { @@ -1567,11 +1581,7 @@ namespace MediaBrowser.Server.Implementations.Session if (!string.IsNullOrWhiteSpace(mediaSourceId)) { - info.MediaStreams = _mediaSourceManager.GetMediaStreams(new MediaStreamQuery - { - ItemId = new Guid(mediaSourceId) - - }).ToList(); + info.MediaStreams = _mediaSourceManager.GetMediaStreams(mediaSourceId).ToList(); } return info; @@ -1632,6 +1642,64 @@ namespace MediaBrowser.Server.Implementations.Session string.Equals(i.Client, client)); } + public Task<SessionInfo> GetSessionByAuthenticationToken(AuthenticationInfo info, string deviceId, string remoteEndpoint, string appVersion) + { + if (info == null) + { + throw new ArgumentNullException("info"); + } + + var user = string.IsNullOrWhiteSpace(info.UserId) + ? null + : _userManager.GetUserById(info.UserId); + + appVersion = string.IsNullOrWhiteSpace(appVersion) + ? info.AppVersion + : appVersion; + + var deviceName = info.DeviceName; + var appName = info.AppName; + + if (!string.IsNullOrWhiteSpace(deviceId)) + { + // Replace the info from the token with more recent info + var device = _deviceManager.GetDevice(deviceId); + if (device != null) + { + deviceName = device.Name; + appName = device.AppName; + + if (!string.IsNullOrWhiteSpace(device.AppVersion)) + { + appVersion = device.AppVersion; + } + } + } + else + { + deviceId = info.DeviceId; + } + + return GetSessionInfo(appName, appVersion, deviceId, deviceName, remoteEndpoint, user); + } + + public Task<SessionInfo> GetSessionByAuthenticationToken(string token, string deviceId, string remoteEndpoint) + { + var result = _authRepo.Get(new AuthenticationInfoQuery + { + AccessToken = token + }); + + var info = result.Items.FirstOrDefault(); + + if (info == null) + { + return Task.FromResult<SessionInfo>(null); + } + + return GetSessionByAuthenticationToken(info, deviceId, remoteEndpoint, null); + } + public Task SendMessageToUserSessions<T>(string userId, string name, T data, CancellationToken cancellationToken) { diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs index 36a7fcbd8..b8cab0c19 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs @@ -1,10 +1,11 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Session; using System; +using System.Collections.Specialized; using System.Globalization; using System.Linq; using System.Threading.Tasks; @@ -14,7 +15,7 @@ namespace MediaBrowser.Server.Implementations.Session /// <summary> /// Class SessionWebSocketListener /// </summary> - public class SessionWebSocketListener : IWebSocketListener + public class SessionWebSocketListener : IWebSocketListener, IDisposable { /// <summary> /// The _true task result @@ -36,17 +37,86 @@ namespace MediaBrowser.Server.Implementations.Session /// </summary> private readonly IJsonSerializer _json; + private readonly IHttpServer _httpServer; + private readonly IServerManager _serverManager; + + /// <summary> /// Initializes a new instance of the <see cref="SessionWebSocketListener" /> class. /// </summary> /// <param name="sessionManager">The session manager.</param> /// <param name="logManager">The log manager.</param> /// <param name="json">The json.</param> - public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IJsonSerializer json) + /// <param name="httpServer">The HTTP server.</param> + /// <param name="serverManager">The server manager.</param> + public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IJsonSerializer json, IHttpServer httpServer, IServerManager serverManager) { _sessionManager = sessionManager; _logger = logManager.GetLogger(GetType().Name); _json = json; + _httpServer = httpServer; + _serverManager = serverManager; + httpServer.WebSocketConnecting += _httpServer_WebSocketConnecting; + serverManager.WebSocketConnected += _serverManager_WebSocketConnected; + } + + async void _serverManager_WebSocketConnected(object sender, GenericEventArgs<IWebSocketConnection> e) + { + var session = await GetSession(e.Argument.QueryString, e.Argument.RemoteEndPoint).ConfigureAwait(false); + + if (session != null) + { + var controller = session.SessionController as WebSocketController; + + if (controller == null) + { + controller = new WebSocketController(session, _logger, _sessionManager); + } + + controller.AddWebSocket(e.Argument); + + session.SessionController = controller; + } + else + { + _logger.Warn("Unable to determine session based on url: {0}", e.Argument.Url); + } + } + + async void _httpServer_WebSocketConnecting(object sender, WebSocketConnectingEventArgs e) + { + var token = e.QueryString["api_key"]; + if (!string.IsNullOrWhiteSpace(token)) + { + var session = await GetSession(e.QueryString, e.Endpoint).ConfigureAwait(false); + + if (session == null) + { + e.AllowConnection = false; + } + } + } + + private Task<SessionInfo> GetSession(NameValueCollection queryString, string remoteEndpoint) + { + if (queryString == null) + { + throw new ArgumentNullException("queryString"); + } + + var token = queryString["api_key"]; + if (string.IsNullOrWhiteSpace(token)) + { + return Task.FromResult<SessionInfo>(null); + } + var deviceId = queryString["deviceId"]; + return _sessionManager.GetSessionByAuthenticationToken(token, deviceId, remoteEndpoint); + } + + public void Dispose() + { + _httpServer.WebSocketConnecting -= _httpServer_WebSocketConnecting; + _serverManager.WebSocketConnected -= _serverManager_WebSocketConnected; } /// <summary> |
