aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs
diff options
context:
space:
mode:
authorBond_009 <bond.009@outlook.com>2020-05-02 00:54:04 +0200
committerBond_009 <bond.009@outlook.com>2020-05-02 00:54:04 +0200
commit15634a1913e8c1ad4e921364f30055794644d0bd (patch)
treef0dfb3502728e4786de32c0cb4eaabd06f8e2d87 /Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs
parent407f54e7764a6bfd8e4ccc0df897fac7e8c658b4 (diff)
parent62e251663fce8216cea529f85382299ac2f39fbc (diff)
Merge branch 'master' into websocket
Diffstat (limited to 'Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs')
-rw-r--r--Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs135
1 files changed, 135 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..b85750c9b
--- /dev/null
+++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.WebSockets;
+using System.Threading;
+using System.Threading.Tasks;
+using Emby.Server.Implementations.HttpServer;
+using Emby.Server.Implementations.Net;
+using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Extensions;
+using Microsoft.Extensions.Logging;
+using Microsoft.Net.Http.Headers;
+
+namespace Emby.Server.Implementations.SocketSharp
+{
+ public class WebSocketSharpListener : IHttpListener
+ {
+ private readonly ILogger _logger;
+
+ private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
+ private CancellationToken _disposeCancellationToken;
+
+ public WebSocketSharpListener(ILogger<WebSocketSharpListener> 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<WebSocketConnectEventArgs> WebSocketConnected { get; set; }
+
+ private static void LogRequest(ILogger logger, HttpRequest request)
+ {
+ var url = request.GetDisplayUrl();
+
+ logger.LogInformation("WS {Url}. UserAgent: {UserAgent}", url, request.Headers[HeaderNames.UserAgent].ToString());
+ }
+
+ public async Task ProcessWebSocketRequest(HttpContext ctx)
+ {
+ try
+ {
+ LogRequest(_logger, ctx.Request);
+ var endpoint = ctx.Connection.RemoteIpAddress.ToString();
+ var url = ctx.Request.GetDisplayUrl();
+
+ var webSocketContext = await ctx.WebSockets.AcceptWebSocketAsync(null).ConfigureAwait(false);
+ var socket = new SharpWebSocket(webSocketContext, _logger);
+
+ WebSocketConnected(new WebSocketConnectEventArgs
+ {
+ Url = url,
+ QueryString = ctx.Request.Query,
+ WebSocket = socket,
+ Endpoint = endpoint
+ });
+
+ WebSocketReceiveResult result;
+ var message = new List<byte>();
+
+ do
+ {
+ var buffer = WebSocket.CreateServerBuffer(4096);
+ result = await webSocketContext.ReceiveAsync(buffer, _disposeCancellationToken);
+ message.AddRange(buffer.Array.Take(result.Count));
+
+ if (result.EndOfMessage)
+ {
+ socket.OnReceiveBytes(message.ToArray());
+ message.Clear();
+ }
+ } while (socket.State == WebSocketState.Open && result.MessageType != WebSocketMessageType.Close);
+
+
+ if (webSocketContext.State == WebSocketState.Open)
+ {
+ await webSocketContext.CloseAsync(
+ result.CloseStatus ?? WebSocketCloseStatus.NormalClosure,
+ result.CloseStatusDescription,
+ _disposeCancellationToken).ConfigureAwait(false);
+ }
+
+ socket.Dispose();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "AcceptWebSocketAsync error");
+ if (!ctx.Response.HasStarted)
+ {
+ ctx.Response.StatusCode = 500;
+ }
+ }
+ }
+
+ public Task Stop()
+ {
+ _disposeCancellationTokenSource.Cancel();
+ 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;
+ }
+ }
+}