From 13900bb3f3cb1db9074b3aed16109d4228feb6f6 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Sun, 14 Jul 2024 21:24:49 +0300 Subject: [PATCH] Added autoinstall for modules --- DiscordBot/Entry.cs | 18 +++++-- DiscordBot/Program.cs | 20 +------ DiscordBot/Utilities/Console Utilities.cs | 18 +++++++ DiscordBotCore/Application.cs | 25 ++++++++- DiscordBotCore/Interfaces/Logger/ILogger.cs | 7 +-- DiscordBotCore/Loaders/ModuleLoader.cs | 1 - DiscordBotCore/Modules/ModuleDownloader.cs | 30 +++++++++++ DiscordBotCore/Modules/ModuleManager.cs | 6 ++- .../Exceptions/ModuleNotFoundException.cs | 16 ++++++ LoggerModule/Logger.cs | 52 ++++++++++++++++--- 10 files changed, 153 insertions(+), 40 deletions(-) create mode 100644 DiscordBotCore/Modules/ModuleDownloader.cs create mode 100644 DiscordBotCore/Others/Exceptions/ModuleNotFoundException.cs diff --git a/DiscordBot/Entry.cs b/DiscordBot/Entry.cs index cc34507..0f4b213 100644 --- a/DiscordBot/Entry.cs +++ b/DiscordBot/Entry.cs @@ -4,6 +4,10 @@ using System.IO; using System.Linq; using System.Reflection; +using DiscordBot.Utilities; + +using DiscordBotCore.Modules; + namespace DiscordBot; @@ -13,7 +17,7 @@ public static class Entry /// Some startup actions that can are executed when the console first starts. This actions are invoked externally at application launch /// private static readonly List StartupActions = [ - new StartupAction("/purge_plugins", (args) => { + new StartupAction("/purge_plugins", () => { foreach (var plugin in Directory.GetFiles("./Data/Plugins", "*.dll", SearchOption.AllDirectories)) { File.Delete(plugin); @@ -34,6 +38,12 @@ public static class Entry } Directory.Delete("temp"); + }), + + new StartupAction("--module-install", (args) => { + ModuleDownloader moduleDownloader = new ModuleDownloader(args[0]); + + ConsoleUtilities.ExecuteTaskWithBuiltInProgress(moduleDownloader.DownloadModule, "Downloading logger module").Wait(); }) ]; @@ -51,14 +61,12 @@ public static class Entry "; public static void Main(string[] args) { -#if DEBUG if (args.Length > 0) { - StartupActions.FirstOrDefault(action => action.Command == args[0], null)?.RunAction(args[..1]); + + StartupActions.FirstOrDefault(action => action.Command == args[0], null)?.RunAction(args[1..]); } -#endif - Console.Clear(); Console.ForegroundColor = ConsoleColor.DarkYellow; diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index d83ece1..822484c 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -90,26 +90,8 @@ public class Program await ConsoleUtilities.ExecuteTaskWithBuiltInProgress(updater.SelfUpdate, update, "Discord Bot Update"); return; } - - Application.CurrentApplication.Logger.OnFormattedLog += (sender, logMessage) => - { - var messageColor = logMessage.Type switch - { - LogType.INFO => "[green]", - LogType.WARNING => "[yellow]", - LogType.ERROR => "[red]", - LogType.CRITICAL => "[red]", - _ => "[white]" - }; - if (logMessage.Message.Contains('[') || logMessage.Message.Contains(']')) - { - logMessage.Message = logMessage.Message.Replace("[", "<").Replace("]", ">"); - } - - string messageToPrint = $"{messageColor}{logMessage.Message}[/]"; - AnsiConsole.MarkupLine(messageToPrint); - }; + Application.CurrentApplication.Logger.SetOutFunction(AnsiConsole.MarkupLine); if (!Application.CurrentApplication.ApplicationEnvironmentVariables.ContainsKey("ServerID") || diff --git a/DiscordBot/Utilities/Console Utilities.cs b/DiscordBot/Utilities/Console Utilities.cs index 24020dd..ff72dce 100644 --- a/DiscordBot/Utilities/Console Utilities.cs +++ b/DiscordBot/Utilities/Console Utilities.cs @@ -46,4 +46,22 @@ internal static class ConsoleUtilities } + public static async Task ExecuteTaskWithBuiltInProgress(Func, Task> method, string taskMessage) + { + await AnsiConsole.Progress() + .AutoClear(false) // Do not remove the task list when done + .HideCompleted(false) // Hide tasks as they are completed + .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()) + .StartAsync( + async ctx => + { + var task = ctx.AddTask(taskMessage); + IProgress progress = new Progress(x => task.Value = x); + await method(progress); + task.Value = 100; + } + ); + + } + } \ No newline at end of file diff --git a/DiscordBotCore/Application.cs b/DiscordBotCore/Application.cs index 2403233..a85a5a4 100644 --- a/DiscordBotCore/Application.cs +++ b/DiscordBotCore/Application.cs @@ -15,6 +15,7 @@ using DiscordBotCore.Interfaces.Logger; using DiscordBotCore.Modules; using System.Linq; using System.Collections.Immutable; +using System.Diagnostics; namespace DiscordBotCore @@ -46,7 +47,28 @@ namespace DiscordBotCore public SettingsDictionary ApplicationEnvironmentVariables { get; private set; } public InternalActionManager InternalActionManager { get; private set; } - public ILogger Logger => _ModuleManager.GetModule(); + public ILogger Logger + { + get + { + try { return _ModuleManager.GetModule(); } + catch (ModuleNotFoundException ex) + { + Console.WriteLine("No logger found"); + Console.WriteLine("Not having a valid logger is NOT an option. The default module will be downloaded from the official repo."); + Console.WriteLine("Install the default one ? [y/n]"); + ConsoleKey response = Console.ReadKey().Key; + if (response is ConsoleKey.Y) + { + Process.Start("DiscordBot", "--module-install LoggerModule"); + } + + Environment.Exit(0); + return null!; + } + } + } + public IPluginManager PluginManager { get; private set; } public Bot.App DiscordBotClient { get; internal set; } @@ -61,6 +83,7 @@ namespace DiscordBotCore Directory.CreateDirectory(_PluginsFolder); Directory.CreateDirectory(_ArchivesFolder); Directory.CreateDirectory(_LogsFolder); + Directory.CreateDirectory(_ModuleFolder); CurrentApplication.ApplicationEnvironmentVariables = new SettingsDictionary(_ConfigFile); bool result = await CurrentApplication.ApplicationEnvironmentVariables.LoadFromFile(); diff --git a/DiscordBotCore/Interfaces/Logger/ILogger.cs b/DiscordBotCore/Interfaces/Logger/ILogger.cs index 8515e5e..e73d13f 100644 --- a/DiscordBotCore/Interfaces/Logger/ILogger.cs +++ b/DiscordBotCore/Interfaces/Logger/ILogger.cs @@ -14,16 +14,13 @@ namespace DiscordBotCore.Interfaces.Logger string LogMessageFormat { get; set; } - event EventHandler OnFormattedLog; - event EventHandler OnRawLog; - - void Log(ILogMessage message); - void Log(ILogMessage message, string format); void Log(string message); void Log(string message, LogType logType); void Log(string message, LogType logType, string format); void Log(string message, object Sender); void Log(string message, object Sender, LogType type); void LogException(Exception exception, object Sender, bool logFullStack = false); + + void SetOutFunction(Action outFunction); } } diff --git a/DiscordBotCore/Loaders/ModuleLoader.cs b/DiscordBotCore/Loaders/ModuleLoader.cs index 8a6a5b4..08d3fc5 100644 --- a/DiscordBotCore/Loaders/ModuleLoader.cs +++ b/DiscordBotCore/Loaders/ModuleLoader.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using DiscordBotCore.Interfaces.Modules; using System.Reflection; -using Discord.Commands; namespace DiscordBotCore.Loaders { diff --git a/DiscordBotCore/Modules/ModuleDownloader.cs b/DiscordBotCore/Modules/ModuleDownloader.cs new file mode 100644 index 0000000..fec41a0 --- /dev/null +++ b/DiscordBotCore/Modules/ModuleDownloader.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using DiscordBotCore.Online; + +namespace DiscordBotCore.Modules +{ + public class ModuleDownloader + { + private string _moduleName; + private readonly string _baseUrl = "https://raw.githubusercontent.com/andreitdr/SethPlugins/tests/Modules/"; + private readonly string _moduleFolder = "./Data/Modules"; + + public ModuleDownloader(string moduleName) + { + _moduleName = moduleName; + } + + public async Task DownloadModule(IProgress progressToWrite) + { + Directory.CreateDirectory(_moduleFolder); + string url = _baseUrl + _moduleName + ".dll"; + await ServerCom.DownloadFileAsync(url, _moduleFolder + "/" + _moduleName + ".dll", progressToWrite); + } + } +} diff --git a/DiscordBotCore/Modules/ModuleManager.cs b/DiscordBotCore/Modules/ModuleManager.cs index 673f3ab..c28b6fa 100644 --- a/DiscordBotCore/Modules/ModuleManager.cs +++ b/DiscordBotCore/Modules/ModuleManager.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using DiscordBotCore.Interfaces.Logger; using DiscordBotCore.Interfaces.Modules; using DiscordBotCore.Loaders; +using DiscordBotCore.Others.Exceptions; namespace DiscordBotCore.Modules { @@ -23,7 +24,10 @@ namespace DiscordBotCore.Modules public T GetModule() where T : IBaseModule { if(!LoadedModules.ContainsKey(typeof(T))) - throw new Exception($"No module loaded with this signature: {nameof(T)}"); + throw new ModuleNotFoundException(); + + if (!LoadedModules[typeof(T)].Any()) + throw new ModuleNotFoundException(); IModule module = (IModule)LoadedModules[typeof(T)][0]; return module.Module; diff --git a/DiscordBotCore/Others/Exceptions/ModuleNotFoundException.cs b/DiscordBotCore/Others/Exceptions/ModuleNotFoundException.cs new file mode 100644 index 0000000..aa23282 --- /dev/null +++ b/DiscordBotCore/Others/Exceptions/ModuleNotFoundException.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DiscordBotCore.Others.Exceptions +{ + internal class ModuleNotFoundException : Exception + { + private Type _type = typeof(T); + public ModuleNotFoundException() : base($"No module loaded with this signature: {typeof(T)}") + { + } + } +} diff --git a/LoggerModule/Logger.cs b/LoggerModule/Logger.cs index 5c3ef70..bb150c3 100644 --- a/LoggerModule/Logger.cs +++ b/LoggerModule/Logger.cs @@ -8,14 +8,13 @@ public sealed class Logger : ILogger private readonly FileStream _LogFileStream; public List LogMessageProperties = typeof(ILogMessage).GetProperties().Select(p => p.Name).ToList(); + private Action? _OutFunction; public string LogMessageFormat { get ; set; } - public event EventHandler OnFormattedLog; - public event EventHandler OnRawLog; - - public Logger(string logFolder, string logMessageFormat) + public Logger(string logFolder, string logMessageFormat, Action? outFunction = null) { this.LogMessageFormat = logMessageFormat; + this._OutFunction = outFunction; var logFile = logFolder + DateTime.Now.ToString("yyyy-MM-dd") + ".log"; _LogFileStream = File.Open(logFile, FileMode.Append, FileAccess.Write, FileShare.Read); } @@ -34,6 +33,23 @@ public sealed class Logger : ILogger messageAsString = messageAsString.Replace("{" + prop + "}", messageType?.GetProperty(prop)?.GetValue(message)?.ToString()); } + switch (message.LogMessageType) + { + case LogType.INFO: + messageAsString = $"[green]{messageAsString} [/]"; + break; + case LogType.WARNING: + messageAsString = $"[yellow]{messageAsString} [/]"; + break; + case LogType.ERROR: + messageAsString = $"[red]{messageAsString} [/]"; + break; + case LogType.CRITICAL: + messageAsString = $"[red] [bold]{messageAsString} [/][/]"; + break; + + } + return messageAsString; } @@ -57,22 +73,37 @@ public sealed class Logger : ILogger messageAsString = messageAsString.Replace("{" + prop + "}", messageType?.GetProperty(prop)?.GetValue(message)?.ToString()); } + switch (message.LogMessageType) + { + case LogType.INFO: + messageAsString = $"[green]{messageAsString} [/]"; + break; + case LogType.WARNING: + messageAsString = $"[yellow]{messageAsString} [/]"; + break; + case LogType.ERROR: + messageAsString = $"[red]{messageAsString} [/]"; + break; + case LogType.CRITICAL: + messageAsString = $"[red][bold]{messageAsString} [/][/]"; + break; + + } + return messageAsString; } public void Log(ILogMessage message, string format) { - OnRawLog?.Invoke(this, message); string messageAsString = GenerateLogMessage(message, format); - OnFormattedLog?.Invoke(this, new ILogger.FormattedMessage() { Message = messageAsString, Type = message.LogMessageType }); + _OutFunction?.Invoke(messageAsString); LogToFile(messageAsString); } public void Log(ILogMessage message) { - OnRawLog?.Invoke(this, message); string messageAsString = GenerateLogMessage(message); - OnFormattedLog?.Invoke(this, new ILogger.FormattedMessage() { Message = messageAsString, Type = message.LogMessageType }) ; + _OutFunction?.Invoke(messageAsString); LogToFile(messageAsString); } @@ -83,4 +114,9 @@ public sealed class Logger : ILogger public void Log(string message, object Sender) => Log(new LogMessage(message, Sender)); public void Log(string message, object Sender, LogType type) => Log(new LogMessage(message, Sender, type)); public void LogException(Exception exception, object Sender, bool logFullStack = false) => Log(LogMessage.CreateFromException(exception, Sender, logFullStack)); + + public void SetOutFunction(Action outFunction) + { + this._OutFunction = outFunction; + } }