using CommandLine;
using Newtonsoft.Json;
using System.Diagnostics.CodeAnalysis;
namespace RegexBot;
class Configuration {
///
/// Token used for Discord authentication.
///
internal string BotToken { get; }
///
/// List of assemblies to load, by file. Paths are always relative to the bot directory.
///
internal IReadOnlyList Assemblies { get; }
public JObject ServerConfigs { get; }
// SQL properties:
public string? Host { get; }
public string? Database { get; }
public string Username { get; }
public string Password { get; }
///
/// Sets up instance configuration object from file and command line parameters.
///
internal Configuration() {
var args = CommandLineParameters.Parse(Environment.GetCommandLineArgs());
var path = args?.ConfigFile!;
JObject conf;
try {
var conftxt = File.ReadAllText(path);
conf = JObject.Parse(conftxt);
} catch (Exception ex) {
string pfx;
if (ex is JsonException) pfx = "Unable to parse configuration: ";
else pfx = "Unable to access configuration: ";
throw new Exception(pfx + ex.Message, ex);
}
BotToken = ReadConfKey(conf, nameof(BotToken), true);
try {
Assemblies = Common.Utilities.LoadStringOrStringArray(conf[nameof(Assemblies)]).AsReadOnly();
} catch (ArgumentNullException) {
Assemblies = Array.Empty();
} catch (ArgumentException) {
throw new Exception($"'{nameof(Assemblies)}' is not properly specified in configuration.");
}
var dbconf = (conf["DatabaseOptions"]?.Value())
?? throw new Exception("Database settings were not specified in configuration.");
Host = ReadConfKey(dbconf, nameof(Host), false);
Database = ReadConfKey(dbconf, nameof(Database), false);
Username = ReadConfKey(dbconf, nameof(Username), true);
Password = ReadConfKey(dbconf, nameof(Password), true);
ServerConfigs = conf["Servers"]?.Value();
if (ServerConfigs == null) throw new Exception("No server configurations were specified.");
}
private static T? ReadConfKey(JObject jc, string key, [DoesNotReturnIf(true)] bool failOnEmpty) {
if (jc.ContainsKey(key)) return jc[key]!.Value();
if (failOnEmpty) throw new Exception($"'{key}' must be specified in the instance configuration.");
return default;
}
class CommandLineParameters {
[Option('c', "config", Default = "config.json")]
public string? ConfigFile { get; set; } = null;
public static CommandLineParameters? Parse(string[] args) {
CommandLineParameters? result = null;
new Parser(settings => {
settings.IgnoreUnknownArguments = true;
settings.AutoHelp = false;
settings.AutoVersion = false;
}).ParseArguments(args)
.WithParsed(p => result = p)
.WithNotParsed(e => { /* ignore */ });
return result;
}
}
}