diff --git a/DiscordBot/Installer.cs b/DiscordBot/Installer.cs new file mode 100644 index 0000000..35b6fa9 --- /dev/null +++ b/DiscordBot/Installer.cs @@ -0,0 +1,117 @@ +using System.Diagnostics; +using System.IO; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using PluginManager; +using PluginManager.Others; +using PluginManager.Online; + +namespace DiscordBot +{ + 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 tokn is required to run the bot. You can get it from the Discord Developer Portal. (https://discord.com/developers/applications)"); + Console.WriteLine("Please enter the bot token :"); + var token = Console.ReadLine(); + + Console.WriteLine("Please enter the bot prefix :"); + var prefix = Console.ReadLine(); + + Console.WriteLine("Please enter the Server ID :"); + var serverId = Console.ReadLine(); + + Config.Data.Add("token", token); + Config.Data.Add("prefix", prefix); + Config.Data.Add("ServerID", serverId); + + Config.Logger.Log("Config Saved", "Installer", TextType.NORMAL); + + Config.Data.Save(); + + Console.WriteLine("Config saved !"); + + + } + + public static async Task SetupPluginDatabase() + { + Console.WriteLine("The plugin database is required to run the bot but there is nothing configured yet."); + Console.WriteLine("Please select one option : "); + Console.WriteLine("1. Download the official database file"); + Console.WriteLine("2. Create a new (CUSTOM) database file"); + int choice = 0; + Console.Write("Choice : "); + choice = int.Parse(Console.ReadLine()); + if (choice != 1 && choice != 2) + { + Console.WriteLine("Invalid choice !"); + Console.WriteLine("Please restart the installer !"); + Console.ReadKey(); + Environment.Exit(0); + } + + if (choice == 1) + await DownloadPluginDatabase(); + + if (choice == 2) + { + Console.WriteLine("Do you have a url to a valid database file ? (y/n)"); + var answer = Console.ReadLine(); + if (answer == "y") + { + Console.WriteLine("Please enter the url :"); + var url = Console.ReadLine(); + await DownloadPluginDatabase(url); + return; + } + + Console.WriteLine("Do you want to create a new database file ? (y/n)"); + answer = Console.ReadLine(); + if (answer == "y") + { + Console.WriteLine("A new file will be generated at ./Data/Resources/URLs.json"); + System.Console.WriteLine("Please edit the file and restart the bot !"); + Directory.CreateDirectory("./Data/Resources"); + await File.WriteAllTextAsync("./Data/Resources/URLs.json", + @" + { + ""PluginList"": """", + ""PluginVersions"": """", + ""StartupMessage"": """", + ""SetupKeys"": """", + ""Versions"": """", + ""Changelog"": """", + ""LinuxBot"": """", + ""WindowsLauncher"": """", + } + ".Replace(" ", "")); + Environment.Exit(0); + return; + } + } + } + + private static async Task DownloadPluginDatabase(string url = "https://raw.githubusercontent.com/Wizzy69/SethDiscordBot/gh-pages/defaultURLs.json") + { + string path = "./Data/Resources/URLs.json"; + + Directory.CreateDirectory("./Data/Resources"); + Utilities.Utilities.ProgressBar bar = new Utilities.Utilities.ProgressBar(Utilities.ProgressBarType.NORMAL){ + Max = 100, + Color = ConsoleColor.Green, + NoColor = true + }; + IProgress downloadProgress = new Progress(p => bar.Update(p)); + await ServerCom.DownloadFileAsync(url, path, downloadProgress, null); + bar.Update(bar.Max); + } + } +} \ No newline at end of file diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 1394dfd..2a540ef 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -15,12 +15,14 @@ using PluginManager.Others; using DiscordBot.Utilities; using OperatingSystem = PluginManager.Others.OperatingSystem; +using static PluginManager.Config; namespace DiscordBot; public class Program { - private static bool loadPluginsOnStartup; + public static Json URLs; + private static bool loadPluginsOnStartup = false; private static ConsoleCommandsHandler consoleCommandsHandler; /// @@ -38,7 +40,7 @@ public class Program Config.Data["prefix"]?.Length != 1 || (args.Length == 1 && args[0] == "/reset")) { - GenerateStartupConfig(); + Installer.GenerateStartupConfig(); } HandleInput(args).Wait(); @@ -79,8 +81,7 @@ public class Program Console.ForegroundColor = ConsoleColor.DarkYellow; var startupMessageList = - await ServerCom.ReadTextFromURL( - "https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/StartupMessage"); + await ServerCom.ReadTextFromURL(URLs["StartupMessage"]); foreach (var message in startupMessageList) Console.WriteLine(message); @@ -132,6 +133,8 @@ public class Program { var len = args.Length; + Console.WriteLine("Loading Core ..."); + var b = await StartNoGui(); consoleCommandsHandler = new ConsoleCommandsHandler(b.client); @@ -139,6 +142,7 @@ public class Program { try { + Console.WriteLine("Launching core functions ..."); NoGUI(); } catch (IOException ex) @@ -157,8 +161,17 @@ public class Program private static async Task PreLoadComponents(string[] args) { + await Config.Initialize(); + if (!Directory.Exists("./Data/Resources") || !File.Exists("./Data/Resources/URLs.json")) + { + await Installer.SetupPluginDatabase(); + } + + + URLs = new Json("./Data/Resources/URLs.json"); + Config.Logger.LogEvent += (message, type) => { Console.WriteLine(message); }; @@ -171,8 +184,7 @@ public class Program foreach (var file in Directory.GetFiles("./Output/Logs/")) File.Delete(file); var OnlineDefaultKeys = - await ServerCom.ReadTextFromURL( - "https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/SetupKeys"); + await ServerCom.ReadTextFromURL(URLs["SetupKeys"]); Config.Data["Version"] = Assembly.GetExecutingAssembly().GetName().Version.ToString(); @@ -192,9 +204,7 @@ public class Program } - var onlineSettingsList = - await ServerCom.ReadTextFromURL( - "https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/OnlineData"); + var onlineSettingsList = await ServerCom.ReadTextFromURL(URLs["Versions"]); main.Stop("Loaded online settings. Loading updates ..."); foreach (var key in onlineSettingsList) { @@ -245,15 +255,13 @@ public class Program Console.WriteLine("Changelog :"); - List changeLog = await ServerCom.ReadTextFromURL( - "https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/VersionData/DiscordBot"); + List changeLog = await ServerCom.ReadTextFromURL(URLs["Changelog"]); foreach (var item in changeLog) Utilities.Utilities.WriteColorText(item); Console.WriteLine("Do you want to update the bot ? (y/n)"); if (Console.ReadKey().Key == ConsoleKey.Y) { - var url = - $"https://github.com/Wizzy69/SethDiscordBot/releases/download/v{newVersion}/net6.0_linux.zip"; + var url = URLs["LinuxBot"].Replace("{0}", newVersion); Config.Logger.Log($"executing: download_file {url}"); await ServerCom.DownloadFileAsync(url, "./update.zip", new Progress(percent => { Console.WriteLine($"\rProgress: {percent}% "); })); @@ -301,9 +309,7 @@ public class Program Console.WriteLine("Installing a new Launcher ...\nDo NOT close the bot during update !"); var bar = new Utilities.Utilities.ProgressBar(ProgressBarType.NO_END); bar.Start(); - await ServerCom.DownloadFileAsync( - "https://github.com/Wizzy69/installer/releases/download/release-1-discordbot/Launcher.exe", - $"./Launcher.exe", null); + await ServerCom.DownloadFileAsync(URLs["WindowsLauncher"], $"./Launcher.exe", null); //await ArchiveManager.ExtractArchive("./Updater.zip", "./", null, // UnzipProgressType.PercentageFromTotalSize); Config.Data["LauncherVersion"] = updaternewversion; @@ -318,28 +324,4 @@ public class Program Console.Clear(); } - - 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 tokn is required to run the bot. You can get it from the Discord Developer Portal. (https://discord.com/developers/applications)"); - Console.WriteLine("Please enter the bot token :"); - var token = Console.ReadLine(); - - Console.WriteLine("Please enter the bot prefix :"); - var prefix = Console.ReadLine(); - - Console.WriteLine("Please enter the Server ID :"); - var serverId = Console.ReadLine(); - - Config.Data.Add("token", token); - Config.Data.Add("prefix", prefix); - Config.Data.Add("ServerID", serverId); - - Config.Logger.Log("Config Saved", "Installer", TextType.NORMAL); - - Config.Data.Save(); - } } \ No newline at end of file diff --git a/DiscordBot/Utilities/Console Utilities.cs b/DiscordBot/Utilities/Console Utilities.cs index 1834cbc..191e1b3 100644 --- a/DiscordBot/Utilities/Console Utilities.cs +++ b/DiscordBot/Utilities/Console Utilities.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using PluginManager; @@ -200,6 +201,45 @@ public static class Utilities Console.WriteLine(); } + public class Spinner + { + private Thread thread; + private bool isRunning; + private readonly string[] Sequence; + private int position; + + public Spinner() + { + Sequence = new[] {"|", "/", "-", "\\"}; + position = 0; + } + + public void Start() + { + Console.CursorVisible = false; + isRunning=true; + thread = new Thread(() => { + while (isRunning) + { + Console.Write("\r" + Sequence[position]); + position++; + if (position >= Sequence.Length) + position = 0; + Thread.Sleep(100); + } + }); + + thread.Start(); + + } + + public void Stop() + { + isRunning=false; + Console.CursorVisible = true; + } + } + /// /// Progress bar object @@ -227,6 +267,7 @@ public static class Utilities public async void Start() { + Console.WriteLine(); if (type != ProgressBarType.NO_END) throw new Exception("Only NO_END progress bar can use this method"); if (isRunning) diff --git a/DiscordBot/Utilities/ConsoleCommandsHandler.cs b/DiscordBot/Utilities/ConsoleCommandsHandler.cs index 4cc0fdc..338445e 100644 --- a/DiscordBot/Utilities/ConsoleCommandsHandler.cs +++ b/DiscordBot/Utilities/ConsoleCommandsHandler.cs @@ -1,4 +1,5 @@ -using System; +using System.Threading; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -20,20 +21,29 @@ namespace DiscordBot.Utilities; public class ConsoleCommandsHandler { - private static readonly PluginsManager manager = - new("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/Plugins.txt"); - private static readonly List commandList = new(); + public static ConsoleCommandsHandler handler; + private readonly PluginsManager manager; + + private readonly List commandList = new(); - private static bool isDownloading; - private static bool pluginsLoaded; - private readonly DiscordSocketClient? client; + private bool isDownloading; + private bool pluginsLoaded; + private DiscordSocketClient client; public ConsoleCommandsHandler(DiscordSocketClient client) { this.client = client; + + manager = new PluginsManager(Program.URLs["PluginList"], Program.URLs["PluginVersions"]); InitializeBasicCommands(); + Console.WriteLine("Done"); + + if (handler == null) + handler = this; + else + throw new Exception("ConsoleCommandsHandler already initialized"); } private void InitializeBasicCommands() @@ -77,7 +87,6 @@ public class ConsoleCommandsHandler } ); - AddCommand("lp", "Load plugins", () => { if (pluginsLoaded) @@ -150,6 +159,11 @@ public class ConsoleCommandsHandler ); AddCommand("listplugs", "list available plugins", async () => { + if(manager == null) + { + Console.WriteLine("Plugin manager is null"); + return; + } var data = await manager.GetAvailablePlugins(); var items = new List { @@ -170,6 +184,7 @@ public class ConsoleCommandsHandler AddCommand("dwplug", "download plugin", "dwplug [name]", async args => { isDownloading = true; + Utilities.Spinner spinner = new Utilities.Spinner(); if (args.Length == 1) { isDownloading = false; @@ -197,27 +212,17 @@ public class ConsoleCommandsHandler return; } + spinner.Start(); + string path; if (info[0] == "Plugin") path = "./Data/Plugins/" + name + ".dll"; else path = $"./{info[1].Split('/')[info[1].Split('/').Length - 1]}"; - if (OperatingSystem.WINDOWS == Functions.GetOperatingSystem()) - { - await ServerCom.DownloadFileAsync(info[1], path, null); - Console.WriteLine("Plugin Downloaded !", this, TextType.SUCCESS); - } - else if (OperatingSystem.LINUX == Functions.GetOperatingSystem()) - { - var bar = new Utilities.ProgressBar(ProgressBarType.NO_END); - bar.Start(); - await ServerCom.DownloadFileAsync(info[1], path, null); - bar.Stop("Plugin Downloaded !"); - } - - + Console.WriteLine($"Downloading plugin {name} from {info[1]} to {path}"); + await ServerCom.DownloadFileAsync(info[1], path, null); Console.WriteLine("\n"); @@ -236,18 +241,9 @@ public class ConsoleCommandsHandler var split = line.Split(','); Console.WriteLine($"\nDownloading item: {split[1]}"); if (File.Exists("./" + split[1])) File.Delete("./" + split[1]); - if (OperatingSystem.WINDOWS == Functions.GetOperatingSystem()) - { - await ServerCom.DownloadFileAsync(split[0], "./" + split[1], null); - Console.WriteLine("Item "+split[1]+" downloaded !", this, TextType.SUCCESS); - } - else if (OperatingSystem.LINUX == Functions.GetOperatingSystem()) - { - var bar = new Utilities.ProgressBar(ProgressBarType.NO_END); - bar.Start(); - await ServerCom.DownloadFileAsync(split[0], "./" + split[1], null); - bar.Stop("Item downloaded !"); - } + await ServerCom.DownloadFileAsync(split[0], "./" + split[1], null); + + Console.WriteLine("Item " + split[1] + " downloaded !", this, TextType.SUCCESS); Console.WriteLine(); if (split[0].EndsWith(".pak")) @@ -257,12 +253,8 @@ public class ConsoleCommandsHandler else if (split[0].EndsWith(".zip") || split[0].EndsWith(".pkg")) { Console.WriteLine($"Extracting {split[1]} ..."); - var bar = new Utilities.ProgressBar( - ProgressBarType.NO_END); - bar.Start(); await ArchiveManager.ExtractArchive("./" + split[1], "./", null, UnzipProgressType.PercentageFromTotalSize); - bar.Stop("Extracted"); Console.WriteLine("\n"); File.Delete("./" + split[1]); } @@ -270,12 +262,14 @@ public class ConsoleCommandsHandler Console.WriteLine(); } + spinner.Stop(); - var ver = await ServerCom.GetVersionOfPackageFromWeb(name); + var ver = await manager.GetVersionOfPackageFromWeb(name); if (ver is null) throw new Exception("Incorrect version"); Config.Plugins[name] = ver.ToShortString(); isDownloading = false; + Config.Logger.Log("Plugin installed !", this, TextType.SUCCESS); @@ -387,45 +381,35 @@ public class ConsoleCommandsHandler commandList.Sort((x, y) => x.CommandName.CompareTo(y.CommandName)); } - public static void AddCommand(string command, string description, string usage, Action action) + public void AddCommand(string command, string description, string usage, Action action) { + Console.WriteLine($"Adding command {command} ..."); commandList.Add(new ConsoleCommand { CommandName = command, Description = description, Action = action, Usage = usage }); Console.ForegroundColor = ConsoleColor.White; Utilities.WriteColorText($"Command &r{command} &cadded to the list of commands"); } - public static void AddCommand(string command, string description, Action action) + public void AddCommand(string command, string description, Action action) { AddCommand(command, description, command, args => action()); } - public static void RemoveCommand(string command) + public void RemoveCommand(string command) { commandList.RemoveAll(x => x.CommandName == command); } - public static bool CommandExists(string command) + public bool CommandExists(string command) { return GetCommand(command) is not null; } - public static ConsoleCommand? GetCommand(string command) + public ConsoleCommand? GetCommand(string command) { return commandList.FirstOrDefault(t => t.CommandName == command); } - public static async Task ExecuteCommad(string command) - { - var args = command.Split(' '); - foreach (var item in commandList.ToList()) - if (item.CommandName == args[0]) - { - item.Action.Invoke(args); - while (isDownloading) await Task.Delay(1000); - } - } - public bool HandleCommand(string command, bool removeCommandExecution = true) { Console.ForegroundColor = ConsoleColor.White; diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index e4ca614..bfee239 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -47,20 +47,17 @@ public static class Config public class Json : IDictionary { protected IDictionary _dictionary; - - public Json(IDictionary dictionary) - { - _dictionary = dictionary; - } - + private readonly string _file = ""; + public Json(string file) { _dictionary = PrivateReadConfig(file).GetAwaiter().GetResult(); + this._file = file; } public async void Save() { - await Functions.SaveToJsonFile("./Data/Resources/config.json", _dictionary); + await Functions.SaveToJsonFile(_file, _dictionary); } public virtual void Add(TKey key, TValue value) @@ -91,7 +88,7 @@ public static class Config get { if (_dictionary.TryGetValue(key, out TValue value)) return value; - return default; + throw new Exception("Key not found in dictionary " + key.ToString() + " (Json )" + this.GetType().Name + ")"); } set diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index 8e38d99..9b9edf3 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -15,15 +15,17 @@ public class PluginsManager /// The Plugin Manager constructor /// /// The link to the file where all plugins are stored - public PluginsManager(string link) + public PluginsManager(string plink, string vlink) { - PluginsLink = link; + PluginsLink = plink; + VersionsLink = vlink; } /// /// The URL of the server /// public string PluginsLink { get; } + public string VersionsLink {get; } /// /// The method to load all plugins @@ -54,7 +56,7 @@ public class PluginsManager display[1] = content[1]; display[2] = content[2]; display[3] = - (await ServerCom.GetVersionOfPackageFromWeb(content[0]) ?? new VersionString("0.0.0")) + (await GetVersionOfPackageFromWeb(content[0]) ?? new VersionString("0.0.0")) .ToShortString(); data.Add(display); } @@ -67,7 +69,7 @@ public class PluginsManager display[1] = content[1]; display[2] = content[2]; display[3] = - (await ServerCom.GetVersionOfPackageFromWeb(content[0]) ?? new VersionString("0.0.0")) + (await GetVersionOfPackageFromWeb(content[0]) ?? new VersionString("0.0.0")) .ToShortString(); data.Add(display); } @@ -86,6 +88,25 @@ public class PluginsManager return null; } + public async Task GetVersionOfPackageFromWeb(string pakName) + { + var data = await ServerCom.ReadTextFromURL(VersionsLink); + foreach (var item in data) + { + if (item.StartsWith("#")) + continue; + + string[] split = item.Split(','); + if (split[0] == pakName) + { + Console.WriteLine("Searched for " + pakName + " and found " + split[1] + " as version.\nUsed url: " + VersionsLink); + return new VersionString(split[1]); + } + + } + return null; + } + /// /// The method to get plugin information by its name /// diff --git a/PluginManager/Online/ServerCom.cs b/PluginManager/Online/ServerCom.cs index 89d41d8..b28fd4e 100644 --- a/PluginManager/Online/ServerCom.cs +++ b/PluginManager/Online/ServerCom.cs @@ -50,20 +50,4 @@ public static class ServerCom { await DownloadFileAsync(URl, location, progress, null); } - - public static async Task GetVersionOfPackageFromWeb(string pakName) - { - var url = "https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/Versions"; - var data = await ReadTextFromURL(url); - foreach (var item in data) - { - if (item.StartsWith("#")) - continue; - - string[] split = item.Split(','); - if (split[0] == pakName) - return new VersionString(split[1]); - } - return null; - } } \ No newline at end of file