Re-added chat relaying

Fixed async naming scheme
Added webhook for every channel
Added colorful logging
This commit is contained in:
Michael Chen
2022-01-18 10:10:49 +01:00
parent e7b056342f
commit f912b9db8f
6 changed files with 104 additions and 29 deletions

View File

@ -0,0 +1,26 @@
using Discord.WebSocket;
using MinecraftDiscordBot.Commands;
namespace MinecraftDiscordBot.Services;
public class ChatBoxService : CommandRouter {
private readonly ITaskWaitSource _taskSource;
public ChatBoxService(ITaskWaitSource taskSource) => _taskSource = taskSource;
public override string HelpTextPrefix => "!chat ";
public override Task<ResponseType> FallbackHandler(SocketUserMessage message, string method, string[] parameters, CancellationToken ct)
=> throw new ReplyException($"The chat box cannot do '{method}'!");
private Task<T> Method<T>(string methodName, Func<string, T> parser, CancellationToken ct, Dictionary<string, object>? parameters = null)
=> RootCommandService.Method(_taskSource, methodName, parser, ct, parameters);
public Task<bool> SendMessageAsync(string message, string prefix, CancellationToken ct) => Method("send", RootCommandService.Deserialize<bool>(), ct, new() {
["message"] = message,
["prefix"] = prefix
});
public Task<bool> SendMessageToPlayerAsync(string message, string username, string prefix, CancellationToken ct) => Method("send", RootCommandService.Deserialize<bool>(), ct, new() {
["message"] = message,
["username"] = username,
["prefix"] = prefix
});
}

View File

@ -5,7 +5,7 @@ using Newtonsoft.Json;
namespace MinecraftDiscordBot.Services;
internal class PlayerDetectorService : CommandRouter {
public class PlayerDetectorService : CommandRouter {
private readonly ITaskWaitSource _taskSource;
public PlayerDetectorService(ITaskWaitSource taskSource) => _taskSource = taskSource;
@ -16,21 +16,21 @@ internal class PlayerDetectorService : CommandRouter {
private Task<T> Method<T>(string methodName, Func<string, T> parser, CancellationToken ct, Dictionary<string, object>? parameters = null)
=> RootCommandService.Method(_taskSource, methodName, parser, ct, parameters);
public Task<string[]> GetOnlinePlayers(CancellationToken ct) => Method("getonline", RootCommandService.Deserialize<string[]>(), ct);
public Task<string[]> GetOnlinePlayersAsync(CancellationToken ct) => Method("getonline", RootCommandService.Deserialize<string[]>(), ct);
public async Task<PlayerPosition> GetPlayerPosition(string username, CancellationToken ct)
=> (await FindPlayer(username, ct)) ?? throw new ReplyException($"User '{username}' is not online!");
private Task<PlayerPosition?> FindPlayer(string username, CancellationToken ct) => Method("whereis", i => JsonConvert.DeserializeObject<PlayerPosition?>(i), ct, new() {
=> (await FindPlayerAsync(username, ct)) ?? throw new ReplyException($"User '{username}' is not online!");
private Task<PlayerPosition?> FindPlayerAsync(string username, CancellationToken ct) => Method("whereis", i => JsonConvert.DeserializeObject<PlayerPosition?>(i), ct, new() {
["username"] = username
});
[CommandHandler("getonline", HelpText ="Get a list of online players.")]
[CommandHandler("getonline", HelpText = "Get a list of online players.")]
public async Task<ResponseType> HandleOnlinePlayers(SocketUserMessage message, string[] parameters, CancellationToken ct)
=> ResponseType.AsString($"The following players are currently online:\n{string.Join("\n", await GetOnlinePlayers(ct))}");
=> ResponseType.AsString($"The following players are currently online:\n{string.Join("\n", await GetOnlinePlayersAsync(ct))}");
[CommandHandler("whereis", HelpText = "Find a player in the world.")]
public async Task<ResponseType> HandleFindPlayers(SocketUserMessage message, string[] parameters, CancellationToken ct) {
if (parameters is not { Length: 1 }) throw new ReplyException($"Give me only one username!");
var username = parameters[0];
var player = await FindPlayer(username, ct);
var player = await FindPlayerAsync(username, ct);
if (player is null) throw new ReplyException($"{username} is currently offline!");
return ResponseType.AsString($"{username} is at coordinates {player.X} {player.Y} {player.Z} in dimension {player.Dimension}.");
}

View File

@ -19,7 +19,7 @@ public class RefinedStorageService : CommandRouter {
=> throw new ReplyException($"The RS system has no command '{method}'!");
private Task<T> Method<T>(string methodName, Func<string, T> parser, CancellationToken ct, Dictionary<string, object>? parameters = null)
=> RootCommandService.Method<T>(_taskSource, methodName, parser, ct, parameters);
=> RootCommandService.Method(_taskSource, methodName, parser, ct, parameters);
private const string CmdEnergyUsage = "energyusage";
private const string CmdEnergyStorage = "energystorage";
@ -34,17 +34,17 @@ public class RefinedStorageService : CommandRouter {
public async Task<int> GetEnergyStorageAsync(CancellationToken ct) => await Method(CmdEnergyStorage, int.Parse, ct);
public async Task<IEnumerable<Item>> ListItemsAsync(CancellationToken ct) => await Method(CmdListItems, RootCommandService.Deserialize<IEnumerable<Item>>(), ct);
public async Task<IEnumerable<Fluid>> ListFluidsAsync(CancellationToken ct) => await Method(CmdListFluids, RootCommandService.Deserialize<IEnumerable<Fluid>>(), ct);
public async Task<Item> GetItemData(string itemid, CancellationToken ct) => await Method(CmdGetItem, RootCommandService.Deserialize<Item>(), ct, new() {
public async Task<Item> GetItemDataAsync(string itemid, CancellationToken ct) => await Method(CmdGetItem, RootCommandService.Deserialize<Item>(), ct, new() {
["name"] = itemid
});
public async Task<Item> GetItemData(Md5Hash fingerprint, CancellationToken ct) => await Method(CmdGetItem, RootCommandService.Deserialize<Item>(), ct, new() {
public async Task<Item> GetItemDataAsync(Md5Hash fingerprint, CancellationToken ct) => await Method(CmdGetItem, RootCommandService.Deserialize<Item>(), ct, new() {
["fingerprint"] = fingerprint.ToString()
});
public async Task<bool> CraftItem(string itemid, int amount, CancellationToken ct) => await Method(CmdCraftItem, RootCommandService.Deserialize<bool>(), ct, new() {
public async Task<bool> CraftItemAsync(string itemid, int amount, CancellationToken ct) => await Method(CmdCraftItem, RootCommandService.Deserialize<bool>(), ct, new() {
["name"] = itemid,
["count"] = amount
});
public async Task<LuaPackedArray> RawCommand(string command, CancellationToken ct) => await Method(CmdCommand, LuaPackedArray.Deserialize, ct, new() {
public async Task<LuaPackedArray> RawCommandAsync(string command, CancellationToken ct) => await Method(CmdCommand, LuaPackedArray.Deserialize, ct, new() {
["command"] = command
});
@ -91,7 +91,7 @@ public class RefinedStorageService : CommandRouter {
: parameters.Length is > 2
? throw new ReplyException("Yo, those are way too many arguments! I want only item name and maybe an amount!")
: throw new InvalidOperationException($"Forgot to match parameter length {parameters.Length}!");
return await CraftItem(itemid, amount, ct)
return await CraftItemAsync(itemid, amount, ct)
? ResponseType.AsString($"Alright, I'm starting to craft {amount} {itemid}.")
: ResponseType.AsString($"Nope, that somehow doesn't work!");
}
@ -101,8 +101,8 @@ public class RefinedStorageService : CommandRouter {
if (parameters.Length is not 1) throw new ReplyException($"I only want one name or fingerprint to search for, you gave me {parameters.Length} arguments!");
itemid = parameters[0];
var item = await (Md5Hash.TryParse(itemid, out var fingerprint)
? GetItemData(fingerprint, ct)
: GetItemData(itemid, ct));
? GetItemDataAsync(fingerprint, ct)
: GetItemDataAsync(itemid, ct));
var sb = new StringBuilder();
sb.Append($"We currently have {item.Amount:n0} {item.CleanDisplayName}!");
if (item.Tags is not null and var tags) {
@ -140,7 +140,7 @@ public class RefinedStorageService : CommandRouter {
public async Task<ResponseType> HandleRawCommand(SocketUserMessage message, string[] parameters, CancellationToken ct) {
_roleManager.RequireAdministrator(message.Author.Id, "You are not authorized to run raw commands on this instance!");
var command = string.Join(' ', parameters);
var response = await RawCommand(command, ct);
var response = await RawCommandAsync(command, ct);
return ResponseType.AsString(response.ToString());
}

View File

@ -13,8 +13,9 @@ public class RootCommandService : CommandRouter, ITaskWaitSource {
protected IWebSocketConnection? _socketField;
public override string HelpTextPrefix => "!";
public RootCommandService(IUserRoleManager roleManager) : base() {
_rs = new RefinedStorageService(this, roleManager);
_pd = new PlayerDetectorService(this);
RefinedStorage = new RefinedStorageService(this, roleManager);
Players = new PlayerDetectorService(this);
Chat = new ChatBoxService(this);
}
public static async Task<T> Method<T>(ITaskWaitSource taskSource, string methodName, Func<string, T> parser, CancellationToken ct, Dictionary<string, object>? parameters) {
@ -38,6 +39,10 @@ public class RootCommandService : CommandRouter, ITaskWaitSource {
}
}
public RefinedStorageService RefinedStorage { get; }
public PlayerDetectorService Players { get; }
public ChatBoxService Chat { get; }
private void OnMessage(string message) {
switch (Message.Deserialize(message)) {
case ChatEvent msg:
@ -92,15 +97,15 @@ public class RootCommandService : CommandRouter, ITaskWaitSource {
return waiter;
}
private readonly ICommandHandler<ResponseType> _rs;
private readonly ICommandHandler<ResponseType> _pd;
[CommandHandler("rs", HelpText = "Provides some commands for interacting with the Refined Storage system.")]
public Task<ResponseType> RefinedStorageHandler(SocketUserMessage message, string[] parameters, CancellationToken ct)
=> _rs.HandleCommand(message, parameters, ct);
=> RefinedStorage.HandleCommand(message, parameters, ct);
[CommandHandler("pd", HelpText = "Provides some commands for interacting with the Player Detector.")]
public Task<ResponseType> PlayerDetectorHandler(SocketUserMessage message, string[] parameters, CancellationToken ct)
=> _pd.HandleCommand(message, parameters, ct);
=> Players.HandleCommand(message, parameters, ct);
[CommandHandler("chat", HelpText = "Provides some commands for chatting.")]
public Task<ResponseType> ChatBoxHandler(SocketUserMessage message, string[] parameters, CancellationToken ct)
=> Chat.HandleCommand(message, parameters, ct);
public static Func<string, T> Deserialize<T>() => msg
=> JsonConvert.DeserializeObject<T>(msg) ?? throw new InvalidProgramException("Empty response!");