diff --git a/wow2.Bot/BotService.cs b/wow2.Bot/BotService.cs index 1a23bd5e..2651a69e 100644 --- a/wow2.Bot/BotService.cs +++ b/wow2.Bot/BotService.cs @@ -39,6 +39,8 @@ public static class BotService public static CommandService CommandService { get; set; } + public static IDataManager DataManager { get; set; } + public static IServiceProvider Services { get; set; } public static bool IsDisabled { get; set; } = false; @@ -75,6 +77,7 @@ public static async Task InstallCommandsAsync() } Services = new ServiceCollection() + .AddSingleton(DataManager) .AddSingleton(new YoutubeModuleService(DataManager.Secrets.GoogleApiKey)) .AddSingleton(new OsuModuleService(DataManager.Secrets.OsuClientId, DataManager.Secrets.OsuClientSecret)) .AddSingleton(new SpotifyModuleService(DataManager.Secrets.SpotifyClientId, DataManager.Secrets.SpotifyClientSecret)) @@ -166,8 +169,7 @@ public static async Task JoinedGuildAsync(SocketGuild guild) // Only set if it's the first time the bot has joined this guild. if (guildData.DateTimeJoinedBinary == 0) { - DataManager.AllGuildData[guild.Id] - .DateTimeJoinedBinary = DateTime.Now.ToBinary(); + DataManager.AllGuildData[guild.Id].DateTimeJoinedBinary = DateTime.Now.ToBinary(); } // This could take a while. @@ -325,7 +327,7 @@ public static async Task ExecuteCommandAsync(SocketCommandContext conte public static async Task SendErrorMessageToChannel(CommandError? commandError, SocketCommandContext context) { - string commandPrefix = context.Guild.GetCommandPrefix(); + string commandPrefix = DataManager.AllGuildData[context.Guild.Id].Main.CommandPrefix; var matchingCommands = await SearchCommandsAsync( context, context.Message.Content.MakeCommandInput(commandPrefix)); @@ -406,7 +408,7 @@ private static async Task ActOnMessageAsync(SocketCommandContext context) } if (message.Content.StartsWithWord( - context.Guild.GetCommandPrefix(), true)) + DataManager.AllGuildData[context.Guild.Id].Main.CommandPrefix, true)) { // The message starts with the command prefix and the prefix is not part of another word. await ActOnMessageAsCommandAsync(context); @@ -422,7 +424,7 @@ private static async Task ActOnMessageAsync(SocketCommandContext context) private static async Task ActOnMessageAsCommandAsync(SocketCommandContext context) { - string commandPrefix = context.Guild.GetCommandPrefix(); + string commandPrefix = DataManager.AllGuildData[context.Guild.Id].Main.CommandPrefix; if (context.Message.Content == commandPrefix) { diff --git a/wow2.Bot/Data/DataManager.cs b/wow2.Bot/Data/DataManager.cs index e2631bc4..37d4a36f 100644 --- a/wow2.Bot/Data/DataManager.cs +++ b/wow2.Bot/Data/DataManager.cs @@ -10,25 +10,26 @@ namespace wow2.Bot.Data { - public static class DataManager + public class DataManager : IDataManager { - public static readonly string AppDataDirPath = Environment.GetEnvironmentVariable("WOW2_APPDATA_FOLDER") ?? $"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}/wow2"; private static readonly JsonSerializerOptions SerializerOptions = new() { WriteIndented = true, ReferenceHandler = ReferenceHandler.Preserve, }; - public static Dictionary AllGuildData { get; set; } = new Dictionary(); + public string AppDataDirPath { get; } = Environment.GetEnvironmentVariable("WOW2_APPDATA_FOLDER") ?? $"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}/wow2"; - public static Secrets Secrets { get; set; } = new Secrets(); + public Secrets Secrets { get; set; } = new Secrets(); - public static string GuildDataDirPath => $"{AppDataDirPath}/GuildData"; + public string GuildDataDirPath => $"{AppDataDirPath}/GuildData"; - public static string LogsDirPath => $"{AppDataDirPath}/Logs"; + public string LogsDirPath => $"{AppDataDirPath}/Logs"; + + public Dictionary AllGuildData { get; } = new(); /// Creates required directories if necessary and loads all guild data. - public static async Task InitializeAsync() + public async Task InitializeAsync() { try { @@ -50,7 +51,7 @@ public static async Task InitializeAsync() } /// Deserializes the secrets.json file into the Secrets property. If it doesn't exist, creates one and stops the program. - public static async Task LoadSecretsFromFileAsync() + public async Task LoadSecretsFromFileAsync() { string fullPath = AppDataDirPath + "/secrets.json"; if (!File.Exists(fullPath)) @@ -68,7 +69,7 @@ public static async Task LoadSecretsFromFileAsync() } /// Load all guild data from all files, excluding the guilds the client is not in. - public static async Task LoadGuildDataFromFileAsync() + public async Task LoadGuildDataFromFileAsync() { Logger.Log("About to load all guild data.", LogSeverity.Verbose); foreach (FileInfo fileInfo in new DirectoryInfo(GuildDataDirPath).EnumerateFiles()) @@ -92,7 +93,7 @@ public static async Task LoadGuildDataFromFileAsync() } /// Load guild data from the corresponding file. - public static async Task LoadGuildDataFromFileAsync(ulong guildId) + public async Task LoadGuildDataFromFileAsync(ulong guildId) { try { @@ -107,7 +108,7 @@ public static async Task LoadGuildDataFromFileAsync(ulong guildId) } /// Write all guild data to corresponding files. - public static async Task SaveGuildDataToFileAsync() + public async Task SaveGuildDataToFileAsync() { Logger.Log("About to save all guild data.", LogSeverity.Verbose); foreach (ulong guildId in AllGuildData.Keys) @@ -124,7 +125,7 @@ public static async Task SaveGuildDataToFileAsync() } /// Write guild data to file for a specific guild. - public static async Task SaveGuildDataToFileAsync(ulong guildId) + public async Task SaveGuildDataToFileAsync(ulong guildId) { if (!AllGuildData.TryGetValue(guildId, out GuildData guildData)) throw new KeyNotFoundException($"The guild ID {guildId} was not found in the dictionary"); @@ -137,7 +138,7 @@ await File.WriteAllTextAsync( /// If the GuildData for the specified guild does not exist, one will be created. /// The GuildData for the guild. - public static async Task EnsureGuildDataExistsAsync(ulong guildId) + public async Task EnsureGuildDataExistsAsync(ulong guildId) { if (File.Exists($"{GuildDataDirPath}/{guildId}.json")) { @@ -155,14 +156,14 @@ public static async Task EnsureGuildDataExistsAsync(ulong guildId) return AllGuildData[guildId]; } - public static async Task UnloadGuildDataAsync(ulong guildId) + public async Task UnloadGuildDataAsync(ulong guildId) { await SaveGuildDataToFileAsync(guildId); AllGuildData.Remove(guildId); Logger.Log($"Unloaded guild data for {guildId}", LogSeverity.Verbose); } - public static void EnsureGuildNameExists(ulong guildId) + public void EnsureGuildNameExists(ulong guildId) { var guildData = AllGuildData[guildId]; if (guildData?.NameOfGuild == null) diff --git a/wow2.Bot/Data/IDataManager.cs b/wow2.Bot/Data/IDataManager.cs new file mode 100644 index 00000000..da375d5f --- /dev/null +++ b/wow2.Bot/Data/IDataManager.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace wow2.Bot.Data +{ + public interface IDataManager + { + string GuildDataDirPath { get; } + + string AppDataDirPath { get; } + + string LogsDirPath { get; } + + Dictionary AllGuildData { get; } + + Secrets Secrets { get; set; } + + Task InitializeAsync(); + + Task LoadSecretsFromFileAsync(); + + Task LoadGuildDataFromFileAsync(); + + Task LoadGuildDataFromFileAsync(ulong guildId); + + Task SaveGuildDataToFileAsync(); + + Task SaveGuildDataToFileAsync(ulong guildId); + + Task UnloadGuildDataAsync(ulong guildId); + + Task EnsureGuildDataExistsAsync(ulong guildId); + } +} \ No newline at end of file diff --git a/wow2.Bot/Extensions/DiscordExtensions.cs b/wow2.Bot/Extensions/DiscordExtensions.cs index 891d907e..de42ebe2 100644 --- a/wow2.Bot/Extensions/DiscordExtensions.cs +++ b/wow2.Bot/Extensions/DiscordExtensions.cs @@ -14,9 +14,6 @@ public static SocketGuild GetGuild(this IMessage userMessage) public static SocketGuild GetGuild(this ISocketMessageChannel messageChannel) => ((SocketGuildChannel)messageChannel).Guild; - public static string GetCommandPrefix(this IGuild guild) => - DataManager.AllGuildData[guild.Id].Main.CommandPrefix; - /// Creates a string from a list of commands, with newlines placed between each command. /// A string representing the list of commands. public static string MakeReadableString(this IEnumerable commands, string commandPrefix) diff --git a/wow2.Bot/Modules/Dev/DevModule.cs b/wow2.Bot/Modules/Dev/DevModule.cs index 9d3349b8..863a4613 100644 --- a/wow2.Bot/Modules/Dev/DevModule.cs +++ b/wow2.Bot/Modules/Dev/DevModule.cs @@ -25,6 +25,8 @@ namespace wow2.Bot.Modules.Dev [Summary("Boring stuff for developers.")] public class DevModule : Module { + public IDataManager DataManager { get; set; } + [Command("load-guild-data")] [Alias("load")] [Summary("Loads guild data from file to memory, discarding any unsaved changes.")] @@ -94,7 +96,7 @@ public async Task GuildListAsync() public async Task GetGuildDataAsync(ulong id = 0) { await Context.Channel.SendFileAsync( - filePath: $"{DataManager.AppDataDirPath}/GuildData/{(id != 0 ? id : Context.Guild.Id)}.json"); + filePath: $"{DataManager.GuildDataDirPath}/{(id != 0 ? id : Context.Guild.Id)}.json"); } [Command("set-status")] diff --git a/wow2.Bot/Modules/Dev/Tests.cs b/wow2.Bot/Modules/Dev/Tests.cs index 496c5a69..da358392 100644 --- a/wow2.Bot/Modules/Dev/Tests.cs +++ b/wow2.Bot/Modules/Dev/Tests.cs @@ -35,7 +35,8 @@ static Tests() } } - [Test("messages")] + // TODO: uncomment (or honestly just nuke this) + /*[Test("messages")] public static async Task MessagesTest(SocketCommandContext context) { await new SuccessMessage("This is a success message.", "Success").SendAsync(context.Channel); @@ -295,6 +296,6 @@ private static async Task AssertAsync(SocketCommandContext context, Dictionary { - await new InfoMessage($"You can do that by typing `{Context.Guild.GetCommandPrefix()} keywords remove {keyword} [VALUE]`", "Just want to remove one value?") + await new InfoMessage($"You can do that by typing `{CommandPrefix} keywords remove {keyword} [VALUE]`", "Just want to remove one value?") .SendAsync(Context.Channel); }) .SendAsync(Context.Channel); diff --git a/wow2.Bot/Modules/Module.cs b/wow2.Bot/Modules/Module.cs index 913968e6..bc35cee5 100644 --- a/wow2.Bot/Modules/Module.cs +++ b/wow2.Bot/Modules/Module.cs @@ -8,6 +8,10 @@ namespace wow2.Bot.Modules { public abstract class Module : ModuleBase { + public IDataManager DataManager { get; set; } + + public string CommandPrefix => DataManager.AllGuildData[Context.Guild.Id].Main.CommandPrefix; + public async Task SendToggleQuestionAsync( bool currentState, Action setter, diff --git a/wow2.Bot/Program.cs b/wow2.Bot/Program.cs index e3f33a5a..ea6f8c5b 100644 --- a/wow2.Bot/Program.cs +++ b/wow2.Bot/Program.cs @@ -30,7 +30,6 @@ private async Task MainAsync(string[] args) IsDebug = true; #endif await Logger.LogInitialize(); - await DataManager.LoadSecretsFromFileAsync(); Options.Parse(args);