浏览代码

extracted http server, web socket server and udp server dependancies

LukePulverenti 12 年之前
父节点
当前提交
2e4db75540
共有 39 个文件被更改,包括 890 次插入356 次删除
  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>