aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs')
-rw-r--r--Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs261
1 files changed, 261 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs
new file mode 100644
index 000000000..ab7ddeca2
--- /dev/null
+++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs
@@ -0,0 +1,261 @@
+using System;
+using System.Collections.Generic;
+ using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+using Emby.Server.Implementations.HttpServer;
+using Emby.Server.Implementations.Net;
+using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+
+ namespace Emby.Server.Implementations.SocketSharp
+{
+ public class WebSocketSharpListener : IHttpListener
+ {
+ private HttpListener _listener;
+
+ private readonly ILogger _logger;
+
+ private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
+ private CancellationToken _disposeCancellationToken;
+
+ public WebSocketSharpListener(
+ ILogger logger)
+ {
+ _logger = logger;
+
+ _disposeCancellationToken = _disposeCancellationTokenSource.Token;
+ }
+
+ public Func<Exception, IRequest, bool, bool, Task> ErrorHandler { get; set; }
+ public Func<IHttpRequest, string, string, string, CancellationToken, Task> RequestHandler { get; set; }
+
+ public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
+
+ public Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; }
+
+// public void Start(IEnumerable<string> urlPrefixes)
+// {
+// // TODO
+// //if (_listener == null)
+// //{
+// // _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _streamHelper, _fileSystem, _environment);
+// //}
+//
+// //_listener.EnableDualMode = _enableDualMode;
+//
+// //if (_certificate != null)
+// //{
+// // _listener.LoadCert(_certificate);
+// //}
+//
+// //_logger.LogInformation("Adding HttpListener prefixes {Prefixes}", urlPrefixes);
+// //_listener.Prefixes.AddRange(urlPrefixes);
+//
+// //_listener.OnContext = async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false);
+//
+// //_listener.Start();
+//
+// if (_listener == null)
+// {
+// _listener = new HttpListener();
+// }
+//
+// _logger.LogInformation("Adding HttpListener prefixes {Prefixes}", urlPrefixes);
+//
+// //foreach (var urlPrefix in urlPrefixes)
+// //{
+// // _listener.Prefixes.Add(urlPrefix);
+// //}
+// _listener.Prefixes.Add("http://localhost:8096/");
+//
+// _listener.Start();
+//
+// // TODO how to do this in netcore?
+// _listener.BeginGetContext(async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false),
+// null);
+// }
+
+ private static void LogRequest(ILogger logger, HttpListenerRequest request)
+ {
+ var url = request.Url.ToString();
+
+ logger.LogInformation(
+ "{0} {1}. UserAgent: {2}",
+ request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod,
+ url,
+ request.UserAgent ?? string.Empty);
+ }
+//
+// private Task InitTask(IAsyncResult asyncResult, CancellationToken cancellationToken)
+// {
+// var context = _listener.EndGetContext(asyncResult);
+// _listener.BeginGetContext(async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false), null);
+// IHttpRequest httpReq = null;
+// var request = context.Request;
+//
+// try
+// {
+// if (request.IsWebSocketRequest)
+// {
+// LogRequest(_logger, request);
+//
+// return ProcessWebSocketRequest(context);
+// }
+//
+// httpReq = GetRequest(context);
+// }
+// catch (Exception ex)
+// {
+// _logger.LogError(ex, "Error processing request");
+//
+// httpReq = httpReq ?? GetRequest(context);
+// return ErrorHandler(ex, httpReq, true, true);
+// }
+//
+// var uri = request.Url;
+//
+// return RequestHandler(httpReq, uri.OriginalString, uri.Host, uri.LocalPath, cancellationToken);
+// }
+
+ private async Task ProcessWebSocketRequest(HttpListenerContext ctx)
+ {
+ try
+ {
+ var endpoint = ctx.Request.RemoteEndPoint.ToString();
+ var url = ctx.Request.RawUrl;
+
+ var queryString = new QueryParamCollection(ctx.Request.QueryString);
+
+ var connectingArgs = new WebSocketConnectingEventArgs
+ {
+ Url = url,
+ QueryString = queryString,
+ Endpoint = endpoint
+ };
+
+ WebSocketConnecting?.Invoke(connectingArgs);
+
+ if (connectingArgs.AllowConnection)
+ {
+ _logger.LogDebug("Web socket connection allowed");
+
+ var webSocketContext = await ctx.AcceptWebSocketAsync(null).ConfigureAwait(false);
+
+ if (WebSocketConnected != null)
+ {
+ SharpWebSocket socket = null; //new SharpWebSocket(webSocketContext.WebSocket, _logger);
+ await socket.ConnectAsServerAsync().ConfigureAwait(false);
+
+ WebSocketConnected(new WebSocketConnectEventArgs
+ {
+ Url = url,
+ QueryString = queryString,
+ WebSocket = socket,
+ Endpoint = endpoint
+ });
+
+ await ReceiveWebSocketAsync(ctx, socket).ConfigureAwait(false);
+ }
+ }
+ else
+ {
+ _logger.LogWarning("Web socket connection not allowed");
+ ctx.Response.StatusCode = 401;
+ ctx.Response.Close();
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "AcceptWebSocketAsync error");
+ ctx.Response.StatusCode = 500;
+ ctx.Response.Close();
+ }
+ }
+
+ private async Task ReceiveWebSocketAsync(HttpListenerContext ctx, SharpWebSocket socket)
+ {
+ try
+ {
+ await socket.StartReceive().ConfigureAwait(false);
+ }
+ finally
+ {
+ TryClose(ctx, 200);
+ }
+ }
+
+ private void TryClose(HttpListenerContext ctx, int statusCode)
+ {
+ try
+ {
+ ctx.Response.StatusCode = statusCode;
+ ctx.Response.Close();
+ }
+ catch (ObjectDisposedException)
+ {
+ // TODO: Investigate and properly fix.
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error closing web socket response");
+ }
+ }
+
+ private IHttpRequest GetRequest(HttpRequest httpContext)
+ {
+ var urlSegments = httpContext.Path;
+
+ var operationName = urlSegments;
+
+ var req = new WebSocketSharpRequest(httpContext, httpContext.HttpContext.Response, operationName, _logger);
+
+ return req;
+ }
+
+ public void Start(IEnumerable<string> urlPrefixes)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task Stop()
+ {
+ _disposeCancellationTokenSource.Cancel();
+ _listener?.Close();
+
+ return Task.CompletedTask;
+ }
+
+ /// <summary>
+ /// Releases the unmanaged resources and disposes of the managed resources used.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private bool _disposed;
+
+ /// <summary>
+ /// Releases the unmanaged resources and disposes of the managed resources used.
+ /// </summary>
+ /// <param name="disposing">Whether or not the managed resources should be disposed</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ Stop().GetAwaiter().GetResult();
+ }
+
+ _disposed = true;
+ }
+ }
+}