PluralKit/PluralKit.Bot/Services/InteractionDispatchService.cs

94 lines
2.4 KiB
C#
Raw Permalink Normal View History

2021-05-26 20:27:52 +00:00
using System.Collections.Concurrent;
using NodaTime;
using Serilog;
namespace PluralKit.Bot;
public class InteractionDispatchService: IDisposable
2021-05-26 20:27:52 +00:00
{
private static readonly Duration DefaultExpiry = Duration.FromMinutes(15);
private readonly Task _cleanupWorker;
private readonly IClock _clock;
private readonly CancellationTokenSource _cts = new();
2021-05-26 20:27:52 +00:00
private readonly ConcurrentDictionary<Guid, RegisteredInteraction> _handlers = new();
private readonly ILogger _logger;
2021-08-27 15:03:47 +00:00
public InteractionDispatchService(IClock clock, ILogger logger)
{
_clock = clock;
_logger = logger.ForContext<InteractionDispatchService>();
2021-05-26 20:27:52 +00:00
_cleanupWorker = CleanupLoop(_cts.Token);
}
2021-05-26 20:27:52 +00:00
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
2021-08-27 15:03:47 +00:00
public async ValueTask<bool> Dispatch(string customId, InteractionContext context)
{
if (!Guid.TryParse(customId, out var customIdGuid))
return false;
2021-05-26 20:27:52 +00:00
if (!_handlers.TryGetValue(customIdGuid, out var handler))
return false;
2021-05-26 20:27:52 +00:00
await handler.Callback.Invoke(context);
return true;
}
2021-05-30 14:45:29 +00:00
public void Unregister(string customId)
{
if (!Guid.TryParse(customId, out var customIdGuid))
return;
_handlers.TryRemove(customIdGuid, out _);
}
2021-05-30 14:45:29 +00:00
public string Register(Func<InteractionContext, Task> callback, Duration? expiry = null)
{
var key = Guid.NewGuid();
var handler = new RegisteredInteraction
2021-05-26 20:27:52 +00:00
{
Callback = callback,
Expiry = _clock.GetCurrentInstant() + (expiry ?? DefaultExpiry)
};
2021-08-27 15:03:47 +00:00
_handlers[key] = handler;
return key.ToString();
}
2021-05-26 20:27:52 +00:00
private async Task CleanupLoop(CancellationToken ct)
{
while (true)
2021-05-26 20:27:52 +00:00
{
DoCleanup();
await Task.Delay(TimeSpan.FromMinutes(1), ct);
2021-05-26 20:27:52 +00:00
}
}
2021-05-26 20:27:52 +00:00
private void DoCleanup()
{
var now = _clock.GetCurrentInstant();
var removedCount = 0;
foreach (var (key, value) in _handlers.ToArray())
if (value.Expiry < now)
2021-05-26 20:27:52 +00:00
{
_handlers.TryRemove(key, out _);
removedCount++;
2021-05-26 20:27:52 +00:00
}
_logger.Debug("Removed {ExpiredInteractions} expired interactions", removedCount);
}
2021-05-26 20:27:52 +00:00
private struct RegisteredInteraction
{
public Instant Expiry;
public Func<InteractionContext, Task> Callback;
2021-05-26 20:27:52 +00:00
}
}