diff options
| author | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-26 11:10:55 -0500 |
|---|---|---|
| committer | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-26 11:10:55 -0500 |
| commit | 6efd22a3d22f8d87ad17da3a1e47ca26c5bb09f2 (patch) | |
| tree | 04a9058a1f3ad39d1247245427589def347d710d | |
| parent | efdb2f3990f6a5250949b7a86bbd83def876f612 (diff) | |
added a shutdown api method, font size fix and other decouplings
30 files changed, 420 insertions, 235 deletions
diff --git a/MediaBrowser.Api/SystemService.cs b/MediaBrowser.Api/SystemService.cs index cf0be35a2..55e8ee693 100644 --- a/MediaBrowser.Api/SystemService.cs +++ b/MediaBrowser.Api/SystemService.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Kernel; using MediaBrowser.Controller; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Serialization; @@ -29,6 +30,11 @@ namespace MediaBrowser.Api { } + [Route("/System/Shutdown", "POST")] + public class ShutdownApplication + { + } + /// <summary> /// Class GetConfiguration /// </summary> @@ -62,18 +68,29 @@ namespace MediaBrowser.Api private readonly IJsonSerializer _jsonSerializer; /// <summary> + /// The _app host + /// </summary> + private readonly IApplicationHost _appHost; + + /// <summary> /// Initializes a new instance of the <see cref="SystemService" /> class. /// </summary> /// <param name="jsonSerializer">The json serializer.</param> + /// <param name="appHost">The app host.</param> /// <exception cref="System.ArgumentNullException">jsonSerializer</exception> - public SystemService(IJsonSerializer jsonSerializer) + public SystemService(IJsonSerializer jsonSerializer, IApplicationHost appHost) : base() { if (jsonSerializer == null) { throw new ArgumentNullException("jsonSerializer"); } + if (appHost == null) + { + throw new ArgumentNullException("appHost"); + } + _appHost = appHost; _jsonSerializer = jsonSerializer; } @@ -119,6 +136,19 @@ namespace MediaBrowser.Api } /// <summary> + /// Posts the specified request. + /// </summary> + /// <param name="request">The request.</param> + public void Post(ShutdownApplication request) + { + Task.Run(async () => + { + await Task.Delay(100); + _appHost.Shutdown(); + }); + } + + /// <summary> /// Posts the specified configuraiton. /// </summary> /// <param name="request">The request.</param> diff --git a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs index 6e3e10361..e0879d924 100644 --- a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs +++ b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs @@ -1,6 +1,5 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Kernel; -using MediaBrowser.Controller; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; @@ -27,18 +26,20 @@ namespace MediaBrowser.Api.WebSocket /// <summary> /// The _kernel /// </summary> + private readonly IApplicationHost _appHost; private readonly IKernel _kernel; - + /// <summary> /// Initializes a new instance of the <see cref="LogFileWebSocketListener" /> class. /// </summary> /// <param name="logger">The logger.</param> /// <param name="kernel">The kernel.</param> - public LogFileWebSocketListener(ILogger logger, Kernel kernel) + public LogFileWebSocketListener(ILogger logger, IApplicationHost host, IKernel kernel) : base(logger) { + _appHost = host; _kernel = kernel; - _kernel.LoggerLoaded += kernel_LoggerLoaded; + kernel.LoggerLoaded += kernel_LoggerLoaded; } /// <summary> @@ -48,9 +49,9 @@ namespace MediaBrowser.Api.WebSocket /// <returns>IEnumerable{System.String}.</returns> protected override async Task<IEnumerable<string>> GetDataToSend(LogFileWebSocketState state) { - if (!string.Equals(_kernel.LogFilePath, state.LastLogFilePath)) + if (!string.Equals(_appHost.LogFilePath, state.LastLogFilePath)) { - state.LastLogFilePath = _kernel.LogFilePath; + state.LastLogFilePath = _appHost.LogFilePath; state.StartLine = 0; } diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index c5af5059f..f5855bf75 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -151,21 +151,22 @@ namespace MediaBrowser.Common.Implementations /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj">The obj.</param> - protected void RegisterSingleInstance<T>(T obj) + /// <param name="manageLifetime">if set to <c>true</c> [manage lifetime].</param> + protected void RegisterSingleInstance<T>(T obj, bool manageLifetime = true) where T : class { Container.RegisterSingle(obj); - } - /// <summary> - /// Registers the specified func. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="func">The func.</param> - protected void Register<T>(Func<T> func) - where T : class - { - Container.Register(func); + if (manageLifetime) + { + var disposable = obj as IDisposable; + + if (disposable != null) + { + Logger.Info("Registering " + disposable.GetType().Name); + DisposableParts.Add(disposable); + } + } } /// <summary> @@ -206,16 +207,6 @@ namespace MediaBrowser.Common.Implementations } /// <summary> - /// Registers the specified service type. - /// </summary> - /// <param name="serviceType">Type of the service.</param> - /// <param name="implementation">Type of the concrete.</param> - protected void Register(Type serviceType, Type implementation) - { - Container.Register(serviceType, implementation); - } - - /// <summary> /// Loads the assembly. /// </summary> /// <param name="file">The file.</param> @@ -282,13 +273,17 @@ namespace MediaBrowser.Common.Implementations /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> protected virtual void Dispose(bool dispose) { - foreach (var part in DisposableParts) + var type = GetType(); + + Logger.Info("Disposing " + type.Name); + + foreach (var part in DisposableParts.Distinct().Where(i => i.GetType() != type).ToList()) { + Logger.Info("Disposing " + part.GetType().Name); + part.Dispose(); } - var b = Container.GetCurrentRegistrations(); - DisposableParts.Clear(); } } diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index acd798d73..59ec01aaf 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -47,10 +47,7 @@ <Reference Include="System" /> <Reference Include="System.Configuration" /> <Reference Include="System.Core" /> - <Reference Include="System.Xml.Linq" /> - <Reference Include="System.Data.DataSetExtensions" /> <Reference Include="Microsoft.CSharp" /> - <Reference Include="System.Data" /> <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> @@ -69,6 +66,8 @@ <Compile Include="Serialization\JsonSerializer.cs" /> <Compile Include="Serialization\ProtobufSerializer.cs" /> <Compile Include="Serialization\XmlSerializer.cs" /> + <Compile Include="Server\ServerManager.cs" /> + <Compile Include="Server\WebSocketConnection.cs" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj"> @@ -82,6 +81,7 @@ </ItemGroup> <ItemGroup> <None Include="packages.config" /> + <EmbeddedResource Include="Server\RegisterServer.bat" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(SolutionDir)\.nuget\nuget.targets" /> diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 7fa30f4ae..320f440fc 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -49,6 +49,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks private ITaskManager TaskManager { get; set; } /// <summary> + /// Gets or sets the server manager. + /// </summary> + /// <value>The server manager.</value> + private IServerManager ServerManager { get; set; } + + /// <summary> /// Initializes a new instance of the <see cref="ScheduledTaskWorker" /> class. /// </summary> /// <param name="scheduledTask">The scheduled task.</param> @@ -56,13 +62,15 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks /// <param name="taskManager">The task manager.</param> /// <param name="jsonSerializer">The json serializer.</param> /// <param name="logger">The logger.</param> - public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, IJsonSerializer jsonSerializer, ILogger logger) + /// <param name="serverManager">The server manager.</param> + public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, IJsonSerializer jsonSerializer, ILogger logger, IServerManager serverManager) { ScheduledTask = scheduledTask; ApplicationPaths = applicationPaths; TaskManager = taskManager; JsonSerializer = jsonSerializer; Logger = logger; + ServerManager = serverManager; } /// <summary> @@ -302,7 +310,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks TaskCompletionStatus status; CurrentExecutionStartTime = DateTime.UtcNow; - //Kernel.TcpManager.SendWebSocketMessage("ScheduledTaskBeginExecute", Name); + ServerManager.SendWebSocketMessage("ScheduledTaskBeginExecute", Name); try { @@ -324,7 +332,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks var startTime = CurrentExecutionStartTime; var endTime = DateTime.UtcNow; - //Kernel.TcpManager.SendWebSocketMessage("ScheduledTaskEndExecute", LastExecutionResult); + ServerManager.SendWebSocketMessage("ScheduledTaskEndExecute", LastExecutionResult); progress.ProgressChanged -= progress_ProgressChanged; CurrentCancellationTokenSource.Dispose(); diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs index 4b61492d6..335820e1c 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs @@ -44,17 +44,25 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks private ILogger Logger { get; set; } /// <summary> + /// Gets or sets the server manager. + /// </summary> + /// <value>The server manager.</value> + private IServerManager ServerManager { get; set; } + + /// <summary> /// Initializes a new instance of the <see cref="TaskManager" /> class. /// </summary> /// <param name="applicationPaths">The application paths.</param> /// <param name="jsonSerializer">The json serializer.</param> /// <param name="logger">The logger.</param> + /// <param name="serverManager">The server manager.</param> /// <exception cref="System.ArgumentException">kernel</exception> - public TaskManager(IApplicationPaths applicationPaths, IJsonSerializer jsonSerializer, ILogger logger) + public TaskManager(IApplicationPaths applicationPaths, IJsonSerializer jsonSerializer, ILogger logger, IServerManager serverManager) { ApplicationPaths = applicationPaths; JsonSerializer = jsonSerializer; Logger = logger; + ServerManager = serverManager; ScheduledTasks = new IScheduledTaskWorker[] { }; } @@ -155,7 +163,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks { var myTasks = ScheduledTasks.ToList(); - myTasks.AddRange(tasks.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger))); + myTasks.AddRange(tasks.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger, ServerManager))); ScheduledTasks = myTasks.ToArray(); } diff --git a/MediaBrowser.Common/Kernel/RegisterServer.bat b/MediaBrowser.Common.Implementations/Server/RegisterServer.bat index d762dfaf7..d762dfaf7 100644 --- a/MediaBrowser.Common/Kernel/RegisterServer.bat +++ b/MediaBrowser.Common.Implementations/Server/RegisterServer.bat diff --git a/MediaBrowser.Common/Kernel/TcpManager.cs b/MediaBrowser.Common.Implementations/Server/ServerManager.cs index 2dfed501a..04747bad6 100644 --- a/MediaBrowser.Common/Kernel/TcpManager.cs +++ b/MediaBrowser.Common.Implementations/Server/ServerManager.cs @@ -1,5 +1,5 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Configuration; +using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using System; @@ -14,12 +14,12 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Common.Kernel +namespace MediaBrowser.Common.Implementations.Server { /// <summary> /// Manages the Http Server, Udp Server and WebSocket connections /// </summary> - public class TcpManager : IDisposable + public class ServerManager : IServerManager, IDisposable { /// <summary> /// This is the udp server used for server discovery by clients @@ -49,7 +49,7 @@ namespace MediaBrowser.Common.Kernel /// <summary> /// The web socket connections /// </summary> - private readonly List<WebSocketConnection> _webSocketConnections = new List<WebSocketConnection>(); + private readonly List<IWebSocketConnection> _webSocketConnections = new List<IWebSocketConnection>(); /// <summary> /// Gets or sets the external web socket server. @@ -81,7 +81,7 @@ namespace MediaBrowser.Common.Kernel /// Gets a value indicating whether [supports web socket]. /// </summary> /// <value><c>true</c> if [supports web socket]; otherwise, <c>false</c>.</value> - internal bool SupportsNativeWebSocket + public bool SupportsNativeWebSocket { get { return HttpServer != null && HttpServer.SupportsWebSockets; } } @@ -96,7 +96,7 @@ namespace MediaBrowser.Common.Kernel } /// <summary> - /// Initializes a new instance of the <see cref="TcpManager" /> class. + /// Initializes a new instance of the <see cref="ServerManager" /> class. /// </summary> /// <param name="applicationHost">The application host.</param> /// <param name="kernel">The kernel.</param> @@ -104,7 +104,7 @@ namespace MediaBrowser.Common.Kernel /// <param name="jsonSerializer">The json serializer.</param> /// <param name="logger">The logger.</param> /// <exception cref="System.ArgumentNullException">applicationHost</exception> - public TcpManager(IApplicationHost applicationHost, IKernel kernel, INetworkManager networkManager, IJsonSerializer jsonSerializer, ILogger logger) + public ServerManager(IApplicationHost applicationHost, IKernel kernel, INetworkManager networkManager, IJsonSerializer jsonSerializer, ILogger logger) { if (applicationHost == null) { @@ -132,8 +132,14 @@ namespace MediaBrowser.Common.Kernel _kernel = kernel; _applicationHost = applicationHost; _networkManager = networkManager; + } - if (applicationHost.IsFirstRun) + /// <summary> + /// Starts this instance. + /// </summary> + public void Start() + { + if (_applicationHost.IsFirstRun) { RegisterServerWithAdministratorAccess(); } @@ -145,6 +151,8 @@ namespace MediaBrowser.Common.Kernel { ReloadExternalWebSocketServer(); } + + _kernel.ConfigurationUpdated += _kernel_ConfigurationUpdated; } /// <summary> @@ -170,7 +178,7 @@ namespace MediaBrowser.Common.Kernel /// Restarts the Http Server, or starts it if not currently running /// </summary> /// <param name="registerServerOnFailure">if set to <c>true</c> [register server on failure].</param> - public void ReloadHttpServer(bool registerServerOnFailure = true) + private void ReloadHttpServer(bool registerServerOnFailure = true) { // Only reload if the port has changed, so that we don't disconnect any active users if (HttpServer != null && HttpServer.UrlPrefix.Equals(_kernel.HttpServerUrlPrefix, StringComparison.OrdinalIgnoreCase)) @@ -426,7 +434,7 @@ namespace MediaBrowser.Common.Kernel var tmpFile = Path.Combine(_kernel.ApplicationPaths.TempDirectory, Guid.NewGuid() + ".bat"); // Extract the bat file - using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MediaBrowser.Common.Kernel.RegisterServer.bat")) + using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MediaBrowser.Common.Implementations.Server.bat")) { using (var fileStream = File.Create(tmpFile)) { @@ -489,20 +497,21 @@ namespace MediaBrowser.Common.Kernel } /// <summary> - /// Called when [application configuration changed]. + /// Handles the ConfigurationUpdated event of the _kernel control. /// </summary> - /// <param name="oldConfig">The old config.</param> - /// <param name="newConfig">The new config.</param> - public void OnApplicationConfigurationChanged(BaseApplicationConfiguration oldConfig, BaseApplicationConfiguration newConfig) + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> + /// <exception cref="System.NotImplementedException"></exception> + void _kernel_ConfigurationUpdated(object sender, EventArgs e) { - HttpServer.EnableHttpRequestLogging = newConfig.EnableHttpLevelLogging; + HttpServer.EnableHttpRequestLogging = _kernel.Configuration.EnableHttpLevelLogging; - if (oldConfig.HttpServerPortNumber != newConfig.HttpServerPortNumber) + if (!string.Equals(HttpServer.UrlPrefix, _kernel.HttpServerUrlPrefix, StringComparison.OrdinalIgnoreCase)) { ReloadHttpServer(); } - if (!SupportsNativeWebSocket && oldConfig.LegacyWebSocketPortNumber != newConfig.LegacyWebSocketPortNumber) + if (!SupportsNativeWebSocket && ExternalWebSocketServer != null && ExternalWebSocketServer.Port != _kernel.Configuration.LegacyWebSocketPortNumber) { ReloadExternalWebSocketServer(); } diff --git a/MediaBrowser.Common/Net/WebSocketConnection.cs b/MediaBrowser.Common.Implementations/Server/WebSocketConnection.cs index 1ad0e8f06..b8766523c 100644 --- a/MediaBrowser.Common/Net/WebSocketConnection.cs +++ b/MediaBrowser.Common.Implementations/Server/WebSocketConnection.cs @@ -1,16 +1,17 @@ -using MediaBrowser.Model.Logging; +using MediaBrowser.Common.Net; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using System; using System.IO; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Common.Net +namespace MediaBrowser.Common.Implementations.Server { /// <summary> /// Class WebSocketConnection /// </summary> - public class WebSocketConnection : IDisposable + public class WebSocketConnection : IWebSocketConnection { /// <summary> /// The _socket @@ -20,7 +21,7 @@ namespace MediaBrowser.Common.Net /// <summary> /// The _remote end point /// </summary> - public readonly string RemoteEndPoint; + public string RemoteEndPoint { get; private set; } /// <summary> /// The _cancellation token source @@ -221,34 +222,4 @@ namespace MediaBrowser.Common.Net } } } - - /// <summary> - /// Class WebSocketMessage - /// </summary> - /// <typeparam name="T"></typeparam> - public class WebSocketMessage<T> - { - /// <summary> - /// Gets or sets the type of the message. - /// </summary> - /// <value>The type of the message.</value> - public string MessageType { get; set; } - /// <summary> - /// Gets or sets the data. - /// </summary> - /// <value>The data.</value> - public T Data { get; set; } - } - - /// <summary> - /// Class WebSocketMessageInfo - /// </summary> - public class WebSocketMessageInfo : WebSocketMessage<string> - { - /// <summary> - /// Gets or sets the connection. - /// </summary> - /// <value>The connection.</value> - public WebSocketConnection Connection { get; set; } - } } diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index 5b8da5d09..2ec1dd829 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -1,5 +1,4 @@ using MediaBrowser.Common.Events; -using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; @@ -165,7 +164,7 @@ namespace MediaBrowser.Common.Kernel /// Gets or sets the TCP manager. /// </summary> /// <value>The TCP manager.</value> - public TcpManager TcpManager { get; private set; } + public IServerManager ServerManager { get; private set; } /// <summary> /// Gets the UDP server port number. @@ -203,15 +202,6 @@ namespace MediaBrowser.Common.Kernel public abstract KernelContext KernelContext { get; } /// <summary> - /// Gets the log file path. - /// </summary> - /// <value>The log file path.</value> - public string LogFilePath - { - get { return ApplicationHost.LogFilePath; } - } - - /// <summary> /// Gets the logger. /// </summary> /// <value>The logger.</value> @@ -238,23 +228,6 @@ namespace MediaBrowser.Common.Kernel /// <exception cref="System.ArgumentNullException">isoManager</exception> protected BaseKernel(IApplicationHost appHost, TApplicationPathsType appPaths, IXmlSerializer xmlSerializer, ILogger logger) { - if (appHost == null) - { - throw new ArgumentNullException("appHost"); - } - if (appPaths == null) - { - throw new ArgumentNullException("appPaths"); - } - if (xmlSerializer == null) - { - throw new ArgumentNullException("xmlSerializer"); - } - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - ApplicationPaths = appPaths; ApplicationHost = appHost; _xmlSerializer = xmlSerializer; @@ -291,8 +264,8 @@ namespace MediaBrowser.Common.Kernel await OnComposablePartsLoaded().ConfigureAwait(false); - DisposeTcpManager(); - TcpManager = (TcpManager)ApplicationHost.CreateInstance(typeof(TcpManager)); + ServerManager = ApplicationHost.Resolve<IServerManager>(); + ServerManager.Start(); } /// <summary> @@ -357,7 +330,7 @@ namespace MediaBrowser.Common.Kernel { HasPendingRestart = true; - TcpManager.SendWebSocketMessage("HasPendingRestartChanged", GetSystemInfo()); + ServerManager.SendWebSocketMessage("HasPendingRestartChanged", GetSystemInfo()); EventHelper.QueueEventIfNotNull(HasPendingRestartChanged, this, EventArgs.Empty, Logger); } @@ -377,22 +350,7 @@ namespace MediaBrowser.Common.Kernel /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> protected virtual void Dispose(bool dispose) { - if (dispose) - { - DisposeTcpManager(); - } - } - /// <summary> - /// Disposes the TCP manager. - /// </summary> - private void DisposeTcpManager() - { - if (TcpManager != null) - { - TcpManager.Dispose(); - TcpManager = null; - } } /// <summary> @@ -424,8 +382,8 @@ namespace MediaBrowser.Common.Kernel HasPendingRestart = HasPendingRestart, Version = ApplicationHost.ApplicationVersion.ToString(), IsNetworkDeployed = ApplicationHost.CanSelfUpdate, - WebSocketPortNumber = TcpManager.WebSocketPortNumber, - SupportsNativeWebSocket = TcpManager.SupportsNativeWebSocket, + WebSocketPortNumber = ServerManager.WebSocketPortNumber, + SupportsNativeWebSocket = ServerManager.SupportsNativeWebSocket, FailedPluginAssemblies = ApplicationHost.FailedAssemblies.ToArray() }; } diff --git a/MediaBrowser.Common/Kernel/BasePeriodicWebSocketListener.cs b/MediaBrowser.Common/Kernel/BasePeriodicWebSocketListener.cs index 5374bb714..6a44cf372 100644 --- a/MediaBrowser.Common/Kernel/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Common/Kernel/BasePeriodicWebSocketListener.cs @@ -19,8 +19,8 @@ namespace MediaBrowser.Common.Kernel /// <summary> /// The _active connections /// </summary> - protected readonly List<Tuple<WebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim>> ActiveConnections = - new List<Tuple<WebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim>>(); + protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim>> ActiveConnections = + new List<Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim>>(); /// <summary> /// Gets the name. @@ -103,7 +103,7 @@ namespace MediaBrowser.Common.Kernel lock (ActiveConnections) { - ActiveConnections.Add(new Tuple<WebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim>(message.Connection, cancellationTokenSource, timer, state, semaphore)); + ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim>(message.Connection, cancellationTokenSource, timer, state, semaphore)); } timer.Change(TimeSpan.FromMilliseconds(dueTimeMs), TimeSpan.FromMilliseconds(periodMs)); @@ -115,9 +115,9 @@ namespace MediaBrowser.Common.Kernel /// <param name="state">The state.</param> private async void TimerCallback(object state) { - var connection = (WebSocketConnection)state; + var connection = (IWebSocketConnection)state; - Tuple<WebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim> tuple; + Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim> tuple; lock (ActiveConnections) { @@ -187,7 +187,7 @@ namespace MediaBrowser.Common.Kernel /// Disposes the connection. /// </summary> /// <param name="connection">The connection.</param> - private void DisposeConnection(Tuple<WebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim> connection) + private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType, SemaphoreSlim> connection) { Logger.Info("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); diff --git a/MediaBrowser.Common/Kernel/IApplicationHost.cs b/MediaBrowser.Common/Kernel/IApplicationHost.cs index af9b039bc..1f99d10db 100644 --- a/MediaBrowser.Common/Kernel/IApplicationHost.cs +++ b/MediaBrowser.Common/Kernel/IApplicationHost.cs @@ -97,5 +97,10 @@ namespace MediaBrowser.Common.Kernel /// <typeparam name="T"></typeparam> /// <returns>``0.</returns> T TryResolve<T>(); + + /// <summary> + /// Shuts down. + /// </summary> + void Shutdown(); } } diff --git a/MediaBrowser.Common/Kernel/IKernel.cs b/MediaBrowser.Common/Kernel/IKernel.cs index 06c2e7b64..a28500eca 100644 --- a/MediaBrowser.Common/Kernel/IKernel.cs +++ b/MediaBrowser.Common/Kernel/IKernel.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Common.Plugins; +using MediaBrowser.Common.Plugins; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.System; using System; @@ -72,12 +71,6 @@ namespace MediaBrowser.Common.Kernel string WebApplicationName { get; } /// <summary> - /// Gets the log file path. - /// </summary> - /// <value>The log file path.</value> - string LogFilePath { get; } - - /// <summary> /// Performs the pending restart. /// </summary> void PerformPendingRestart(); @@ -104,7 +97,7 @@ namespace MediaBrowser.Common.Kernel /// Gets the TCP manager. /// </summary> /// <value>The TCP manager.</value> - TcpManager TcpManager { get; } + IServerManager ServerManager { get; } /// <summary> /// Gets the web socket listeners. diff --git a/MediaBrowser.Common/Kernel/IServerManager.cs b/MediaBrowser.Common/Kernel/IServerManager.cs new file mode 100644 index 000000000..cfea6eee1 --- /dev/null +++ b/MediaBrowser.Common/Kernel/IServerManager.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Common.Kernel +{ + public interface IServerManager : IDisposable + { + /// <summary> + /// Gets a value indicating whether [supports web socket]. + /// </summary> + /// <value><c>true</c> if [supports web socket]; otherwise, <c>false</c>.</value> + bool SupportsNativeWebSocket { get; } + + /// <summary> + /// Gets the web socket port number. + /// </summary> + /// <value>The web socket port number.</value> + int WebSocketPortNumber { get; } + + /// <summary> + /// Starts this instance. + /// </summary> + void Start(); + + /// <summary> + /// Sends a message to all clients currently connected via a web socket + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="messageType">Type of the message.</param> + /// <param name="data">The data.</param> + /// <returns>Task.</returns> + void SendWebSocketMessage<T>(string messageType, T data); + + /// <summary> + /// Sends a message to all clients currently connected via a web socket + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="messageType">Type of the message.</param> + /// <param name="dataFunction">The function that generates the data to send, if there are any connected clients</param> + void SendWebSocketMessage<T>(string messageType, Func<T> dataFunction); + + /// <summary> + /// Sends a message to all clients currently connected via a web socket + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="messageType">Type of the message.</param> + /// <param name="dataFunction">The function that generates the data to send, if there are any connected clients</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException">messageType</exception> + Task SendWebSocketMessageAsync<T>(string messageType, Func<T> dataFunction, CancellationToken cancellationToken); + } +}
\ No newline at end of file diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 333c20beb..b136eb43c 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -91,10 +91,10 @@ <Compile Include="IO\StreamDefaults.cs" /> <Compile Include="Kernel\BasePeriodicWebSocketListener.cs" /> <Compile Include="Kernel\IApplicationPaths.cs" /> + <Compile Include="Kernel\IServerManager.cs" /> <Compile Include="Kernel\IWebSocketListener.cs" /> <Compile Include="Kernel\IApplicationHost.cs" /> <Compile Include="Kernel\IKernel.cs" /> - <Compile Include="Kernel\TcpManager.cs" /> <Compile Include="Net\Handlers\IHttpServerHandler.cs" /> <Compile Include="Net\Handlers\StaticFileHandler.cs" /> <Compile Include="Net\IHttpClient.cs" /> @@ -103,12 +103,12 @@ <Compile Include="Net\IRestfulService.cs" /> <Compile Include="Net\IUdpServer.cs" /> <Compile Include="Net\IWebSocket.cs" /> + <Compile Include="Net\IWebSocketConnection.cs" /> <Compile Include="Net\IWebSocketServer.cs" /> <Compile Include="Net\MimeTypes.cs" /> <Compile Include="Net\StreamWriter.cs" /> <Compile Include="Net\UdpMessageReceivedEventArgs.cs" /> <Compile Include="Net\WebSocketConnectEventArgs.cs" /> - <Compile Include="Net\WebSocketConnection.cs" /> <Compile Include="Net\WebSocketMessageType.cs" /> <Compile Include="Net\WebSocketState.cs" /> <Compile Include="Plugins\BaseUiPlugin.cs" /> @@ -138,7 +138,6 @@ </ItemGroup> <ItemGroup> <None Include="app.config" /> - <EmbeddedResource Include="Kernel\RegisterServer.bat" /> <None Include="packages.config" /> </ItemGroup> <ItemGroup> diff --git a/MediaBrowser.Common/Net/IWebSocketConnection.cs b/MediaBrowser.Common/Net/IWebSocketConnection.cs new file mode 100644 index 000000000..8e1b13ceb --- /dev/null +++ b/MediaBrowser.Common/Net/IWebSocketConnection.cs @@ -0,0 +1,85 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Common.Net +{ + public interface IWebSocketConnection : IDisposable + { + /// <summary> + /// Gets or sets the receive action. + /// </summary> + /// <value>The receive action.</value> + Action<WebSocketMessageInfo> OnReceive { get; set; } + + /// <summary> + /// Gets the state. + /// </summary> + /// <value>The state.</value> + WebSocketState State { get; } + + /// <summary> + /// Gets the remote end point. + /// </summary> + /// <value>The remote end point.</value> + string RemoteEndPoint { get; } + + /// <summary> + /// Sends a message asynchronously. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="message">The message.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException">message</exception> + Task SendAsync<T>(WebSocketMessage<T> message, CancellationToken cancellationToken); + + /// <summary> + /// Sends a message asynchronously. + /// </summary> + /// <param name="buffer">The buffer.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task SendAsync(byte[] buffer, CancellationToken cancellationToken); + + /// <summary> + /// Sends a message asynchronously. + /// </summary> + /// <param name="buffer">The buffer.</param> + /// <param name="type">The type.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException">buffer</exception> + Task SendAsync(byte[] buffer, WebSocketMessageType type, CancellationToken cancellationToken); + } + + /// <summary> + /// Class WebSocketMessage + /// </summary> + /// <typeparam name="T"></typeparam> + public class WebSocketMessage<T> + { + /// <summary> + /// Gets or sets the type of the message. + /// </summary> + /// <value>The type of the message.</value> + public string MessageType { get; set; } + /// <summary> + /// Gets or sets the data. + /// </summary> + /// <value>The data.</value> + public T Data { get; set; } + } + + /// <summary> + /// Class WebSocketMessageInfo + /// </summary> + public class WebSocketMessageInfo : WebSocketMessage<string> + { + /// <summary> + /// Gets or sets the connection. + /// </summary> + /// <value>The connection.</value> + public IWebSocketConnection Connection { get; set; } + } +}
\ No newline at end of file diff --git a/MediaBrowser.Common/Net/IWebSocketServer.cs b/MediaBrowser.Common/Net/IWebSocketServer.cs index 5ce571fbb..187e03e09 100644 --- a/MediaBrowser.Common/Net/IWebSocketServer.cs +++ b/MediaBrowser.Common/Net/IWebSocketServer.cs @@ -22,5 +22,11 @@ namespace MediaBrowser.Common.Net /// Occurs when [web socket connected]. /// </summary> event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; + + /// <summary> + /// Gets the port. + /// </summary> + /// <value>The port.</value> + int Port { get; } } } diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index d879b888b..ed49d26d8 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -12,7 +12,6 @@ using MediaBrowser.Controller.Playback; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; -using MediaBrowser.Controller.ScheduledTasks; using MediaBrowser.Controller.Updates; using MediaBrowser.Controller.Weather; using MediaBrowser.Model.Configuration; @@ -293,8 +292,6 @@ namespace MediaBrowser.Controller get { return 7359; } } - private readonly ITaskManager _taskManager; - /// <summary> /// Creates a kernel based on a Data path, which is akin to our current programdata path /// </summary> @@ -304,13 +301,11 @@ namespace MediaBrowser.Controller /// <param name="taskManager">The task manager.</param> /// <param name="logger">The logger.</param> /// <exception cref="System.ArgumentNullException">isoManager</exception> - public Kernel(IApplicationHost appHost, IServerApplicationPaths appPaths, IXmlSerializer xmlSerializer, ITaskManager taskManager, ILogger logger) + public Kernel(IApplicationHost appHost, IServerApplicationPaths appPaths, IXmlSerializer xmlSerializer, ILogger logger) : base(appHost, appPaths, xmlSerializer, logger) { Instance = this; - _taskManager = taskManager; - // For now there's no real way to inject this properly BaseItem.Logger = logger; Ratings.Logger = logger; @@ -469,7 +464,7 @@ namespace MediaBrowser.Controller { DisposeFileSystemManager(); - FileSystemManager = new FileSystemManager(this, Logger, _taskManager); + FileSystemManager = new FileSystemManager(this, Logger, ApplicationHost.Resolve<ITaskManager>()); FileSystemManager.StartWatchers(); } @@ -540,18 +535,6 @@ namespace MediaBrowser.Controller var reloadLogger = config.ShowLogWindow != oldConfiguration.ShowLogWindow; - // Figure out whether or not we should refresh people after the update is finished - var refreshPeopleAfterUpdate = !oldConfiguration.EnableInternetProviders && config.EnableInternetProviders; - - // This is true if internet providers has just been turned on, or if People have just been removed from InternetProviderExcludeTypes - if (!refreshPeopleAfterUpdate) - { - var oldConfigurationFetchesPeopleImages = oldConfiguration.InternetProviderExcludeTypes == null || !oldConfiguration.InternetProviderExcludeTypes.Contains(typeof(Person).Name, StringComparer.OrdinalIgnoreCase); - var newConfigurationFetchesPeopleImages = config.InternetProviderExcludeTypes == null || !config.InternetProviderExcludeTypes.Contains(typeof(Person).Name, StringComparer.OrdinalIgnoreCase); - - refreshPeopleAfterUpdate = newConfigurationFetchesPeopleImages && !oldConfigurationFetchesPeopleImages; - } - Configuration = config; SaveConfiguration(); @@ -560,20 +543,10 @@ namespace MediaBrowser.Controller ReloadLogger(); } - TcpManager.OnApplicationConfigurationChanged(oldConfiguration, config); - // Validate currently executing providers, in the background Task.Run(() => { ProviderManager.ValidateCurrentlyRunningProviders(); - - // Any number of configuration settings could change the way the library is refreshed, so do that now - _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>(); - - if (refreshPeopleAfterUpdate) - { - _taskManager.CancelIfRunningAndQueue<PeopleValidationTask>(); - } }); } diff --git a/MediaBrowser.Controller/Library/LibraryManager.cs b/MediaBrowser.Controller/Library/LibraryManager.cs index c0c1fe1d6..53f4af4b2 100644 --- a/MediaBrowser.Controller/Library/LibraryManager.cs +++ b/MediaBrowser.Controller/Library/LibraryManager.cs @@ -1,8 +1,10 @@ using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Resolvers; +using MediaBrowser.Controller.ScheduledTasks; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MoreLinq; @@ -20,7 +22,7 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Class LibraryManager /// </summary> - public class LibraryManager : BaseManager<Kernel> + public class LibraryManager { #region LibraryChanged Event /// <summary> @@ -48,7 +50,7 @@ namespace MediaBrowser.Controller.Library private void SendLibraryChangedWebSocketMessage(ChildrenChangedEventArgs args) { // Notify connected ui's - Kernel.TcpManager.SendWebSocketMessage("LibraryChanged", () => DtoBuilder.GetLibraryUpdateInfo(args)); + Kernel.ServerManager.SendWebSocketMessage("LibraryChanged", () => DtoBuilder.GetLibraryUpdateInfo(args)); } #endregion @@ -58,14 +60,56 @@ namespace MediaBrowser.Controller.Library private readonly ILogger _logger; /// <summary> + /// The _task manager + /// </summary> + private readonly ITaskManager _taskManager; + + /// <summary> + /// Gets or sets the kernel. + /// </summary> + /// <value>The kernel.</value> + private Kernel Kernel { get; set; } + + /// <summary> /// Initializes a new instance of the <see cref="LibraryManager" /> class. /// </summary> /// <param name="kernel">The kernel.</param> /// <param name="logger">The logger.</param> - public LibraryManager(Kernel kernel, ILogger logger) - : base(kernel) + /// <param name="taskManager">The task manager.</param> + public LibraryManager(Kernel kernel, ILogger logger, ITaskManager taskManager) { + Kernel = kernel; _logger = logger; + _taskManager = taskManager; + + kernel.ConfigurationUpdated += kernel_ConfigurationUpdated; + } + + /// <summary> + /// Handles the ConfigurationUpdated event of the kernel control. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> + void kernel_ConfigurationUpdated(object sender, EventArgs e) + { + //// Figure out whether or not we should refresh people after the update is finished + //var refreshPeopleAfterUpdate = !oldConfiguration.EnableInternetProviders && config.EnableInternetProviders; + + //// This is true if internet providers has just been turned on, or if People have just been removed from InternetProviderExcludeTypes + //if (!refreshPeopleAfterUpdate) + //{ + // var oldConfigurationFetchesPeopleImages = oldConfiguration.InternetProviderExcludeTypes == null || !oldConfiguration.InternetProviderExcludeTypes.Contains(typeof(Person).Name, StringComparer.OrdinalIgnoreCase); + // var newConfigurationFetchesPeopleImages = config.InternetProviderExcludeTypes == null || !config.InternetProviderExcludeTypes.Contains(typeof(Person).Name, StringComparer.OrdinalIgnoreCase); + + // refreshPeopleAfterUpdate = newConfigurationFetchesPeopleImages && !oldConfigurationFetchesPeopleImages; + //} + + Task.Run(() => + { + // Any number of configuration settings could change the way the library is refreshed, so do that now + _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>(); + _taskManager.CancelIfRunningAndQueue<PeopleValidationTask>(); + }); } /// <summary> diff --git a/MediaBrowser.Controller/Library/UserManager.cs b/MediaBrowser.Controller/Library/UserManager.cs index 8084366b7..5340e70be 100644 --- a/MediaBrowser.Controller/Library/UserManager.cs +++ b/MediaBrowser.Controller/Library/UserManager.cs @@ -73,7 +73,7 @@ namespace MediaBrowser.Controller.Library EventHelper.QueueEventIfNotNull(UserUpdated, this, new GenericEventArgs<User> { Argument = user }, _logger); // Notify connected ui's - Kernel.TcpManager.SendWebSocketMessage("UserUpdated", new DtoBuilder(_logger).GetDtoUser(user)); + Kernel.ServerManager.SendWebSocketMessage("UserUpdated", new DtoBuilder(_logger).GetDtoUser(user)); } #endregion @@ -91,7 +91,7 @@ namespace MediaBrowser.Controller.Library EventHelper.QueueEventIfNotNull(UserDeleted, this, new GenericEventArgs<User> { Argument = user }, _logger); // Notify connected ui's - Kernel.TcpManager.SendWebSocketMessage("UserDeleted", user.Id.ToString()); + Kernel.ServerManager.SendWebSocketMessage("UserDeleted", user.Id.ToString()); } #endregion diff --git a/MediaBrowser.Controller/Updates/InstallationManager.cs b/MediaBrowser.Controller/Updates/InstallationManager.cs index 8751bd427..efef87f86 100644 --- a/MediaBrowser.Controller/Updates/InstallationManager.cs +++ b/MediaBrowser.Controller/Updates/InstallationManager.cs @@ -49,7 +49,7 @@ namespace MediaBrowser.Controller.Updates EventHelper.QueueEventIfNotNull(PluginUninstalled, this, new GenericEventArgs<IPlugin> { Argument = plugin }, _logger); // Notify connected ui's - Kernel.TcpManager.SendWebSocketMessage("PluginUninstalled", plugin.GetPluginInfo()); + Kernel.ServerManager.SendWebSocketMessage("PluginUninstalled", plugin.GetPluginInfo()); } #endregion @@ -371,7 +371,7 @@ namespace MediaBrowser.Controller.Updates var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token).Token; - Kernel.TcpManager.SendWebSocketMessage("PackageInstalling", installationInfo); + Kernel.ServerManager.SendWebSocketMessage("PackageInstalling", installationInfo); try { @@ -384,7 +384,7 @@ namespace MediaBrowser.Controller.Updates CompletedInstallations.Add(installationInfo); - Kernel.TcpManager.SendWebSocketMessage("PackageInstallationCompleted", installationInfo); + Kernel.ServerManager.SendWebSocketMessage("PackageInstallationCompleted", installationInfo); } catch (OperationCanceledException) { @@ -395,7 +395,7 @@ namespace MediaBrowser.Controller.Updates _logger.Info("Package installation cancelled: {0} {1}", package.name, package.versionStr); - Kernel.TcpManager.SendWebSocketMessage("PackageInstallationCancelled", installationInfo); + Kernel.ServerManager.SendWebSocketMessage("PackageInstallationCancelled", installationInfo); throw; } @@ -406,7 +406,7 @@ namespace MediaBrowser.Controller.Updates CurrentInstallations.Remove(tuple); } - Kernel.TcpManager.SendWebSocketMessage("PackageInstallationFailed", installationInfo); + Kernel.ServerManager.SendWebSocketMessage("PackageInstallationFailed", installationInfo); throw; } diff --git a/MediaBrowser.Networking/Udp/UdpServer.cs b/MediaBrowser.Networking/Udp/UdpServer.cs index 9b1c254cf..00eb2a0d1 100644 --- a/MediaBrowser.Networking/Udp/UdpServer.cs +++ b/MediaBrowser.Networking/Udp/UdpServer.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Net; +using MediaBrowser.Model.Logging; using MediaBrowser.Networking.Management; using System; using System.Net; @@ -20,6 +21,21 @@ namespace MediaBrowser.Networking.Udp public event EventHandler<UdpMessageReceivedEventArgs> MessageReceived; /// <summary> + /// Gets or sets the logger. + /// </summary> + /// <value>The logger.</value> + private ILogger Logger { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="UdpServer" /> class. + /// </summary> + /// <param name="logger">The logger.</param> + public UdpServer(ILogger logger) + { + Logger = logger; + } + + /// <summary> /// Raises the <see cref="E:MessageReceived" /> event. /// </summary> /// <param name="e">The <see cref="UdpMessageReceivedEventArgs" /> instance containing the event data.</param> @@ -54,8 +70,24 @@ namespace MediaBrowser.Networking.Udp private IObservable<UdpReceiveResult> CreateObservable() { return Observable.Create<UdpReceiveResult>(obs => - Observable.FromAsync(() => _udpClient.ReceiveAsync()) - .Subscribe(obs)) + Observable.FromAsync(() => + { + try + { + return _udpClient.ReceiveAsync(); + } + catch (ObjectDisposedException) + { + return Task.FromResult(new UdpReceiveResult(new byte[]{}, new IPEndPoint(IPAddress.Any, 0))); + } + catch (Exception ex) + { + Logger.ErrorException("Error receiving udp message", ex); + return Task.FromResult(new UdpReceiveResult(new byte[] { }, new IPEndPoint(IPAddress.Any, 0))); + } + }) + + .Subscribe(obs)) .Repeat() .Retry() .Publish() @@ -68,6 +100,10 @@ namespace MediaBrowser.Networking.Udp /// <param name="message">The message.</param> private void OnMessageReceived(UdpReceiveResult message) { + if (message.RemoteEndPoint.Port == 0) + { + return; + } var bytes = message.Buffer; OnMessageReceived(new UdpMessageReceivedEventArgs diff --git a/MediaBrowser.Networking/WebSocket/AlchemyServer.cs b/MediaBrowser.Networking/WebSocket/AlchemyServer.cs index 1a3971c7f..b3d5d710e 100644 --- a/MediaBrowser.Networking/WebSocket/AlchemyServer.cs +++ b/MediaBrowser.Networking/WebSocket/AlchemyServer.cs @@ -43,6 +43,12 @@ namespace MediaBrowser.Networking.WebSocket } /// <summary> + /// Gets the port. + /// </summary> + /// <value>The port.</value> + public int Port { get; private set; } + + /// <summary> /// Starts the specified port number. /// </summary> /// <param name="portNumber">The port number.</param> @@ -56,6 +62,8 @@ namespace MediaBrowser.Networking.WebSocket WebSocketServer.Start(); + Port = portNumber; + _logger.Info("Alchemy Web Socket Server started"); } diff --git a/MediaBrowser.ServerApplication/App.xaml.cs b/MediaBrowser.ServerApplication/App.xaml.cs index f6f70b382..1199aeaf1 100644 --- a/MediaBrowser.ServerApplication/App.xaml.cs +++ b/MediaBrowser.ServerApplication/App.xaml.cs @@ -255,7 +255,6 @@ namespace MediaBrowser.ServerApplication base.OnExit(e); - Kernel.Dispose(); CompositionRoot.Dispose(); } @@ -360,7 +359,7 @@ namespace MediaBrowser.ServerApplication { Dispatcher.Invoke(ReleaseMutex); - Kernel.Dispose(); + CompositionRoot.Dispose(); System.Windows.Forms.Application.Restart(); diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index e862a394e..07246eded 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -4,6 +4,7 @@ using MediaBrowser.Common.Implementations; using MediaBrowser.Common.Implementations.ScheduledTasks; using MediaBrowser.Common.Implementations.Serialization; using MediaBrowser.Common.IO; +using MediaBrowser.Common.Implementations.Server; using MediaBrowser.Common.Kernel; using MediaBrowser.Common.Net; using MediaBrowser.Common.ScheduledTasks; @@ -66,16 +67,6 @@ namespace MediaBrowser.ServerApplication private readonly IServerApplicationPaths _applicationPaths = new ServerApplicationPaths(); /// <summary> - /// The _task manager - /// </summary> - private readonly ITaskManager _taskManager; - - /// <summary> - /// The _task manager - /// </summary> - private readonly IHttpServer _httpServer; - - /// <summary> /// Gets a value indicating whether this instance is first run. /// </summary> /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value> @@ -89,29 +80,34 @@ namespace MediaBrowser.ServerApplication : base() { IsFirstRun = !File.Exists(_applicationPaths.SystemConfigurationFilePath); - + Logger = new NLogger("App"); DiscoverTypes(); - _taskManager = new TaskManager(_applicationPaths, _jsonSerializer, Logger); + Kernel = new Kernel(this, _applicationPaths, _xmlSerializer, Logger); + + var networkManager = new NetworkManager(); + + var serverManager = new ServerManager(this, Kernel, networkManager, _jsonSerializer, Logger); + + var taskManager = new TaskManager(_applicationPaths, _jsonSerializer, Logger, serverManager); - Kernel = new Kernel(this, _applicationPaths, _xmlSerializer, _taskManager, Logger); ReloadLogger(); Logger.Info("Version {0} initializing", ApplicationVersion); - _httpServer = ServerFactory.CreateServer(this, ProtobufSerializer, Logger, "Media Browser", "index.html"); + var httpServer = ServerFactory.CreateServer(this, ProtobufSerializer, Logger, "Media Browser", "index.html"); - RegisterResources(); + RegisterResources(taskManager, httpServer, networkManager, serverManager); - FindParts(); + FindParts(taskManager, httpServer); } /// <summary> /// Registers resources that classes will depend on /// </summary> - private void RegisterResources() + private void RegisterResources(ITaskManager taskManager, IHttpServer httpServer, INetworkManager networkManager, IServerManager serverManager) { RegisterSingleInstance<IKernel>(Kernel); RegisterSingleInstance(Kernel); @@ -121,28 +117,31 @@ namespace MediaBrowser.ServerApplication RegisterSingleInstance(_applicationPaths); RegisterSingleInstance<IApplicationPaths>(_applicationPaths); - RegisterSingleInstance(_taskManager); + RegisterSingleInstance(taskManager); RegisterSingleInstance<IIsoManager>(new PismoIsoManager(Logger)); RegisterSingleInstance<IBlurayExaminer>(new BdInfoExaminer()); RegisterSingleInstance<IHttpClient>(new HttpManager(_applicationPaths, Logger)); - RegisterSingleInstance<INetworkManager>(new NetworkManager()); RegisterSingleInstance<IZipClient>(new DotNetZipClient()); RegisterSingleInstance<IWebSocketServer>(() => new AlchemyServer(Logger)); RegisterSingleInstance(_jsonSerializer); RegisterSingleInstance(_xmlSerializer); RegisterSingleInstance(ProtobufSerializer); - RegisterSingleInstance<IUdpServer>(new UdpServer()); - RegisterSingleInstance(_httpServer); + RegisterSingleInstance<IUdpServer>(new UdpServer(Logger), false); + RegisterSingleInstance(httpServer, false); + + RegisterSingleInstance(networkManager); + + RegisterSingleInstance(serverManager); } /// <summary> /// Finds the parts. /// </summary> - private void FindParts() + private void FindParts(ITaskManager taskManager, IHttpServer httpServer) { - _taskManager.AddTasks(GetExports<IScheduledTask>(false)); + taskManager.AddTasks(GetExports<IScheduledTask>(false)); - _httpServer.Init(GetExports<IRestfulService>(false)); + httpServer.Init(GetExports<IRestfulService>(false)); } /// <summary> @@ -240,5 +239,13 @@ namespace MediaBrowser.ServerApplication // Include composable parts in the running assembly yield return GetType().Assembly; } + + /// <summary> + /// Shuts down. + /// </summary> + public void Shutdown() + { + App.Instance.Shutdown(); + } } } diff --git a/MediaBrowser.WebDashboard/Html/css/site.css b/MediaBrowser.WebDashboard/Html/css/site.css index 32818e3cc..3e32d4e1f 100644 --- a/MediaBrowser.WebDashboard/Html/css/site.css +++ b/MediaBrowser.WebDashboard/Html/css/site.css @@ -293,10 +293,6 @@ form, .readOnlyContent { right: 30px;
}
- .localnav .ui-btn-inner {
- font-size: 16px;
- }
-
.libraryPage .ui-content {
padding-right: 50px;
padding-left: 50px;
diff --git a/Nuget/MediaBrowser.ApiClient.nuspec b/Nuget/MediaBrowser.ApiClient.nuspec index 3d6ec3a31..a13bfd84c 100644 --- a/Nuget/MediaBrowser.ApiClient.nuspec +++ b/Nuget/MediaBrowser.ApiClient.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd"> <metadata> <id>MediaBrowser.ApiClient</id> - <version>3.0.0.6-beta</version> + <version>3.0.0.7-beta</version> <title>MediaBrowser.ApiClient</title> <authors>Media Browser Team</authors> <owners>scottisafool,Luke</owners> diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 6fc5414b6..d215e503b 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>MediaBrowser.Common.Internal</id> - <version>3.0.6</version> + <version>3.0.7</version> <title /> <authors>Luke</authors> <owners>Media Browser Team</owners> @@ -10,7 +10,7 @@ <requireLicenseAcceptance>false</requireLicenseAcceptance> <description>Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption.</description> <dependencies> - <dependency id="MediaBrowser.Common" version="3.0.6" /> + <dependency id="MediaBrowser.Common" version="3.0.7" /> <dependency id="NLog" version="2.0.0.2000" /> <dependency id="ServiceStack" version="3.9.37" /> <dependency id="ServiceStack.Api.Swagger" version="3.9.35" /> diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 1044fd633..c529f29a3 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>MediaBrowser.Common</id> - <version>3.0.6</version> + <version>3.0.7</version> <title>MediaBrowser.Common</title> <authors>Media Browser Team</authors> <owners /> diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index b152a5d3e..d07345f09 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>MediaBrowser.Server.Core</id> - <version>3.0.6</version> + <version>3.0.7</version> <title>Media Browser.Server.Core</title> <authors>Media Browser Team</authors> <owners /> @@ -10,7 +10,7 @@ <requireLicenseAcceptance>false</requireLicenseAcceptance> <description>Contains core components required to build plugins for Media Browser Server.</description> <dependencies> - <dependency id="MediaBrowser.Common" version="3.0.6" /> + <dependency id="MediaBrowser.Common" version="3.0.7" /> </dependencies> </metadata> <files> |
