From 58624f4037e2da04726e9e4d61093b6450da5b88 Mon Sep 17 00:00:00 2001 From: Tudor Andrei Date: Mon, 18 Sep 2023 23:13:44 +0300 Subject: [PATCH] Improved download speed and started using Spectre.Console package --- DiscordBot/Bot/Actions/Plugin.cs | 197 +++++++++++------- DiscordBot/DiscordBot.csproj | 1 + DiscordBot/Entry.cs | 12 ++ DiscordBot/Installer.cs | 47 ++--- DiscordBot/Program.cs | 6 +- .../Online/Helpers/OnlineFunctions.cs | 20 +- PluginManager/Online/ServerCom.cs | 1 + 7 files changed, 167 insertions(+), 117 deletions(-) diff --git a/DiscordBot/Bot/Actions/Plugin.cs b/DiscordBot/Bot/Actions/Plugin.cs index 16663dd..81a82da 100644 --- a/DiscordBot/Bot/Actions/Plugin.cs +++ b/DiscordBot/Bot/Actions/Plugin.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Globalization; +using System.Threading; using System.Threading.Tasks; using DiscordBot.Utilities; using PluginManager; @@ -7,16 +9,17 @@ using PluginManager.Interfaces; using PluginManager.Loaders; using PluginManager.Online; using PluginManager.Others; +using Spectre.Console; namespace DiscordBot.Bot.Actions; public class Plugin : ICommandAction { - private bool pluginsLoaded; - public string ActionName => "plugin"; - public string Description => "Manages plugins. Use plugin help for more info."; - public string Usage => "plugin [help|list|load|install|refresh]"; - public InternalActionRunType RunType => InternalActionRunType.ON_CALL; + private bool pluginsLoaded; + public string ActionName => "plugin"; + public string Description => "Manages plugins. Use plugin help for more info."; + public string Usage => "plugin [help|list|load|install|refresh]"; + public InternalActionRunType RunType => InternalActionRunType.ON_CALL; public async Task Execute(string[] args) { @@ -31,10 +34,10 @@ public class Plugin : ICommandAction return; } - + var manager = new PluginsManager(); - switch ( args[0] ) + switch (args[0]) { case "refresh": await Program.internalActionManager.Refresh(); @@ -67,8 +70,8 @@ public class Plugin : ICommandAction pluginsLoaded = true; break; } - - var cc = Console.ForegroundColor; + + var cc = Console.ForegroundColor; loader.onCMDLoad += (name, typeName, success, exception) => { if (name == null || name.Length < 2) @@ -87,7 +90,7 @@ public class Plugin : ICommandAction else Console.WriteLine("[CMD] Failed to load command : " + name + " because " + exception!.Message - ); + ); } Console.ForegroundColor = cc; @@ -126,7 +129,7 @@ public class Plugin : ICommandAction Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("[SLASH] Failed to load command : " + name + " because " + exception!.Message - ); + ); } Console.ForegroundColor = cc; @@ -134,7 +137,7 @@ public class Plugin : ICommandAction loader.LoadPlugins(); Console.ForegroundColor = cc; - pluginsLoaded = true; + pluginsLoaded = true; break; case "install": @@ -150,68 +153,116 @@ public class Plugin : ICommandAction break; } } - - var pluginData = await manager.GetPluginLinkByName(pluginName); - if (pluginData == null || pluginData.Length == 0) - { - Console.WriteLine($"Plugin {pluginName} not found. Please check the spelling and try again."); - break; - } - var pluginType = pluginData[0]; - var pluginLink = pluginData[1]; - var pluginRequirements = pluginData[2]; - - - Console.WriteLine("Downloading plugin..."); - //download plugin progress bar for linux and windows terminals - var spinner = new ConsoleUtilities.Spinner(); - spinner.Start(); - IProgress progress = new Progress(p => { spinner.Message = $"Downloading {pluginName}... {Math.Round(p, 2)}% "; }); - await ServerCom.DownloadFileAsync(pluginLink, $"./Data/{pluginType}s/{pluginName}.dll", progress); - spinner.Stop(); - Console.WriteLine(); - - if (pluginRequirements == string.Empty) - { - Console.WriteLine("Finished installing " + pluginName + " successfully"); - Console.WriteLine("Reloading plugins list..."); - await Program.internalActionManager.Execute("plugin", "load"); - await Program.internalActionManager.Refresh(); - - Console.WriteLine("Finished reloading plugins list"); - break; - } - - Console.WriteLine("Downloading plugin requirements..."); - var requirementsURLs = await ServerCom.ReadTextFromURL(pluginRequirements); - - foreach (var requirement in requirementsURLs) - { - if (requirement.Length < 2) - continue; - var reqdata = requirement.Split(','); - var url = reqdata[0]; - var filename = reqdata[1]; - - Console.WriteLine($"Downloading {filename}... "); - progress = new Progress(p => { spinner.Message = $"Downloading {filename}... {Math.Round(p, 2)}% "; }); - spinner.Start(); - await ServerCom.DownloadFileAsync(url, $"./{filename}", progress); - spinner.Stop(); - progress.Report(1); - await Task.Delay(1000); - Console.WriteLine("Downloaded " + filename + " successfully"); - } - - Console.WriteLine("Finished installing " + pluginName + " successfully"); - - Console.WriteLine("Reloading plugins list..."); - await Program.internalActionManager.Execute("plugin", "load", "-q"); - await Program.internalActionManager.Refresh(); - - Console.WriteLine("Finished reloading plugins list"); + await DownloadPlugin(manager, pluginName); break; } } -} + + private async Task RefreshPlugins() + { + Console.WriteLine("Reloading plugins list..."); + await Program.internalActionManager.Execute("plugin", "load"); + await Program.internalActionManager.Refresh(); + + Console.WriteLine("Finished reloading plugins list"); + } + + + public async Task DownloadPlugin(PluginsManager manager, string pluginName) + { + var pluginData = await manager.GetPluginLinkByName(pluginName); + if (pluginData.Length == 0) + { + Console.WriteLine($"Plugin {pluginName} not found. Please check the spelling and try again."); + return; + } + + var pluginType = pluginData[0]; + var pluginLink = pluginData[1]; + var pluginRequirements = pluginData[2]; + + + await AnsiConsole.Progress() + .Columns(new ProgressColumn[] + { + new TaskDescriptionColumn(), + new ProgressBarColumn(), + new PercentageColumn() + }) + .StartAsync(async ctx => + { + var downloadTask = ctx.AddTask("Downloading plugin..."); + + IProgress progress = new Progress(p => { downloadTask.Value = p; }); + + await ServerCom.DownloadFileAsync(pluginLink, $"./Data/{pluginType}s/{pluginName}.dll", progress); + + downloadTask.Increment(100); + + ctx.Refresh(); + }); + + if (pluginRequirements == string.Empty) + { + Console.WriteLine("Finished installing " + pluginName + " successfully"); + await RefreshPlugins(); + return; + } + + List requirementsUrLs = new(); + + await AnsiConsole.Progress() + .Columns(new ProgressColumn[] + { + new TaskDescriptionColumn(), + new ProgressBarColumn(), + new PercentageColumn() + }) + .StartAsync(async ctx => + { + var gatherInformationTask = ctx.AddTask("Gathering info..."); + gatherInformationTask.IsIndeterminate = true; + requirementsUrLs = await ServerCom.ReadTextFromURL(pluginRequirements); + await Task.Delay(2000); + gatherInformationTask.Increment(100); + }); + + await AnsiConsole.Progress() + .Columns(new ProgressColumn[] + { + new TaskDescriptionColumn(), + new ProgressBarColumn(), + new PercentageColumn() + }) + .StartAsync(async ctx => + { + List, Task>> downloadTasks = new(); + + foreach (var info in requirementsUrLs) + { + if (info.Length < 2) continue; + string[] data = info.Split(','); + string url = data[0]; + string fileName = data[1]; + + var task = ctx.AddTask($"Downloading {fileName}..."); + IProgress progress = new Progress(p => + { + task.Value = p; + }); + + var downloadTask = ServerCom.DownloadFileAsync(url, $"./{fileName}", progress); + downloadTasks.Add(new Tuple, Task>(task, progress, downloadTask)); + } + + foreach (var task in downloadTasks) + { + await task.Item3; + } + + }); + + await RefreshPlugins(); + } +} \ No newline at end of file diff --git a/DiscordBot/DiscordBot.csproj b/DiscordBot/DiscordBot.csproj index 614d97f..fa3c2ed 100644 --- a/DiscordBot/DiscordBot.csproj +++ b/DiscordBot/DiscordBot.csproj @@ -35,6 +35,7 @@ + diff --git a/DiscordBot/Entry.cs b/DiscordBot/Entry.cs index 3f553c0..2834a51 100644 --- a/DiscordBot/Entry.cs +++ b/DiscordBot/Entry.cs @@ -8,6 +8,18 @@ public class Entry { public static void Main(string[] args) { + #if DEBUG + if (args.Length == 1 && args[0] == "/purge_plugins") + { + foreach (var plugin in Directory.GetFiles("./Data/Plugins", "*.dll", SearchOption.AllDirectories)) + { + File.Delete(plugin); + } + } + + #endif + + var currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve += LoadFromSameFolder; diff --git a/DiscordBot/Installer.cs b/DiscordBot/Installer.cs index 02bb91c..be92fae 100644 --- a/DiscordBot/Installer.cs +++ b/DiscordBot/Installer.cs @@ -1,8 +1,6 @@ using System; -using System.IO; -using System.Threading.Tasks; using PluginManager; -using PluginManager.Online; +using Spectre.Console; namespace DiscordBot; @@ -10,36 +8,21 @@ public static class Installer { public static void GenerateStartupConfig() { - Console.WriteLine("Welcome to the SethBot installer !"); - Console.WriteLine("First, we need to configure the bot. Don't worry, it will be quick !"); - Console.WriteLine("The following information will be stored in the config.json file in the ./Data/Resources folder. You can change it later from there."); - Console.WriteLine("The bot token is required to run the bot. You can get it from the Discord Developer Portal. (https://discord.com/developers/applications)"); - - if (!Config.AppSettings.ContainsKey("token")) - { - Console.WriteLine("Please enter the bot token :"); - var token = Console.ReadLine(); - Config.AppSettings.Add("token", token); - } - - if (!Config.AppSettings.ContainsKey("prefix")) - { - Console.WriteLine("Please enter the bot prefix :"); - var prefix = Console.ReadLine(); - Config.AppSettings.Add("prefix", prefix); - } - - if (!Config.AppSettings.ContainsKey("ServerID")) - { - Console.WriteLine("Please enter the Server ID :"); - var serverId = Console.ReadLine(); - Config.AppSettings.Add("ServerID", serverId); - } - - Config.Logger.Log("Config Saved", "Installer", isInternal: true); + AnsiConsole.WriteLine("Welcome to the [bold]SethBot[/] installer !"); + AnsiConsole.WriteLine("First, we need to configure the bot. Don't worry, it will be quick !"); + + var token = AnsiConsole.Ask("Please enter the bot token :"); + var prefix = AnsiConsole.Ask("Please enter the bot prefix :"); + var serverId = AnsiConsole.Ask("Please enter the Server ID :"); + + Config.AppSettings.Add("token", token); + Config.AppSettings.Add("prefix", prefix); + Config.AppSettings.Add("ServerID", serverId); Config.AppSettings.SaveToFile(); - - Console.WriteLine("Config saved !"); + + AnsiConsole.MarkupLine("[bold]Config saved ![/]"); + + Config.Logger.Log("Config Saved", "Installer", isInternal: true); } } diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 32fae9c..3035402 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -1,13 +1,10 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using DiscordBot.Utilities; using PluginManager.Bot; -using PluginManager.Online; -using PluginManager.Online.Helpers; using PluginManager.Others; using PluginManager.Others.Actions; using static PluginManager.Config; @@ -32,7 +29,7 @@ public class Program !AppSettings.ContainsKey("prefix") || AppSettings["prefix"] == null || AppSettings["prefix"]?.Length != 1 || args.Length == 1 && args[0] == "/reset") - Installer.GenerateStartupConfig(); + Installer.GenerateStartupConfig(); HandleInput().Wait(); } @@ -137,6 +134,7 @@ public class Program Console.WriteLine($"[{type.ToString()}] {message}"); Console.ResetColor(); }; + AppSettings["Version"] = Assembly.GetExecutingAssembly().GetName().Version.ToString(); } } diff --git a/PluginManager/Online/Helpers/OnlineFunctions.cs b/PluginManager/Online/Helpers/OnlineFunctions.cs index 36407cd..03faa29 100644 --- a/PluginManager/Online/Helpers/OnlineFunctions.cs +++ b/PluginManager/Online/Helpers/OnlineFunctions.cs @@ -35,21 +35,25 @@ internal static class OnlineFunctions if (progress == null || !contentLength.HasValue) { await download.CopyToAsync(destination, cancellation); + if(!contentLength.HasValue) + progress?.Report(100f); return; } // Convert absolute progress (bytes downloaded) into relative progress (0% - 100%) - var relativeProgress = new Progress(totalBytes => - { - progress?.Report((float)totalBytes / contentLength.Value * - 100); - downloadedBytes?.Report(totalBytes); - } - ); + // total ... 100% + // downloaded ... x% + // x = downloaded * 100 / total => x = downloaded / total * 100 + var relativeProgress = new Progress(totalBytesDownloaded => + { + progress?.Report(totalBytesDownloaded / (float)contentLength.Value * 100); + downloadedBytes?.Report(totalBytesDownloaded); + } + ); // Use extension method to report progress while downloading await download.CopyToOtherStreamAsync(destination, bufferSize, relativeProgress, cancellation); - progress.Report(100); + progress.Report(100f); } } } diff --git a/PluginManager/Online/ServerCom.cs b/PluginManager/Online/ServerCom.cs index 8c99abb..49ace6e 100644 --- a/PluginManager/Online/ServerCom.cs +++ b/PluginManager/Online/ServerCom.cs @@ -48,4 +48,5 @@ public static class ServerCom { await DownloadFileAsync(URl, location, progress, null); } + }