mirror of
https://github.com/AlexMacocian/Net.Sdk.Web.Extensions.git
synced 2026-07-22 08:49:31 +00:00
120 lines
4.5 KiB
C#
120 lines
4.5 KiB
C#
using AspNetCore.Extensions.Attributes;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using System.Extensions;
|
|
using System.Net.WebSockets;
|
|
|
|
namespace AspNetCore.Extensions.Websockets;
|
|
|
|
public abstract class WebSocketRouteBase
|
|
{
|
|
public HttpContext? Context { get; internal set; }
|
|
|
|
public WebSocket? WebSocket { get; internal set; }
|
|
|
|
public virtual Task SocketAccepted(CancellationToken cancellationToken)
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public virtual Task SocketClosed()
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public abstract Task ExecuteAsync(WebSocketMessageType type, byte[] data, CancellationToken cancellationToken);
|
|
}
|
|
|
|
public abstract class WebSocketRouteBase<TReceiveType> : WebSocketRouteBase
|
|
where TReceiveType : class, new()
|
|
{
|
|
private readonly Lazy<WebSocketMessageConverterBase> converter;
|
|
|
|
public WebSocketRouteBase()
|
|
{
|
|
this.converter = new Lazy<WebSocketMessageConverterBase>(() =>
|
|
{
|
|
var attribute = typeof(TReceiveType).GetCustomAttributes(true).First(a => a is WebSocketConverterAttributeBase).Cast<WebSocketConverterAttributeBase>();
|
|
var parsedConverter = GetConverter(attribute.ConverterType, this.Context!);
|
|
return parsedConverter;
|
|
});
|
|
}
|
|
|
|
public sealed override Task ExecuteAsync(WebSocketMessageType type, byte[] data, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
var objData = this.converter.Value.ConvertToObject(new WebSocketConverterRequest { Type = type, Payload = data }).Cast<TReceiveType>();
|
|
return this.ExecuteAsync(objData, cancellationToken);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var scoppedLogger = this.Context!.RequestServices.GetRequiredService<ILogger<WebSocketRouteBase<TReceiveType>>>().CreateScopedLogger(nameof(this.ExecuteAsync), string.Empty);
|
|
scoppedLogger.LogError(ex, "Failed to process data");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public abstract Task ExecuteAsync(TReceiveType? type, CancellationToken cancellationToken);
|
|
|
|
internal static WebSocketMessageConverterBase GetConverter(Type converterType, HttpContext context)
|
|
{
|
|
var constructors = converterType.GetConstructors();
|
|
foreach (var constructor in constructors)
|
|
{
|
|
if (constructor.GetCustomAttributes(false).Any(a => a is DoNotInjectAttribute))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var dependencies = constructor.GetParameters().Select(param => context.RequestServices.GetService(param.ParameterType));
|
|
if (dependencies.Any(d => d is null))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var route = constructor.Invoke(dependencies.ToArray());
|
|
return route.Cast<WebSocketMessageConverterBase>();
|
|
}
|
|
|
|
throw new InvalidOperationException($"Unable to resolve {converterType.Name}");
|
|
}
|
|
}
|
|
|
|
public abstract class WebSocketRouteBase<TReceiveType, TSendType> : WebSocketRouteBase<TReceiveType>
|
|
where TReceiveType : class, new()
|
|
{
|
|
private readonly Lazy<WebSocketMessageConverterBase> converter = new(() =>
|
|
{
|
|
var attribute = typeof(TSendType).GetCustomAttributes(true).First(a => a is WebSocketConverterAttributeBase).Cast<WebSocketConverterAttributeBase>();
|
|
var converter = Activator.CreateInstance(attribute.ConverterType)!.Cast<WebSocketMessageConverterBase>();
|
|
return converter;
|
|
});
|
|
|
|
public WebSocketRouteBase()
|
|
{
|
|
this.converter = new Lazy<WebSocketMessageConverterBase>(() =>
|
|
{
|
|
var attribute = typeof(TSendType).GetCustomAttributes(true).First(a => a is WebSocketConverterAttributeBase).Cast<WebSocketConverterAttributeBase>();
|
|
var parsedConverter = GetConverter(attribute.ConverterType, this.Context!);
|
|
return parsedConverter;
|
|
});
|
|
}
|
|
|
|
public Task SendMessage(TSendType sendType, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
var response = this.converter.Value.ConvertFromObject(sendType!);
|
|
return this.WebSocket!.SendAsync(response.Payload!, response.Type, response.EndOfMessage, cancellationToken);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var scoppedLogger = this.Context!.RequestServices.GetRequiredService<ILogger<WebSocketRouteBase<TReceiveType, TSendType>>>().CreateScopedLogger(nameof(this.SendMessage), string.Empty);
|
|
scoppedLogger.LogError(ex, "Failed to send data");
|
|
throw;
|
|
}
|
|
}
|
|
}
|