diff options
| author | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-23 17:31:51 -0500 |
|---|---|---|
| committer | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-23 17:31:51 -0500 |
| commit | 2e4db7554041ecf481d3a38656fccc309e13eb5b (patch) | |
| tree | 73c064988db630f97edc18bbc3ea5fac9132483b | |
| parent | 1a423c43b4284848e155fc4a060ef7061b084ed8 (diff) | |
extracted http server, web socket server and udp server dependancies
39 files changed, 890 insertions, 356 deletions
diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index 08e8c3e75..28ccd8602 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -504,8 +504,8 @@ namespace MediaBrowser.Common.Kernel /// <param name="container">The container.</param> protected virtual void RegisterExportedValues() { - ApplicationHost.Register<IKernel>(this); - ApplicationHost.Register(TaskManager); + ApplicationHost.RegisterSingleInstance<IKernel>(this); + ApplicationHost.RegisterSingleInstance(TaskManager); } /// <summary> diff --git a/MediaBrowser.Common/Kernel/IApplicationHost.cs b/MediaBrowser.Common/Kernel/IApplicationHost.cs index dccb65b2a..fe2f00a12 100644 --- a/MediaBrowser.Common/Kernel/IApplicationHost.cs +++ b/MediaBrowser.Common/Kernel/IApplicationHost.cs @@ -56,9 +56,23 @@ namespace MediaBrowser.Common.Kernel /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj">The obj.</param> - void Register<T>(T obj) where T : class; + void RegisterSingleInstance<T>(T obj) where T : class; /// <summary> + /// Registers the single instance. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="func">The func.</param> + void RegisterSingleInstance<T>(Func<T> func) where T : class; + + /// <summary> + /// Registers the specified func. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="func">The func.</param> + void Register<T>(Func<T> func) where T : class; + + /// <summary> /// Registers the specified service type. /// </summary> /// <param name="serviceType">Type of the service.</param> diff --git a/MediaBrowser.Common/Kernel/TcpManager.cs b/MediaBrowser.Common/Kernel/TcpManager.cs index 0b171c492..9a998823f 100644 --- a/MediaBrowser.Common/Kernel/TcpManager.cs +++ b/MediaBrowser.Common/Kernel/TcpManager.cs @@ -1,6 +1,4 @@ -using Alchemy; -using Alchemy.Classes; -using MediaBrowser.Common.Net; +using MediaBrowser.Common.Net; using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; @@ -28,20 +26,14 @@ namespace MediaBrowser.Common.Kernel /// This is the udp server used for server discovery by clients /// </summary> /// <value>The UDP server.</value> - private UdpServer UdpServer { get; set; } - - /// <summary> - /// Gets or sets the UDP listener. - /// </summary> - /// <value>The UDP listener.</value> - private IDisposable UdpListener { get; set; } + private IUdpServer UdpServer { get; set; } /// <summary> /// Both the Ui and server will have a built-in HttpServer. /// People will inevitably want remote control apps so it's needed in the Ui too. /// </summary> /// <value>The HTTP server.</value> - public HttpServer HttpServer { get; private set; } + private IHttpServer HttpServer { get; set; } /// <summary> /// This subscribes to HttpListener requests and finds the appropriate BaseHandler to process it @@ -58,7 +50,7 @@ namespace MediaBrowser.Common.Kernel /// Gets or sets the external web socket server. /// </summary> /// <value>The external web socket server.</value> - private WebSocketServer ExternalWebSocketServer { get; set; } + private IWebSocketServer ExternalWebSocketServer { get; set; } /// <summary> /// The _logger @@ -69,46 +61,24 @@ namespace MediaBrowser.Common.Kernel /// The _network manager /// </summary> private readonly INetworkManager _networkManager; - + /// <summary> /// The _application host /// </summary> private readonly IApplicationHost _applicationHost; - - /// <summary> - /// The _supports native web socket - /// </summary> - private bool? _supportsNativeWebSocket; /// <summary> /// The _kernel /// </summary> private readonly IKernel _kernel; - + /// <summary> /// 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 { - get - { - if (!_supportsNativeWebSocket.HasValue) - { - try - { - new ClientWebSocket(); - - _supportsNativeWebSocket = true; - } - catch (PlatformNotSupportedException) - { - _supportsNativeWebSocket = false; - } - } - - return _supportsNativeWebSocket.Value; - } + get { return HttpServer != null && HttpServer.SupportsWebSockets; } } /// <summary> @@ -145,7 +115,7 @@ namespace MediaBrowser.Common.Kernel { throw new ArgumentNullException("logger"); } - + _logger = logger; _kernel = kernel; _applicationHost = applicationHost; @@ -178,26 +148,10 @@ namespace MediaBrowser.Common.Kernel DisposeExternalWebSocketServer(); - ExternalWebSocketServer = new WebSocketServer(_kernel.Configuration.LegacyWebSocketPortNumber, IPAddress.Any) - { - OnConnected = OnAlchemyWebSocketClientConnected, - TimeOut = TimeSpan.FromMinutes(60) - }; - - ExternalWebSocketServer.Start(); + ExternalWebSocketServer = _applicationHost.Resolve<IWebSocketServer>(); - _logger.Info("Alchemy Web Socket Server started"); - } - - /// <summary> - /// Called when [alchemy web socket client connected]. - /// </summary> - /// <param name="context">The context.</param> - private void OnAlchemyWebSocketClientConnected(UserContext context) - { - var connection = new WebSocketConnection(new AlchemyWebSocket(context, _logger), context.ClientAddress, ProcessWebSocketMessageReceived, _logger); - - _webSocketConnections.Add(connection); + ExternalWebSocketServer.Start(_kernel.Configuration.LegacyWebSocketPortNumber); + ExternalWebSocketServer.WebSocketConnected += HttpServer_WebSocketConnected; } /// <summary> @@ -218,7 +172,9 @@ namespace MediaBrowser.Common.Kernel try { - HttpServer = new HttpServer(_kernel.HttpServerUrlPrefix, "Media Browser", _applicationHost, _kernel, _logger); + HttpServer = _applicationHost.Resolve<IHttpServer>(); + HttpServer.EnableHttpRequestLogging = _kernel.Configuration.EnableHttpLevelLogging; + HttpServer.Start(_kernel.HttpServerUrlPrefix); } catch (HttpListenerException ex) { @@ -295,7 +251,8 @@ namespace MediaBrowser.Common.Kernel try { // The port number can't be in configuration because we don't want it to ever change - UdpServer = new UdpServer(new IPEndPoint(IPAddress.Any, _kernel.UdpServerPortNumber)); + UdpServer = _applicationHost.Resolve<IUdpServer>(); + UdpServer.Start(_kernel.UdpServerPortNumber); } catch (SocketException ex) { @@ -303,21 +260,28 @@ namespace MediaBrowser.Common.Kernel return; } - UdpListener = UdpServer.Subscribe(async res => - { - var expectedMessage = String.Format("who is MediaBrowser{0}?", _kernel.KernelContext); - var expectedMessageBytes = Encoding.UTF8.GetBytes(expectedMessage); + UdpServer.MessageReceived += UdpServer_MessageReceived; + } - if (expectedMessageBytes.SequenceEqual(res.Buffer)) - { - _logger.Info("Received UDP server request from " + res.RemoteEndPoint.ToString()); + /// <summary> + /// Handles the MessageReceived event of the UdpServer control. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="UdpMessageReceivedEventArgs" /> instance containing the event data.</param> + async void UdpServer_MessageReceived(object sender, UdpMessageReceivedEventArgs e) + { + var expectedMessage = String.Format("who is MediaBrowser{0}?", _kernel.KernelContext); + var expectedMessageBytes = Encoding.UTF8.GetBytes(expectedMessage); - // Send a response back with our ip address and port - var response = String.Format("MediaBrowser{0}|{1}:{2}", _kernel.KernelContext, _networkManager.GetLocalIpAddress(), _kernel.UdpServerPortNumber); + if (expectedMessageBytes.SequenceEqual(e.Bytes)) + { + _logger.Info("Received UDP server request from " + e.RemoteEndPoint); - await UdpServer.SendAsync(response, res.RemoteEndPoint); - } - }); + // Send a response back with our ip address and port + var response = String.Format("MediaBrowser{0}|{1}:{2}", _kernel.KernelContext, _networkManager.GetLocalIpAddress(), _kernel.UdpServerPortNumber); + + await UdpServer.SendAsync(Encoding.UTF8.GetBytes(response), e.RemoteEndPoint); + } } /// <summary> @@ -407,13 +371,9 @@ namespace MediaBrowser.Common.Kernel { if (UdpServer != null) { + UdpServer.MessageReceived -= UdpServer_MessageReceived; UdpServer.Dispose(); } - - if (UdpListener != null) - { - UdpListener.Dispose(); - } } /// <summary> @@ -523,6 +483,8 @@ namespace MediaBrowser.Common.Kernel /// <param name="newConfig">The new config.</param> public void OnApplicationConfigurationChanged(BaseApplicationConfiguration oldConfig, BaseApplicationConfiguration newConfig) { + HttpServer.EnableHttpRequestLogging = newConfig.EnableHttpLevelLogging; + if (oldConfig.HttpServerPortNumber != newConfig.HttpServerPortNumber) { ReloadHttpServer(); diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 57b30eedc..28789a816 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -38,13 +38,6 @@ </ApplicationIcon> </PropertyGroup> <ItemGroup> - <Reference Include="Alchemy"> - <HintPath>..\packages\Alchemy.2.2.1\lib\net40\Alchemy.dll</HintPath> - </Reference> - <Reference Include="NLog"> - <HintPath>..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll</HintPath> - </Reference> - <Reference Include="PresentationCore" /> <Reference Include="protobuf-net, Version=2.0.0.621, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\protobuf-net.2.0.0.621\lib\net40\protobuf-net.dll</HintPath> @@ -53,9 +46,6 @@ <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.dll</HintPath> </Reference> - <Reference Include="ServiceStack.Api.Swagger"> - <HintPath>..\packages\ServiceStack.Api.Swagger.3.9.35\lib\net35\ServiceStack.Api.Swagger.dll</HintPath> - </Reference> <Reference Include="ServiceStack.Common, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Common.dll</HintPath> @@ -64,9 +54,6 @@ <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Interfaces.dll</HintPath> </Reference> - <Reference Include="ServiceStack.Logging.NLog"> - <HintPath>..\packages\ServiceStack.Logging.NLog.1.0.6.0\lib\net35\ServiceStack.Logging.NLog.dll</HintPath> - </Reference> <Reference Include="ServiceStack.OrmLite, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.dll</HintPath> @@ -93,18 +80,6 @@ <Reference Include="System.Net" /> <Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http.WebRequest" /> - <Reference Include="System.Reactive.Core, Version=2.0.20823.0, Culture=neutral, PublicKeyToken=f300afd708cefcd3, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Rx-Core.2.0.21114\lib\Net45\System.Reactive.Core.dll</HintPath> - </Reference> - <Reference Include="System.Reactive.Interfaces, Version=2.0.20823.0, Culture=neutral, PublicKeyToken=f300afd708cefcd3, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Rx-Interfaces.2.0.21114\lib\Net45\System.Reactive.Interfaces.dll</HintPath> - </Reference> - <Reference Include="System.Reactive.Linq, Version=2.0.20823.0, Culture=neutral, PublicKeyToken=f300afd708cefcd3, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Rx-Linq.2.0.21114\lib\Net45\System.Reactive.Linq.dll</HintPath> - </Reference> <Reference Include="System.Web" /> <Reference Include="Microsoft.CSharp" /> <Reference Include="System.Xml" /> @@ -129,19 +104,21 @@ <Compile Include="Kernel\IApplicationHost.cs" /> <Compile Include="Kernel\IKernel.cs" /> <Compile Include="Kernel\TcpManager.cs" /> - <Compile Include="Net\AlchemyWebSocket.cs" /> <Compile Include="Net\BaseRestService.cs" /> <Compile Include="Net\Handlers\BaseActionHandler.cs" /> <Compile Include="Net\Handlers\IHttpServerHandler.cs" /> <Compile Include="Net\Handlers\StaticFileHandler.cs" /> <Compile Include="Net\HttpManager.cs" /> + <Compile Include="Net\IHttpServer.cs" /> <Compile Include="Net\INetworkManager.cs" /> <Compile Include="Net\IRestfulService.cs" /> <Compile Include="Net\IUdpServer.cs" /> <Compile Include="Net\IWebSocket.cs" /> + <Compile Include="Net\IWebSocketServer.cs" /> <Compile Include="Net\MimeTypes.cs" /> <Compile Include="Net\NativeWebSocket.cs" /> - <Compile Include="Net\UdpServer.cs" /> + <Compile Include="Net\UdpMessageReceivedEventArgs.cs" /> + <Compile Include="Net\WebSocketConnectEventArgs.cs" /> <Compile Include="Net\WebSocketConnection.cs" /> <Compile Include="Plugins\BaseUiPlugin.cs" /> <Compile Include="Plugins\IPlugin.cs" /> @@ -165,7 +142,6 @@ <Compile Include="Kernel\KernelContext.cs" /> <Compile Include="Net\Handlers\BaseHandler.cs" /> <Compile Include="Net\Handlers\BaseSerializationHandler.cs" /> - <Compile Include="Net\HttpServer.cs" /> <Compile Include="Plugins\BasePlugin.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Serialization\XmlSerializer.cs" /> @@ -196,23 +172,6 @@ <SubType>Designer</SubType> </EmbeddedResource> </ItemGroup> - <ItemGroup> - <Resource Include="README.txt" /> - <Content Include="swagger-ui\css\screen.css" /> - <Resource Include="swagger-ui\images\pet_store_api.png" /> - <Resource Include="swagger-ui\images\wordnik_api.png" /> - <Content Include="swagger-ui\index.html" /> - <Content Include="swagger-ui\lib\backbone-min.js" /> - <Content Include="swagger-ui\lib\handlebars.runtime-1.0.0.beta.6.js" /> - <Content Include="swagger-ui\lib\jquery.ba-bbq.min.js" /> - <Content Include="swagger-ui\lib\jquery.min.js" /> - <Content Include="swagger-ui\lib\jquery.slideto.min.js" /> - <Content Include="swagger-ui\lib\jquery.wiggle.min.js" /> - <Content Include="swagger-ui\lib\swagger.js" /> - <Content Include="swagger-ui\lib\underscore-min.js" /> - <Content Include="swagger-ui\swagger-ui.js" /> - <Content Include="swagger-ui\swagger-ui.min.js" /> - </ItemGroup> <ItemGroup /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(SolutionDir)\.nuget\nuget.targets" /> diff --git a/MediaBrowser.Common/Net/IHttpServer.cs b/MediaBrowser.Common/Net/IHttpServer.cs new file mode 100644 index 000000000..a640fb262 --- /dev/null +++ b/MediaBrowser.Common/Net/IHttpServer.cs @@ -0,0 +1,44 @@ +using System; + +namespace MediaBrowser.Common.Net +{ + /// <summary> + /// Interface IHttpServer + /// </summary> + public interface IHttpServer : IDisposable + { + /// <summary> + /// Gets the URL prefix. + /// </summary> + /// <value>The URL prefix.</value> + string UrlPrefix { get; } + + /// <summary> + /// Starts the specified server name. + /// </summary> + /// <param name="urlPrefix">The URL.</param> + void Start(string urlPrefix); + + /// <summary> + /// Gets a value indicating whether [supports web sockets]. + /// </summary> + /// <value><c>true</c> if [supports web sockets]; otherwise, <c>false</c>.</value> + bool SupportsWebSockets { get; } + + /// <summary> + /// Stops this instance. + /// </summary> + void Stop(); + + /// <summary> + /// Gets or sets a value indicating whether [enable HTTP request logging]. + /// </summary> + /// <value><c>true</c> if [enable HTTP request logging]; otherwise, <c>false</c>.</value> + bool EnableHttpRequestLogging { get; set; } + + /// <summary> + /// Occurs when [web socket connected]. + /// </summary> + event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; + } +}
\ No newline at end of file diff --git a/MediaBrowser.Common/Net/IUdpServer.cs b/MediaBrowser.Common/Net/IUdpServer.cs index 01a8ef021..036977eab 100644 --- a/MediaBrowser.Common/Net/IUdpServer.cs +++ b/MediaBrowser.Common/Net/IUdpServer.cs @@ -1,7 +1,46 @@ - +using System; +using System.Threading.Tasks; + namespace MediaBrowser.Common.Net { - public interface IUdpServer + /// <summary> + /// Interface IUdpServer + /// </summary> + public interface IUdpServer : IDisposable { + /// <summary> + /// Occurs when [message received]. + /// </summary> + event EventHandler<UdpMessageReceivedEventArgs> MessageReceived; + + /// <summary> + /// Starts the specified port. + /// </summary> + /// <param name="port">The port.</param> + void Start(int port); + + /// <summary> + /// Stops this instance. + /// </summary> + void Stop(); + + /// <summary> + /// Sends the async. + /// </summary> + /// <param name="bytes">The bytes.</param> + /// <param name="remoteEndPoint">The remote end point.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException">data</exception> + Task SendAsync(byte[] bytes, string remoteEndPoint); + + /// <summary> + /// Sends the async. + /// </summary> + /// <param name="bytes">The bytes.</param> + /// <param name="ipAddress">The ip address.</param> + /// <param name="port">The port.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException">bytes</exception> + Task SendAsync(byte[] bytes, string ipAddress, int port); } } diff --git a/MediaBrowser.Common/Net/IWebSocketServer.cs b/MediaBrowser.Common/Net/IWebSocketServer.cs new file mode 100644 index 000000000..5ce571fbb --- /dev/null +++ b/MediaBrowser.Common/Net/IWebSocketServer.cs @@ -0,0 +1,26 @@ +using System; + +namespace MediaBrowser.Common.Net +{ + /// <summary> + /// Interface IWebSocketServer + /// </summary> + public interface IWebSocketServer : IDisposable + { + /// <summary> + /// Starts the specified port number. + /// </summary> + /// <param name="portNumber">The port number.</param> + void Start(int portNumber); + + /// <summary> + /// Stops this instance. + /// </summary> + void Stop(); + + /// <summary> + /// Occurs when [web socket connected]. + /// </summary> + event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; + } +} diff --git a/MediaBrowser.Common/Net/UdpMessageReceivedEventArgs.cs b/MediaBrowser.Common/Net/UdpMessageReceivedEventArgs.cs new file mode 100644 index 000000000..bd5034c47 --- /dev/null +++ b/MediaBrowser.Common/Net/UdpMessageReceivedEventArgs.cs @@ -0,0 +1,21 @@ +using System; + +namespace MediaBrowser.Common.Net +{ + /// <summary> + /// Class UdpMessageReceivedEventArgs + /// </summary> + public class UdpMessageReceivedEventArgs : EventArgs + { + /// <summary> + /// Gets or sets the bytes. + /// </summary> + /// <value>The bytes.</value> + public byte[] Bytes { get; set; } + /// <summary> + /// Gets or sets the remote end point. + /// </summary> + /// <value>The remote end point.</value> + public string RemoteEndPoint { get; set; } + } +} diff --git a/MediaBrowser.Common/Net/UdpServer.cs b/MediaBrowser.Common/Net/UdpServer.cs deleted file mode 100644 index a3c6a8a78..000000000 --- a/MediaBrowser.Common/Net/UdpServer.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Reactive.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Net -{ - /// <summary> - /// Provides a Udp Server - /// </summary> - public class UdpServer : IObservable<UdpReceiveResult>, IDisposable - { - /// <summary> - /// The _udp client - /// </summary> - private readonly UdpClient _udpClient; - /// <summary> - /// The _stream - /// </summary> - private readonly IObservable<UdpReceiveResult> _stream; - - /// <summary> - /// Initializes a new instance of the <see cref="UdpServer" /> class. - /// </summary> - /// <param name="endPoint">The end point.</param> - /// <exception cref="System.ArgumentNullException">endPoint</exception> - public UdpServer(IPEndPoint endPoint) - { - if (endPoint == null) - { - throw new ArgumentNullException("endPoint"); - } - - _udpClient = new UdpClient(endPoint); - - _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - //_udpClient.ExclusiveAddressUse = false; - - _stream = CreateObservable(); - } - - /// <summary> - /// Creates the observable. - /// </summary> - /// <returns>IObservable{UdpReceiveResult}.</returns> - private IObservable<UdpReceiveResult> CreateObservable() - { - return Observable.Create<UdpReceiveResult>(obs => - Observable.FromAsync(() => _udpClient.ReceiveAsync()) - .Subscribe(obs)) - .Repeat() - .Retry() - .Publish() - .RefCount(); - } - - /// <summary> - /// Subscribes the specified observer. - /// </summary> - /// <param name="observer">The observer.</param> - /// <returns>IDisposable.</returns> - /// <exception cref="System.ArgumentNullException">observer</exception> - public IDisposable Subscribe(IObserver<UdpReceiveResult> observer) - { - if (observer == null) - { - throw new ArgumentNullException("observer"); - } - - return _stream.Subscribe(observer); - } - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <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) - { - _udpClient.Close(); - } - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="data">The data.</param> - /// <param name="endPoint">The end point.</param> - /// <returns>Task{System.Int32}.</returns> - /// <exception cref="System.ArgumentNullException">data</exception> - public async Task<int> SendAsync(string data, IPEndPoint endPoint) - { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - if (endPoint == null) - { - throw new ArgumentNullException("endPoint"); - } - - var bytes = Encoding.UTF8.GetBytes(data); - - return await _udpClient.SendAsync(bytes, bytes.Length, endPoint).ConfigureAwait(false); - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="bytes">The bytes.</param> - /// <param name="endPoint">The end point.</param> - /// <returns>Task{System.Int32}.</returns> - /// <exception cref="System.ArgumentNullException">bytes</exception> - public async Task<int> SendAsync(byte[] bytes, IPEndPoint endPoint) - { - if (bytes == null) - { - throw new ArgumentNullException("bytes"); - } - - if (endPoint == null) - { - throw new ArgumentNullException("endPoint"); - } - - return await _udpClient.SendAsync(bytes, bytes.Length, endPoint).ConfigureAwait(false); - } - } -} diff --git a/MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs b/MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs new file mode 100644 index 000000000..711da7a50 --- /dev/null +++ b/MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs @@ -0,0 +1,22 @@ +using System; +using System.Net; + +namespace MediaBrowser.Common.Net +{ + /// <summary> + /// Class WebSocketConnectEventArgs + /// </summary> + public class WebSocketConnectEventArgs : EventArgs + { + /// <summary> + /// Gets or sets the web socket. + /// </summary> + /// <value>The web socket.</value> + public IWebSocket WebSocket { get; set; } + /// <summary> + /// Gets or sets the endpoint. + /// </summary> + /// <value>The endpoint.</value> + public string Endpoint { get; set; } + } +} diff --git a/MediaBrowser.Common/Net/WebSocketConnection.cs b/MediaBrowser.Common/Net/WebSocketConnection.cs index d274d390d..ab691c823 100644 --- a/MediaBrowser.Common/Net/WebSocketConnection.cs +++ b/MediaBrowser.Common/Net/WebSocketConnection.cs @@ -21,7 +21,7 @@ namespace MediaBrowser.Common.Net /// <summary> /// The _remote end point /// </summary> - public readonly EndPoint RemoteEndPoint; + public readonly string RemoteEndPoint; /// <summary> /// The _cancellation token source @@ -45,13 +45,13 @@ namespace MediaBrowser.Common.Net /// <param name="remoteEndPoint">The remote end point.</param> /// <param name="receiveAction">The receive action.</param> /// <exception cref="System.ArgumentNullException">socket</exception> - public WebSocketConnection(IWebSocket socket, EndPoint remoteEndPoint, Action<WebSocketMessageInfo> receiveAction, ILogger logger) + public WebSocketConnection(IWebSocket socket, string remoteEndPoint, Action<WebSocketMessageInfo> receiveAction, ILogger logger) { if (socket == null) { throw new ArgumentNullException("socket"); } - if (remoteEndPoint == null) + if (string.IsNullOrEmpty(remoteEndPoint)) { throw new ArgumentNullException("remoteEndPoint"); } diff --git a/MediaBrowser.Common/packages.config b/MediaBrowser.Common/packages.config index 536640094..0ebaf6297 100644 --- a/MediaBrowser.Common/packages.config +++ b/MediaBrowser.Common/packages.config @@ -1,15 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="Alchemy" version="2.2.1" targetFramework="net45" /> - <package id="NLog" version="2.0.0.2000" targetFramework="net45" /> <package id="protobuf-net" version="2.0.0.621" targetFramework="net45" /> - <package id="Rx-Core" version="2.0.21114" targetFramework="net45" /> - <package id="Rx-Interfaces" version="2.0.21114" targetFramework="net45" /> - <package id="Rx-Linq" version="2.0.21114" targetFramework="net45" /> <package id="ServiceStack" version="3.9.37" targetFramework="net45" /> - <package id="ServiceStack.Api.Swagger" version="3.9.35" targetFramework="net45" /> <package id="ServiceStack.Common" version="3.9.37" targetFramework="net45" /> - <package id="ServiceStack.Logging.NLog" version="1.0.6.0" targetFramework="net45" /> <package id="ServiceStack.OrmLite.SqlServer" version="3.9.37" targetFramework="net45" /> <package id="ServiceStack.Redis" version="3.9.37" targetFramework="net45" /> <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" /> diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index 21cfb5ddb..5ee590bde 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -315,7 +315,7 @@ namespace MediaBrowser.Controller /// </summary> protected override void RegisterExportedValues() { - ApplicationHost.Register(this); + ApplicationHost.RegisterSingleInstance(this); base.RegisterExportedValues(); } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 070120563..35540020e 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -69,7 +69,6 @@ <Reference Include="System.Drawing" /> <Reference Include="System.Net" /> <Reference Include="System.Runtime.Serialization" /> - <Reference Include="System.Xml.Linq" /> <Reference Include="Microsoft.CSharp" /> <Reference Include="System.Xml" /> </ItemGroup> diff --git a/MediaBrowser.Networking/Management/NetworkManager.cs b/MediaBrowser.Networking/Management/NetworkManager.cs index fcead43d3..208c64a6e 100644 --- a/MediaBrowser.Networking/Management/NetworkManager.cs +++ b/MediaBrowser.Networking/Management/NetworkManager.cs @@ -260,6 +260,118 @@ namespace MediaBrowser.Networking.Management throw new ArgumentException("Unknown share type"); } } + + /// <summary> + /// Parses the specified endpointstring. + /// </summary> + /// <param name="endpointstring">The endpointstring.</param> + /// <returns>IPEndPoint.</returns> + public IPEndPoint Parse(string endpointstring) + { + return Parse(endpointstring, -1); + } + + /// <summary> + /// Parses the specified endpointstring. + /// </summary> + /// <param name="endpointstring">The endpointstring.</param> + /// <param name="defaultport">The defaultport.</param> + /// <returns>IPEndPoint.</returns> + /// <exception cref="System.ArgumentException">Endpoint descriptor may not be empty.</exception> + /// <exception cref="System.FormatException"></exception> + private static IPEndPoint Parse(string endpointstring, int defaultport) + { + if (string.IsNullOrEmpty(endpointstring) + || endpointstring.Trim().Length == 0) + { + throw new ArgumentException("Endpoint descriptor may not be empty."); + } + + if (defaultport != -1 && + (defaultport < IPEndPoint.MinPort + || defaultport > IPEndPoint.MaxPort)) + { + throw new ArgumentException(string.Format("Invalid default port '{0}'", defaultport)); + } + + string[] values = endpointstring.Split(new char[] { ':' }); + IPAddress ipaddy; + int port = -1; + + //check if we have an IPv6 or ports + if (values.Length <= 2) // ipv4 or hostname + { + if (values.Length == 1) + //no port is specified, default + port = defaultport; + else + port = GetPort(values[1]); + + //try to use the address as IPv4, otherwise get hostname + if (!IPAddress.TryParse(values[0], out ipaddy)) + ipaddy = GetIPfromHost(values[0]); + } + else if (values.Length > 2) //ipv6 + { + //could [a:b:c]:d + if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]")) + { + string ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray()); + ipaddy = IPAddress.Parse(ipaddressstring); + port = GetPort(values[values.Length - 1]); + } + else //[a:b:c] or a:b:c + { + ipaddy = IPAddress.Parse(endpointstring); + port = defaultport; + } + } + else + { + throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", endpointstring)); + } + + if (port == -1) + throw new ArgumentException(string.Format("No port specified: '{0}'", endpointstring)); + + return new IPEndPoint(ipaddy, port); + } + + /// <summary> + /// Gets the port. + /// </summary> + /// <param name="p">The p.</param> + /// <returns>System.Int32.</returns> + /// <exception cref="System.FormatException"></exception> + private static int GetPort(string p) + { + int port; + + if (!int.TryParse(p, out port) + || port < IPEndPoint.MinPort + || port > IPEndPoint.MaxPort) + { + throw new FormatException(string.Format("Invalid end point port '{0}'", p)); + } + + return port; + } + + /// <summary> + /// Gets the I pfrom host. + /// </summary> + /// <param name="p">The p.</param> + /// <returns>IPAddress.</returns> + /// <exception cref="System.ArgumentException"></exception> + private static IPAddress GetIPfromHost(string p) + { + var hosts = Dns.GetHostAddresses(p); + + if (hosts == null || hosts.Length == 0) + throw new ArgumentException(string.Format("Host not found: {0}", p)); + + return hosts[0]; + } } } diff --git a/MediaBrowser.Networking/MediaBrowser.Networking.csproj b/MediaBrowser.Networking/MediaBrowser.Networking.csproj index 194f9e400..7e4a0b160 100644 --- a/MediaBrowser.Networking/MediaBrowser.Networking.csproj +++ b/MediaBrowser.Networking/MediaBrowser.Networking.csproj @@ -11,6 +11,8 @@ <AssemblyName>MediaBrowser.Networking</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> + <RestorePackages>true</RestorePackages> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> @@ -30,9 +32,68 @@ <WarningLevel>4</WarningLevel> </PropertyGroup> <ItemGroup> + <Reference Include="Alchemy, Version=2.2.0.238, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Alchemy.2.2.1\lib\net40\Alchemy.dll</HintPath> + </Reference> + <Reference Include="NLog, Version=2.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll</HintPath> + </Reference> + <Reference Include="ServiceStack, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.Api.Swagger, Version=3.9.35.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.Api.Swagger.3.9.35\lib\net35\ServiceStack.Api.Swagger.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.Common, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Common.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.Interfaces, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Interfaces.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.Logging.NLog, Version=1.0.6.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.Logging.NLog.1.0.6.0\lib\net35\ServiceStack.Logging.NLog.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.OrmLite, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.OrmLite.SqlServer"> + <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.SqlServer.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.Redis"> + <HintPath>..\packages\ServiceStack.Redis.3.9.37\lib\net35\ServiceStack.Redis.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.ServiceInterface, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.ServiceInterface.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.Text, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Management" /> + <Reference Include="System.Reactive.Core, Version=2.0.20823.0, Culture=neutral, PublicKeyToken=f300afd708cefcd3, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Rx-Core.2.0.21114\lib\Net45\System.Reactive.Core.dll</HintPath> + </Reference> + <Reference Include="System.Reactive.Interfaces, Version=2.0.20823.0, Culture=neutral, PublicKeyToken=f300afd708cefcd3, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Rx-Interfaces.2.0.21114\lib\Net45\System.Reactive.Interfaces.dll</HintPath> + </Reference> + <Reference Include="System.Reactive.Linq, Version=2.0.20823.0, Culture=neutral, PublicKeyToken=f300afd708cefcd3, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Rx-Linq.2.0.21114\lib\Net45\System.Reactive.Linq.dll</HintPath> + </Reference> + <Reference Include="System.Web" /> <Reference Include="System.Xml.Linq" /> <Reference Include="System.Data.DataSetExtensions" /> <Reference Include="Microsoft.CSharp" /> @@ -43,6 +104,10 @@ <Compile Include="..\SharedVersion.cs"> <Link>Properties\SharedVersion.cs</Link> </Compile> + <Compile Include="Udp\UdpServer.cs" /> + <Compile Include="WebSocket\AlchemyServer.cs" /> + <Compile Include="WebSocket\AlchemyWebSocket.cs" /> + <Compile Include="Web\HttpServer.cs" /> <Compile Include="Management\NativeMethods.cs" /> <Compile Include="Management\NetworkManager.cs" /> <Compile Include="Management\NetworkShares.cs" /> @@ -58,10 +123,31 @@ <Name>MediaBrowser.Model</Name> </ProjectReference> </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + <Content Include="README.txt" /> + <Content Include="swagger-ui\css\screen.css" /> + <Content Include="swagger-ui\images\pet_store_api.png" /> + <Content Include="swagger-ui\images\wordnik_api.png" /> + <Content Include="swagger-ui\index.html" /> + <Content Include="swagger-ui\lib\backbone-min.js" /> + <Content Include="swagger-ui\lib\handlebars.runtime-1.0.0.beta.6.js" /> + <Content Include="swagger-ui\lib\jquery.ba-bbq.min.js" /> + <Content Include="swagger-ui\lib\jquery.min.js" /> + <Content Include="swagger-ui\lib\jquery.slideto.min.js" /> + <Content Include="swagger-ui\lib\jquery.wiggle.min.js" /> + <Content Include="swagger-ui\lib\swagger.js" /> + <Content Include="swagger-ui\lib\underscore-min.js" /> + <Content Include="swagger-ui\swagger-ui.js" /> + <Content Include="swagger-ui\swagger-ui.min.js" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <PropertyGroup> <PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i</PostBuildEvent> </PropertyGroup> + <Import Project="$(SolutionDir)\.nuget\nuget.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. <Target Name="BeforeBuild"> diff --git a/MediaBrowser.Common/README.txt b/MediaBrowser.Networking/README.txt index e8ce34205..e8ce34205 100644 --- a/MediaBrowser.Common/README.txt +++ b/MediaBrowser.Networking/README.txt diff --git a/MediaBrowser.Networking/Udp/UdpServer.cs b/MediaBrowser.Networking/Udp/UdpServer.cs new file mode 100644 index 000000000..9b1c254cf --- /dev/null +++ b/MediaBrowser.Networking/Udp/UdpServer.cs @@ -0,0 +1,167 @@ +using MediaBrowser.Common.Net; +using MediaBrowser.Networking.Management; +using System; +using System.Net; +using System.Net.Sockets; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MediaBrowser.Networking.Udp +{ + /// <summary> + /// Provides a Udp Server + /// </summary> + public class UdpServer : IUdpServer + { + /// <summary> + /// Occurs when [message received]. + /// </summary> + public event EventHandler<UdpMessageReceivedEventArgs> MessageReceived; + + /// <summary> + /// Raises the <see cref="E:MessageReceived" /> event. + /// </summary> + /// <param name="e">The <see cref="UdpMessageReceivedEventArgs" /> instance containing the event data.</param> + protected virtual void OnMessageReceived(UdpMessageReceivedEventArgs e) + { + EventHandler<UdpMessageReceivedEventArgs> handler = MessageReceived; + if (handler != null) handler(this, e); + } + + /// <summary> + /// The _udp client + /// </summary> + private UdpClient _udpClient; + + /// <summary> + /// Starts the specified port. + /// </summary> + /// <param name="port">The port.</param> + public void Start(int port) + { + _udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, port)); + + _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + + CreateObservable().Subscribe(OnMessageReceived); + } + + /// <summary> + /// Creates the observable. + /// </summary> + /// <returns>IObservable{UdpReceiveResult}.</returns> + private IObservable<UdpReceiveResult> CreateObservable() + { + return Observable.Create<UdpReceiveResult>(obs => + Observable.FromAsync(() => _udpClient.ReceiveAsync()) + .Subscribe(obs)) + .Repeat() + .Retry() + .Publish() + .RefCount(); + } + + /// <summary> + /// Called when [message received]. + /// </summary> + /// <param name="message">The message.</param> + private void OnMessageReceived(UdpReceiveResult message) + { + var bytes = message.Buffer; + + OnMessageReceived(new UdpMessageReceivedEventArgs + { + Bytes = bytes, + RemoteEndPoint = message.RemoteEndPoint.ToString() + }); + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Stops this instance. + /// </summary> + public void Stop() + { + _udpClient.Close(); + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources. + /// </summary> + /// <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) + { + Stop(); + } + } + + /// <summary> + /// Sends the async. + /// </summary> + /// <param name="data">The data.</param> + /// <param name="ipAddress">The ip address.</param> + /// <param name="port">The port.</param> + /// <returns>Task{System.Int32}.</returns> + /// <exception cref="System.ArgumentNullException">data</exception> + public Task SendAsync(string data, string ipAddress, int port) + { + return SendAsync(Encoding.UTF8.GetBytes(data), ipAddress, port); + } + + /// <summary> + /// Sends the async. + /// </summary> + /// <param name="bytes">The bytes.</param> + /// <param name="ipAddress">The ip address.</param> + /// <param name="port">The port.</param> + /// <returns>Task{System.Int32}.</returns> + /// <exception cref="System.ArgumentNullException">bytes</exception> + public Task SendAsync(byte[] bytes, string ipAddress, int port) + { + if (bytes == null) + { + throw new ArgumentNullException("bytes"); + } + + if (string.IsNullOrEmpty(ipAddress)) + { + throw new ArgumentNullException("ipAddress"); + } + + return _udpClient.SendAsync(bytes, bytes.Length, ipAddress, port); + } + + /// <summary> + /// Sends the async. + /// </summary> + /// <param name="bytes">The bytes.</param> + /// <param name="remoteEndPoint">The remote end point.</param> + /// <returns>Task.</returns> + public Task SendAsync(byte[] bytes, string remoteEndPoint) + { + if (bytes == null) + { + throw new ArgumentNullException("bytes"); + } + + if (string.IsNullOrEmpty(remoteEndPoint)) + { + throw new ArgumentNullException("remoteEndPoint"); + } + + return _udpClient.SendAsync(bytes, bytes.Length, new NetworkManager().Parse(remoteEndPoint)); + } + } + +} diff --git a/MediaBrowser.Common/Net/HttpServer.cs b/MediaBrowser.Networking/Web/HttpServer.cs index 20ee615ad..c280abedf 100644 --- a/MediaBrowser.Common/Net/HttpServer.cs +++ b/MediaBrowser.Networking/Web/HttpServer.cs @@ -1,6 +1,8 @@ +using System.Net.WebSockets; using Funq; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; using ServiceStack.Api.Swagger; using ServiceStack.Common.Web; @@ -22,12 +24,12 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; -namespace MediaBrowser.Common.Net +namespace MediaBrowser.Networking.Web { /// <summary> /// Class HttpServer /// </summary> - public class HttpServer : HttpListenerBase + public class HttpServer : HttpListenerBase, IHttpServer { /// <summary> /// The logger @@ -51,7 +53,7 @@ namespace MediaBrowser.Common.Net /// </summary> /// <value>The application host.</value> private IApplicationHost ApplicationHost { get; set; } - + /// <summary> /// This subscribes to HttpListener requests and finds the appropriate BaseHandler to process it /// </summary> @@ -67,25 +69,26 @@ namespace MediaBrowser.Common.Net /// Gets the default redirect path. /// </summary> /// <value>The default redirect path.</value> - public string DefaultRedirectPath { get; private set; } + private string DefaultRedirectPath { get; set; } + + /// <summary> + /// Gets or sets the name of the server. + /// </summary> + /// <value>The name of the server.</value> + private string ServerName { get; set; } /// <summary> /// Initializes a new instance of the <see cref="HttpServer" /> class. /// </summary> - /// <param name="urlPrefix">The URL.</param> - /// <param name="serverName">Name of the product.</param> /// <param name="applicationHost">The application host.</param> /// <param name="kernel">The kernel.</param> /// <param name="logger">The logger.</param> + /// <param name="serverName">Name of the server.</param> /// <param name="defaultRedirectpath">The default redirectpath.</param> /// <exception cref="System.ArgumentNullException">urlPrefix</exception> - public HttpServer(string urlPrefix, string serverName, IApplicationHost applicationHost, IKernel kernel, ILogger logger, string defaultRedirectpath = null) + public HttpServer(IApplicationHost applicationHost, IKernel kernel, ILogger logger, string serverName, string defaultRedirectpath) : base() { - if (string.IsNullOrEmpty(urlPrefix)) - { - throw new ArgumentNullException("urlPrefix"); - } if (kernel == null) { throw new ArgumentNullException("kernel"); @@ -98,7 +101,16 @@ namespace MediaBrowser.Common.Net { throw new ArgumentNullException("applicationHost"); } + if (string.IsNullOrEmpty(serverName)) + { + throw new ArgumentNullException("serverName"); + } + if (string.IsNullOrEmpty(defaultRedirectpath)) + { + throw new ArgumentNullException("defaultRedirectpath"); + } + ServerName = serverName; DefaultRedirectPath = defaultRedirectpath; _logger = logger; ApplicationHost = applicationHost; @@ -106,34 +118,12 @@ namespace MediaBrowser.Common.Net EndpointHostConfig.Instance.ServiceStackHandlerFactoryPath = null; EndpointHostConfig.Instance.MetadataRedirectPath = "metadata"; - UrlPrefix = urlPrefix; Kernel = kernel; - EndpointHost.ConfigureHost(this, serverName, CreateServiceManager()); - + EndpointHost.ConfigureHost(this, ServerName, CreateServiceManager()); ContentTypeFilters.Register(ContentType.ProtoBuf, (reqCtx, res, stream) => Kernel.ProtobufSerializer.SerializeToStream(res, stream), (type, stream) => Kernel.ProtobufSerializer.DeserializeFromStream(stream, type)); Init(); - Start(urlPrefix); - } - - /// <summary> - /// Shut down the Web Service - /// </summary> - public override void Stop() - { - if (HttpListener != null) - { - HttpListener.Dispose(); - HttpListener = null; - } - - if (Listener != null) - { - Listener.Prefixes.Remove(UrlPrefix); - } - - base.Stop(); } /// <summary> @@ -142,24 +132,17 @@ namespace MediaBrowser.Common.Net /// <param name="container">The container.</param> public override void Configure(Container container) { - if (!string.IsNullOrEmpty(DefaultRedirectPath)) + SetConfig(new EndpointHostConfig { - SetConfig(new EndpointHostConfig - { - DefaultRedirectPath = DefaultRedirectPath, + DefaultRedirectPath = DefaultRedirectPath, - // Tell SS to bubble exceptions up to here - WriteErrorsToResponse = false, + // Tell SS to bubble exceptions up to here + WriteErrorsToResponse = false, - DebugMode = true - }); - } + DebugMode = true + }); container.Adapter = new ContainerAdapter(ApplicationHost); - - container.Register(Kernel); - container.Register(_logger); - container.Register(ApplicationHost); foreach (var service in Kernel.RestServices) { @@ -169,8 +152,6 @@ namespace MediaBrowser.Common.Net Plugins.Add(new SwaggerFeature()); Plugins.Add(new CorsFeature()); - Serialization.JsonSerializer.Configure(); - ServiceStack.Logging.LogManager.LogFactory = new NLogFactory(); } @@ -183,6 +164,11 @@ namespace MediaBrowser.Common.Net /// HttpListener.Prefixes property on MSDN.</param> public override void Start(string urlBase) { + if (string.IsNullOrEmpty(urlBase)) + { + throw new ArgumentNullException("urlBase"); + } + // *** Already running - just leave it in place if (IsStarted) { @@ -196,6 +182,8 @@ namespace MediaBrowser.Common.Net EndpointHost.Config.ServiceStackHandlerFactoryPath = HttpListenerRequestWrapper.GetHandlerPathIfAny(urlBase); + UrlPrefix = urlBase; + Listener.Prefixes.Add(urlBase); IsStarted = true; @@ -300,7 +288,7 @@ namespace MediaBrowser.Common.Net if (WebSocketConnected != null) { - WebSocketConnected(this, new WebSocketConnectEventArgs { WebSocket = new NativeWebSocket(webSocketContext.WebSocket, _logger), Endpoint = ctx.Request.RemoteEndPoint }); + WebSocketConnected(this, new WebSocketConnectEventArgs { WebSocket = new NativeWebSocket(webSocketContext.WebSocket, _logger), Endpoint = ctx.Request.RemoteEndPoint.ToString() }); } } catch (Exception ex) @@ -325,7 +313,7 @@ namespace MediaBrowser.Common.Net var type = ctx.Request.IsWebSocketRequest ? "Web Socket" : "HTTP " + ctx.Request.HttpMethod; - if (Kernel.Configuration.EnableHttpLevelLogging) + if (EnableHttpRequestLogging) { _logger.LogMultiline(type + " request received from " + ctx.Request.RemoteEndPoint, LogSeverity.Debug, log); } @@ -432,7 +420,7 @@ namespace MediaBrowser.Common.Net var msg = "Http Response Sent (" + statusode + ") to " + ctx.Request.RemoteEndPoint; - if (Kernel.Configuration.EnableHttpLevelLogging) + if (EnableHttpRequestLogging) { _logger.LogMultiline(msg, LogSeverity.Debug, log); } @@ -449,38 +437,98 @@ namespace MediaBrowser.Common.Net return new ServiceManager(new Container(), new ServiceController(() => types)); } - } - /// <summary> - /// Class WebSocketConnectEventArgs - /// </summary> - public class WebSocketConnectEventArgs : EventArgs - { /// <summary> - /// Gets or sets the web socket. + /// Shut down the Web Service /// </summary> - /// <value>The web socket.</value> - public IWebSocket WebSocket { get; set; } + public override void Stop() + { + if (HttpListener != null) + { + HttpListener.Dispose(); + HttpListener = null; + } + + if (Listener != null) + { + Listener.Prefixes.Remove(UrlPrefix); + } + + base.Stop(); + } + /// <summary> - /// Gets or sets the endpoint. + /// The _supports native web socket /// </summary> - /// <value>The endpoint.</value> - public IPEndPoint Endpoint { get; set; } + private bool? _supportsNativeWebSocket; + + /// <summary> + /// Gets a value indicating whether [supports web sockets]. + /// </summary> + /// <value><c>true</c> if [supports web sockets]; otherwise, <c>false</c>.</value> + public bool SupportsWebSockets + { + get + { + if (!_supportsNativeWebSocket.HasValue) + { + try + { + new ClientWebSocket(); + + _supportsNativeWebSocket = true; + } + catch (PlatformNotSupportedException) + { + _supportsNativeWebSocket = false; + } + } + + return _supportsNativeWebSocket.Value; + } + } + + + /// <summary> + /// Gets or sets a value indicating whether [enable HTTP request logging]. + /// </summary> + /// <value><c>true</c> if [enable HTTP request logging]; otherwise, <c>false</c>.</value> + public bool EnableHttpRequestLogging { get; set; } } + /// <summary> + /// Class ContainerAdapter + /// </summary> class ContainerAdapter : IContainerAdapter { + /// <summary> + /// The _app host + /// </summary> private readonly IApplicationHost _appHost; + /// <summary> + /// Initializes a new instance of the <see cref="ContainerAdapter" /> class. + /// </summary> + /// <param name="appHost">The app host.</param> public ContainerAdapter(IApplicationHost appHost) { _appHost = appHost; } + /// <summary> + /// Resolves this instance. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <returns>``0.</returns> public T Resolve<T>() { return _appHost.Resolve<T>(); } + /// <summary> + /// Tries the resolve. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <returns>``0.</returns> public T TryResolve<T>() { return _appHost.TryResolve<T>(); diff --git a/MediaBrowser.Networking/WebSocket/AlchemyServer.cs b/MediaBrowser.Networking/WebSocket/AlchemyServer.cs new file mode 100644 index 000000000..1a3971c7f --- /dev/null +++ b/MediaBrowser.Networking/WebSocket/AlchemyServer.cs @@ -0,0 +1,105 @@ +using Alchemy; +using Alchemy.Classes; +using MediaBrowser.Common.Net; +using MediaBrowser.Model.Logging; +using System; +using System.Net; + +namespace MediaBrowser.Networking.WebSocket +{ + /// <summary> + /// Class AlchemyServer + /// </summary> + public class AlchemyServer : IWebSocketServer + { + /// <summary> + /// Occurs when [web socket connected]. + /// </summary> + public event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; + + /// <summary> + /// Gets or sets the web socket server. + /// </summary> + /// <value>The web socket server.</value> + private WebSocketServer WebSocketServer { get; set; } + + /// <summary> + /// The _logger + /// </summary> + private readonly ILogger _logger; + + /// <summary> + /// Initializes a new instance of the <see cref="AlchemyServer" /> class. + /// </summary> + /// <param name="logger">The logger.</param> + /// <exception cref="System.ArgumentNullException">logger</exception> + public AlchemyServer(ILogger logger) + { + if (logger == null) + { + throw new ArgumentNullException("logger"); + } + _logger = logger; + } + + /// <summary> + /// Starts the specified port number. + /// </summary> + /// <param name="portNumber">The port number.</param> + public void Start(int portNumber) + { + WebSocketServer = new WebSocketServer(portNumber, IPAddress.Any) + { + OnConnected = OnAlchemyWebSocketClientConnected, + TimeOut = TimeSpan.FromMinutes(60) + }; + + WebSocketServer.Start(); + + _logger.Info("Alchemy Web Socket Server started"); + } + + /// <summary> + /// Called when [alchemy web socket client connected]. + /// </summary> + /// <param name="context">The context.</param> + private void OnAlchemyWebSocketClientConnected(UserContext context) + { + if (WebSocketConnected != null) + { + var socket = new AlchemyWebSocket(context, _logger); + + WebSocketConnected(this, new WebSocketConnectEventArgs + { + WebSocket = socket, + Endpoint = context.ClientAddress.ToString() + }); + } + } + + /// <summary> + /// Stops this instance. + /// </summary> + public void Stop() + { + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources. + /// </summary> + /// <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) + { + + } + } +} diff --git a/MediaBrowser.Common/Net/AlchemyWebSocket.cs b/MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs index 584efa999..fbdb3186f 100644 --- a/MediaBrowser.Common/Net/AlchemyWebSocket.cs +++ b/MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs @@ -1,4 +1,5 @@ using Alchemy.Classes; +using MediaBrowser.Common.Net; using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Logging; using System; @@ -6,7 +7,7 @@ using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Common.Net +namespace MediaBrowser.Networking.WebSocket { /// <summary> /// Class AlchemyWebSocket diff --git a/MediaBrowser.Networking/packages.config b/MediaBrowser.Networking/packages.config new file mode 100644 index 000000000..7a5d717d1 --- /dev/null +++ b/MediaBrowser.Networking/packages.config @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Alchemy" version="2.2.1" targetFramework="net45" /> + <package id="NLog" version="2.0.0.2000" targetFramework="net45" /> + <package id="Rx-Core" version="2.0.21114" targetFramework="net45" /> + <package id="Rx-Interfaces" version="2.0.21114" targetFramework="net45" /> + <package id="Rx-Linq" version="2.0.21114" targetFramework="net45" /> + <package id="ServiceStack" version="3.9.37" targetFramework="net45" /> + <package id="ServiceStack.Api.Swagger" version="3.9.35" targetFramework="net45" /> + <package id="ServiceStack.Common" version="3.9.37" targetFramework="net45" /> + <package id="ServiceStack.Logging.NLog" version="1.0.6.0" targetFramework="net45" /> + <package id="ServiceStack.OrmLite.SqlServer" version="3.9.37" targetFramework="net45" /> + <package id="ServiceStack.Redis" version="3.9.37" targetFramework="net45" /> + <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" /> +</packages>
\ No newline at end of file diff --git a/MediaBrowser.Common/swagger-ui/css/screen.css b/MediaBrowser.Networking/swagger-ui/css/screen.css index 07773f9ef..07773f9ef 100644 --- a/MediaBrowser.Common/swagger-ui/css/screen.css +++ b/MediaBrowser.Networking/swagger-ui/css/screen.css diff --git a/MediaBrowser.Common/swagger-ui/images/pet_store_api.png b/MediaBrowser.Networking/swagger-ui/images/pet_store_api.png Binary files differindex f9f9cd4ae..f9f9cd4ae 100644 --- a/MediaBrowser.Common/swagger-ui/images/pet_store_api.png +++ b/MediaBrowser.Networking/swagger-ui/images/pet_store_api.png diff --git a/MediaBrowser.Common/swagger-ui/images/wordnik_api.png b/MediaBrowser.Networking/swagger-ui/images/wordnik_api.png Binary files differindex dca4f1455..dca4f1455 100644 --- a/MediaBrowser.Common/swagger-ui/images/wordnik_api.png +++ b/MediaBrowser.Networking/swagger-ui/images/wordnik_api.png diff --git a/MediaBrowser.Common/swagger-ui/index.html b/MediaBrowser.Networking/swagger-ui/index.html index 5d2a8d88d..5d2a8d88d 100644 --- a/MediaBrowser.Common/swagger-ui/index.html +++ b/MediaBrowser.Networking/swagger-ui/index.html diff --git a/MediaBrowser.Common/swagger-ui/lib/backbone-min.js b/MediaBrowser.Networking/swagger-ui/lib/backbone-min.js index c1c0d4fff..c1c0d4fff 100644 --- a/MediaBrowser.Common/swagger-ui/lib/backbone-min.js +++ b/MediaBrowser.Networking/swagger-ui/lib/backbone-min.js diff --git a/MediaBrowser.Common/swagger-ui/lib/handlebars.runtime-1.0.0.beta.6.js b/MediaBrowser.Networking/swagger-ui/lib/handlebars.runtime-1.0.0.beta.6.js index 987a5cd4d..987a5cd4d 100644 --- a/MediaBrowser.Common/swagger-ui/lib/handlebars.runtime-1.0.0.beta.6.js +++ b/MediaBrowser.Networking/swagger-ui/lib/handlebars.runtime-1.0.0.beta.6.js diff --git a/MediaBrowser.Common/swagger-ui/lib/jquery.ba-bbq.min.js b/MediaBrowser.Networking/swagger-ui/lib/jquery.ba-bbq.min.js index bcbf24834..bcbf24834 100644 --- a/MediaBrowser.Common/swagger-ui/lib/jquery.ba-bbq.min.js +++ b/MediaBrowser.Networking/swagger-ui/lib/jquery.ba-bbq.min.js diff --git a/MediaBrowser.Common/swagger-ui/lib/jquery.min.js b/MediaBrowser.Networking/swagger-ui/lib/jquery.min.js index 16ad06c5a..16ad06c5a 100644 --- a/MediaBrowser.Common/swagger-ui/lib/jquery.min.js +++ b/MediaBrowser.Networking/swagger-ui/lib/jquery.min.js diff --git a/MediaBrowser.Common/swagger-ui/lib/jquery.slideto.min.js b/MediaBrowser.Networking/swagger-ui/lib/jquery.slideto.min.js index ba32cff36..ba32cff36 100644 --- a/MediaBrowser.Common/swagger-ui/lib/jquery.slideto.min.js +++ b/MediaBrowser.Networking/swagger-ui/lib/jquery.slideto.min.js diff --git a/MediaBrowser.Common/swagger-ui/lib/jquery.wiggle.min.js b/MediaBrowser.Networking/swagger-ui/lib/jquery.wiggle.min.js index 2adb0d6d5..2adb0d6d5 100644 --- a/MediaBrowser.Common/swagger-ui/lib/jquery.wiggle.min.js +++ b/MediaBrowser.Networking/swagger-ui/lib/jquery.wiggle.min.js diff --git a/MediaBrowser.Common/swagger-ui/lib/swagger.js b/MediaBrowser.Networking/swagger-ui/lib/swagger.js index 68d8e40cc..68d8e40cc 100644 --- a/MediaBrowser.Common/swagger-ui/lib/swagger.js +++ b/MediaBrowser.Networking/swagger-ui/lib/swagger.js diff --git a/MediaBrowser.Common/swagger-ui/lib/underscore-min.js b/MediaBrowser.Networking/swagger-ui/lib/underscore-min.js index 5a0cb3b00..5a0cb3b00 100644 --- a/MediaBrowser.Common/swagger-ui/lib/underscore-min.js +++ b/MediaBrowser.Networking/swagger-ui/lib/underscore-min.js diff --git a/MediaBrowser.Common/swagger-ui/swagger-ui.js b/MediaBrowser.Networking/swagger-ui/swagger-ui.js index 4cdcc3976..4cdcc3976 100644 --- a/MediaBrowser.Common/swagger-ui/swagger-ui.js +++ b/MediaBrowser.Networking/swagger-ui/swagger-ui.js diff --git a/MediaBrowser.Common/swagger-ui/swagger-ui.min.js b/MediaBrowser.Networking/swagger-ui/swagger-ui.min.js index 6ab803707..6ab803707 100644 --- a/MediaBrowser.Common/swagger-ui/swagger-ui.min.js +++ b/MediaBrowser.Networking/swagger-ui/swagger-ui.min.js diff --git a/MediaBrowser.ServerApplication/App.xaml.cs b/MediaBrowser.ServerApplication/App.xaml.cs index 4aa3cdbb4..1b6b6f98e 100644 --- a/MediaBrowser.ServerApplication/App.xaml.cs +++ b/MediaBrowser.ServerApplication/App.xaml.cs @@ -11,6 +11,9 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Updates; using MediaBrowser.Networking.Management; +using MediaBrowser.Networking.Udp; +using MediaBrowser.Networking.Web; +using MediaBrowser.Networking.WebSocket; using MediaBrowser.Server.Uninstall; using MediaBrowser.ServerApplication.Implementations; using Microsoft.Win32; @@ -195,10 +198,10 @@ namespace MediaBrowser.ServerApplication /// </summary> protected async void LoadKernel() { - RegisterResources(); - Kernel = new Kernel(this, Logger); + RegisterResources(); + try { new MainWindow(Logger).Show(); @@ -511,15 +514,18 @@ namespace MediaBrowser.ServerApplication /// </summary> private void RegisterResources() { - Register<IApplicationHost>(this); - Register(Logger); + RegisterSingleInstance<IApplicationHost>(this); + RegisterSingleInstance(Logger); IsoManager = new PismoIsoManager(Logger); - Register(IsoManager); - Register<IBlurayExaminer>(new BdInfoExaminer()); - Register<IZipClient>(new DotNetZipClient()); - Register(typeof (INetworkManager), typeof (NetworkManager)); + RegisterSingleInstance(IsoManager); + RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer()); + RegisterSingleInstance<INetworkManager>(() => new NetworkManager()); + RegisterSingleInstance<IZipClient>(() => new DotNetZipClient()); + RegisterSingleInstance<IWebSocketServer>(() => new AlchemyServer(Logger)); + Register(typeof(IUdpServer), typeof(UdpServer)); + RegisterSingleInstance<IHttpServer>(() => new HttpServer(this, Kernel, Logger, "Media Browser", "index.html")); } /// <summary> @@ -546,20 +552,42 @@ namespace MediaBrowser.ServerApplication /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj">The obj.</param> - public void Register<T>(T obj) + public void RegisterSingleInstance<T>(T obj) where T : class { _container.RegisterSingle(obj); } /// <summary> + /// Registers the specified func. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="func">The func.</param> + public void Register<T>(Func<T> func) + where T : class + { + _container.Register(func); + } + + /// <summary> + /// Registers the single instance. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="func">The func.</param> + public void RegisterSingleInstance<T>(Func<T> func) + where T : class + { + _container.RegisterSingle(func); + } + + /// <summary> /// Resolves this instance. /// </summary> /// <typeparam name="T"></typeparam> /// <returns>``0.</returns> public T Resolve<T>() { - return (T)_container.GetRegistration(typeof (T), true).GetInstance(); + return (T)_container.GetRegistration(typeof(T), true).GetInstance(); } /// <summary> @@ -569,7 +597,7 @@ namespace MediaBrowser.ServerApplication /// <returns>``0.</returns> public T TryResolve<T>() { - var result = _container.GetRegistration(typeof (T), false); + var result = _container.GetRegistration(typeof(T), false); if (result == null) { diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index 9b27351a1..0a364756a 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -128,6 +128,36 @@ <SpecificVersion>False</SpecificVersion> <HintPath>..\ThirdParty\UPnP\Libs\Platinum.Managed.dll</HintPath> </Reference> + <Reference Include="ServiceStack, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.Common, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Common.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.Interfaces, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Interfaces.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.OrmLite, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.OrmLite.SqlServer"> + <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.SqlServer.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.Redis"> + <HintPath>..\packages\ServiceStack.Redis.3.9.37\lib\net35\ServiceStack.Redis.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.ServiceInterface, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.ServiceInterface.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.Text, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath> + </Reference> <Reference Include="SimpleInjector, Version=2.0.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\SimpleInjector.2.0.0-beta5\lib\net40-client\SimpleInjector.dll</HintPath> diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config index e1beae6da..28d6202f8 100644 --- a/MediaBrowser.ServerApplication/packages.config +++ b/MediaBrowser.ServerApplication/packages.config @@ -3,6 +3,11 @@ <package id="DotNetZip" version="1.9.1.8" targetFramework="net45" /> <package id="Hardcodet.Wpf.TaskbarNotification" version="1.0.4.0" targetFramework="net45" /> <package id="NLog" version="2.0.0.2000" targetFramework="net45" /> + <package id="ServiceStack" version="3.9.37" targetFramework="net45" /> + <package id="ServiceStack.Common" version="3.9.37" targetFramework="net45" /> + <package id="ServiceStack.OrmLite.SqlServer" version="3.9.37" targetFramework="net45" /> + <package id="ServiceStack.Redis" version="3.9.37" targetFramework="net45" /> + <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" /> <package id="SimpleInjector" version="2.0.0-beta5" targetFramework="net45" /> <package id="System.Data.SQLite" version="1.0.84.0" targetFramework="net45" /> </packages>
\ No newline at end of file |
