Browse Source

extracted http server, web socket server and udp server dependancies

LukePulverenti 12 năm trước cách đây
mục cha
commit
2e4db75540
39 tập tin đã thay đổi với 890 bổ sung356 xóa
  1. 2 2
      MediaBrowser.Common/Kernel/BaseKernel.cs
  2. 15 1
      MediaBrowser.Common/Kernel/IApplicationHost.cs
  3. 38 76
      MediaBrowser.Common/Kernel/TcpManager.cs
  4. 4 45
      MediaBrowser.Common/MediaBrowser.Common.csproj
  5. 44 0
      MediaBrowser.Common/Net/IHttpServer.cs
  6. 41 2
      MediaBrowser.Common/Net/IUdpServer.cs
  7. 26 0
      MediaBrowser.Common/Net/IWebSocketServer.cs
  8. 21 0
      MediaBrowser.Common/Net/UdpMessageReceivedEventArgs.cs
  9. 0 142
      MediaBrowser.Common/Net/UdpServer.cs
  10. 22 0
      MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs
  11. 3 3
      MediaBrowser.Common/Net/WebSocketConnection.cs
  12. 0 7
      MediaBrowser.Common/packages.config
  13. 1 1
      MediaBrowser.Controller/Kernel.cs
  14. 0 1
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  15. 112 0
      MediaBrowser.Networking/Management/NetworkManager.cs
  16. 86 0
      MediaBrowser.Networking/MediaBrowser.Networking.csproj
  17. 0 0
      MediaBrowser.Networking/README.txt
  18. 167 0
      MediaBrowser.Networking/Udp/UdpServer.cs
  19. 112 64
      MediaBrowser.Networking/Web/HttpServer.cs
  20. 105 0
      MediaBrowser.Networking/WebSocket/AlchemyServer.cs
  21. 2 1
      MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs
  22. 15 0
      MediaBrowser.Networking/packages.config
  23. 0 0
      MediaBrowser.Networking/swagger-ui/css/screen.css
  24. 0 0
      MediaBrowser.Networking/swagger-ui/images/pet_store_api.png
  25. 0 0
      MediaBrowser.Networking/swagger-ui/images/wordnik_api.png
  26. 0 0
      MediaBrowser.Networking/swagger-ui/index.html
  27. 0 0
      MediaBrowser.Networking/swagger-ui/lib/backbone-min.js
  28. 0 0
      MediaBrowser.Networking/swagger-ui/lib/handlebars.runtime-1.0.0.beta.6.js
  29. 0 0
      MediaBrowser.Networking/swagger-ui/lib/jquery.ba-bbq.min.js
  30. 0 0
      MediaBrowser.Networking/swagger-ui/lib/jquery.min.js
  31. 0 0
      MediaBrowser.Networking/swagger-ui/lib/jquery.slideto.min.js
  32. 0 0
      MediaBrowser.Networking/swagger-ui/lib/jquery.wiggle.min.js
  33. 0 0
      MediaBrowser.Networking/swagger-ui/lib/swagger.js
  34. 0 0
      MediaBrowser.Networking/swagger-ui/lib/underscore-min.js
  35. 0 0
      MediaBrowser.Networking/swagger-ui/swagger-ui.js
  36. 0 0
      MediaBrowser.Networking/swagger-ui/swagger-ui.min.js
  37. 39 11
      MediaBrowser.ServerApplication/App.xaml.cs
  38. 30 0
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
  39. 5 0
      MediaBrowser.ServerApplication/packages.config

+ 2 - 2
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>

+ 15 - 1
MediaBrowser.Common/Kernel/IApplicationHost.cs

@@ -56,8 +56,22 @@ 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>

+ 38 - 76
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();

+ 4 - 45
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" />

+ 44 - 0
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;
+    }
+}

+ 41 - 2
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);
     }
 }

+ 26 - 0
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;
+    }
+}

+ 21 - 0
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; }
+    }
+}

+ 0 - 142
MediaBrowser.Common/Net/UdpServer.cs

@@ -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);
-        }
-    }
-}

+ 22 - 0
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; }
+    }
+}

+ 3 - 3
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");
             }

+ 0 - 7
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" />

+ 1 - 1
MediaBrowser.Controller/Kernel.cs

@@ -315,7 +315,7 @@ namespace MediaBrowser.Controller
         /// </summary>
         protected override void RegisterExportedValues()
         {
-            ApplicationHost.Register(this);
+            ApplicationHost.RegisterSingleInstance(this);
             
             base.RegisterExportedValues();
         }

+ 0 - 1
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>

+ 112 - 0
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];
+        }
     }
 
 }

+ 86 - 0
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">

+ 0 - 0
MediaBrowser.Common/README.txt → MediaBrowser.Networking/README.txt


+ 167 - 0
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));
+        }
+    }
+
+}

+ 112 - 64
MediaBrowser.Common/Net/HttpServer.cs → 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>();

+ 105 - 0
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)
+        {
+            
+        }
+    }
+}

+ 2 - 1
MediaBrowser.Common/Net/AlchemyWebSocket.cs → 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

+ 15 - 0
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>

+ 0 - 0
MediaBrowser.Common/swagger-ui/css/screen.css → MediaBrowser.Networking/swagger-ui/css/screen.css


+ 0 - 0
MediaBrowser.Common/swagger-ui/images/pet_store_api.png → MediaBrowser.Networking/swagger-ui/images/pet_store_api.png


+ 0 - 0
MediaBrowser.Common/swagger-ui/images/wordnik_api.png → MediaBrowser.Networking/swagger-ui/images/wordnik_api.png


+ 0 - 0
MediaBrowser.Common/swagger-ui/index.html → MediaBrowser.Networking/swagger-ui/index.html


+ 0 - 0
MediaBrowser.Common/swagger-ui/lib/backbone-min.js → MediaBrowser.Networking/swagger-ui/lib/backbone-min.js


+ 0 - 0
MediaBrowser.Common/swagger-ui/lib/handlebars.runtime-1.0.0.beta.6.js → MediaBrowser.Networking/swagger-ui/lib/handlebars.runtime-1.0.0.beta.6.js


+ 0 - 0
MediaBrowser.Common/swagger-ui/lib/jquery.ba-bbq.min.js → MediaBrowser.Networking/swagger-ui/lib/jquery.ba-bbq.min.js


+ 0 - 0
MediaBrowser.Common/swagger-ui/lib/jquery.min.js → MediaBrowser.Networking/swagger-ui/lib/jquery.min.js


+ 0 - 0
MediaBrowser.Common/swagger-ui/lib/jquery.slideto.min.js → MediaBrowser.Networking/swagger-ui/lib/jquery.slideto.min.js


+ 0 - 0
MediaBrowser.Common/swagger-ui/lib/jquery.wiggle.min.js → MediaBrowser.Networking/swagger-ui/lib/jquery.wiggle.min.js


+ 0 - 0
MediaBrowser.Common/swagger-ui/lib/swagger.js → MediaBrowser.Networking/swagger-ui/lib/swagger.js


+ 0 - 0
MediaBrowser.Common/swagger-ui/lib/underscore-min.js → MediaBrowser.Networking/swagger-ui/lib/underscore-min.js


+ 0 - 0
MediaBrowser.Common/swagger-ui/swagger-ui.js → MediaBrowser.Networking/swagger-ui/swagger-ui.js


+ 0 - 0
MediaBrowser.Common/swagger-ui/swagger-ui.min.js → MediaBrowser.Networking/swagger-ui/swagger-ui.min.js


+ 39 - 11
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,12 +552,34 @@ 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>
@@ -559,7 +587,7 @@ namespace MediaBrowser.ServerApplication
         /// <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)
             {

+ 30 - 0
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>

+ 5 - 0
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>