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/HttpSessionController.cs90
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs34
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs10
-rw-r--r--MediaBrowser.Server.Implementations/Session/WebSocketController.cs136
4 files changed, 177 insertions, 93 deletions
diff --git a/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs b/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs
index 8d6289217..0b0f21e2c 100644
--- a/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs
+++ b/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs
@@ -1,5 +1,8 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
+using System.Net;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Net;
@@ -16,23 +19,18 @@ namespace MediaBrowser.Server.Implementations.Session
{
private readonly IHttpClient _httpClient;
private readonly IJsonSerializer _json;
- private readonly IServerApplicationHost _appHost;
public SessionInfo Session { get; private set; }
- //var postUrl = string.Format("http://{0}/mediabrowser/message", session.RemoteEndPoint);
-
private readonly string _postUrl;
- public HttpSessionController(IHttpClient httpClient,
- IJsonSerializer json,
- IServerApplicationHost appHost,
- SessionInfo session,
+ public HttpSessionController(IHttpClient httpClient,
+ IJsonSerializer json,
+ SessionInfo session,
string postUrl)
{
_httpClient = httpClient;
_json = json;
- _appHost = appHost;
Session = session;
_postUrl = postUrl;
}
@@ -45,6 +43,11 @@ namespace MediaBrowser.Server.Implementations.Session
}
}
+ public bool SupportsMediaControl
+ {
+ get { return true; }
+ }
+
private Task SendMessage(object obj, CancellationToken cancellationToken)
{
var json = _json.SerializeToString(obj);
@@ -58,6 +61,21 @@ namespace MediaBrowser.Server.Implementations.Session
});
}
+ private Task SendMessage(string name, CancellationToken cancellationToken)
+ {
+ return SendMessage(name, new NameValueCollection(), cancellationToken);
+ }
+
+ private Task SendMessage(string name, NameValueCollection args, CancellationToken cancellationToken)
+ {
+ return SendMessage(new WebSocketMessage<string>
+ {
+ MessageType = name,
+ Data = string.Empty
+
+ }, cancellationToken);
+ }
+
public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
{
return Task.FromResult(true);
@@ -75,22 +93,25 @@ namespace MediaBrowser.Server.Implementations.Session
public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
{
- return SendMessage(new WebSocketMessage<PlayRequest>
- {
- MessageType = "Play",
- Data = command
+ return Task.FromResult(true);
+ //return SendMessage(new WebSocketMessage<PlayRequest>
+ //{
+ // MessageType = "Play",
+ // Data = command
- }, cancellationToken);
+ //}, cancellationToken);
}
public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
{
- return SendMessage(new WebSocketMessage<PlaystateRequest>
+ var args = new Dictionary<string, string>();
+
+ if (command.Command == PlaystateCommand.Seek)
{
- MessageType = "Playstate",
- Data = command
- }, cancellationToken);
+ }
+
+ return SendMessage(command.Command.ToString(), cancellationToken);
}
public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken)
@@ -98,14 +119,9 @@ namespace MediaBrowser.Server.Implementations.Session
return Task.FromResult(true);
}
- public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
+ public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
{
- return SendMessage(new WebSocketMessage<SystemInfo>
- {
- MessageType = "RestartRequired",
- Data = _appHost.GetSystemInfo()
-
- }, cancellationToken);
+ return SendMessage("RestartRequired", cancellationToken);
}
public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken)
@@ -115,22 +131,12 @@ namespace MediaBrowser.Server.Implementations.Session
public Task SendServerShutdownNotification(CancellationToken cancellationToken)
{
- return SendMessage(new WebSocketMessage<string>
- {
- MessageType = "ServerShuttingDown",
- Data = string.Empty
-
- }, cancellationToken);
+ return SendMessage("ServerShuttingDown", cancellationToken);
}
public Task SendServerRestartNotification(CancellationToken cancellationToken)
{
- return SendMessage(new WebSocketMessage<string>
- {
- MessageType = "ServerRestarting",
- Data = string.Empty
-
- }, cancellationToken);
+ return SendMessage("ServerRestarting", cancellationToken);
}
public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
@@ -142,5 +148,13 @@ namespace MediaBrowser.Server.Implementations.Session
}, cancellationToken);
}
+
+ private string ToQueryString(Dictionary<string, string> nvc)
+ {
+ var array = (from item in nvc
+ select string.Format("{0}={1}", WebUtility.UrlEncode(item.Key), WebUtility.UrlEncode(item.Value)))
+ .ToArray();
+ return "?" + string.Join("&", array);
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 26e451a81..d78fae87b 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -1,6 +1,7 @@
-using System.Globalization;
-using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
@@ -14,10 +15,12 @@ using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Session;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -51,6 +54,10 @@ namespace MediaBrowser.Server.Implementations.Session
private readonly IImageProcessor _imageProcessor;
private readonly IItemRepository _itemRepo;
+ private readonly IHttpClient _httpClient;
+ private readonly IJsonSerializer _jsonSerializer;
+ private readonly IServerApplicationHost _appHost;
+
/// <summary>
/// Gets or sets the configuration manager.
/// </summary>
@@ -93,7 +100,7 @@ namespace MediaBrowser.Server.Implementations.Session
/// <param name="logger">The logger.</param>
/// <param name="userRepository">The user repository.</param>
/// <param name="libraryManager">The library manager.</param>
- public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo)
+ public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient)
{
_userDataRepository = userDataRepository;
_configurationManager = configurationManager;
@@ -105,6 +112,9 @@ namespace MediaBrowser.Server.Implementations.Session
_dtoService = dtoService;
_imageProcessor = imageProcessor;
_itemRepo = itemRepo;
+ _jsonSerializer = jsonSerializer;
+ _appHost = appHost;
+ _httpClient = httpClient;
}
/// <summary>
@@ -908,11 +918,13 @@ namespace MediaBrowser.Server.Implementations.Session
{
var sessions = Sessions.Where(i => i.IsActive && i.SessionController != null).ToList();
+ var info = _appHost.GetSystemInfo();
+
var tasks = sessions.Select(session => Task.Run(async () =>
{
try
{
- await session.SessionController.SendRestartRequiredNotification(cancellationToken).ConfigureAwait(false);
+ await session.SessionController.SendRestartRequiredNotification(info, cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -1135,6 +1147,18 @@ namespace MediaBrowser.Server.Implementations.Session
session.PlayableMediaTypes = capabilities.PlayableMediaTypes;
session.SupportedCommands = capabilities.SupportedCommands;
+ if (!string.IsNullOrWhiteSpace(capabilities.MessageCallbackUrl))
+ {
+ var postUrl = string.Format("http://{0}{1}", session.RemoteEndPoint, capabilities.MessageCallbackUrl);
+
+ var controller = session.SessionController as HttpSessionController;
+
+ if (controller == null)
+ {
+ session.SessionController = new HttpSessionController(_httpClient, _jsonSerializer, session, postUrl);
+ }
+ }
+
EventHelper.FireEventIfNotNull(CapabilitiesChanged, this, new SessionEventArgs
{
SessionInfo = session
@@ -1164,7 +1188,7 @@ namespace MediaBrowser.Server.Implementations.Session
SupportedCommands = session.SupportedCommands,
UserName = session.UserName,
NowPlayingItem = session.NowPlayingItem,
-
+ SupportsRemoteControl = session.SupportsMediaControl,
PlayState = session.PlayState
};
diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
index fd10c0389..365845f41 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
@@ -35,19 +35,17 @@ namespace MediaBrowser.Server.Implementations.Session
/// The _dto service
/// </summary>
private readonly IJsonSerializer _json;
- private readonly IServerApplicationHost _appHost;
/// <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="appHost">The application host.</param>
- public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IServerApplicationHost appHost, IJsonSerializer json)
+ /// <param name="json">The json.</param>
+ public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IJsonSerializer json)
{
_sessionManager = sessionManager;
_logger = logManager.GetLogger(GetType().Name);
- _appHost = appHost;
_json = json;
}
@@ -138,10 +136,10 @@ namespace MediaBrowser.Server.Implementations.Session
if (controller == null)
{
- controller = new WebSocketController(session, _appHost);
+ controller = new WebSocketController(session, _logger, _sessionManager);
}
- controller.Sockets.Add(message.Connection);
+ controller.AddWebSocket(message.Connection);
session.SessionController = controller;
}
diff --git a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
index 0edd57d2a..5fc28e81b 100644
--- a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
+++ b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs
@@ -1,7 +1,7 @@
using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
using MediaBrowser.Model.System;
@@ -13,17 +13,20 @@ using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.Session
{
- public class WebSocketController : ISessionController
+ public class WebSocketController : ISessionController, IDisposable
{
public SessionInfo Session { get; private set; }
- public List<IWebSocketConnection> Sockets { get; private set; }
+ public IReadOnlyList<IWebSocketConnection> Sockets { get; private set; }
- private readonly IServerApplicationHost _appHost;
+ private readonly ILogger _logger;
- public WebSocketController(SessionInfo session, IServerApplicationHost appHost)
+ private readonly ISessionManager _sessionManager;
+
+ public WebSocketController(SessionInfo session, ILogger logger, ISessionManager sessionManager)
{
Session = session;
- _appHost = appHost;
+ _logger = logger;
+ _sessionManager = sessionManager;
Sockets = new List<IWebSocketConnection>();
}
@@ -35,11 +38,44 @@ namespace MediaBrowser.Server.Implementations.Session
}
}
- private IWebSocketConnection GetActiveSocket()
+ public bool SupportsMediaControl
{
- var socket = Sockets
+ get { return GetActiveSockets().Any(); }
+ }
+
+ private IEnumerable<IWebSocketConnection> GetActiveSockets()
+ {
+ return Sockets
.OrderByDescending(i => i.LastActivityDate)
- .FirstOrDefault(i => i.State == WebSocketState.Open);
+ .Where(i => i.State == WebSocketState.Open);
+ }
+
+ public void AddWebSocket(IWebSocketConnection connection)
+ {
+ var sockets = Sockets.ToList();
+ sockets.Add(connection);
+
+ Sockets = sockets;
+
+ connection.Closed += connection_Closed;
+ }
+
+ void connection_Closed(object sender, EventArgs e)
+ {
+ var capabilities = new SessionCapabilities
+ {
+ PlayableMediaTypes = Session.PlayableMediaTypes,
+ SupportedCommands = Session.SupportedCommands,
+ SupportsMediaControl = SupportsMediaControl
+ };
+
+ _sessionManager.ReportCapabilities(Session.Id, capabilities);
+ }
+
+ private IWebSocketConnection GetActiveSocket()
+ {
+ var socket = GetActiveSockets()
+ .FirstOrDefault();
if (socket == null)
{
@@ -51,9 +87,7 @@ namespace MediaBrowser.Server.Implementations.Session
public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
{
- var socket = GetActiveSocket();
-
- return socket.SendAsync(new WebSocketMessage<PlayRequest>
+ return SendMessage(new WebSocketMessage<PlayRequest>
{
MessageType = "Play",
Data = command
@@ -63,9 +97,7 @@ namespace MediaBrowser.Server.Implementations.Session
public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
{
- var socket = GetActiveSocket();
-
- return socket.SendAsync(new WebSocketMessage<PlaystateRequest>
+ return SendMessage(new WebSocketMessage<PlaystateRequest>
{
MessageType = "Playstate",
Data = command
@@ -75,9 +107,7 @@ namespace MediaBrowser.Server.Implementations.Session
public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken)
{
- var socket = GetActiveSocket();
-
- return socket.SendAsync(new WebSocketMessage<LibraryUpdateInfo>
+ return SendMessages(new WebSocketMessage<LibraryUpdateInfo>
{
MessageType = "LibraryChanged",
Data = info
@@ -88,16 +118,15 @@ namespace MediaBrowser.Server.Implementations.Session
/// <summary>
/// Sends the restart required message.
/// </summary>
+ /// <param name="info">The information.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
+ public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
{
- var socket = GetActiveSocket();
-
- return socket.SendAsync(new WebSocketMessage<SystemInfo>
+ return SendMessages(new WebSocketMessage<SystemInfo>
{
MessageType = "RestartRequired",
- Data = _appHost.GetSystemInfo()
+ Data = info
}, cancellationToken);
}
@@ -111,9 +140,7 @@ namespace MediaBrowser.Server.Implementations.Session
/// <returns>Task.</returns>
public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken)
{
- var socket = GetActiveSocket();
-
- return socket.SendAsync(new WebSocketMessage<UserDataChangeInfo>
+ return SendMessages(new WebSocketMessage<UserDataChangeInfo>
{
MessageType = "UserDataChanged",
Data = info
@@ -128,9 +155,7 @@ namespace MediaBrowser.Server.Implementations.Session
/// <returns>Task.</returns>
public Task SendServerShutdownNotification(CancellationToken cancellationToken)
{
- var socket = GetActiveSocket();
-
- return socket.SendAsync(new WebSocketMessage<string>
+ return SendMessages(new WebSocketMessage<string>
{
MessageType = "ServerShuttingDown",
Data = string.Empty
@@ -145,9 +170,7 @@ namespace MediaBrowser.Server.Implementations.Session
/// <returns>Task.</returns>
public Task SendServerRestartNotification(CancellationToken cancellationToken)
{
- var socket = GetActiveSocket();
-
- return socket.SendAsync(new WebSocketMessage<string>
+ return SendMessages(new WebSocketMessage<string>
{
MessageType = "ServerRestarting",
Data = string.Empty
@@ -157,9 +180,7 @@ namespace MediaBrowser.Server.Implementations.Session
public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
{
- var socket = GetActiveSocket();
-
- return socket.SendAsync(new WebSocketMessage<GeneralCommand>
+ return SendMessage(new WebSocketMessage<GeneralCommand>
{
MessageType = "GeneralCommand",
Data = command
@@ -169,9 +190,7 @@ namespace MediaBrowser.Server.Implementations.Session
public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
{
- var socket = GetActiveSocket();
-
- return socket.SendAsync(new WebSocketMessage<SessionInfoDto>
+ return SendMessages(new WebSocketMessage<SessionInfoDto>
{
MessageType = "SessionEnded",
Data = sessionInfo
@@ -181,9 +200,7 @@ namespace MediaBrowser.Server.Implementations.Session
public Task SendPlaybackStartNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
{
- var socket = GetActiveSocket();
-
- return socket.SendAsync(new WebSocketMessage<SessionInfoDto>
+ return SendMessages(new WebSocketMessage<SessionInfoDto>
{
MessageType = "PlaybackStart",
Data = sessionInfo
@@ -193,14 +210,45 @@ namespace MediaBrowser.Server.Implementations.Session
public Task SendPlaybackStoppedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
{
- var socket = GetActiveSocket();
-
- return socket.SendAsync(new WebSocketMessage<SessionInfoDto>
+ return SendMessages(new WebSocketMessage<SessionInfoDto>
{
MessageType = "PlaybackStopped",
Data = sessionInfo
}, cancellationToken);
}
+
+ private Task SendMessage<T>(WebSocketMessage<T> message, CancellationToken cancellationToken)
+ {
+ var socket = GetActiveSocket();
+
+ return socket.SendAsync(message, cancellationToken);
+ }
+
+ private Task SendMessages<T>(WebSocketMessage<T> message, CancellationToken cancellationToken)
+ {
+ var tasks = GetActiveSockets().Select(i => Task.Run(async () =>
+ {
+ try
+ {
+ await i.SendAsync(message, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error sending web socket message", ex);
+ }
+
+ }, cancellationToken));
+
+ return Task.WhenAll(tasks);
+ }
+
+ public void Dispose()
+ {
+ foreach (var socket in Sockets.ToList())
+ {
+ socket.Closed -= connection_Closed;
+ }
+ }
}
}