Restructure

This commit is contained in:
Myx
2024-04-13 20:04:51 +02:00
parent 3699a13cd9
commit f7b54ca80c
23 changed files with 186 additions and 11 deletions

View File

@@ -0,0 +1,15 @@
using Discord.WebSocket;
using MediatR;
namespace Lunaris2.Handler.GoodByeCommand
{
public record GoodbyeCommand(SocketSlashCommand Message) : IRequest;
public class GoodbyeHandler : IRequestHandler<GoodbyeCommand>
{
public async Task Handle(GoodbyeCommand message, CancellationToken cancellationToken)
{
await message.Message.RespondAsync($"Goodbye, {message.Message.User.Username}! :c");
}
}
}

View File

@@ -0,0 +1,19 @@
using Discord.WebSocket;
using Lunaris2.SlashCommand;
using MediatR;
using Newtonsoft.Json;
namespace Lunaris2.Handler.HelloCommand
{
public record HelloCommand(SocketSlashCommand Message) : IRequest;
public class HelloHandler : IRequestHandler<HelloCommand>
{
public async Task Handle(HelloCommand message, CancellationToken cancellationToken)
{
Console.WriteLine(JsonConvert.SerializeObject(Command.GetAllCommands()));
await message.Message.RespondAsync($"Hello, {message.Message.User.Username}!");
}
}
}

View File

@@ -0,0 +1,24 @@
using Lunaris2.Handler.GoodByeCommand;
using Lunaris2.Notification;
using Lunaris2.SlashCommand;
using MediatR;
namespace Lunaris2.Handler;
public class MessageReceivedHandler(ISender mediator) : INotificationHandler<MessageReceivedNotification>
{
public async Task Handle(MessageReceivedNotification notification, CancellationToken cancellationToken)
{
switch (notification.Message.CommandName)
{
case Command.Hello.Name:
await mediator.Send(new HelloCommand.HelloCommand(notification.Message), cancellationToken);
break;
case Command.Goodbye.Name:
await mediator.Send(new GoodbyeCommand(notification.Message), cancellationToken);
break;
default:
break;
}
}
}

View File

@@ -0,0 +1,15 @@
using System.Threading.Tasks;
using Discord.WebSocket;
using Lunaris2.SlashCommand;
namespace Lunaris2.Helpers
{
public static class ClientReadyHandler
{
public static Task Client_Ready(this DiscordSocketClient client)
{
client.RegisterCommands();
return Task.CompletedTask;
}
}
}

View File

@@ -0,0 +1,12 @@
using Discord.Commands;
namespace Lunaris2.Helpers
{
public static class CommandServiceSetup
{
public static CommandService Setup()
{
return new CommandService();
}
}
}

View File

@@ -0,0 +1,17 @@
using Discord;
using Discord.WebSocket;
namespace Lunaris2.Helpers
{
public static class DiscordSocketClientSetup
{
public static DiscordSocketClient Setup()
{
var config = new DiscordSocketConfig
{
GatewayIntents = GatewayIntents.All
};
return new DiscordSocketClient(config);
}
}
}

13
Bot/Helpers/LogHandler.cs Normal file
View File

@@ -0,0 +1,13 @@
using Discord;
namespace Lunaris2.Helpers
{
public static class LogHandler
{
public static Task Log(LogMessage arg)
{
Console.WriteLine(arg);
return Task.CompletedTask;
}
}
}

29
Bot/Lunaris2.csproj Normal file
View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Discord.Net" Version="3.14.1" />
<PackageReference Include="Discord.Net.Commands" Version="3.14.1" />
<PackageReference Include="Discord.Net.Core" Version="3.14.1" />
<PackageReference Include="Discord.Net.Interactions" Version="3.14.1" />
<PackageReference Include="Discord.Net.Rest" Version="3.14.1" />
<PackageReference Include="MediatR" Version="12.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,31 @@
using Discord.WebSocket;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
namespace Lunaris2.Notification;
public class DiscordEventListener(DiscordSocketClient client, IServiceScopeFactory serviceScope)
{
private readonly CancellationToken _cancellationToken = new CancellationTokenSource().Token;
private IMediator Mediator
{
get
{
var scope = serviceScope.CreateScope();
return scope.ServiceProvider.GetRequiredService<IMediator>();
}
}
public async Task StartAsync()
{
client.SlashCommandExecuted += OnMessageReceivedAsync;
await Task.CompletedTask;
}
private Task OnMessageReceivedAsync(SocketSlashCommand arg)
{
return Mediator.Publish(new MessageReceivedNotification(arg), _cancellationToken);
}
}

View File

@@ -0,0 +1,9 @@
using Discord.WebSocket;
using MediatR;
namespace Lunaris2.Notification;
public class MessageReceivedNotification(SocketSlashCommand message) : INotification
{
public SocketSlashCommand Message { get; } = message ?? throw new ArgumentNullException(nameof(message));
}

78
Bot/Program.cs Normal file
View File

@@ -0,0 +1,78 @@
using System.Reflection;
using Discord;
using Discord.Commands;
using Discord.Interactions;
using Discord.WebSocket;
using Lunaris2.Notification;
using Lunaris2.SlashCommand;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Lunaris2
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((_, services) =>
{
var config = new DiscordSocketConfig
{
GatewayIntents = GatewayIntents.All
};
var client = new DiscordSocketClient(config);
var commands = new CommandService();
var configuration = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json")
.Build();
services.AddSingleton(client)
.AddSingleton(commands)
.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()))
.AddSingleton<DiscordEventListener>()
.AddSingleton(x => new InteractionService(x.GetRequiredService<DiscordSocketClient>()));
client.Ready += () => Client_Ready(client);
client.Log += Log;
client
.LoginAsync(TokenType.Bot, configuration["Token"])
.GetAwaiter()
.GetResult();
client
.StartAsync()
.GetAwaiter()
.GetResult();
var listener = services
.BuildServiceProvider()
.GetRequiredService<DiscordEventListener>();
listener
.StartAsync()
.GetAwaiter()
.GetResult();
});
private static Task Client_Ready(DiscordSocketClient client)
{
client.RegisterCommands();
return Task.CompletedTask;
}
private static Task Log(LogMessage arg)
{
Console.WriteLine(arg);
return Task.CompletedTask;
}
}
}

1
Bot/README.md Normal file
View File

@@ -0,0 +1 @@
# WIP Rewrite of Lunaris music bot for discord.

View File

@@ -0,0 +1,24 @@
namespace Lunaris2.SlashCommand;
public static class Command
{
public static class Hello
{
public const string Name = "hello";
public const string Description = "Say hello to the bot!";
}
public static class Goodbye
{
public const string Name = "goodbye";
public const string Description = "Say goodbye to the bot!";
}
public static string[] GetAllCommands()
{
return typeof(Command)
.GetNestedTypes()
.Select(command => command.GetField("Name")?.GetValue(null)?.ToString())
.ToArray()!;
}
}

View File

@@ -0,0 +1,57 @@
using Discord.Net;
using Discord.WebSocket;
using Newtonsoft.Json;
namespace Lunaris2.SlashCommand;
public class SlashCommandBuilder(string commandName, string commandDescription)
{
private string CommandName { get; set; } = commandName;
private string CommandDescription { get; set; } = commandDescription;
public async Task CreateSlashCommand(DiscordSocketClient client)
{
var registeredCommands = await client.GetGlobalApplicationCommandsAsync();
await RemoveUnusedCommands(Command.GetAllCommands(), registeredCommands);
if (await CommandExists(registeredCommands))
return;
var globalCommand = new Discord.SlashCommandBuilder();
globalCommand.WithName(CommandName);
globalCommand.WithDescription(CommandDescription);
try
{
await client.CreateGlobalApplicationCommandAsync(globalCommand.Build());
Console.WriteLine($"Command {CommandName} has been registered.");
}
catch(HttpException exception)
{
var json = JsonConvert.SerializeObject(exception.Errors, Formatting.Indented);
Console.WriteLine(json);
}
}
private static async Task RemoveUnusedCommands(string[] commands, IEnumerable<SocketApplicationCommand> registeredCommands)
{
// Remove commands from Discord(registeredCommands) that are not in the list of commands
foreach(var command in registeredCommands)
{
if (commands.Contains(command.Name))
continue;
await command.DeleteAsync();
Console.WriteLine($"Command {command.Name} has been removed.");
}
}
private async Task<bool> CommandExists(IEnumerable<SocketApplicationCommand> registeredCommands)
{
if (!registeredCommands.Any(command => command.Name == CommandName && command.Description == CommandDescription))
return false;
Console.WriteLine($"Command {CommandName} already exists.");
return true;
}
}

View File

@@ -0,0 +1,18 @@
using Discord.WebSocket;
namespace Lunaris2.SlashCommand;
public static class SlashCommandRegistration
{
public static void RegisterCommands(this DiscordSocketClient client)
{
RegisterCommand(client, Command.Hello.Name, Command.Hello.Description);
RegisterCommand(client, Command.Goodbye.Name, Command.Goodbye.Description);
}
private static void RegisterCommand(DiscordSocketClient client, string commandName, string commandDescription)
{
var command = new SlashCommandBuilder(commandName, commandDescription);
_ = command.CreateSlashCommand(client);
}
}