extracted http server, web socket server and udp server dependancies

pull/702/head
LukePulverenti 12 years ago
parent 1a423c43b4
commit 2e4db75540

@ -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>

@ -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>

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

@ -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" />

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

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

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

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

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

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

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

@ -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" />

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

@ -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>

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

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

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

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

@ -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

@ -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>

@ -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)
{

@ -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>

@ -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>
Loading…
Cancel
Save