Files
ClubPenguinClient/MareSynchronos/WebAPI/SignalR/HubFactory.cs
2023-12-11 23:15:38 +00:00

122 lines
4.1 KiB
C#

using MareSynchronos.API.SignalR;
using MareSynchronos.Services.Mediator;
using MareSynchronos.Services.ServerConfiguration;
using MareSynchronos.WebAPI.SignalR.Utils;
using MessagePack;
using MessagePack.Resolvers;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace MareSynchronos.WebAPI.SignalR;
public class HubFactory : MediatorSubscriberBase
{
private readonly ILoggerProvider _loggingProvider;
private readonly ServerConfigurationManager _serverConfigurationManager;
private readonly TokenProvider _tokenProvider;
private HubConnection? _instance;
private bool _isDisposed = false;
public HubFactory(ILogger<HubFactory> logger, MareMediator mediator,
ServerConfigurationManager serverConfigurationManager,
TokenProvider tokenProvider, ILoggerProvider pluginLog) : base(logger, mediator)
{
_serverConfigurationManager = serverConfigurationManager;
_tokenProvider = tokenProvider;
_loggingProvider = pluginLog;
}
public async Task DisposeHubAsync()
{
if (_instance == null || _isDisposed) return;
Logger.LogDebug("Disposing current HubConnection");
_isDisposed = true;
_instance.Closed -= HubOnClosed;
_instance.Reconnecting -= HubOnReconnecting;
_instance.Reconnected -= HubOnReconnected;
await _instance.StopAsync().ConfigureAwait(false);
await _instance.DisposeAsync().ConfigureAwait(false);
_instance = null;
Logger.LogDebug("Current HubConnection disposed");
}
public HubConnection GetOrCreate(CancellationToken ct)
{
if (!_isDisposed && _instance != null) return _instance;
return BuildHubConnection(ct);
}
private HubConnection BuildHubConnection(CancellationToken ct)
{
Logger.LogDebug("Building new HubConnection");
_instance = new HubConnectionBuilder()
.WithUrl(_serverConfigurationManager.CurrentApiUrl + IMareHub.Path, options =>
{
options.AccessTokenProvider = () => _tokenProvider.GetOrUpdateToken(ct);
options.SkipNegotiation = true;
options.Transports = HttpTransportType.WebSockets;
})
.AddMessagePackProtocol(opt =>
{
var resolver = CompositeResolver.Create(StandardResolverAllowPrivate.Instance,
BuiltinResolver.Instance,
AttributeFormatterResolver.Instance,
// replace enum resolver
DynamicEnumAsStringResolver.Instance,
DynamicGenericResolver.Instance,
DynamicUnionResolver.Instance,
DynamicObjectResolver.Instance,
PrimitiveObjectResolver.Instance,
// final fallback(last priority)
StandardResolver.Instance);
opt.SerializerOptions =
MessagePackSerializerOptions.Standard
.WithCompression(MessagePackCompression.Lz4Block)
.WithResolver(resolver);
})
.WithAutomaticReconnect(new ForeverRetryPolicy(Mediator))
.ConfigureLogging(a =>
{
a.ClearProviders().AddProvider(_loggingProvider);
a.SetMinimumLevel(LogLevel.Information);
})
.Build();
_instance.Closed += HubOnClosed;
_instance.Reconnecting += HubOnReconnecting;
_instance.Reconnected += HubOnReconnected;
_isDisposed = false;
return _instance;
}
private Task HubOnClosed(Exception? arg)
{
Mediator.Publish(new HubClosedMessage(arg));
return Task.CompletedTask;
}
private Task HubOnReconnected(string? arg)
{
Mediator.Publish(new HubReconnectedMessage(arg));
return Task.CompletedTask;
}
private Task HubOnReconnecting(Exception? arg)
{
Mediator.Publish(new HubReconnectingMessage(arg));
return Task.CompletedTask;
}
}