using CommandLine; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace WorldTime; /// /// Loads and holds configuration values. /// class Configuration { public string BotToken { get; } public string? DBotsToken { get; } public int ShardTotal { get; } public string? SqlHost { get; } public string? SqlDatabase { get; } public string SqlUsername { get; } public string SqlPassword { get; } public Configuration() { var args = CommandLineParameters.Parse(Environment.GetCommandLineArgs()); var path = args?.ConfigFile ?? Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location) + Path.DirectorySeparatorChar + "." + Path.DirectorySeparatorChar + "settings.json"; // Looks for configuration file JObject jc; try { var conftxt = File.ReadAllText(path); jc = 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(jc, nameof(BotToken), true); DBotsToken = ReadConfKey(jc, nameof(DBotsToken), false); ShardTotal = args.ShardTotal ?? ReadConfKey(jc, nameof(ShardTotal), false) ?? 1; if (ShardTotal < 1) throw new Exception($"'{nameof(ShardTotal)}' must be a positive integer."); SqlHost = ReadConfKey(jc, nameof(SqlHost), false); SqlDatabase = ReadConfKey(jc, nameof(SqlDatabase), false); SqlUsername = ReadConfKey(jc, nameof(SqlUsername), true); SqlPassword = ReadConfKey(jc, nameof(SqlPassword), true); } 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."); return default; } class CommandLineParameters { [Option('c', "config")] public string? ConfigFile { get; set; } [Option("shardtotal")] public int? ShardTotal { get; set; } 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; } } }