diff options
| author | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-23 17:31:51 -0500 |
|---|---|---|
| committer | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-23 17:31:51 -0500 |
| commit | 2e4db7554041ecf481d3a38656fccc309e13eb5b (patch) | |
| tree | 73c064988db630f97edc18bbc3ea5fac9132483b /MediaBrowser.Common/Net | |
| parent | 1a423c43b4284848e155fc4a060ef7061b084ed8 (diff) | |
extracted http server, web socket server and udp server dependancies
Diffstat (limited to 'MediaBrowser.Common/Net')
| -rw-r--r-- | MediaBrowser.Common/Net/AlchemyWebSocket.cs | 132 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/HttpServer.cs | 489 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/IHttpServer.cs | 44 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/IUdpServer.cs | 43 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/IWebSocketServer.cs | 26 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/UdpMessageReceivedEventArgs.cs | 21 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/UdpServer.cs | 142 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs | 22 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/WebSocketConnection.cs | 6 |
9 files changed, 157 insertions, 768 deletions
diff --git a/MediaBrowser.Common/Net/AlchemyWebSocket.cs b/MediaBrowser.Common/Net/AlchemyWebSocket.cs deleted file mode 100644 index 584efa999..000000000 --- a/MediaBrowser.Common/Net/AlchemyWebSocket.cs +++ /dev/null @@ -1,132 +0,0 @@ -using Alchemy.Classes; -using MediaBrowser.Common.Serialization; -using MediaBrowser.Model.Logging; -using System; -using System.Net.WebSockets; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Net -{ - /// <summary> - /// Class AlchemyWebSocket - /// </summary> - public class AlchemyWebSocket : IWebSocket - { - /// <summary> - /// The logger - /// </summary> - private readonly ILogger _logger; - - /// <summary> - /// Gets or sets the web socket. - /// </summary> - /// <value>The web socket.</value> - private UserContext UserContext { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="AlchemyWebSocket" /> class. - /// </summary> - /// <param name="context">The context.</param> - /// <param name="logger">The logger.</param> - /// <exception cref="System.ArgumentNullException">context</exception> - public AlchemyWebSocket(UserContext context, ILogger logger) - { - if (context == null) - { - throw new ArgumentNullException("context"); - } - - _logger = logger; - UserContext = context; - - context.SetOnDisconnect(OnDisconnected); - context.SetOnReceive(OnReceive); - - _logger.Info("Client connected from {0}", context.ClientAddress); - } - - /// <summary> - /// The _disconnected - /// </summary> - private bool _disconnected = false; - /// <summary> - /// Gets or sets the state. - /// </summary> - /// <value>The state.</value> - public WebSocketState State - { - get { return _disconnected ? WebSocketState.Closed : WebSocketState.Open; } - } - - /// <summary> - /// Called when [disconnected]. - /// </summary> - /// <param name="context">The context.</param> - private void OnDisconnected(UserContext context) - { - _disconnected = true; - } - - /// <summary> - /// Called when [receive]. - /// </summary> - /// <param name="context">The context.</param> - private void OnReceive(UserContext context) - { - if (OnReceiveDelegate != null) - { - var json = context.DataFrame.ToString(); - - if (!string.IsNullOrWhiteSpace(json)) - { - try - { - var messageResult = JsonSerializer.DeserializeFromString<WebSocketMessageInfo>(json); - - OnReceiveDelegate(messageResult); - } - catch (Exception ex) - { - _logger.ErrorException("Error processing web socket message", ex); - } - } - } - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="bytes">The bytes.</param> - /// <param name="type">The type.</param> - /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken) - { - return Task.Run(() => UserContext.Send(bytes)); - } - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - } - - /// <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) - { - } - - /// <summary> - /// Gets or sets the receive action. - /// </summary> - /// <value>The receive action.</value> - public Action<WebSocketMessageInfo> OnReceiveDelegate { get; set; } - } -} diff --git a/MediaBrowser.Common/Net/HttpServer.cs b/MediaBrowser.Common/Net/HttpServer.cs deleted file mode 100644 index 20ee615ad..000000000 --- a/MediaBrowser.Common/Net/HttpServer.cs +++ /dev/null @@ -1,489 +0,0 @@ -using Funq; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Kernel; -using MediaBrowser.Model.Logging; -using ServiceStack.Api.Swagger; -using ServiceStack.Common.Web; -using ServiceStack.Configuration; -using ServiceStack.Logging.NLogger; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Cors; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.Endpoints.Extensions; -using ServiceStack.WebHost.Endpoints.Support; -using System; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Reactive.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Net -{ - /// <summary> - /// Class HttpServer - /// </summary> - public class HttpServer : HttpListenerBase - { - /// <summary> - /// The logger - /// </summary> - private readonly ILogger _logger; - - /// <summary> - /// Gets the URL prefix. - /// </summary> - /// <value>The URL prefix.</value> - public string UrlPrefix { get; private set; } - - /// <summary> - /// Gets or sets the kernel. - /// </summary> - /// <value>The kernel.</value> - private IKernel Kernel { get; set; } - - /// <summary> - /// Gets or sets the application host. - /// </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> - /// <value>The HTTP listener.</value> - private IDisposable HttpListener { get; set; } - - /// <summary> - /// Occurs when [web socket connected]. - /// </summary> - public event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; - - /// <summary> - /// Gets the default redirect path. - /// </summary> - /// <value>The default redirect path.</value> - public string DefaultRedirectPath { get; private 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="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) - : base() - { - if (string.IsNullOrEmpty(urlPrefix)) - { - throw new ArgumentNullException("urlPrefix"); - } - if (kernel == null) - { - throw new ArgumentNullException("kernel"); - } - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - if (applicationHost == null) - { - throw new ArgumentNullException("applicationHost"); - } - - DefaultRedirectPath = defaultRedirectpath; - _logger = logger; - ApplicationHost = applicationHost; - - EndpointHostConfig.Instance.ServiceStackHandlerFactoryPath = null; - EndpointHostConfig.Instance.MetadataRedirectPath = "metadata"; - - UrlPrefix = urlPrefix; - Kernel = kernel; - - 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> - /// Configures the specified container. - /// </summary> - /// <param name="container">The container.</param> - public override void Configure(Container container) - { - if (!string.IsNullOrEmpty(DefaultRedirectPath)) - { - SetConfig(new EndpointHostConfig - { - DefaultRedirectPath = DefaultRedirectPath, - - // Tell SS to bubble exceptions up to here - WriteErrorsToResponse = false, - - DebugMode = true - }); - } - - container.Adapter = new ContainerAdapter(ApplicationHost); - - container.Register(Kernel); - container.Register(_logger); - container.Register(ApplicationHost); - - foreach (var service in Kernel.RestServices) - { - service.Configure(this); - } - - Plugins.Add(new SwaggerFeature()); - Plugins.Add(new CorsFeature()); - - Serialization.JsonSerializer.Configure(); - - ServiceStack.Logging.LogManager.LogFactory = new NLogFactory(); - } - - /// <summary> - /// Starts the Web Service - /// </summary> - /// <param name="urlBase">A Uri that acts as the base that the server is listening on. - /// Format should be: http://127.0.0.1:8080/ or http://127.0.0.1:8080/somevirtual/ - /// Note: the trailing slash is required! For more info see the - /// HttpListener.Prefixes property on MSDN.</param> - public override void Start(string urlBase) - { - // *** Already running - just leave it in place - if (IsStarted) - { - return; - } - - if (Listener == null) - { - Listener = new HttpListener(); - } - - EndpointHost.Config.ServiceStackHandlerFactoryPath = HttpListenerRequestWrapper.GetHandlerPathIfAny(urlBase); - - Listener.Prefixes.Add(urlBase); - - IsStarted = true; - Listener.Start(); - - HttpListener = CreateObservableStream().Subscribe(ProcessHttpRequestAsync); - } - - /// <summary> - /// Creates the observable stream. - /// </summary> - /// <returns>IObservable{HttpListenerContext}.</returns> - private IObservable<HttpListenerContext> CreateObservableStream() - { - return Observable.Create<HttpListenerContext>(obs => - Observable.FromAsync(() => Listener.GetContextAsync()) - .Subscribe(obs)) - .Repeat() - .Retry() - .Publish() - .RefCount(); - } - - /// <summary> - /// Processes incoming http requests by routing them to the appropiate handler - /// </summary> - /// <param name="context">The CTX.</param> - private async void ProcessHttpRequestAsync(HttpListenerContext context) - { - LogHttpRequest(context); - - if (context.Request.IsWebSocketRequest) - { - await ProcessWebSocketRequest(context).ConfigureAwait(false); - return; - } - - - Task.Run(() => - { - RaiseReceiveWebRequest(context); - - try - { - ProcessRequest(context); - } - catch (InvalidOperationException ex) - { - HandleException(context.Response, ex, 422); - - throw; - } - catch (ResourceNotFoundException ex) - { - HandleException(context.Response, ex, 404); - - throw; - } - catch (FileNotFoundException ex) - { - HandleException(context.Response, ex, 404); - - throw; - } - catch (DirectoryNotFoundException ex) - { - HandleException(context.Response, ex, 404); - - throw; - } - catch (UnauthorizedAccessException ex) - { - HandleException(context.Response, ex, 401); - - throw; - } - catch (ArgumentException ex) - { - HandleException(context.Response, ex, 400); - - throw; - } - catch (Exception ex) - { - HandleException(context.Response, ex, 500); - - throw; - } - }); - } - - /// <summary> - /// Processes the web socket request. - /// </summary> - /// <param name="ctx">The CTX.</param> - /// <returns>Task.</returns> - private async Task ProcessWebSocketRequest(HttpListenerContext ctx) - { - try - { - var webSocketContext = await ctx.AcceptWebSocketAsync(null).ConfigureAwait(false); - - if (WebSocketConnected != null) - { - WebSocketConnected(this, new WebSocketConnectEventArgs { WebSocket = new NativeWebSocket(webSocketContext.WebSocket, _logger), Endpoint = ctx.Request.RemoteEndPoint }); - } - } - catch (Exception ex) - { - _logger.ErrorException("AcceptWebSocketAsync error", ex); - - ctx.Response.StatusCode = 500; - ctx.Response.Close(); - } - } - - /// <summary> - /// Logs the HTTP request. - /// </summary> - /// <param name="ctx">The CTX.</param> - private void LogHttpRequest(HttpListenerContext ctx) - { - var log = new StringBuilder(); - - log.AppendLine("Url: " + ctx.Request.Url); - log.AppendLine("Headers: " + string.Join(",", ctx.Request.Headers.AllKeys.Select(k => k + "=" + ctx.Request.Headers[k]))); - - var type = ctx.Request.IsWebSocketRequest ? "Web Socket" : "HTTP " + ctx.Request.HttpMethod; - - if (Kernel.Configuration.EnableHttpLevelLogging) - { - _logger.LogMultiline(type + " request received from " + ctx.Request.RemoteEndPoint, LogSeverity.Debug, log); - } - } - - /// <summary> - /// Appends the error message. - /// </summary> - /// <param name="response">The response.</param> - /// <param name="ex">The ex.</param> - /// <param name="statusCode">The status code.</param> - private void HandleException(HttpListenerResponse response, Exception ex, int statusCode) - { - _logger.ErrorException("Error processing request", ex); - - response.StatusCode = statusCode; - - response.Headers.Add("Status", statusCode.ToString(new CultureInfo("en-US"))); - - response.Headers.Remove("Age"); - response.Headers.Remove("Expires"); - response.Headers.Remove("Cache-Control"); - response.Headers.Remove("Etag"); - response.Headers.Remove("Last-Modified"); - - response.ContentType = "text/plain"; - - if (!string.IsNullOrEmpty(ex.Message)) - { - response.AddHeader("X-Application-Error-Code", ex.Message); - } - - // This could fail, but try to add the stack trace as the body content - try - { - var sb = new StringBuilder(); - sb.AppendLine("{"); - sb.AppendLine("\"ResponseStatus\":{"); - sb.AppendFormat(" \"ErrorCode\":{0},\n", ex.GetType().Name.EncodeJson()); - sb.AppendFormat(" \"Message\":{0},\n", ex.Message.EncodeJson()); - sb.AppendFormat(" \"StackTrace\":{0}\n", ex.StackTrace.EncodeJson()); - sb.AppendLine("}"); - sb.AppendLine("}"); - - response.StatusCode = 500; - response.ContentType = ContentType.Json; - var sbBytes = sb.ToString().ToUtf8Bytes(); - response.OutputStream.Write(sbBytes, 0, sbBytes.Length); - response.Close(); - } - catch (Exception errorEx) - { - _logger.ErrorException("Error processing failed request", errorEx); - } - } - - - /// <summary> - /// Overridable method that can be used to implement a custom hnandler - /// </summary> - /// <param name="context">The context.</param> - /// <exception cref="System.NotImplementedException">Cannot execute handler: + handler + at PathInfo: + httpReq.PathInfo</exception> - protected override void ProcessRequest(HttpListenerContext context) - { - if (string.IsNullOrEmpty(context.Request.RawUrl)) return; - - var operationName = context.Request.GetOperationName(); - - var httpReq = new HttpListenerRequestWrapper(operationName, context.Request); - var httpRes = new HttpListenerResponseWrapper(context.Response); - var handler = ServiceStackHttpHandlerFactory.GetHandler(httpReq); - - var serviceStackHandler = handler as IServiceStackHttpHandler; - - if (serviceStackHandler != null) - { - var restHandler = serviceStackHandler as RestHandler; - if (restHandler != null) - { - httpReq.OperationName = operationName = restHandler.RestPath.RequestType.Name; - } - serviceStackHandler.ProcessRequest(httpReq, httpRes, operationName); - LogResponse(context); - httpRes.Close(); - return; - } - - throw new NotImplementedException("Cannot execute handler: " + handler + " at PathInfo: " + httpReq.PathInfo); - } - - /// <summary> - /// Logs the response. - /// </summary> - /// <param name="ctx">The CTX.</param> - private void LogResponse(HttpListenerContext ctx) - { - var statusode = ctx.Response.StatusCode; - - var log = new StringBuilder(); - - log.AppendLine(string.Format("Url: {0}", ctx.Request.Url)); - - log.AppendLine("Headers: " + string.Join(",", ctx.Response.Headers.AllKeys.Select(k => k + "=" + ctx.Response.Headers[k]))); - - var msg = "Http Response Sent (" + statusode + ") to " + ctx.Request.RemoteEndPoint; - - if (Kernel.Configuration.EnableHttpLevelLogging) - { - _logger.LogMultiline(msg, LogSeverity.Debug, log); - } - } - - /// <summary> - /// Creates the service manager. - /// </summary> - /// <param name="assembliesWithServices">The assemblies with services.</param> - /// <returns>ServiceManager.</returns> - protected override ServiceManager CreateServiceManager(params Assembly[] assembliesWithServices) - { - var types = Kernel.RestServices.Select(r => r.GetType()).ToArray(); - - return new ServiceManager(new Container(), new ServiceController(() => types)); - } - } - - /// <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 IPEndPoint Endpoint { get; set; } - } - - class ContainerAdapter : IContainerAdapter - { - private readonly IApplicationHost _appHost; - - public ContainerAdapter(IApplicationHost appHost) - { - _appHost = appHost; - } - public T Resolve<T>() - { - return _appHost.Resolve<T>(); - } - - public T TryResolve<T>() - { - return _appHost.TryResolve<T>(); - } - } -}
\ No newline at end of file diff --git a/MediaBrowser.Common/Net/IHttpServer.cs b/MediaBrowser.Common/Net/IHttpServer.cs new file mode 100644 index 000000000..a640fb262 --- /dev/null +++ b/MediaBrowser.Common/Net/IHttpServer.cs @@ -0,0 +1,44 @@ +using System; + +namespace MediaBrowser.Common.Net +{ + /// <summary> + /// Interface IHttpServer + /// </summary> + public interface IHttpServer : IDisposable + { + /// <summary> + /// Gets the URL prefix. + /// </summary> + /// <value>The URL prefix.</value> + string UrlPrefix { get; } + + /// <summary> + /// Starts the specified server name. + /// </summary> + /// <param name="urlPrefix">The URL.</param> + void Start(string urlPrefix); + + /// <summary> + /// Gets a value indicating whether [supports web sockets]. + /// </summary> + /// <value><c>true</c> if [supports web sockets]; otherwise, <c>false</c>.</value> + bool SupportsWebSockets { get; } + + /// <summary> + /// Stops this instance. + /// </summary> + void Stop(); + + /// <summary> + /// Gets or sets a value indicating whether [enable HTTP request logging]. + /// </summary> + /// <value><c>true</c> if [enable HTTP request logging]; otherwise, <c>false</c>.</value> + bool EnableHttpRequestLogging { get; set; } + + /// <summary> + /// Occurs when [web socket connected]. + /// </summary> + event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; + } +}
\ No newline at end of file diff --git a/MediaBrowser.Common/Net/IUdpServer.cs b/MediaBrowser.Common/Net/IUdpServer.cs index 01a8ef021..036977eab 100644 --- a/MediaBrowser.Common/Net/IUdpServer.cs +++ b/MediaBrowser.Common/Net/IUdpServer.cs @@ -1,7 +1,46 @@ - +using System; +using System.Threading.Tasks; + namespace MediaBrowser.Common.Net { - public interface IUdpServer + /// <summary> + /// Interface IUdpServer + /// </summary> + public interface IUdpServer : IDisposable { + /// <summary> + /// Occurs when [message received]. + /// </summary> + event EventHandler<UdpMessageReceivedEventArgs> MessageReceived; + + /// <summary> + /// Starts the specified port. + /// </summary> + /// <param name="port">The port.</param> + void Start(int port); + + /// <summary> + /// Stops this instance. + /// </summary> + void Stop(); + + /// <summary> + /// Sends the async. + /// </summary> + /// <param name="bytes">The bytes.</param> + /// <param name="remoteEndPoint">The remote end point.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException">data</exception> + Task SendAsync(byte[] bytes, string remoteEndPoint); + + /// <summary> + /// Sends the async. + /// </summary> + /// <param name="bytes">The bytes.</param> + /// <param name="ipAddress">The ip address.</param> + /// <param name="port">The port.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException">bytes</exception> + Task SendAsync(byte[] bytes, string ipAddress, int port); } } diff --git a/MediaBrowser.Common/Net/IWebSocketServer.cs b/MediaBrowser.Common/Net/IWebSocketServer.cs new file mode 100644 index 000000000..5ce571fbb --- /dev/null +++ b/MediaBrowser.Common/Net/IWebSocketServer.cs @@ -0,0 +1,26 @@ +using System; + +namespace MediaBrowser.Common.Net +{ + /// <summary> + /// Interface IWebSocketServer + /// </summary> + public interface IWebSocketServer : IDisposable + { + /// <summary> + /// Starts the specified port number. + /// </summary> + /// <param name="portNumber">The port number.</param> + void Start(int portNumber); + + /// <summary> + /// Stops this instance. + /// </summary> + void Stop(); + + /// <summary> + /// Occurs when [web socket connected]. + /// </summary> + event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; + } +} diff --git a/MediaBrowser.Common/Net/UdpMessageReceivedEventArgs.cs b/MediaBrowser.Common/Net/UdpMessageReceivedEventArgs.cs new file mode 100644 index 000000000..bd5034c47 --- /dev/null +++ b/MediaBrowser.Common/Net/UdpMessageReceivedEventArgs.cs @@ -0,0 +1,21 @@ +using System; + +namespace MediaBrowser.Common.Net +{ + /// <summary> + /// Class UdpMessageReceivedEventArgs + /// </summary> + public class UdpMessageReceivedEventArgs : EventArgs + { + /// <summary> + /// Gets or sets the bytes. + /// </summary> + /// <value>The bytes.</value> + public byte[] Bytes { get; set; } + /// <summary> + /// Gets or sets the remote end point. + /// </summary> + /// <value>The remote end point.</value> + public string RemoteEndPoint { get; set; } + } +} diff --git a/MediaBrowser.Common/Net/UdpServer.cs b/MediaBrowser.Common/Net/UdpServer.cs deleted file mode 100644 index a3c6a8a78..000000000 --- a/MediaBrowser.Common/Net/UdpServer.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Reactive.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Net -{ - /// <summary> - /// Provides a Udp Server - /// </summary> - public class UdpServer : IObservable<UdpReceiveResult>, IDisposable - { - /// <summary> - /// The _udp client - /// </summary> - private readonly UdpClient _udpClient; - /// <summary> - /// The _stream - /// </summary> - private readonly IObservable<UdpReceiveResult> _stream; - - /// <summary> - /// Initializes a new instance of the <see cref="UdpServer" /> class. - /// </summary> - /// <param name="endPoint">The end point.</param> - /// <exception cref="System.ArgumentNullException">endPoint</exception> - public UdpServer(IPEndPoint endPoint) - { - if (endPoint == null) - { - throw new ArgumentNullException("endPoint"); - } - - _udpClient = new UdpClient(endPoint); - - _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - //_udpClient.ExclusiveAddressUse = false; - - _stream = CreateObservable(); - } - - /// <summary> - /// Creates the observable. - /// </summary> - /// <returns>IObservable{UdpReceiveResult}.</returns> - private IObservable<UdpReceiveResult> CreateObservable() - { - return Observable.Create<UdpReceiveResult>(obs => - Observable.FromAsync(() => _udpClient.ReceiveAsync()) - .Subscribe(obs)) - .Repeat() - .Retry() - .Publish() - .RefCount(); - } - - /// <summary> - /// Subscribes the specified observer. - /// </summary> - /// <param name="observer">The observer.</param> - /// <returns>IDisposable.</returns> - /// <exception cref="System.ArgumentNullException">observer</exception> - public IDisposable Subscribe(IObserver<UdpReceiveResult> observer) - { - if (observer == null) - { - throw new ArgumentNullException("observer"); - } - - return _stream.Subscribe(observer); - } - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - _udpClient.Close(); - } - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="data">The data.</param> - /// <param name="endPoint">The end point.</param> - /// <returns>Task{System.Int32}.</returns> - /// <exception cref="System.ArgumentNullException">data</exception> - public async Task<int> SendAsync(string data, IPEndPoint endPoint) - { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - if (endPoint == null) - { - throw new ArgumentNullException("endPoint"); - } - - var bytes = Encoding.UTF8.GetBytes(data); - - return await _udpClient.SendAsync(bytes, bytes.Length, endPoint).ConfigureAwait(false); - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="bytes">The bytes.</param> - /// <param name="endPoint">The end point.</param> - /// <returns>Task{System.Int32}.</returns> - /// <exception cref="System.ArgumentNullException">bytes</exception> - public async Task<int> SendAsync(byte[] bytes, IPEndPoint endPoint) - { - if (bytes == null) - { - throw new ArgumentNullException("bytes"); - } - - if (endPoint == null) - { - throw new ArgumentNullException("endPoint"); - } - - return await _udpClient.SendAsync(bytes, bytes.Length, endPoint).ConfigureAwait(false); - } - } -} diff --git a/MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs b/MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs new file mode 100644 index 000000000..711da7a50 --- /dev/null +++ b/MediaBrowser.Common/Net/WebSocketConnectEventArgs.cs @@ -0,0 +1,22 @@ +using System; +using System.Net; + +namespace MediaBrowser.Common.Net +{ + /// <summary> + /// Class WebSocketConnectEventArgs + /// </summary> + public class WebSocketConnectEventArgs : EventArgs + { + /// <summary> + /// Gets or sets the web socket. + /// </summary> + /// <value>The web socket.</value> + public IWebSocket WebSocket { get; set; } + /// <summary> + /// Gets or sets the endpoint. + /// </summary> + /// <value>The endpoint.</value> + public string Endpoint { get; set; } + } +} diff --git a/MediaBrowser.Common/Net/WebSocketConnection.cs b/MediaBrowser.Common/Net/WebSocketConnection.cs index d274d390d..ab691c823 100644 --- a/MediaBrowser.Common/Net/WebSocketConnection.cs +++ b/MediaBrowser.Common/Net/WebSocketConnection.cs @@ -21,7 +21,7 @@ namespace MediaBrowser.Common.Net /// <summary> /// The _remote end point /// </summary> - public readonly EndPoint RemoteEndPoint; + public readonly string RemoteEndPoint; /// <summary> /// The _cancellation token source @@ -45,13 +45,13 @@ namespace MediaBrowser.Common.Net /// <param name="remoteEndPoint">The remote end point.</param> /// <param name="receiveAction">The receive action.</param> /// <exception cref="System.ArgumentNullException">socket</exception> - public WebSocketConnection(IWebSocket socket, EndPoint remoteEndPoint, Action<WebSocketMessageInfo> receiveAction, ILogger logger) + public WebSocketConnection(IWebSocket socket, string remoteEndPoint, Action<WebSocketMessageInfo> receiveAction, ILogger logger) { if (socket == null) { throw new ArgumentNullException("socket"); } - if (remoteEndPoint == null) + if (string.IsNullOrEmpty(remoteEndPoint)) { throw new ArgumentNullException("remoteEndPoint"); } |
