You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
3.8 KiB
92 lines
3.8 KiB
using System;
|
|
using System.Net.WebSockets;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Infrastructure.Extensions;
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
namespace Infrastructure.WebSockets
|
|
{
|
|
public class WebSocketManager
|
|
{
|
|
private readonly RequestDelegate _next;
|
|
|
|
public delegate void SendHandler(ArraySegment<byte> buffer, WebSocketMessageType messageType, Func<WebSocketWrapper, bool> condition);
|
|
|
|
public static event SendHandler SendMessage;
|
|
|
|
public WebSocketManager(RequestDelegate next)
|
|
{
|
|
_next = next;
|
|
}
|
|
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "<¹ÒÆð>")]
|
|
public async Task InvokeAsync(HttpContext context)
|
|
{
|
|
if (context is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(context));
|
|
}
|
|
|
|
if (context.Request.Path.StartsWithSegments("/ws", StringComparison.CurrentCulture))
|
|
{
|
|
if (context.Request.Path.StartsWithSegments("/ws", StringComparison.CurrentCulture))
|
|
{
|
|
if (context.WebSockets.IsWebSocketRequest)
|
|
{
|
|
try
|
|
{
|
|
var sec = "Sec-WebSocket-Protocol";
|
|
if (context.Request.Headers.ContainsKey(sec))
|
|
{
|
|
context.Response.Headers.Add(sec, context.Request.Headers[sec]);
|
|
}
|
|
var webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(true);
|
|
var key = Guid.NewGuid();
|
|
var wrapper = new WebSocketWrapper { Context = context, WebSocket = webSocket };
|
|
SendMessage += wrapper.Send;
|
|
var buffer = new byte[1024 * 4];
|
|
WebSocketReceiveResult result = null;
|
|
while (webSocket.State == WebSocketState.Open)
|
|
{
|
|
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None).ConfigureAwait(true);
|
|
if (result == null || result.CloseStatus.HasValue || result.MessageType == WebSocketMessageType.Close)
|
|
{
|
|
break;
|
|
}
|
|
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
|
wrapper.OnReceived(message);
|
|
}
|
|
SendMessage -= wrapper.Send;
|
|
if (webSocket.State == WebSocketState.Open || webSocket.State == WebSocketState.CloseSent)
|
|
{
|
|
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(true);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
context.Response.StatusCode = 400;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
await this._next(context).ConfigureAwait(true);
|
|
}
|
|
}
|
|
|
|
public static async Task Send(ArraySegment<byte> data, WebSocketMessageType messageType, Func<WebSocketWrapper, bool> condition)
|
|
{
|
|
await Task.Run(() =>
|
|
{
|
|
SendMessage?.Invoke(data, messageType, condition);
|
|
}).ConfigureAwait(true);
|
|
}
|
|
}
|
|
} |