using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Noikoio.RegexBot.ConfigItem; using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Noikoio.RegexBot { /// /// Configuration loader /// class ConfigLoader { public const string LogPrefix = "Config"; private readonly string _configPath; private Server[] _servers; private string _botToken; private string _currentGame; public string BotUserToken => _botToken; public string CurrentGame => _currentGame; public Server[] Servers => _servers; public ConfigLoader() { var dsc = Path.DirectorySeparatorChar; _configPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + dsc + "settings.json"; } private async Task LoadFile() { var Log = Logger.GetLogger(LogPrefix); JObject pcfg; try { var ctxt = File.ReadAllText(_configPath); pcfg = JObject.Parse(ctxt); return pcfg; } catch (Exception ex) when (ex is DirectoryNotFoundException || ex is FileNotFoundException) { await Log("Config file not found! Check bot directory for settings.json file."); return null; } catch (UnauthorizedAccessException) { await Log("Could not access config file. Check file permissions."); return null; } catch (JsonReaderException jex) { await Log("Failed to parse JSON."); await Log(jex.GetType().Name + " " + jex.Message); return null; } } /// /// Called only on bot startup. Returns false on failure. /// public bool LoadInitialConfig() { var lt = LoadFile(); lt.Wait(); JObject conf = lt.Result; if (conf == null) return false; _botToken = conf["bot-token"]?.Value(); if (String.IsNullOrWhiteSpace(_botToken)) { Logger.GetLogger(LogPrefix)("Error: Bot token not defined. Cannot continue.").Wait(); return false; } _currentGame = conf["playing"]?.Value(); return ProcessServerConfig(conf).GetAwaiter().GetResult(); } /// /// Reloads the server portion of the configuration file. /// /// False on failure. Specific reasons will have been sent to log. public async Task ReloadServerConfig() { await Logger.GetLogger(LogPrefix)("Configuration reload currently not supported."); return false; // TODO actually implement this var lt = LoadFile(); lt.Wait(); JObject conf = lt.Result; if (conf == null) return false; return await ProcessServerConfig(conf); } /// /// Converts a json object containing bot configuration into data usable by this program. /// On success, updates the Servers values and returns true. Returns false on failure. /// private async Task ProcessServerConfig(JObject conf) { var Log = Logger.GetLogger(LogPrefix); if (!conf["servers"].HasValues) { await Log("Error: No server configurations are defined."); return false; } List newservers = new List(); await Log("Reading server configurations..."); foreach (JObject sconf in conf["servers"].Children()) { // Server name if (sconf["name"] == null || string.IsNullOrWhiteSpace(sconf["name"].Value())) { await Log("Error: Server definition is missing a name."); return false; } string snamestr = sconf["name"].Value(); string sname; ulong? sid; int snseparator = snamestr.IndexOf("::"); if (ulong.TryParse(snamestr.Substring(0, snseparator), out var id)) { sid = id; sname = snamestr.Substring(snseparator + 2); } else { sid = null; sname = snamestr; } var SLog = Logger.GetLogger(LogPrefix + "/" + sname); // Load server moderator list EntityList mods = new EntityList(sconf["moderators"]); if (sconf["moderators"] != null) await SLog("Moderator " + mods.ToString()); // Read rules // Also, parsed rules require a server reference. Creating it here. List rules = new List(); Server newserver = new Server(sname, sid, rules, mods); foreach (JObject ruleconf in sconf["rules"]) { // Try and get at least the name before passing it to RuleItem string name = ruleconf["name"]?.Value(); if (name == null) { await SLog("Display name not defined within a rule section."); return false; } await SLog($"Adding rule \"{name}\""); Rule rule; try { rule = new Rule(newserver, ruleconf); } catch (Rule.RuleImportException ex) { await SLog("-> Error: " + ex.Message); return false; } rules.Add(rule); } // Switch to using new data List> rulesfinal = new List>(); newservers.Add(newserver); } _servers = newservers.ToArray(); return true; } } }