Added CLI configuration

Also halt if no valid channels are connected!

Changelog: added
This commit is contained in:
Michael Chen 2022-01-12 14:32:25 +01:00
parent d8c1f81023
commit d120860322
No known key found for this signature in database
GPG Key ID: 1CBC7AA5671437BB
2 changed files with 60 additions and 14 deletions

View File

@ -1,14 +1,46 @@
using Newtonsoft.Json; using CommandLine;
using Newtonsoft.Json;
using System.Text;
namespace MinecraftDiscordBot; namespace MinecraftDiscordBot;
public class BotConfiguration { [Verb("config", HelpText = "Manually configure the bot with CLI arguments.")]
public class BotConfiguration : IBotConfiguration, IBotConfigurator {
private const string DEFAULT_PREFIX = "!";
private const int DEFAULT_PORT = 8080;
[JsonProperty("token", Required = Required.Always)] [JsonProperty("token", Required = Required.Always)]
public string Token { get; set; } = default!; [Option('t', "token", HelpText = "The Discord bot token", Required = true)]
[JsonProperty("port", Required = Required.Always)] public string Token { get; init; } = default!;
public int Port { get; set; } = default!; [JsonProperty("port", Required = Required.DisallowNull)]
[Option('p', "port", Default = DEFAULT_PORT, HelpText = "The websocket server port")]
public int Port { get; init; } = DEFAULT_PORT;
[JsonProperty("channels", Required = Required.Always)] [JsonProperty("channels", Required = Required.Always)]
public IEnumerable<ulong> Channels { get; set; } = default!; [Option('c', "channel", HelpText = "The list of whitelisted channels", Required = true, Min = 1)]
[JsonProperty("prefix", Required = Required.Always)] public IEnumerable<ulong> Channels { get; init; } = default!;
public string Prefix { get; set; } = default!; [JsonProperty("prefix", Required = Required.DisallowNull)]
[Option("prefix", Default = DEFAULT_PREFIX, HelpText = "The Discord bot command prefix")]
public string Prefix { get; init; } = DEFAULT_PREFIX;
[JsonIgnore]
public BotConfiguration Config => this;
}
public interface IBotConfigurator {
BotConfiguration Config { get; }
}
public interface IBotConfiguration {
string Token { get; }
int Port { get; }
IEnumerable<ulong> Channels { get; }
string Prefix { get; }
}
[Verb("file", true, HelpText = "Load a bot configuration file.")]
public class ConfigFile : IBotConfigurator {
private const string DEFAULT_CONFIGPATH = "config.json";
[Option('f', "file", Default = DEFAULT_CONFIGPATH, HelpText = "The path of the configuration file")]
public string ConfigPath { get; set; } = DEFAULT_CONFIGPATH;
public BotConfiguration Config
=> JsonConvert.DeserializeObject<BotConfiguration>(File.ReadAllText(ConfigPath, Encoding.UTF8))
?? throw new InvalidProgramException("Invalid empty config file!");
} }

View File

@ -1,3 +1,4 @@
using CommandLine;
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.Rest; using Discord.Rest;
@ -60,14 +61,19 @@ public class Program : IDisposable {
public static Task<int> Main(string[] args) public static Task<int> Main(string[] args)
=> JsonConvert.DeserializeObject<BotConfiguration>(File.ReadAllText("config.json")) is BotConfiguration config => Parser.Default.ParseArguments<BotConfiguration, ConfigFile>(args)
? new Program(config).RunAsync() .MapResult<BotConfiguration, ConfigFile, Task<int>>(
: throw new InvalidProgramException("Configuration file missing!"); RunWithConfig,
RunWithConfig,
errs => Task.FromResult(1));
private static Task<int> RunWithConfig(IBotConfigurator arg) => new Program(arg.Config).RunAsync();
public async Task<int> RunAsync() { public async Task<int> RunAsync() {
await _client.LoginAsync(TokenType.Bot, _config.Token); await _client.LoginAsync(TokenType.Bot, _config.Token);
await _client.StartAsync(); await _client.StartAsync();
await VerifyTextChannels(); if (!await HasValidChannels())
return 1;
StartWebSocketServer(); StartWebSocketServer();
// Block this task until the program is closed. // Block this task until the program is closed.
@ -75,11 +81,21 @@ public class Program : IDisposable {
return 0; return 0;
} }
private async Task<bool> HasValidChannels() {
if (await GetValidChannels(_whitelistedChannels).ToArrayAsync() is not { Length: > 0 } channels) {
await LogError(BotSource, new InvalidOperationException("No valid textchannel was whitelisted!"));
return false;
}
_channels = channels;
return true;
}
private void StartWebSocketServer() => _wssv.Start(socket => { private void StartWebSocketServer() => _wssv.Start(socket => {
socket.OnOpen = async () => await SocketOpened(socket); socket.OnOpen = async () => await SocketOpened(socket);
socket.OnClose = async () => await SocketClosed(socket); socket.OnClose = async () => await SocketClosed(socket);
socket.OnMessage = async message => await SocketReceived(socket, message); socket.OnMessage = async message => await SocketReceived(socket, message);
}); });
private async IAsyncEnumerable<ITextChannel> GetValidChannels(IEnumerable<ulong> ids) { private async IAsyncEnumerable<ITextChannel> GetValidChannels(IEnumerable<ulong> ids) {
foreach (var channelId in ids) { foreach (var channelId in ids) {
var channel = await _client.GetChannelAsync(channelId); var channel = await _client.GetChannelAsync(channelId);
@ -99,8 +115,6 @@ public class Program : IDisposable {
} }
} }
private async Task VerifyTextChannels() => _channels = await GetValidChannels(_whitelistedChannels).ToArrayAsync();
private async Task SocketReceived(IWebSocketConnection socket, string message) { private async Task SocketReceived(IWebSocketConnection socket, string message) {
if (JsonConvert.DeserializeObject<CapabilityMessage>(message) is not CapabilityMessage capability) return; if (JsonConvert.DeserializeObject<CapabilityMessage>(message) is not CapabilityMessage capability) return;