aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations/Session
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Server.Implementations/Session')
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs164
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs78
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>