diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index bfa23b9975..11cf5bb9d7 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -69,6 +69,8 @@ namespace MediaBrowser.Server.Implementations.Session private IEnumerable _sessionFactories = new List(); + private readonly SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1); + /// /// Initializes a new instance of the class. /// @@ -146,7 +148,7 @@ namespace MediaBrowser.Server.Implementations.Session var userId = user == null ? (Guid?)null : user.Id; var username = user == null ? null : user.Name; - var session = GetSessionInfo(clientType, appVersion, deviceId, deviceName, remoteEndPoint, userId, username); + var session = await GetSessionInfo(clientType, appVersion, deviceId, deviceName, remoteEndPoint, userId, username).ConfigureAwait(false); session.LastActivityDate = activityDate; @@ -171,6 +173,46 @@ namespace MediaBrowser.Server.Implementations.Session return session; } + public async Task ReportSessionEnded(Guid sessionId) + { + var session = GetSession(sessionId); + + if (session == null) + { + throw new ArgumentException("Session not found"); + } + + var key = GetSessionKey(session.Client, session.ApplicationVersion, session.DeviceId); + + await _sessionLock.WaitAsync(CancellationToken.None).ConfigureAwait(false); + + try + { + SessionInfo removed; + + if (_activeConnections.TryRemove(key, out removed)) + { + var disposable = removed.SessionController as IDisposable; + + if (disposable != null) + { + try + { + disposable.Dispose(); + } + catch (Exception ex) + { + _logger.ErrorException("Error disposing session controller", ex); + } + } + } + } + finally + { + _sessionLock.Release(); + } + } + /// /// Updates the now playing item id. /// @@ -207,6 +249,11 @@ namespace MediaBrowser.Server.Implementations.Session } } + private string GetSessionKey(string clientType, string appVersion, string deviceId) + { + return clientType + deviceId + appVersion; + } + /// /// Gets the connection. /// @@ -218,36 +265,45 @@ namespace MediaBrowser.Server.Implementations.Session /// The user identifier. /// The username. /// SessionInfo. - private SessionInfo GetSessionInfo(string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint, Guid? userId, string username) + private async Task GetSessionInfo(string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint, Guid? userId, string username) { - var key = clientType + deviceId + appVersion; + var key = GetSessionKey(clientType, appVersion, deviceId); - var connection = _activeConnections.GetOrAdd(key, keyName => new SessionInfo + await _sessionLock.WaitAsync(CancellationToken.None).ConfigureAwait(false); + + try { - Client = clientType, - DeviceId = deviceId, - ApplicationVersion = appVersion, - Id = Guid.NewGuid() - }); + var connection = _activeConnections.GetOrAdd(key, keyName => new SessionInfo + { + Client = clientType, + DeviceId = deviceId, + ApplicationVersion = appVersion, + Id = Guid.NewGuid() + }); - connection.DeviceName = deviceName; - connection.UserId = userId; - connection.UserName = username; - connection.RemoteEndPoint = remoteEndPoint; + connection.DeviceName = deviceName; + connection.UserId = userId; + connection.UserName = username; + connection.RemoteEndPoint = remoteEndPoint; - if (!userId.HasValue) - { - connection.AdditionalUsers.Clear(); + if (!userId.HasValue) + { + connection.AdditionalUsers.Clear(); + } + + if (connection.SessionController == null) + { + connection.SessionController = _sessionFactories + .Select(i => i.GetSessionController(connection)) + .FirstOrDefault(i => i != null); + } + + return connection; } - - if (connection.SessionController == null) + finally { - connection.SessionController = _sessionFactories - .Select(i => i.GetSessionController(connection)) - .FirstOrDefault(i => i != null); + _sessionLock.Release(); } - - return connection; } private List GetUsers(SessionInfo session)