feat: upgrade to .NET 6, refactor everything

This commit is contained in:
spiral
2021-11-26 21:10:56 -05:00
parent d28e99ba43
commit 1918c56937
314 changed files with 27954 additions and 27966 deletions

View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Autofac;
using Myriad.Rest.Types;
@@ -12,122 +6,119 @@ using Myriad.Types;
using NodaTime;
namespace PluralKit.Bot.Interactive
namespace PluralKit.Bot.Interactive;
public abstract class BaseInteractive
{
public abstract class BaseInteractive
protected readonly List<Button> _buttons = new();
protected readonly Context _ctx;
protected readonly TaskCompletionSource _tcs = new();
protected bool _running;
protected BaseInteractive(Context ctx)
{
protected readonly Context _ctx;
protected readonly List<Button> _buttons = new();
protected readonly TaskCompletionSource _tcs = new();
protected Message _message { get; private set; }
protected bool _running;
_ctx = ctx;
}
protected BaseInteractive(Context ctx)
protected Message _message { get; private set; }
public Duration Timeout { get; set; } = Duration.FromMinutes(5);
protected Button AddButton(Func<InteractionContext, Task> handler, string? label = null,
ButtonStyle style = ButtonStyle.Secondary, bool disabled = false)
{
var dispatch = _ctx.Services.Resolve<InteractionDispatchService>();
var customId = dispatch.Register(handler, Timeout);
var button = new Button
{
_ctx = ctx;
}
Label = label,
Style = style,
Disabled = disabled,
CustomId = customId,
};
_buttons.Add(button);
return button;
}
public Duration Timeout { get; set; } = Duration.FromMinutes(5);
protected async Task Update(InteractionContext ctx)
{
await ctx.Respond(InteractionResponse.ResponseType.UpdateMessage,
new InteractionApplicationCommandCallbackData { Components = GetComponents() });
}
protected Button AddButton(Func<InteractionContext, Task> handler, string? label = null, ButtonStyle style = ButtonStyle.Secondary, bool disabled = false)
{
var dispatch = _ctx.Services.Resolve<InteractionDispatchService>();
var customId = dispatch.Register(handler, Timeout);
protected async Task Finish(InteractionContext? ctx = null)
{
foreach (var button in _buttons)
button.Disabled = true;
var button = new Button
{
Label = label,
Style = style,
Disabled = disabled,
CustomId = customId
};
_buttons.Add(button);
return button;
}
if (ctx != null)
await Update(ctx);
else
await _ctx.Rest.EditMessage(_message.ChannelId, _message.Id,
new MessageEditRequest { Components = GetComponents() });
protected async Task Update(InteractionContext ctx)
{
await ctx.Respond(InteractionResponse.ResponseType.UpdateMessage,
new InteractionApplicationCommandCallbackData
{
Components = GetComponents()
});
}
_tcs.TrySetResult();
}
protected async Task Finish(InteractionContext? ctx = null)
{
foreach (var button in _buttons)
button.Disabled = true;
if (ctx != null)
await Update(ctx);
else
await _ctx.Rest.EditMessage(_message.ChannelId, _message.Id, new MessageEditRequest
{
Components = GetComponents()
});
_tcs.TrySetResult();
}
protected async Task Send(string? content = null, Embed? embed = null, AllowedMentions? mentions = null)
{
_message = await _ctx.Rest.CreateMessage(_ctx.Channel.Id, new MessageRequest
protected async Task Send(string? content = null, Embed? embed = null, AllowedMentions? mentions = null)
{
_message = await _ctx.Rest.CreateMessage(_ctx.Channel.Id,
new MessageRequest
{
Content = content,
Embed = embed,
AllowedMentions = mentions,
Components = GetComponents()
});
}
}
public MessageComponent[] GetComponents()
public MessageComponent[] GetComponents()
{
return new MessageComponent[]
{
return new MessageComponent[]
new()
{
new()
{
Type = ComponentType.ActionRow,
Components = _buttons.Select(b => b.ToMessageComponent()).ToArray()
}
};
}
public void Setup(Context ctx)
{
var dispatch = ctx.Services.Resolve<InteractionDispatchService>();
foreach (var button in _buttons)
button.CustomId = dispatch.Register(button.Handler, Timeout);
}
public abstract Task Start();
public async Task Run()
{
if (_running)
throw new InvalidOperationException("Action is already running");
_running = true;
await Start();
var cts = new CancellationTokenSource(Timeout.ToTimeSpan());
cts.Token.Register(() => _tcs.TrySetException(new TimeoutException("Action timed out")));
try
{
await _tcs.Task;
Type = ComponentType.ActionRow,
Components = _buttons.Select(b => b.ToMessageComponent()).ToArray()
}
finally
{
Cleanup();
}
}
};
}
protected void Cleanup()
public void Setup(Context ctx)
{
var dispatch = ctx.Services.Resolve<InteractionDispatchService>();
foreach (var button in _buttons)
button.CustomId = dispatch.Register(button.Handler, Timeout);
}
public abstract Task Start();
public async Task Run()
{
if (_running)
throw new InvalidOperationException("Action is already running");
_running = true;
await Start();
var cts = new CancellationTokenSource(Timeout.ToTimeSpan());
cts.Token.Register(() => _tcs.TrySetException(new TimeoutException("Action timed out")));
try
{
var dispatch = _ctx.Services.Resolve<InteractionDispatchService>();
foreach (var button in _buttons)
dispatch.Unregister(button.CustomId!);
await _tcs.Task;
}
finally
{
Cleanup();
}
}
protected void Cleanup()
{
var dispatch = _ctx.Services.Resolve<InteractionDispatchService>();
foreach (var button in _buttons)
dispatch.Unregister(button.CustomId!);
}
}

View File

@@ -1,25 +1,21 @@
using System;
using System.Threading.Tasks;
using Myriad.Types;
namespace PluralKit.Bot.Interactive
{
public class Button
{
public string? Label { get; set; }
public ButtonStyle Style { get; set; } = ButtonStyle.Secondary;
public string? CustomId { get; set; }
public bool Disabled { get; set; }
public Func<InteractionContext, Task> Handler { get; init; }
namespace PluralKit.Bot.Interactive;
public MessageComponent ToMessageComponent() => new()
{
Type = ComponentType.Button,
Label = Label,
Style = Style,
CustomId = CustomId,
Disabled = Disabled
};
}
public class Button
{
public string? Label { get; set; }
public ButtonStyle Style { get; set; } = ButtonStyle.Secondary;
public string? CustomId { get; set; }
public bool Disabled { get; set; }
public Func<InteractionContext, Task> Handler { get; init; }
public MessageComponent ToMessageComponent() => new()
{
Type = ComponentType.Button,
Label = Label,
Style = Style,
CustomId = CustomId,
Disabled = Disabled
};
}

View File

@@ -1,6 +1,4 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Autofac;
using Myriad.Gateway;
using Myriad.Rest.Types;
@@ -8,102 +6,99 @@ using Myriad.Types;
using PluralKit.Core;
using Autofac;
namespace PluralKit.Bot.Interactive;
namespace PluralKit.Bot.Interactive
public class YesNoPrompt: BaseInteractive
{
public class YesNoPrompt: BaseInteractive
public YesNoPrompt(Context ctx) : base(ctx)
{
public bool? Result { get; private set; }
public ulong? User { get; set; }
public string Message { get; set; } = "Are you sure?";
User = ctx.Author.Id;
}
public string AcceptLabel { get; set; } = "OK";
public ButtonStyle AcceptStyle { get; set; } = ButtonStyle.Primary;
public bool? Result { get; private set; }
public ulong? User { get; set; }
public string Message { get; set; } = "Are you sure?";
public string CancelLabel { get; set; } = "Cancel";
public ButtonStyle CancelStyle { get; set; } = ButtonStyle.Secondary;
public string AcceptLabel { get; set; } = "OK";
public ButtonStyle AcceptStyle { get; set; } = ButtonStyle.Primary;
public override async Task Start()
public string CancelLabel { get; set; } = "Cancel";
public ButtonStyle CancelStyle { get; set; } = ButtonStyle.Secondary;
public override async Task Start()
{
AddButton(ctx => OnButtonClick(ctx, true), AcceptLabel, AcceptStyle);
AddButton(ctx => OnButtonClick(ctx, false), CancelLabel, CancelStyle);
AllowedMentions mentions = null;
if (User != _ctx.Author.Id)
mentions = new AllowedMentions { Users = new[] { User!.Value } };
await Send(Message, mentions: mentions);
}
private async Task OnButtonClick(InteractionContext ctx, bool result)
{
if (ctx.User.Id != User)
{
AddButton(ctx => OnButtonClick(ctx, true), AcceptLabel, AcceptStyle);
AddButton(ctx => OnButtonClick(ctx, false), CancelLabel, CancelStyle);
AllowedMentions mentions = null;
if (User != _ctx.Author.Id)
mentions = new AllowedMentions { Users = new[] { User!.Value } };
await Send(Message, mentions: mentions);
await Update(ctx);
return;
}
private async Task OnButtonClick(InteractionContext ctx, bool result)
{
if (ctx.User.Id != User)
{
await Update(ctx);
return;
}
Result = result;
await Finish(ctx);
}
Result = result;
await Finish(ctx);
private bool MessagePredicate(MessageCreateEvent e)
{
if (e.ChannelId != _ctx.Channel.Id) return false;
if (e.Author.Id != User) return false;
var response = e.Content.ToLowerInvariant();
if (response == "y" || response == "yes")
{
Result = true;
return true;
}
private bool MessagePredicate(MessageCreateEvent e)
if (response == "n" || response == "no")
{
if (e.ChannelId != _ctx.Channel.Id) return false;
if (e.Author.Id != User) return false;
var response = e.Content.ToLowerInvariant();
if (response == "y" || response == "yes")
{
Result = true;
return true;
}
if (response == "n" || response == "no")
{
Result = false;
return true;
}
return false;
Result = false;
return true;
}
public new async Task Run()
return false;
}
public new async Task Run()
{
// todo: can we split this up somehow so it doesn't need to be *completely* copied from BaseInteractive?
var cts = new CancellationTokenSource(Timeout.ToTimeSpan());
if (_running)
throw new InvalidOperationException("Action is already running");
_running = true;
var queue = _ctx.Services.Resolve<HandlerQueue<MessageCreateEvent>>();
var messageDispatch = queue.WaitFor(MessagePredicate, Timeout, cts.Token);
await Start();
cts.Token.Register(() => _tcs.TrySetException(new TimeoutException("Action timed out")));
try
{
// todo: can we split this up somehow so it doesn't need to be *completely* copied from BaseInteractive?
var cts = new CancellationTokenSource(Timeout.ToTimeSpan());
if (_running)
throw new InvalidOperationException("Action is already running");
_running = true;
var queue = _ctx.Services.Resolve<HandlerQueue<MessageCreateEvent>>();
var messageDispatch = queue.WaitFor(MessagePredicate, Timeout, cts.Token);
await Start();
cts.Token.Register(() => _tcs.TrySetException(new TimeoutException("Action timed out")));
try
{
var doneTask = await Task.WhenAny(_tcs.Task, messageDispatch);
if (doneTask == messageDispatch)
await Finish();
}
finally
{
Cleanup();
}
var doneTask = await Task.WhenAny(_tcs.Task, messageDispatch);
if (doneTask == messageDispatch)
await Finish();
}
public YesNoPrompt(Context ctx) : base(ctx)
finally
{
User = ctx.Author.Id;
Cleanup();
}
}
}