Add preliminary support for buttons
This commit is contained in:
92
PluralKit.Bot/Services/InteractionDispatchService.cs
Normal file
92
PluralKit.Bot/Services/InteractionDispatchService.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using NodaTime;
|
||||
|
||||
using Serilog;
|
||||
|
||||
namespace PluralKit.Bot
|
||||
{
|
||||
public class InteractionDispatchService: IDisposable
|
||||
{
|
||||
private static readonly Duration DefaultExpiry = Duration.FromMinutes(15);
|
||||
|
||||
private readonly ConcurrentDictionary<Guid, RegisteredInteraction> _handlers = new();
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
private readonly IClock _clock;
|
||||
private readonly ILogger _logger;
|
||||
private readonly Task _cleanupWorker;
|
||||
|
||||
public InteractionDispatchService(IClock clock, ILogger logger)
|
||||
{
|
||||
_clock = clock;
|
||||
_logger = logger.ForContext<InteractionDispatchService>();
|
||||
|
||||
_cleanupWorker = CleanupLoop(_cts.Token);
|
||||
}
|
||||
|
||||
public async ValueTask<bool> Dispatch(string customId, InteractionContext context)
|
||||
{
|
||||
if (!Guid.TryParse(customId, out var customIdGuid))
|
||||
return false;
|
||||
|
||||
if (!_handlers.TryGetValue(customIdGuid, out var handler))
|
||||
return false;
|
||||
|
||||
await handler.Callback.Invoke(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
public string Register(Func<InteractionContext, Task> callback, Duration? expiry = null)
|
||||
{
|
||||
var key = Guid.NewGuid();
|
||||
var handler = new RegisteredInteraction
|
||||
{
|
||||
Callback = callback,
|
||||
Expiry = _clock.GetCurrentInstant() + (expiry ?? DefaultExpiry)
|
||||
};
|
||||
|
||||
_handlers[key] = handler;
|
||||
return key.ToString();
|
||||
}
|
||||
|
||||
private async Task CleanupLoop(CancellationToken ct)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
DoCleanup();
|
||||
await Task.Delay(TimeSpan.FromMinutes(1), ct);
|
||||
}
|
||||
}
|
||||
|
||||
private void DoCleanup()
|
||||
{
|
||||
var now = _clock.GetCurrentInstant();
|
||||
var removedCount = 0;
|
||||
foreach (var (key, value) in _handlers.ToArray())
|
||||
{
|
||||
if (value.Expiry < now)
|
||||
{
|
||||
_handlers.TryRemove(key, out _);
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Debug("Removed {ExpiredInteractions} expired interactions", removedCount);
|
||||
}
|
||||
|
||||
private struct RegisteredInteraction
|
||||
{
|
||||
public Instant Expiry;
|
||||
public Func<InteractionContext, Task> Callback;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cts.Cancel();
|
||||
_cts.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user