From d3555b6fca311bee80ffe3a59952150b4e593bf1 Mon Sep 17 00:00:00 2001 From: Tudor Andrei Date: Wed, 25 Oct 2023 10:08:13 +0300 Subject: [PATCH 01/37] fixed typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 97db820..604ddbc 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ namespace SlashCommands { public string Name => "random"; - public string Description => "Generates a random nunber between 2 values"; + public string Description => "Generates a random number between 2 values"; public bool canUseDM => true; From 5f23bdadcfa6f9196450c2660d68e64e49335139 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Mon, 30 Oct 2023 11:07:59 +0200 Subject: [PATCH 02/37] Fixed error on ubuntu downloading the wrong plugins --- PluginManager/Online/PluginsManager.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index f3ca97c..5908a15 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data.Common; using System.Threading.Tasks; using PluginManager.Online.Helpers; using PluginManager.Others; @@ -129,7 +130,8 @@ public class PluginsManager for (var i = 0; i < len; i++) { var contents = lines[i].Split(','); - if (contents[0].ToLowerInvariant() == name.ToLowerInvariant()) + if(Functions.GetOperatingSystem() == OperatingSystem.WINDOWS && contents[4].Contains("Windows")) + {if (contents[0].ToLowerInvariant() == name.ToLowerInvariant()) { if (contents.Length == 6) return new[] { contents[2], contents[3], contents[5] }; @@ -137,6 +139,15 @@ public class PluginsManager return new[] { contents[2], contents[3], string.Empty }; throw new Exception("Failed to download plugin. Invalid Argument Length"); } + }else if (Functions.GetOperatingSystem() == OperatingSystem.LINUX && contents[4].Contains("Linux")) + { + if (contents.Length == 6) + return new[] { contents[2], contents[3], contents[5] }; + if (contents.Length == 5) + return new[] { contents[2], contents[3], string.Empty }; + throw new Exception("Failed to download plugin. Invalid Argument Length"); + + } } } catch (Exception exception) From 6d41d5169453a253db693b4410608e9d29292e28 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Tue, 31 Oct 2023 17:35:58 +0200 Subject: [PATCH 03/37] Added config to set the max concurrent downloads --- DiscordBot/Bot/Actions/Extra/PluginMethods.cs | 48 +++++++++++++------ DiscordBot/Bot/Actions/Plugin.cs | 9 +++- PluginManager/Online/PluginsManager.cs | 13 +++-- PluginManager/Online/ServerCom.cs | 10 ++++ 4 files changed, 60 insertions(+), 20 deletions(-) diff --git a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs index 3b96d7d..58f6868 100644 --- a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs +++ b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; using DiscordBot.Utilities; using PluginManager; @@ -13,11 +16,9 @@ namespace DiscordBot.Bot.Actions.Extra; internal static class PluginMethods { - private static readonly PluginsManager PluginsManager = new(); - - internal static async Task List() + internal static async Task List(PluginsManager manager) { - var data = await ConsoleUtilities.ExecuteWithProgressBar(PluginsManager.GetAvailablePlugins(), "Loading plugins..."); + var data = await ConsoleUtilities.ExecuteWithProgressBar(manager.GetAvailablePlugins(), "Loading plugins..."); TableData tableData = new(new List { "Name", "Description", "Type", "Version" }); foreach (var plugin in data) tableData.AddRow(plugin); @@ -87,10 +88,10 @@ internal static class PluginMethods var gatherInformationTask = ctx.AddTask("Gathering info..."); gatherInformationTask.IsIndeterminate = true; requirementsUrLs = await ServerCom.ReadTextFromURL(pluginRequirements); - await Task.Delay(2000); + gatherInformationTask.Increment(100); }); - + List, string, string>> downloadTasks = new(); await AnsiConsole.Progress() .Columns(new ProgressColumn[] { @@ -100,7 +101,7 @@ internal static class PluginMethods }) .StartAsync(async ctx => { - List, Task>> downloadTasks = new(); + foreach (var info in requirementsUrLs) { @@ -109,22 +110,41 @@ internal static class PluginMethods string url = data[0]; string fileName = data[1]; - var task = ctx.AddTask($"Downloading {fileName}..."); + 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)); + + task.IsIndeterminate = true; + downloadTasks.Add(new Tuple, string, string>(task, progress, url, fileName)); } - - foreach (var task in downloadTasks) + + if (!int.TryParse(Config.AppSettings["MaxParallelDownloads"], out int maxParallelDownloads)) { - await task.Item3; + maxParallelDownloads = 5; + Config.AppSettings.Add("MaxParallelDownloads", "5"); + await Config.AppSettings.SaveToFile(); } + var options = new ParallelOptions() + { + MaxDegreeOfParallelism = maxParallelDownloads, + TaskScheduler = TaskScheduler.Default + }; + + await Parallel.ForEachAsync(downloadTasks, options, async (tuple, token) => + { + tuple.Item1.IsIndeterminate = false; + await ServerCom.DownloadFileAsync(tuple.Item3, $"./{tuple.Item4}", tuple.Item2); + }); + + + }); + + + await RefreshPlugins(false); } diff --git a/DiscordBot/Bot/Actions/Plugin.cs b/DiscordBot/Bot/Actions/Plugin.cs index a24ef12..1632b53 100644 --- a/DiscordBot/Bot/Actions/Plugin.cs +++ b/DiscordBot/Bot/Actions/Plugin.cs @@ -34,7 +34,12 @@ public class Plugin : ICommandAction return; } - var manager = new PluginsManager(); + PluginsManager manager = +#if !DEBUG + new PluginsManager(); +#else + new PluginsManager("tests"); +#endif switch (args[0]) { @@ -43,7 +48,7 @@ public class Plugin : ICommandAction break; case "list": - await PluginMethods.List(); + await PluginMethods.List(manager); break; case "load": if (pluginsLoaded) diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index f3ca97c..e845b4f 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -9,6 +9,8 @@ namespace PluginManager.Online; public class PluginsManager { + + #if DEBUG /// /// The Plugin Manager constructor /// @@ -20,13 +22,16 @@ public class PluginsManager VersionsLink = vlink; } + #endif + /// - /// The default Plugin Manager constructor. It uses the default links. + /// The Plugin Manager constructor. It uses the default links and the default branch. /// - public PluginsManager() + /// The main branch from where the plugin manager gets its info + public PluginsManager(string? branch = "releases") { - PluginsLink = "https://raw.githubusercontent.com/andreitdr/SethPlugins/releases/PluginsList"; - VersionsLink = "https://raw.githubusercontent.com/andreitdr/SethPlugins/releases/Versions"; + PluginsLink = $"https://raw.githubusercontent.com/andreitdr/SethPlugins/{branch}/PluginsList"; + VersionsLink = $"https://raw.githubusercontent.com/andreitdr/SethPlugins/{branch}/Versions"; } /// diff --git a/PluginManager/Online/ServerCom.cs b/PluginManager/Online/ServerCom.cs index 49ace6e..25ccae4 100644 --- a/PluginManager/Online/ServerCom.cs +++ b/PluginManager/Online/ServerCom.cs @@ -49,4 +49,14 @@ public static class ServerCom await DownloadFileAsync(URl, location, progress, null); } + public static Task CreateDownloadTask(string URl, string location) + { + return DownloadFileAsync(URl, location, null, null); + } + + public static Task CreateDownloadTask(string URl, string location, IProgress progress) + { + return DownloadFileAsync(URl, location, progress, null); + } + } From 1f0e6516fdaf9c90771c56be348c9184f22e861f Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Tue, 7 Nov 2023 10:13:22 +0200 Subject: [PATCH 04/37] New SqlDatabase functions --- PluginManager/Bot/Boot.cs | 2 +- PluginManager/Config.cs | 4 +- PluginManager/Database/SqlDatabase.cs | 251 +++++++++++++++++++++----- PluginManager/Loaders/Loader.cs | 14 +- 4 files changed, 215 insertions(+), 56 deletions(-) diff --git a/PluginManager/Bot/Boot.cs b/PluginManager/Bot/Boot.cs index 849cb98..713693a 100644 --- a/PluginManager/Bot/Boot.cs +++ b/PluginManager/Bot/Boot.cs @@ -85,7 +85,7 @@ public class Boot await commandServiceHandler.InstallCommandsAsync(); - Config._DiscordBotClient = this; + Config.DiscordBotClient = this; while (!isReady) ; } diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index 021966b..b0dde70 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -13,9 +13,9 @@ public class Config public static Logger Logger; public static SettingsDictionary AppSettings; - internal static Boot? _DiscordBotClient; + internal static Boot? DiscordBotClient; - public static Boot? DiscordBot => _DiscordBotClient; + public static Boot? DiscordBot => DiscordBotClient; public static async Task Initialize() { diff --git a/PluginManager/Database/SqlDatabase.cs b/PluginManager/Database/SqlDatabase.cs index 43289a4..6b65a84 100644 --- a/PluginManager/Database/SqlDatabase.cs +++ b/PluginManager/Database/SqlDatabase.cs @@ -9,7 +9,7 @@ namespace PluginManager.Database; public class SqlDatabase { - private readonly SQLiteConnection Connection; + private readonly SQLiteConnection _connection; /// /// Initialize a SQL connection by specifing its private path @@ -22,7 +22,7 @@ public class SqlDatabase if (!File.Exists(fileName)) SQLiteConnection.CreateFile(fileName); var connectionString = $"URI=file:{fileName}"; - Connection = new SQLiteConnection(connectionString); + _connection = new SQLiteConnection(connectionString); } @@ -32,7 +32,7 @@ public class SqlDatabase /// public async Task Open() { - await Connection.OpenAsync(); + await _connection.OpenAsync(); } /// @@ -55,7 +55,7 @@ public class SqlDatabase query += ")"; - var command = new SQLiteCommand(query, Connection); + var command = new SQLiteCommand(query, _connection); await command.ExecuteNonQueryAsync(); } @@ -79,7 +79,7 @@ public class SqlDatabase query += ")"; - var command = new SQLiteCommand(query, Connection); + var command = new SQLiteCommand(query, _connection); command.ExecuteNonQuery(); } @@ -94,7 +94,7 @@ public class SqlDatabase { var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'"; - var command = new SQLiteCommand(query, Connection); + var command = new SQLiteCommand(query, _connection); await command.ExecuteNonQueryAsync(); } @@ -109,7 +109,7 @@ public class SqlDatabase { var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'"; - var command = new SQLiteCommand(query, Connection); + var command = new SQLiteCommand(query, _connection); command.ExecuteNonQuery(); } @@ -163,7 +163,7 @@ public class SqlDatabase throw new Exception($"Table {tableName} does not exist"); await ExecuteAsync( - $"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'"); + $"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'"); } /// @@ -224,7 +224,7 @@ public class SqlDatabase /// public async void Stop() { - await Connection.CloseAsync(); + await _connection.CloseAsync(); } /// @@ -236,9 +236,9 @@ public class SqlDatabase /// public async Task AddColumnsToTableAsync(string tableName, string[] columns, string TYPE = "TEXT") { - var command = Connection.CreateCommand(); + var command = _connection.CreateCommand(); command.CommandText = $"SELECT * FROM {tableName}"; - var reader = await command.ExecuteReaderAsync(); + var reader = await command.ExecuteReaderAsync(); var tableColumns = new List(); for (var i = 0; i < reader.FieldCount; i++) tableColumns.Add(reader.GetName(i)); @@ -260,9 +260,9 @@ public class SqlDatabase /// public void AddColumnsToTable(string tableName, string[] columns, string TYPE = "TEXT") { - var command = Connection.CreateCommand(); + var command = _connection.CreateCommand(); command.CommandText = $"SELECT * FROM {tableName}"; - var reader = command.ExecuteReader(); + var reader = command.ExecuteReader(); var tableColumns = new List(); for (var i = 0; i < reader.FieldCount; i++) tableColumns.Add(reader.GetName(i)); @@ -282,7 +282,7 @@ public class SqlDatabase /// True if the table exists, false if not public async Task TableExistsAsync(string tableName) { - var cmd = Connection.CreateCommand(); + var cmd = _connection.CreateCommand(); cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'"; var result = await cmd.ExecuteScalarAsync(); @@ -298,7 +298,7 @@ public class SqlDatabase /// True if the table exists, false if not public bool TableExists(string tableName) { - var cmd = Connection.CreateCommand(); + var cmd = _connection.CreateCommand(); cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'"; var result = cmd.ExecuteScalar(); @@ -315,7 +315,7 @@ public class SqlDatabase /// public async Task CreateTableAsync(string tableName, params string[] columns) { - var cmd = Connection.CreateCommand(); + var cmd = _connection.CreateCommand(); cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})"; await cmd.ExecuteNonQueryAsync(); } @@ -328,7 +328,7 @@ public class SqlDatabase /// public void CreateTable(string tableName, params string[] columns) { - var cmd = Connection.CreateCommand(); + var cmd = _connection.CreateCommand(); cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})"; cmd.ExecuteNonQuery(); } @@ -340,10 +340,10 @@ public class SqlDatabase /// The number of rows that the query modified public async Task ExecuteAsync(string query) { - if (!Connection.State.HasFlag(ConnectionState.Open)) - await Connection.OpenAsync(); - var command = new SQLiteCommand(query, Connection); - var answer = await command.ExecuteNonQueryAsync(); + if (!_connection.State.HasFlag(ConnectionState.Open)) + await _connection.OpenAsync(); + var command = new SQLiteCommand(query, _connection); + var answer = await command.ExecuteNonQueryAsync(); return answer; } @@ -354,10 +354,10 @@ public class SqlDatabase /// The number of rows that the query modified public int Execute(string query) { - if (!Connection.State.HasFlag(ConnectionState.Open)) - Connection.Open(); - var command = new SQLiteCommand(query, Connection); - var r = command.ExecuteNonQuery(); + if (!_connection.State.HasFlag(ConnectionState.Open)) + _connection.Open(); + var command = new SQLiteCommand(query, _connection); + var r = command.ExecuteNonQuery(); return r; } @@ -369,10 +369,10 @@ public class SqlDatabase /// The result is a string that has all values separated by space character public async Task ReadDataAsync(string query) { - if (!Connection.State.HasFlag(ConnectionState.Open)) - await Connection.OpenAsync(); - var command = new SQLiteCommand(query, Connection); - var reader = await command.ExecuteReaderAsync(); + if (!_connection.State.HasFlag(ConnectionState.Open)) + await _connection.OpenAsync(); + var command = new SQLiteCommand(query, _connection); + var reader = await command.ExecuteReaderAsync(); var values = new object[reader.FieldCount]; if (reader.Read()) @@ -391,10 +391,10 @@ public class SqlDatabase /// The result is a string that has all values separated by space character public string? ReadData(string query) { - if (!Connection.State.HasFlag(ConnectionState.Open)) - Connection.Open(); - var command = new SQLiteCommand(query, Connection); - var reader = command.ExecuteReader(); + if (!_connection.State.HasFlag(ConnectionState.Open)) + _connection.Open(); + var command = new SQLiteCommand(query, _connection); + var reader = command.ExecuteReader(); var values = new object[reader.FieldCount]; if (reader.Read()) @@ -413,10 +413,10 @@ public class SqlDatabase /// The first row as separated items public async Task ReadDataArrayAsync(string query) { - if (!Connection.State.HasFlag(ConnectionState.Open)) - await Connection.OpenAsync(); - var command = new SQLiteCommand(query, Connection); - var reader = await command.ExecuteReaderAsync(); + if (!_connection.State.HasFlag(ConnectionState.Open)) + await _connection.OpenAsync(); + var command = new SQLiteCommand(query, _connection); + var reader = await command.ExecuteReaderAsync(); var values = new object[reader.FieldCount]; if (reader.Read()) @@ -436,10 +436,10 @@ public class SqlDatabase /// The first row as separated items public object[]? ReadDataArray(string query) { - if (!Connection.State.HasFlag(ConnectionState.Open)) - Connection.Open(); - var command = new SQLiteCommand(query, Connection); - var reader = command.ExecuteReader(); + if (!_connection.State.HasFlag(ConnectionState.Open)) + _connection.Open(); + var command = new SQLiteCommand(query, _connection); + var reader = command.ExecuteReader(); var values = new object[reader.FieldCount]; if (reader.Read()) @@ -459,10 +459,10 @@ public class SqlDatabase /// A list of string arrays representing the values that the query returns public async Task?> ReadAllRowsAsync(string query) { - if (!Connection.State.HasFlag(ConnectionState.Open)) - await Connection.OpenAsync(); - var command = new SQLiteCommand(query, Connection); - var reader = await command.ExecuteReaderAsync(); + if (!_connection.State.HasFlag(ConnectionState.Open)) + await _connection.OpenAsync(); + var command = new SQLiteCommand(query, _connection); + var reader = await command.ExecuteReaderAsync(); if (!reader.HasRows) return null; @@ -479,4 +479,163 @@ public class SqlDatabase return rows; } -} + + /// + /// Create a parameter for a query + /// + /// The name of the parameter + /// The value of the parameter + /// The SQLiteParameter that has the name, value and DBType set according to your inputs + private SQLiteParameter? CreateParameter(string name, object value) + { + var parameter = new SQLiteParameter(name); + parameter.Value = value; + + if (value is string) + parameter.DbType = DbType.String; + else if (value is int) + parameter.DbType = DbType.Int32; + else if (value is long) + parameter.DbType = DbType.Int64; + else if (value is float) + parameter.DbType = DbType.Single; + else if (value is double) + parameter.DbType = DbType.Double; + else if (value is bool) + parameter.DbType = DbType.Boolean; + else if (value is DateTime) + parameter.DbType = DbType.DateTime; + else if (value is byte[]) + parameter.DbType = DbType.Binary; + else if (value is Guid) + parameter.DbType = DbType.Guid; + else if (value is decimal) + parameter.DbType = DbType.Decimal; + else if (value is TimeSpan) + parameter.DbType = DbType.Time; + else if (value is DateTimeOffset) + parameter.DbType = DbType.DateTimeOffset; + else if (value is ushort) + parameter.DbType = DbType.UInt16; + else if (value is uint) + parameter.DbType = DbType.UInt32; + else if (value is ulong) + parameter.DbType = DbType.UInt64; + else if (value is sbyte) + parameter.DbType = DbType.SByte; + else if (value is short) + parameter.DbType = DbType.Int16; + else if (value is byte) + parameter.DbType = DbType.Byte; + else if (value is char) + parameter.DbType = DbType.StringFixedLength; + else if (value is char[]) + parameter.DbType = DbType.StringFixedLength; + else + return null; + + return parameter; + } + + + /// + /// Create a parameter for a query. The function automatically detects the type of the value. + /// + /// The parameter raw inputs. The Key is name and the Value is the value of the parameter + /// The SQLiteParameter that has the name, value and DBType set according to your inputs + private SQLiteParameter? CreateParameter(KeyValuePair parameterValues) => + CreateParameter(parameterValues.Key, parameterValues.Value); + + /// + /// Execute a query with parameters + /// + /// The query to execute + /// The parameters of the query + /// The number of rows that the query modified in the database + public async Task ExecuteNonQueryAsync(string query, params KeyValuePair[] parameters) + { + if (!_connection.State.HasFlag(ConnectionState.Open)) + await _connection.OpenAsync(); + + var command = new SQLiteCommand(query, _connection); + foreach (var parameter in parameters) + { + var p = CreateParameter(parameter); + if (p is not null) + command.Parameters.Add(p); + } + + return await command.ExecuteNonQueryAsync(); + } + + /// + /// Execute a query with parameters that returns a specific type of object. The function will return the first row of the result transformed into the specified type. + /// + /// The query to execute + /// The convertor function that will convert each row of the response into an object of + /// The parameters of the query + /// The return object type + /// An object of type T that represents the output of the convertor function based on the array of objects that the first row of the result has + public async Task ReadObjectOfTypeAsync (string query, Func convertor, params KeyValuePair[] parameters) + { + if (!_connection.State.HasFlag(ConnectionState.Open)) + await _connection.OpenAsync(); + + var command = new SQLiteCommand(query, _connection); + foreach (var parameter in parameters) + { + var p = CreateParameter(parameter); + if (p is not null) + command.Parameters.Add(p); + } + + var reader = await command.ExecuteReaderAsync(); + var values = new object[reader.FieldCount]; + if (reader.Read()) + { + reader.GetValues(values); + return convertor(values); + } + + return default; + } + + + /// + /// Execute a query with parameters that returns a specific type of object. The function will return a list of objects of the specified type. + /// + /// The query to execute + /// The convertor from object[] to T + /// The parameters of the query + /// The expected object type + /// A list of objects of type T that represents each line of the output of the specified query, converted to T + public async Task> ReadListOfTypeAsync(string query, Func convertor, + params KeyValuePair[] parameters) + { + if (!_connection.State.HasFlag(ConnectionState.Open)) + await _connection.OpenAsync(); + + var command = new SQLiteCommand(query, _connection); + foreach (var parameter in parameters) + { + var p = CreateParameter(parameter); + if (p is not null) + command.Parameters.Add(p); + } + + var reader = await command.ExecuteReaderAsync(); + // + if (!reader.HasRows) + return null; + + List rows = new(); + while (await reader.ReadAsync()) + { + var values = new object[reader.FieldCount]; + reader.GetValues(values); + rows.Add(convertor(values)); + } + + return rows; + } +} \ No newline at end of file diff --git a/PluginManager/Loaders/Loader.cs b/PluginManager/Loaders/Loader.cs index 803fddc..fe3a716 100644 --- a/PluginManager/Loaders/Loader.cs +++ b/PluginManager/Loaders/Loader.cs @@ -21,13 +21,13 @@ internal class Loader { internal Loader(string path, string extension) { - this.path = path; - this.extension = extension; + this.Path = path; + this.Extension = extension; } - private string path { get; } - private string extension { get; } + private string Path { get; } + private string Extension { get; } internal event FileLoadedEventHandler? FileLoaded; @@ -40,13 +40,13 @@ internal class Loader List slashCommands = new(); List commands = new(); - if (!Directory.Exists(path)) + if (!Directory.Exists(Path)) { - Directory.CreateDirectory(path); + Directory.CreateDirectory(Path); return (null, null, null); } - var files = Directory.GetFiles(path, $"*.{extension}", SearchOption.AllDirectories); + var files = Directory.GetFiles(Path, $"*.{Extension}", SearchOption.AllDirectories); foreach (var file in files) { try From 79ecff971b59ba431dd4aaba7492ee9d00417138 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Mon, 20 Nov 2023 13:43:43 +0200 Subject: [PATCH 05/37] Playing with tests --- PluginManager/Others/Logger/Logger.cs | 4 +- SethDiscordBot.sln | 6 +++ .../PluginManagerTests/AppSettingsTests.cs | 46 +++++++++++++++++++ SethTests/SethTests.csproj | 33 +++++++++++++ SethTests/Usings.cs | 1 + 5 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 SethTests/PluginManagerTests/AppSettingsTests.cs create mode 100644 SethTests/SethTests.csproj create mode 100644 SethTests/Usings.cs diff --git a/PluginManager/Others/Logger/Logger.cs b/PluginManager/Others/Logger/Logger.cs index 2a9e2c7..33462f7 100644 --- a/PluginManager/Others/Logger/Logger.cs +++ b/PluginManager/Others/Logger/Logger.cs @@ -10,8 +10,8 @@ public sealed class Logger : ILogger { public bool IsEnabled { get; init; } public bool OutputToFile { get; init; } - - public LogType LowestLogLevel { get; set; } + + private LogType LowestLogLevel { get; } private bool UseShortVersion { get; } public Logger(bool useShortVersion, bool outputToFile, LogType lowestLogLevel = LogType.INFO) diff --git a/SethDiscordBot.sln b/SethDiscordBot.sln index a8d9f43..d355007 100644 --- a/SethDiscordBot.sln +++ b/SethDiscordBot.sln @@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LevelingSystem", "..\SethPl EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PythonCompatibilityLayer", "..\SethPlugins\PythonCompatibilityLayer\PythonCompatibilityLayer.csproj", "{81ED4953-13E5-4950-96A8-8CEF5FD59559}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SethTests", "SethTests\SethTests.csproj", "{B3044E3C-2F68-4556-9E87-3772702B4CE7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -41,6 +43,10 @@ Global {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Debug|Any CPU.Build.0 = Debug|Any CPU {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Release|Any CPU.ActiveCfg = Release|Any CPU {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Release|Any CPU.Build.0 = Release|Any CPU + {B3044E3C-2F68-4556-9E87-3772702B4CE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B3044E3C-2F68-4556-9E87-3772702B4CE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B3044E3C-2F68-4556-9E87-3772702B4CE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B3044E3C-2F68-4556-9E87-3772702B4CE7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SethTests/PluginManagerTests/AppSettingsTests.cs b/SethTests/PluginManagerTests/AppSettingsTests.cs new file mode 100644 index 0000000..ed18d62 --- /dev/null +++ b/SethTests/PluginManagerTests/AppSettingsTests.cs @@ -0,0 +1,46 @@ +using PluginManager; +using Xunit.Abstractions; + +namespace SethTests.PluginManagerTests; + +public class AppSettingsTests +{ + private readonly ITestOutputHelper _testOutputHelper; + + public AppSettingsTests(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; + } + + [Fact] + public void TestAppSettings_ConstructorInitializeTheClassAndFile() + { + var appSettings = new PluginManager.Others.SettingsDictionary("settings.txt"); + + Assert.NotNull(appSettings); + } + + [Theory] + [InlineData("key1", "value1")] + [InlineData("key2", true)] + public void TestAppSettings_InsertingValueIntoSettings(string keyName, object value) + { + var appSettings = new PluginManager.Others.SettingsDictionary("settings.txt"); + + appSettings[keyName] = value; + Assert.True(appSettings.ContainsKey(keyName)); + } + + [Theory] + //[InlineData("key2", 32)] // fails + [InlineData("key1", "value1")] + public void TestAppSettings_GettingTheValueFromSettings(string keyName, object value) + { + var appSettings = new PluginManager.Others.SettingsDictionary("settings.txt"); + + appSettings[keyName] = value; + + Assert.Same(appSettings[keyName], value); + } + +} \ No newline at end of file diff --git a/SethTests/SethTests.csproj b/SethTests/SethTests.csproj new file mode 100644 index 0000000..f55c2d1 --- /dev/null +++ b/SethTests/SethTests.csproj @@ -0,0 +1,33 @@ + + + + net6.0 + enable + enable + + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + diff --git a/SethTests/Usings.cs b/SethTests/Usings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/SethTests/Usings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file From 944d59d9a3ed8b761cd2b6ccc0cda7bd91948676 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Tue, 21 Nov 2023 22:04:38 +0200 Subject: [PATCH 06/37] Reformatting code --- DiscordBot/Bot/Actions/Clear.cs | 10 +- DiscordBot/Bot/Actions/Exit.cs | 12 +- DiscordBot/Bot/Actions/Extra/PluginMethods.cs | 302 +++++++++--------- .../Bot/Actions/Extra/SettingsConfigExtra.cs | 20 +- DiscordBot/Bot/Actions/Help.cs | 10 +- DiscordBot/Bot/Actions/Plugin.cs | 8 +- DiscordBot/Bot/Actions/SettingsConfig.cs | 28 +- .../Bot/Commands/NormalCommands/Help.cs | 4 +- DiscordBot/Bot/Commands/SlashCommands/Help.cs | 6 +- DiscordBot/DiscordBot.csproj | 8 +- DiscordBot/Entry.cs | 8 +- DiscordBot/Installer.cs | 10 +- DiscordBot/Program.cs | 36 ++- DiscordBot/Utilities/Console Utilities.cs | 102 +++--- PluginManager/Bot/Boot.cs | 4 +- PluginManager/Bot/CommandHandler.cs | 20 +- PluginManager/Config.cs | 15 +- PluginManager/Database/SqlDatabase.cs | 57 ++-- PluginManager/Interfaces/DBSlashCommand.cs | 2 +- PluginManager/Interfaces/Logger/ILog.cs | 7 +- PluginManager/Interfaces/Logger/ILogger.cs | 8 +- PluginManager/Loaders/Loader.cs | 49 +-- PluginManager/Loaders/PluginLoader.cs | 7 +- .../Online/Helpers/OnlineFunctions.cs | 10 +- PluginManager/Online/PluginsManager.cs | 28 +- PluginManager/Online/ServerCom.cs | 8 +- .../Others/Actions/InternalActionsManager.cs | 4 +- PluginManager/Others/ArchiveManager.cs | 16 +- .../Others/DBCommandExecutingArguments.cs | 14 +- PluginManager/Others/Enums.cs | 4 +- PluginManager/Others/Functions.cs | 6 +- PluginManager/Others/JsonManager.cs | 4 +- PluginManager/Others/Logger/Log.cs | 76 ++--- PluginManager/Others/Logger/Logger.cs | 60 ++-- PluginManager/Others/SettingsDictionary.cs | 20 +- PluginManager/PluginManager.csproj | 6 +- SethTests/SethTests.csproj | 6 +- 37 files changed, 509 insertions(+), 486 deletions(-) diff --git a/DiscordBot/Bot/Actions/Clear.cs b/DiscordBot/Bot/Actions/Clear.cs index a4bf0e3..1ae69ca 100644 --- a/DiscordBot/Bot/Actions/Clear.cs +++ b/DiscordBot/Bot/Actions/Clear.cs @@ -5,12 +5,12 @@ using PluginManager.Others; namespace DiscordBot.Bot.Actions; -public class Clear : ICommandAction +public class Clear: ICommandAction { - public string ActionName => "clear"; - public string Description => "Clears the console"; - public string Usage => "clear"; - public InternalActionRunType RunType => InternalActionRunType.ON_CALL; + public string ActionName => "clear"; + public string Description => "Clears the console"; + public string Usage => "clear"; + public InternalActionRunType RunType => InternalActionRunType.ON_CALL; public Task Execute(string[] args) { diff --git a/DiscordBot/Bot/Actions/Exit.cs b/DiscordBot/Bot/Actions/Exit.cs index 1caa641..fa21edf 100644 --- a/DiscordBot/Bot/Actions/Exit.cs +++ b/DiscordBot/Bot/Actions/Exit.cs @@ -6,12 +6,12 @@ using PluginManager.Others; namespace DiscordBot.Bot.Actions; -public class Exit : ICommandAction +public class Exit: ICommandAction { - public string ActionName => "exit"; - public string Description => "Exits the bot and saves the config. Use exit help for more info."; - public string Usage => "exit [help|force (-f)]"; - public InternalActionRunType RunType => InternalActionRunType.ON_CALL; + public string ActionName => "exit"; + public string Description => "Exits the bot and saves the config. Use exit help for more info."; + public string Usage => "exit [help|force (-f)]"; + public InternalActionRunType RunType => InternalActionRunType.ON_CALL; public async Task Execute(string[] args) { @@ -23,7 +23,7 @@ public class Exit : ICommandAction } else { - switch ( args[0] ) + switch (args[0]) { case "help": Console.WriteLine("Usage : exit [help|force]"); diff --git a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs index 58f6868..89da9fe 100644 --- a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs +++ b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs @@ -19,20 +19,20 @@ internal static class PluginMethods internal static async Task List(PluginsManager manager) { var data = await ConsoleUtilities.ExecuteWithProgressBar(manager.GetAvailablePlugins(), "Loading plugins..."); - + TableData tableData = new(new List { "Name", "Description", "Type", "Version" }); foreach (var plugin in data) tableData.AddRow(plugin); - + tableData.HasRoundBorders = false; tableData.PrintAsTable(); } - + internal static async Task RefreshPlugins(bool quiet) { await Program.internalActionManager.Execute("plugin", "load", quiet ? "-q" : string.Empty); await Program.internalActionManager.Refresh(); } - + internal static async Task DownloadPlugin(PluginsManager manager, string pluginName) { var pluginData = await manager.GetPluginLinkByName(pluginName); @@ -42,30 +42,32 @@ internal static class PluginMethods return; } - var pluginType = pluginData[0]; - var pluginLink = pluginData[1]; + 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..."); + .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; }); + IProgress progress = new Progress(p => { downloadTask.Value = p; }); - await ServerCom.DownloadFileAsync(pluginLink, $"./Data/{pluginType}s/{pluginName}.dll", progress); - - downloadTask.Increment(100); - - ctx.Refresh(); - }); + await ServerCom.DownloadFileAsync(pluginLink, $"./Data/{pluginType}s/{pluginName}.dll", progress); + + downloadTask.Increment(100); + + ctx.Refresh(); + } + ); if (pluginRequirements == string.Empty) { @@ -75,150 +77,162 @@ internal static class PluginMethods } 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); - - gatherInformationTask.Increment(100); - }); + .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); + + gatherInformationTask.Increment(100); + } + ); List, string, string>> downloadTasks = new(); await AnsiConsole.Progress() - .Columns(new ProgressColumn[] - { - new TaskDescriptionColumn(), - new ProgressBarColumn(), - new PercentageColumn() - }) - .StartAsync(async ctx => - { - + .Columns(new ProgressColumn[] + { + new TaskDescriptionColumn(), + new ProgressBarColumn(), + new PercentageColumn() + } + ) + .StartAsync(async ctx => + { - 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; - }); - task.IsIndeterminate = true; - downloadTasks.Add(new Tuple, string, string>(task, progress, url, fileName)); - } + foreach (var info in requirementsUrLs) + { + if (info.Length < 2) continue; + string[] data = info.Split(','); + string url = data[0]; + string fileName = data[1]; - if (!int.TryParse(Config.AppSettings["MaxParallelDownloads"], out int maxParallelDownloads)) - { - maxParallelDownloads = 5; - Config.AppSettings.Add("MaxParallelDownloads", "5"); - await Config.AppSettings.SaveToFile(); - } - - var options = new ParallelOptions() - { - MaxDegreeOfParallelism = maxParallelDownloads, - TaskScheduler = TaskScheduler.Default - }; + var task = ctx.AddTask($"Downloading {fileName}: "); + IProgress progress = new Progress(p => + { + task.Value = p; + } + ); - await Parallel.ForEachAsync(downloadTasks, options, async (tuple, token) => - { - tuple.Item1.IsIndeterminate = false; - await ServerCom.DownloadFileAsync(tuple.Item3, $"./{tuple.Item4}", tuple.Item2); - }); + task.IsIndeterminate = true; + downloadTasks.Add(new Tuple, string, string>(task, progress, url, fileName)); + } + + if (!int.TryParse(Config.AppSettings["MaxParallelDownloads"], out int maxParallelDownloads)) + { + maxParallelDownloads = 5; + Config.AppSettings.Add("MaxParallelDownloads", "5"); + await Config.AppSettings.SaveToFile(); + } + + var options = new ParallelOptions() + { + MaxDegreeOfParallelism = maxParallelDownloads, + TaskScheduler = TaskScheduler.Default + }; + + await Parallel.ForEachAsync(downloadTasks, options, async (tuple, token) => + { + tuple.Item1.IsIndeterminate = false; + await ServerCom.DownloadFileAsync(tuple.Item3, $"./{tuple.Item4}", tuple.Item2); + } + ); + + + + } + ); - }); - - - await RefreshPlugins(false); } internal static async Task LoadPlugins(string[] args) { - var loader = new PluginLoader(Config.DiscordBot.client); - if (args.Length == 2 && args[1] == "-q") - { - loader.LoadPlugins(); - return true; - } + var loader = new PluginLoader(Config.DiscordBot.client); + if (args.Length == 2 && args[1] == "-q") + { + loader.LoadPlugins(); + return true; + } - var cc = Console.ForegroundColor; - loader.onCMDLoad += (name, typeName, success, exception) => - { - if (name == null || name.Length < 2) - name = typeName; - if (success) - { - Config.Logger.Log("Successfully loaded command : " + name, source: typeof(ICommandAction), - type: LogType.INFO); - } + var cc = Console.ForegroundColor; + loader.onCMDLoad += (name, typeName, success, exception) => + { + if (name == null || name.Length < 2) + name = typeName; + if (success) + { + Config.Logger.Log("Successfully loaded command : " + name, source: typeof(ICommandAction), + type: LogType.INFO + ); + } - else - { - Config.Logger.Log("Failed to load command : " + name + " because " + exception?.Message, - source: typeof(ICommandAction), type: LogType.ERROR); - } + else + { + Config.Logger.Log("Failed to load command : " + name + " because " + exception?.Message, + source: typeof(ICommandAction), type: LogType.ERROR + ); + } - Console.ForegroundColor = cc; - }; - loader.onEVELoad += (name, typeName, success, exception) => - { - if (name == null || name.Length < 2) - name = typeName; + Console.ForegroundColor = cc; + }; + loader.onEVELoad += (name, typeName, success, exception) => + { + if (name == null || name.Length < 2) + name = typeName; - if (success) - { - Config.Logger.Log("Successfully loaded event : " + name, source: typeof(ICommandAction), - type: LogType.INFO); - } - else - { - Config.Logger.Log("Failed to load event : " + name + " because " + exception?.Message, - source: typeof(ICommandAction), type: LogType.ERROR); - } + if (success) + { + Config.Logger.Log("Successfully loaded event : " + name, source: typeof(ICommandAction), + type: LogType.INFO + ); + } + else + { + Config.Logger.Log("Failed to load event : " + name + " because " + exception?.Message, + source: typeof(ICommandAction), type: LogType.ERROR + ); + } - Console.ForegroundColor = cc; - }; + Console.ForegroundColor = cc; + }; - loader.onSLSHLoad += (name, typeName, success, exception) => - { - if (name == null || name.Length < 2) - name = typeName; + loader.onSLSHLoad += (name, typeName, success, exception) => + { + if (name == null || name.Length < 2) + name = typeName; - if (success) - { - Config.Logger.Log("Successfully loaded slash command : " + name, source: typeof(ICommandAction), - type: LogType.INFO); - } - else - { - Config.Logger.Log("Failed to load slash command : " + name + " because " + exception?.Message, - source: typeof(ICommandAction), type: LogType.ERROR); - } + if (success) + { + Config.Logger.Log("Successfully loaded slash command : " + name, source: typeof(ICommandAction), + type: LogType.INFO + ); + } + else + { + Config.Logger.Log("Failed to load slash command : " + name + " because " + exception?.Message, + source: typeof(ICommandAction), type: LogType.ERROR + ); + } - Console.ForegroundColor = cc; - }; + Console.ForegroundColor = cc; + }; - loader.LoadPlugins(); - Console.ForegroundColor = cc; - return true; + loader.LoadPlugins(); + Console.ForegroundColor = cc; + return true; } - - + + } diff --git a/DiscordBot/Bot/Actions/Extra/SettingsConfigExtra.cs b/DiscordBot/Bot/Actions/Extra/SettingsConfigExtra.cs index b038e39..eac1966 100644 --- a/DiscordBot/Bot/Actions/Extra/SettingsConfigExtra.cs +++ b/DiscordBot/Bot/Actions/Extra/SettingsConfigExtra.cs @@ -5,26 +5,26 @@ namespace DiscordBot.Bot.Actions.Extra; internal static class SettingsConfigExtra { - internal static void SetSettings(string key, params string[] value) + internal static void SetSettings(string key, params string[] value) { if (key is null) return; if (value is null) return; - + if (!Config.AppSettings.ContainsKey(key)) return; - + Config.AppSettings[key] = string.Join(' ', value); - // Config.AppSettings.SaveToFile().Wait(); + // Config.AppSettings.SaveToFile().Wait(); } internal static void RemoveSettings(string key) { if (key is null) return; - - if(!Config.AppSettings.ContainsKey(key)) + + if (!Config.AppSettings.ContainsKey(key)) return; - + Config.AppSettings.Remove(key); } @@ -33,11 +33,11 @@ internal static class SettingsConfigExtra if (key is null) return; if (value is null) return; - + if (Config.AppSettings.ContainsKey(key)) return; - + Config.AppSettings.Add(key, string.Join(' ', value)); // Config.AppSettings.SaveToFile().Wait(); } -} \ No newline at end of file +} diff --git a/DiscordBot/Bot/Actions/Help.cs b/DiscordBot/Bot/Actions/Help.cs index f6e2ea5..ac8de2a 100644 --- a/DiscordBot/Bot/Actions/Help.cs +++ b/DiscordBot/Bot/Actions/Help.cs @@ -7,7 +7,7 @@ using PluginManager.Others; namespace DiscordBot.Bot.Actions; -public class Help : ICommandAction +public class Help: ICommandAction { public string ActionName => "help"; @@ -34,8 +34,8 @@ public class Help : ICommandAction items.Add(new[] { "-", "-", "-" }); ConsoleUtilities.FormatAndAlignTable(items, - TableFormat.CENTER_EACH_COLUMN_BASED - ); + TableFormat.CENTER_EACH_COLUMN_BASED + ); return; } @@ -56,7 +56,7 @@ public class Help : ICommandAction }; ConsoleUtilities.FormatAndAlignTable(actionData, - TableFormat.CENTER_EACH_COLUMN_BASED - ); + TableFormat.CENTER_EACH_COLUMN_BASED + ); } } diff --git a/DiscordBot/Bot/Actions/Plugin.cs b/DiscordBot/Bot/Actions/Plugin.cs index 1632b53..211158c 100644 --- a/DiscordBot/Bot/Actions/Plugin.cs +++ b/DiscordBot/Bot/Actions/Plugin.cs @@ -12,7 +12,7 @@ using Spectre.Console; namespace DiscordBot.Bot.Actions; -public class Plugin : ICommandAction +public class Plugin: ICommandAction { private bool pluginsLoaded; public string ActionName => "plugin"; @@ -46,7 +46,7 @@ public class Plugin : ICommandAction case "refresh": await PluginMethods.RefreshPlugins(true); break; - + case "list": await PluginMethods.List(manager); break; @@ -56,7 +56,7 @@ public class Plugin : ICommandAction Config.Logger.Log("Plugins already loaded", source: typeof(ICommandAction), type: LogType.WARNING); break; } - + if (Config.DiscordBot is null) { Config.Logger.Log("DiscordBot is null", source: typeof(ICommandAction), type: LogType.WARNING); @@ -84,4 +84,4 @@ public class Plugin : ICommandAction break; } } -} \ No newline at end of file +} diff --git a/DiscordBot/Bot/Actions/SettingsConfig.cs b/DiscordBot/Bot/Actions/SettingsConfig.cs index 332ed75..ef67bc8 100644 --- a/DiscordBot/Bot/Actions/SettingsConfig.cs +++ b/DiscordBot/Bot/Actions/SettingsConfig.cs @@ -7,7 +7,7 @@ using PluginManager.Others; namespace DiscordBot.Bot.Actions; -public class SettingsConfig : ICommandAction +public class SettingsConfig: ICommandAction { public string ActionName => "config"; public string Description => "Change the settings of the bot"; @@ -19,7 +19,7 @@ public class SettingsConfig : ICommandAction { foreach (var settings in Config.AppSettings) Console.WriteLine(settings.Key + ": " + settings.Value); - + return Task.CompletedTask; } @@ -27,25 +27,25 @@ public class SettingsConfig : ICommandAction { case "-s": case "set": - if(args.Length < 3) + if (args.Length < 3) return Task.CompletedTask; - SettingsConfigExtra.SetSettings(args[1],args[2..]); + SettingsConfigExtra.SetSettings(args[1], args[2..]); break; - + case "-r": case "remove": - if(args.Length < 2) + if (args.Length < 2) return Task.CompletedTask; SettingsConfigExtra.RemoveSettings(args[1]); break; - + case "-a": case "add": - if(args.Length < 3) + if (args.Length < 3) return Task.CompletedTask; SettingsConfigExtra.AddSettings(args[1], args[2..]); break; - + case "-h": case "-help": Console.WriteLine("Options:"); @@ -54,14 +54,14 @@ public class SettingsConfig : ICommandAction Console.WriteLine("-a : Add a setting"); Console.WriteLine("-h: Show this help message"); break; - + default: Console.WriteLine("Invalid option"); return Task.CompletedTask; } - - - + + + return Task.CompletedTask; } -} \ No newline at end of file +} diff --git a/DiscordBot/Bot/Commands/NormalCommands/Help.cs b/DiscordBot/Bot/Commands/NormalCommands/Help.cs index 0fa3256..8387dc5 100644 --- a/DiscordBot/Bot/Commands/NormalCommands/Help.cs +++ b/DiscordBot/Bot/Commands/NormalCommands/Help.cs @@ -10,7 +10,7 @@ namespace DiscordBot.Bot.Commands; /// /// The help command /// -internal class Help : DBCommand +internal class Help: DBCommand { /// /// Command name @@ -76,7 +76,7 @@ internal class Help : DBCommand var embedBuilder = new EmbedBuilder(); var cmd = PluginLoader.Commands.Find(p => p.Command == command || p.Aliases is not null && p.Aliases.Contains(command) - ); + ); if (cmd == null) return null; embedBuilder.AddField("Usage", Config.AppSettings["prefix"] + cmd.Usage); diff --git a/DiscordBot/Bot/Commands/SlashCommands/Help.cs b/DiscordBot/Bot/Commands/SlashCommands/Help.cs index b733818..030d540 100644 --- a/DiscordBot/Bot/Commands/SlashCommands/Help.cs +++ b/DiscordBot/Bot/Commands/SlashCommands/Help.cs @@ -8,11 +8,11 @@ using PluginManager.Others; namespace DiscordBot.Bot.Commands.SlashCommands; -public class Help : DBSlashCommand +public class Help: DBSlashCommand { - public string Name => "help"; + public string Name => "help"; public string Description => "This command allows you to check all loaded commands"; - public bool canUseDM => true; + public bool canUseDM => true; public List Options => new() diff --git a/DiscordBot/DiscordBot.csproj b/DiscordBot/DiscordBot.csproj index fa3c2ed..3ae8395 100644 --- a/DiscordBot/DiscordBot.csproj +++ b/DiscordBot/DiscordBot.csproj @@ -29,13 +29,13 @@ - - + + - - + + diff --git a/DiscordBot/Entry.cs b/DiscordBot/Entry.cs index e3056be..eb61106 100644 --- a/DiscordBot/Entry.cs +++ b/DiscordBot/Entry.cs @@ -16,16 +16,16 @@ public static class Entry File.Delete(plugin); } } - + #endif - - + + var currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve += LoadFromSameFolder; static Assembly LoadFromSameFolder(object sender, ResolveEventArgs args) { - var folderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "./Libraries"); + var folderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "./Libraries"); var assemblyPath = Path.Combine(folderPath, new AssemblyName(args.Name).Name + ".dll"); if (!File.Exists(assemblyPath)) return null; var assembly = Assembly.LoadFrom(assemblyPath); diff --git a/DiscordBot/Installer.cs b/DiscordBot/Installer.cs index 1e27dc9..e310590 100644 --- a/DiscordBot/Installer.cs +++ b/DiscordBot/Installer.cs @@ -9,9 +9,9 @@ public static class Installer { AnsiConsole.MarkupLine("Welcome to the [bold]SethBot[/] installer !"); AnsiConsole.MarkupLine("First, we need to configure the bot. Don't worry, it will be quick !"); - - var token = AnsiConsole.Ask("Please enter the bot [yellow]token[/]:"); - var prefix = AnsiConsole.Ask("Please enter the bot [yellow]prefix[/]:"); + + var token = AnsiConsole.Ask("Please enter the bot [yellow]token[/]:"); + var prefix = AnsiConsole.Ask("Please enter the bot [yellow]prefix[/]:"); var serverId = AnsiConsole.Ask("Please enter the [yellow]Server ID[/]:"); if (string.IsNullOrWhiteSpace(serverId)) serverId = "NULL"; @@ -20,9 +20,9 @@ public static class Installer Config.AppSettings.Add("ServerID", serverId); Config.AppSettings.SaveToFile(); - + AnsiConsole.MarkupLine("[bold]Config saved ![/]"); - + Config.Logger.Log("Config Saved", source: typeof(Installer)); } } diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 818b4b7..42f3437 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -22,9 +22,9 @@ public class Program public static void Startup(string[] args) { PreLoadComponents(args).Wait(); - + if (!AppSettings.ContainsKey("ServerID") || !AppSettings.ContainsKey("token") || !AppSettings.ContainsKey("prefix")) - Installer.GenerateStartupConfig(); + Installer.GenerateStartupConfig(); HandleInput().Wait(); } @@ -37,8 +37,8 @@ public class Program internalActionManager.Initialize().Wait(); internalActionManager.Execute("plugin", "load").Wait(); internalActionManager.Refresh().Wait(); - - + + while (true) { var cmd = Console.ReadLine(); @@ -64,21 +64,21 @@ public class Program Console.WriteLine($"Running on version: {Assembly.GetExecutingAssembly().GetName().Version}"); Console.WriteLine("Git SethBot: https://github.com/andreitdr/SethDiscordBot"); Console.WriteLine("Git Plugins: https://github.com/andreitdr/SethPlugins"); - + ConsoleUtilities.WriteColorText("&rRemember to close the bot using the ShutDown command (&yexit&r) or some settings won't be saved"); ConsoleUtilities.WriteColorText($"Running on &m{Functions.GetOperatingSystem()}"); Console.WriteLine("============================ LOG ============================"); - + Console.ForegroundColor = ConsoleColor.White; try { - var token = AppSettings["token"]; + var token = AppSettings["token"]; var prefix = AppSettings["prefix"]; var discordbooter = new Boot(token, prefix); await discordbooter.Awake(); } - catch ( Exception ex ) + catch (Exception ex) { Logger.Log(ex.ToString(), source: typeof(Program), type: LogType.CRITICAL); } @@ -96,18 +96,20 @@ public class Program internalActionManager = new InternalActionManager("./Data/Plugins", "*.dll"); NoGUI(); } - catch ( IOException ex ) + catch (IOException ex) { if (ex.Message == "No process is on the other end of the pipe." || (uint)ex.HResult == 0x800700E9) { if (AppSettings.ContainsKey("LaunchMessage")) AppSettings.Add("LaunchMessage", - "An error occured while closing the bot last time. Please consider closing the bot using the &rexit&c method !\n" + - "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !"); - + "An error occured while closing the bot last time. Please consider closing the bot using the &rexit&c method !\n" + + "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !" + ); + Logger.Log("An error occured while closing the bot last time. Please consider closing the bot using the &rexit&c method !\n" + - "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !", - source: typeof(Program), type: LogType.ERROR); + "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !", + source: typeof(Program), type: LogType.ERROR + ); } } } @@ -115,7 +117,7 @@ public class Program private static async Task PreLoadComponents(string[] args) { await Initialize(); - + Logger.OnLog += (sender, logMessage) => { string messageColor = logMessage.Type switch @@ -133,10 +135,10 @@ public class Program Console.WriteLine(logMessage.Message); return; } - + AnsiConsole.MarkupLine($"{messageColor}{logMessage.ThrowTime} {logMessage.Message} [/]"); }; - + AppSettings["Version"] = Assembly.GetExecutingAssembly().GetName().Version.ToString(); } } diff --git a/DiscordBot/Utilities/Console Utilities.cs b/DiscordBot/Utilities/Console Utilities.cs index 5fdbe60..cd68bd0 100644 --- a/DiscordBot/Utilities/Console Utilities.cs +++ b/DiscordBot/Utilities/Console Utilities.cs @@ -9,24 +9,24 @@ namespace DiscordBot.Utilities; public class TableData { - public List Columns; + public List Columns; public List Rows; - + public bool IsEmpty => Rows.Count == 0; public bool HasRoundBorders { get; set; } = true; - + public TableData(List columns) { Columns = columns; Rows = new List(); } - + public TableData(string[] columns) { Columns = columns.ToList(); Rows = new List(); } - + public void AddRow(string[] row) { Rows.Add(row); @@ -41,23 +41,23 @@ public static class ConsoleUtilities T result = default; await AnsiConsole.Progress() .Columns( - new ProgressColumn[] - { - new TaskDescriptionColumn(), - new ProgressBarColumn(), - new PercentageColumn(), - } - ) + new ProgressColumn[] + { + new TaskDescriptionColumn(), + new ProgressBarColumn(), + new PercentageColumn(), + } + ) .StartAsync( - async ctx => - { - var task = ctx.AddTask(message); - task.IsIndeterminate = true; - result = await function; - task.Increment(100); + async ctx => + { + var task = ctx.AddTask(message); + task.IsIndeterminate = true; + result = await function; + task.Increment(100); - } - ); + } + ); return result; } @@ -66,21 +66,23 @@ public static class ConsoleUtilities { await AnsiConsole.Progress() .Columns(new ProgressColumn[] - { - new TaskDescriptionColumn(), - new ProgressBarColumn(), - new PercentageColumn(), - }) + { + new TaskDescriptionColumn(), + new ProgressBarColumn(), + new PercentageColumn(), + } + ) .StartAsync(async ctx => - { - var task = ctx.AddTask(message); - task.IsIndeterminate = true; - await function; - task.Increment(100); - - }); + { + var task = ctx.AddTask(message); + task.IsIndeterminate = true; + await function; + task.Increment(100); + + } + ); } - + private static readonly Dictionary Colors = new() { { 'g', ConsoleColor.Green }, @@ -91,7 +93,7 @@ public static class ConsoleUtilities }; private static readonly char ColorPrefix = '&'; - + private static bool CanAproximateTo(this float f, float y) { return MathF.Abs(f - y) < 0.000001; @@ -104,7 +106,7 @@ public static class ConsoleUtilities table.AddColumns(tableData.Columns.ToArray()); foreach (var row in tableData.Rows) table.AddRow(row); - + AnsiConsole.Write(table); } @@ -123,12 +125,12 @@ public static class ConsoleUtilities data.RemoveAt(0); foreach (var row in data) table.AddRow(row); - + AnsiConsole.Write(table); - + return; } - + if (format == TableFormat.CENTER_EACH_COLUMN_BASED) { var tableLine = '-'; @@ -317,18 +319,18 @@ public static class ConsoleUtilities Console.CursorVisible = false; isRunning = true; thread = new Thread(() => - { - while (isRunning) - { - Console.SetCursorPosition(0, Console.CursorTop); - Console.Write(" " + Sequence[position] + " " + Message + " "); - position++; - if (position >= Sequence.Length) - position = 0; - Thread.Sleep(100); - } - } - ); + { + while (isRunning) + { + Console.SetCursorPosition(0, Console.CursorTop); + Console.Write(" " + Sequence[position] + " " + Message + " "); + position++; + if (position >= Sequence.Length) + position = 0; + Thread.Sleep(100); + } + } + ); thread.Start(); } diff --git a/PluginManager/Bot/Boot.cs b/PluginManager/Bot/Boot.cs index 713693a..5ac16a3 100644 --- a/PluginManager/Bot/Boot.cs +++ b/PluginManager/Bot/Boot.cs @@ -78,7 +78,7 @@ public class Boot CommonTasks(); await client.LoginAsync(TokenType.Bot, botToken); - + await client.StartAsync(); commandServiceHandler = new CommandHandler(client, service, botPrefix); @@ -105,7 +105,7 @@ public class Boot if (arg.Message.Contains("401")) { Config.AppSettings.Remove("token"); - Config.Logger.Log("The token is invalid. Please restart the bot and enter a valid token.", source:typeof(Boot), type: LogType.CRITICAL); + Config.Logger.Log("The token is invalid. Please restart the bot and enter a valid token.", source: typeof(Boot), type: LogType.CRITICAL); await Config.AppSettings.SaveToFile(); await Task.Delay(4000); Environment.Exit(0); diff --git a/PluginManager/Bot/CommandHandler.cs b/PluginManager/Bot/CommandHandler.cs index 1a4e9fa..1a8b098 100644 --- a/PluginManager/Bot/CommandHandler.cs +++ b/PluginManager/Bot/CommandHandler.cs @@ -106,9 +106,11 @@ internal class CommandHandler ( plug.Aliases is not null && plug.Aliases.Contains(message.CleanContent - .Substring(mentionPrefix.Length + 1) - .Split(' ')[0]) - )); + .Substring(mentionPrefix.Length + 1) + .Split(' ')[0] + ) + ) + ); cleanMessage = message.Content.Substring(mentionPrefix.Length + 1); } @@ -120,11 +122,13 @@ internal class CommandHandler message.Content.Split(' ')[0].Substring(botPrefix.Length) || (p.Aliases is not null && p.Aliases.Contains( - message.Content.Split(' ')[0] - .Substring(botPrefix.Length)))); + message.Content.Split(' ')[0] + .Substring(botPrefix.Length) + )) + ); cleanMessage = message.Content.Substring(botPrefix.Length); } - + if (plugin is null) return; @@ -138,13 +142,13 @@ internal class CommandHandler argsClean = string.Join(' ', split, 1, split.Length - 1).Split(' '); DBCommandExecutingArguments cmd = new(context, cleanMessage, split[0], argsClean); - + Config.Logger.Log( message: $"User ({context.User.Username}) from Guild \"{context.Guild.Name}\" executed command \"{cmd.cleanContent}\"", source: typeof(CommandHandler), type: LogType.INFO ); - + if (context.Channel is SocketDMChannel) plugin.ExecuteDM(cmd); else plugin.ExecuteServer(cmd); diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index b0dde70..2b32f52 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -20,18 +20,19 @@ public class Config public static async Task Initialize() { if (_isLoaded) return; - + Directory.CreateDirectory("./Data/Resources"); Directory.CreateDirectory("./Data/Plugins"); - Directory.CreateDirectory("./Data/PAKS"); - Directory.CreateDirectory("./Data/Logs/Logs"); - Directory.CreateDirectory("./Data/Logs/Errors"); + Directory.CreateDirectory("./Data/Archives"); + Directory.CreateDirectory("./Data/Logs"); AppSettings = new SettingsDictionary("./Data/Resources/config.json"); - AppSettings["LogFolder"] = "./Data/Logs/Logs"; + AppSettings["LogFolder"] = "./Data/Logs"; - Logger = new Logger(false, true); + Logger = new Logger(false, true, + AppSettings["LogFolder"] + $"/{DateTime.Today.ToShortDateString().Replace("/", "")}.log" + ); ArchiveManager.Initialize(); @@ -39,5 +40,5 @@ public class Config Logger.Log(message: "Config initialized", source: typeof(Config)); } - + } diff --git a/PluginManager/Database/SqlDatabase.cs b/PluginManager/Database/SqlDatabase.cs index 6b65a84..3c9fdd0 100644 --- a/PluginManager/Database/SqlDatabase.cs +++ b/PluginManager/Database/SqlDatabase.cs @@ -163,7 +163,8 @@ public class SqlDatabase throw new Exception($"Table {tableName} does not exist"); await ExecuteAsync( - $"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'"); + $"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'" + ); } /// @@ -238,7 +239,7 @@ public class SqlDatabase { var command = _connection.CreateCommand(); command.CommandText = $"SELECT * FROM {tableName}"; - var reader = await command.ExecuteReaderAsync(); + var reader = await command.ExecuteReaderAsync(); var tableColumns = new List(); for (var i = 0; i < reader.FieldCount; i++) tableColumns.Add(reader.GetName(i)); @@ -262,7 +263,7 @@ public class SqlDatabase { var command = _connection.CreateCommand(); command.CommandText = $"SELECT * FROM {tableName}"; - var reader = command.ExecuteReader(); + var reader = command.ExecuteReader(); var tableColumns = new List(); for (var i = 0; i < reader.FieldCount; i++) tableColumns.Add(reader.GetName(i)); @@ -343,7 +344,7 @@ public class SqlDatabase if (!_connection.State.HasFlag(ConnectionState.Open)) await _connection.OpenAsync(); var command = new SQLiteCommand(query, _connection); - var answer = await command.ExecuteNonQueryAsync(); + var answer = await command.ExecuteNonQueryAsync(); return answer; } @@ -357,7 +358,7 @@ public class SqlDatabase if (!_connection.State.HasFlag(ConnectionState.Open)) _connection.Open(); var command = new SQLiteCommand(query, _connection); - var r = command.ExecuteNonQuery(); + var r = command.ExecuteNonQuery(); return r; } @@ -372,7 +373,7 @@ public class SqlDatabase if (!_connection.State.HasFlag(ConnectionState.Open)) await _connection.OpenAsync(); var command = new SQLiteCommand(query, _connection); - var reader = await command.ExecuteReaderAsync(); + var reader = await command.ExecuteReaderAsync(); var values = new object[reader.FieldCount]; if (reader.Read()) @@ -394,7 +395,7 @@ public class SqlDatabase if (!_connection.State.HasFlag(ConnectionState.Open)) _connection.Open(); var command = new SQLiteCommand(query, _connection); - var reader = command.ExecuteReader(); + var reader = command.ExecuteReader(); var values = new object[reader.FieldCount]; if (reader.Read()) @@ -416,7 +417,7 @@ public class SqlDatabase if (!_connection.State.HasFlag(ConnectionState.Open)) await _connection.OpenAsync(); var command = new SQLiteCommand(query, _connection); - var reader = await command.ExecuteReaderAsync(); + var reader = await command.ExecuteReaderAsync(); var values = new object[reader.FieldCount]; if (reader.Read()) @@ -439,7 +440,7 @@ public class SqlDatabase if (!_connection.State.HasFlag(ConnectionState.Open)) _connection.Open(); var command = new SQLiteCommand(query, _connection); - var reader = command.ExecuteReader(); + var reader = command.ExecuteReader(); var values = new object[reader.FieldCount]; if (reader.Read()) @@ -462,7 +463,7 @@ public class SqlDatabase if (!_connection.State.HasFlag(ConnectionState.Open)) await _connection.OpenAsync(); var command = new SQLiteCommand(query, _connection); - var reader = await command.ExecuteReaderAsync(); + var reader = await command.ExecuteReaderAsync(); if (!reader.HasRows) return null; @@ -479,7 +480,7 @@ public class SqlDatabase return rows; } - + /// /// Create a parameter for a query /// @@ -490,7 +491,7 @@ public class SqlDatabase { var parameter = new SQLiteParameter(name); parameter.Value = value; - + if (value is string) parameter.DbType = DbType.String; else if (value is int) @@ -531,13 +532,13 @@ public class SqlDatabase parameter.DbType = DbType.StringFixedLength; else if (value is char[]) parameter.DbType = DbType.StringFixedLength; - else + else return null; return parameter; } - - + + /// /// Create a parameter for a query. The function automatically detects the type of the value. /// @@ -545,7 +546,7 @@ public class SqlDatabase /// The SQLiteParameter that has the name, value and DBType set according to your inputs private SQLiteParameter? CreateParameter(KeyValuePair parameterValues) => CreateParameter(parameterValues.Key, parameterValues.Value); - + /// /// Execute a query with parameters /// @@ -556,7 +557,7 @@ public class SqlDatabase { if (!_connection.State.HasFlag(ConnectionState.Open)) await _connection.OpenAsync(); - + var command = new SQLiteCommand(query, _connection); foreach (var parameter in parameters) { @@ -564,10 +565,10 @@ public class SqlDatabase if (p is not null) command.Parameters.Add(p); } - + return await command.ExecuteNonQueryAsync(); } - + /// /// Execute a query with parameters that returns a specific type of object. The function will return the first row of the result transformed into the specified type. /// @@ -576,11 +577,11 @@ public class SqlDatabase /// The parameters of the query /// The return object type /// An object of type T that represents the output of the convertor function based on the array of objects that the first row of the result has - public async Task ReadObjectOfTypeAsync (string query, Func convertor, params KeyValuePair[] parameters) + public async Task ReadObjectOfTypeAsync(string query, Func convertor, params KeyValuePair[] parameters) { if (!_connection.State.HasFlag(ConnectionState.Open)) await _connection.OpenAsync(); - + var command = new SQLiteCommand(query, _connection); foreach (var parameter in parameters) { @@ -588,7 +589,7 @@ public class SqlDatabase if (p is not null) command.Parameters.Add(p); } - + var reader = await command.ExecuteReaderAsync(); var values = new object[reader.FieldCount]; if (reader.Read()) @@ -599,8 +600,8 @@ public class SqlDatabase return default; } - - + + /// /// Execute a query with parameters that returns a specific type of object. The function will return a list of objects of the specified type. /// @@ -614,7 +615,7 @@ public class SqlDatabase { if (!_connection.State.HasFlag(ConnectionState.Open)) await _connection.OpenAsync(); - + var command = new SQLiteCommand(query, _connection); foreach (var parameter in parameters) { @@ -622,12 +623,12 @@ public class SqlDatabase if (p is not null) command.Parameters.Add(p); } - + var reader = await command.ExecuteReaderAsync(); // if (!reader.HasRows) return null; - + List rows = new(); while (await reader.ReadAsync()) { @@ -638,4 +639,4 @@ public class SqlDatabase return rows; } -} \ No newline at end of file +} diff --git a/PluginManager/Interfaces/DBSlashCommand.cs b/PluginManager/Interfaces/DBSlashCommand.cs index eb2df8a..7cb1782 100644 --- a/PluginManager/Interfaces/DBSlashCommand.cs +++ b/PluginManager/Interfaces/DBSlashCommand.cs @@ -6,7 +6,7 @@ namespace PluginManager.Interfaces; public interface DBSlashCommand { - string Name { get; } + string Name { get; } string Description { get; } bool canUseDM { get; } diff --git a/PluginManager/Interfaces/Logger/ILog.cs b/PluginManager/Interfaces/Logger/ILog.cs index fd5a300..19c4b8a 100644 --- a/PluginManager/Interfaces/Logger/ILog.cs +++ b/PluginManager/Interfaces/Logger/ILog.cs @@ -5,11 +5,10 @@ namespace PluginManager.Interfaces.Logger; internal interface ILog { - string Message { get; set; } - string OutputFile { get; set; } - + string Message { get; set; } + Type? Source { get; set; } - LogType Type { get; set; } + LogType Type { get; set; } DateTime ThrowTime { get; set; } } diff --git a/PluginManager/Interfaces/Logger/ILogger.cs b/PluginManager/Interfaces/Logger/ILogger.cs index c513cc6..d45e527 100644 --- a/PluginManager/Interfaces/Logger/ILogger.cs +++ b/PluginManager/Interfaces/Logger/ILogger.cs @@ -7,11 +7,13 @@ namespace PluginManager.Interfaces.Logger; internal interface ILogger { - bool IsEnabled { get; init; } - bool OutputToFile { get; init; } + bool IsEnabled { get; init; } + bool OutputToFile { get; init; } + + string OutputFile { get; init; } event EventHandler OnLog; void Log( - string message = "", string outputFile = "", Type? source = default, LogType type = LogType.INFO, + string message = "", Type? source = default, LogType type = LogType.INFO, DateTime throwTime = default); } diff --git a/PluginManager/Loaders/Loader.cs b/PluginManager/Loaders/Loader.cs index fe3a716..946e5de 100644 --- a/PluginManager/Loaders/Loader.cs +++ b/PluginManager/Loaders/Loader.cs @@ -8,13 +8,13 @@ using PluginManager.Others; namespace PluginManager.Loaders; -internal class LoaderArgs : EventArgs +internal class LoaderArgs: EventArgs { - internal string? PluginName { get; init; } - internal string? TypeName { get; init; } - internal bool IsLoaded { get; init; } - internal Exception? Exception { get; init; } - internal object? Plugin { get; init; } + internal string? PluginName { get; init; } + internal string? TypeName { get; init; } + internal bool IsLoaded { get; init; } + internal Exception? Exception { get; init; } + internal object? Plugin { get; init; } } internal class Loader @@ -26,7 +26,7 @@ internal class Loader } - private string Path { get; } + private string Path { get; } private string Extension { get; } internal event FileLoadedEventHandler? FileLoaded; @@ -101,28 +101,29 @@ internal class Loader if (PluginLoaded != null) PluginLoaded.Invoke(new LoaderArgs - { - Exception = null, - IsLoaded = true, - PluginName = type.FullName, - TypeName = typeof(T) == typeof(DBCommand) ? "DBCommand" : - typeof(T) == typeof(DBEvent) ? "DBEvent" : - typeof(T) == typeof(DBSlashCommand) ? "DBSlashCommand" : - null, - Plugin = plugin - } - ); + { + Exception = null, + IsLoaded = true, + PluginName = type.FullName, + TypeName = typeof(T) == typeof(DBCommand) ? "DBCommand" : + typeof(T) == typeof(DBEvent) ? "DBEvent" : + typeof(T) == typeof(DBSlashCommand) ? "DBSlashCommand" : + null, + Plugin = plugin + } + ); } catch (Exception ex) { if (PluginLoaded != null) PluginLoaded.Invoke(new LoaderArgs - { - Exception = ex, - IsLoaded = false, - PluginName = type.FullName, - TypeName = nameof(T) - }); + { + Exception = ex, + IsLoaded = false, + PluginName = type.FullName, + TypeName = nameof(T) + } + ); } return list; diff --git a/PluginManager/Loaders/PluginLoader.cs b/PluginManager/Loaders/PluginLoader.cs index 409edb4..58e73ff 100644 --- a/PluginManager/Loaders/PluginLoader.cs +++ b/PluginManager/Loaders/PluginLoader.cs @@ -131,7 +131,8 @@ public class PluginLoader builder.Options = slash.Options; onSLSHLoad?.Invoke(((DBSlashCommand)args.Plugin!).Name, args.TypeName, args.IsLoaded, - args.Exception); + args.Exception + ); await _client.CreateGlobalApplicationCommandAsync(builder.Build()); } @@ -161,7 +162,7 @@ public class PluginLoader else if (type.IsClass && typeof(DBSlashCommand).IsAssignableFrom(type)) { var instance = (DBSlashCommand)Activator.CreateInstance(type); - var builder = new SlashCommandBuilder(); + var builder = new SlashCommandBuilder(); builder.WithName(instance.Name); builder.WithDescription(instance.Description); builder.WithDMPermission(instance.canUseDM); @@ -177,6 +178,6 @@ public class PluginLoader //Console.WriteLine(ex.Message); Config.Logger.Log(ex.Message, source: typeof(PluginLoader), type: LogType.ERROR); } - + } } diff --git a/PluginManager/Online/Helpers/OnlineFunctions.cs b/PluginManager/Online/Helpers/OnlineFunctions.cs index 03faa29..0762d14 100644 --- a/PluginManager/Online/Helpers/OnlineFunctions.cs +++ b/PluginManager/Online/Helpers/OnlineFunctions.cs @@ -19,10 +19,10 @@ internal static class OnlineFunctions /// The cancellation token /// internal static async Task DownloadFileAsync( - this HttpClient client, string url, Stream destination, - IProgress? progress = null, - IProgress? downloadedBytes = null, int bufferSize = 81920, - CancellationToken cancellation = default) + this HttpClient client, string url, Stream destination, + IProgress? progress = null, + IProgress? downloadedBytes = null, int bufferSize = 81920, + CancellationToken cancellation = default) { using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellation)) { @@ -35,7 +35,7 @@ internal static class OnlineFunctions if (progress == null || !contentLength.HasValue) { await download.CopyToAsync(destination, cancellation); - if(!contentLength.HasValue) + if (!contentLength.HasValue) progress?.Report(100f); return; } diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index 6737579..482b398 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -10,7 +10,7 @@ namespace PluginManager.Online; public class PluginsManager { - + #if DEBUG /// /// The Plugin Manager constructor @@ -22,16 +22,16 @@ public class PluginsManager PluginsLink = plink; VersionsLink = vlink; } - + #endif - + /// /// The Plugin Manager constructor. It uses the default links and the default branch. /// /// The main branch from where the plugin manager gets its info public PluginsManager(string? branch = "releases") { - PluginsLink = $"https://raw.githubusercontent.com/andreitdr/SethPlugins/{branch}/PluginsList"; + PluginsLink = $"https://raw.githubusercontent.com/andreitdr/SethPlugins/{branch}/PluginsList"; VersionsLink = $"https://raw.githubusercontent.com/andreitdr/SethPlugins/{branch}/Versions"; } @@ -95,7 +95,7 @@ public class PluginsManager } catch (Exception exception) { - Config.Logger.Log(message: "Failed to execute command: listplugs\nReason: " + exception.Message, source: typeof(PluginsManager), type: LogType.ERROR ); + Config.Logger.Log(message: "Failed to execute command: listplugs\nReason: " + exception.Message, source: typeof(PluginsManager), type: LogType.ERROR); } return null; @@ -135,16 +135,18 @@ public class PluginsManager for (var i = 0; i < len; i++) { var contents = lines[i].Split(','); - if(Functions.GetOperatingSystem() == OperatingSystem.WINDOWS && contents[4].Contains("Windows")) - {if (contents[0].ToLowerInvariant() == name.ToLowerInvariant()) + if (Functions.GetOperatingSystem() == OperatingSystem.WINDOWS && contents[4].Contains("Windows")) { - if (contents.Length == 6) - return new[] { contents[2], contents[3], contents[5] }; - if (contents.Length == 5) - return new[] { contents[2], contents[3], string.Empty }; - throw new Exception("Failed to download plugin. Invalid Argument Length"); + if (contents[0].ToLowerInvariant() == name.ToLowerInvariant()) + { + if (contents.Length == 6) + return new[] { contents[2], contents[3], contents[5] }; + if (contents.Length == 5) + return new[] { contents[2], contents[3], string.Empty }; + throw new Exception("Failed to download plugin. Invalid Argument Length"); + } } - }else if (Functions.GetOperatingSystem() == OperatingSystem.LINUX && contents[4].Contains("Linux")) + else if (Functions.GetOperatingSystem() == OperatingSystem.LINUX && contents[4].Contains("Linux")) { if (contents.Length == 6) return new[] { contents[2], contents[3], contents[5] }; diff --git a/PluginManager/Online/ServerCom.cs b/PluginManager/Online/ServerCom.cs index 25ccae4..340825b 100644 --- a/PluginManager/Online/ServerCom.cs +++ b/PluginManager/Online/ServerCom.cs @@ -30,7 +30,7 @@ public static class ServerCom /// The to track the download /// public static async Task DownloadFileAsync( - string URL, string location, IProgress progress, + string URL, string location, IProgress progress, IProgress? downloadedBytes) { using (var client = new HttpClient()) @@ -48,15 +48,15 @@ public static class ServerCom { await DownloadFileAsync(URl, location, progress, null); } - + public static Task CreateDownloadTask(string URl, string location) { return DownloadFileAsync(URl, location, null, null); } - + public static Task CreateDownloadTask(string URl, string location, IProgress progress) { return DownloadFileAsync(URl, location, progress, null); } - + } diff --git a/PluginManager/Others/Actions/InternalActionsManager.cs b/PluginManager/Others/Actions/InternalActionsManager.cs index 8b67091..8c8563b 100644 --- a/PluginManager/Others/Actions/InternalActionsManager.cs +++ b/PluginManager/Others/Actions/InternalActionsManager.cs @@ -26,7 +26,7 @@ public class InternalActionManager Actions.TryAdd(action.ActionName, action); } } - + public async Task Refresh() { Actions.Clear(); @@ -59,7 +59,7 @@ public class InternalActionManager } catch (Exception e) { - Config.Logger.Log(e.Message , type: LogType.ERROR, source: typeof(InternalActionManager)); + Config.Logger.Log(e.Message, type: LogType.ERROR, source: typeof(InternalActionManager)); return e.Message; } } diff --git a/PluginManager/Others/ArchiveManager.cs b/PluginManager/Others/ArchiveManager.cs index 24f9c64..d2affa9 100644 --- a/PluginManager/Others/ArchiveManager.cs +++ b/PluginManager/Others/ArchiveManager.cs @@ -37,24 +37,24 @@ public static class ArchiveManager if (!File.Exists(archName)) throw new Exception("Failed to load file !"); - + byte[]? data = null; - + using (var zip = ZipFile.OpenRead(archName)) { var entry = zip.Entries.FirstOrDefault(entry => entry.FullName == fileName || entry.Name == fileName); if (entry is null) throw new Exception("File not found in archive"); - + var MemoryStream = new MemoryStream(); - + var stream = entry.Open(); await stream.CopyToAsync(MemoryStream); data = MemoryStream.ToArray(); - + stream.Close(); MemoryStream.Close(); } - + return data; } @@ -117,7 +117,7 @@ public static class ArchiveManager { if (type == UnzipProgressType.PERCENTAGE_FROM_NUMBER_OF_FILES) { - var totalZIPFiles = archive.Entries.Count(); + var totalZIPFiles = archive.Entries.Count(); var currentZIPFile = 0; foreach (var entry in archive.Entries) { @@ -173,4 +173,4 @@ public static class ArchiveManager } } } -} \ No newline at end of file +} diff --git a/PluginManager/Others/DBCommandExecutingArguments.cs b/PluginManager/Others/DBCommandExecutingArguments.cs index 4b44a8f..bd8b5e6 100644 --- a/PluginManager/Others/DBCommandExecutingArguments.cs +++ b/PluginManager/Others/DBCommandExecutingArguments.cs @@ -29,19 +29,19 @@ public class DBCommandExecutingArguments { this.cleanContent = message.Content.Substring(Config.DiscordBot.botPrefix.Length); } - + var split = this.cleanContent.Split(' '); string[]? argsClean = null; if (split.Length > 1) argsClean = string.Join(' ', split, 1, split.Length - 1).Split(' '); - + this.commandUsed = split[0]; - this.arguments = argsClean; + this.arguments = argsClean; } - public SocketCommandContext context { get; init; } - public string cleanContent { get; init; } - public string commandUsed { get; init; } - public string[]? arguments { get; init; } + public SocketCommandContext context { get; init; } + public string cleanContent { get; init; } + public string commandUsed { get; init; } + public string[]? arguments { get; init; } } diff --git a/PluginManager/Others/Enums.cs b/PluginManager/Others/Enums.cs index ac601dc..4f080ad 100644 --- a/PluginManager/Others/Enums.cs +++ b/PluginManager/Others/Enums.cs @@ -40,8 +40,8 @@ public enum InternalActionRunType ON_CALL } -internal enum ExceptionExitCode : int +internal enum ExceptionExitCode: int { CONFIG_FAILED_TO_LOAD = 1, - CONFIG_KEY_NOT_FOUND = 2, + CONFIG_KEY_NOT_FOUND = 2, } diff --git a/PluginManager/Others/Functions.cs b/PluginManager/Others/Functions.cs index 64503b3..7c71576 100644 --- a/PluginManager/Others/Functions.cs +++ b/PluginManager/Others/Functions.cs @@ -54,8 +54,8 @@ public static class Functions /// Triggered if is not readable /// Triggered in is not writable public static async Task CopyToOtherStreamAsync( - this Stream stream, Stream destination, int bufferSize, - IProgress? progress = null, + this Stream stream, Stream destination, int bufferSize, + IProgress? progress = null, CancellationToken cancellationToken = default) { if (stream == null) throw new ArgumentNullException(nameof(stream)); @@ -76,7 +76,7 @@ public static class Functions progress?.Report(totalBytesRead); } } - + public static T SelectRandomValueOf() { diff --git a/PluginManager/Others/JsonManager.cs b/PluginManager/Others/JsonManager.cs index 1950346..11fc42b 100644 --- a/PluginManager/Others/JsonManager.cs +++ b/PluginManager/Others/JsonManager.cs @@ -38,10 +38,10 @@ public class JsonManager else text = new MemoryStream(Encoding.ASCII.GetBytes(input)); text.Position = 0; - + var obj = await JsonSerializer.DeserializeAsync(text); await text.FlushAsync(); text.Close(); return (obj ?? default)!; } -} \ No newline at end of file +} diff --git a/PluginManager/Others/Logger/Log.cs b/PluginManager/Others/Logger/Log.cs index 03e2921..1048004 100644 --- a/PluginManager/Others/Logger/Log.cs +++ b/PluginManager/Others/Logger/Log.cs @@ -4,60 +4,46 @@ using PluginManager.Interfaces.Logger; namespace PluginManager.Others.Logger; -public class Log : ILog +public class Log: ILog { - public string Message { get; set; } - public string OutputFile { get; set; } - public Type? Source { get; set; } - public LogType Type { get; set; } - public DateTime ThrowTime { get; set; } - - public Log(string message, string outputFile, Type? source, LogType type, DateTime throwTime) + public string Message { get; set; } + public Type? Source { get; set; } + public LogType Type { get; set; } + public DateTime ThrowTime { get; set; } + + public Log(string message, Type? source, LogType type, DateTime throwTime) { - Message = message; - OutputFile = outputFile; - Source = source; - Type = type; - ThrowTime = throwTime; + Message = message; + Source = source; + Type = type; + ThrowTime = throwTime; } - - public Log(string message, string outputFile, Type? source, LogType type) + + public Log(string message, Type? source, LogType type) { - Message = message; - OutputFile = outputFile; - Source = source; - Type = type; - ThrowTime = DateTime.Now; + Message = message; + Source = source; + Type = type; + ThrowTime = DateTime.Now; } - - public Log(string message, string outputFile, Type? source) + + public Log(string message, Type? source) { - Message = message; - OutputFile = outputFile; - Source = source; - Type = LogType.INFO; - ThrowTime = DateTime.Now; + Message = message; + Source = source; + Type = LogType.INFO; + ThrowTime = DateTime.Now; } - - public Log(string message, string outputFile) - { - Message = message; - OutputFile = outputFile; - Source = typeof(Log); - Type = LogType.INFO; - ThrowTime = DateTime.Now; - } - + public Log(string message) { - Message = message; - OutputFile = ""; - Source = typeof(Log); - Type = LogType.INFO; - ThrowTime = DateTime.Now; + Message = message; + Source = typeof(Log); + Type = LogType.INFO; + ThrowTime = DateTime.Now; } - - public static implicit operator Log(string message) => new (message); + + public static implicit operator Log(string message) => new(message); public static implicit operator string(Log log) => $"[{log.ThrowTime}] {log.Message}"; @@ -65,7 +51,7 @@ public class Log : ILog { return $"[{ThrowTime}] [{Source}] [{Type}] {Message}"; } - + public string AsShortString() { return this; diff --git a/PluginManager/Others/Logger/Logger.cs b/PluginManager/Others/Logger/Logger.cs index 33462f7..b4f543b 100644 --- a/PluginManager/Others/Logger/Logger.cs +++ b/PluginManager/Others/Logger/Logger.cs @@ -6,64 +6,72 @@ using PluginManager.Interfaces.Logger; namespace PluginManager.Others.Logger; -public sealed class Logger : ILogger +public sealed class Logger: ILogger { - public bool IsEnabled { get; init; } - public bool OutputToFile { get; init; } + public bool IsEnabled { get; init; } + public bool OutputToFile { get; init; } + public string? OutputFile { get; init; } - private LogType LowestLogLevel { get; } - private bool UseShortVersion { get; } - - public Logger(bool useShortVersion, bool outputToFile, LogType lowestLogLevel = LogType.INFO) + private LogType LowestLogLevel { get; } + private bool UseShortVersion { get; } + + public Logger(bool useShortVersion, bool outputToFile, string outputFile, LogType lowestLogLevel = LogType.INFO) { UseShortVersion = useShortVersion; OutputToFile = outputToFile; IsEnabled = true; LowestLogLevel = lowestLogLevel; + OutputFile = outputFile; + } + + public Logger(bool useShortVersion, LogType lowestLogLevel = LogType.INFO) + { + UseShortVersion = useShortVersion; + OutputToFile = false; + IsEnabled = true; + LowestLogLevel = lowestLogLevel; + OutputFile = null; } public event EventHandler? OnLog; - + private async Task Log(Log logMessage) { if (!IsEnabled) return; - + OnLog?.Invoke(this, logMessage); - + if (logMessage.Type < LowestLogLevel) return; if (OutputToFile) await File.AppendAllTextAsync( - logMessage.OutputFile, - (UseShortVersion ? logMessage : logMessage.AsLongString()) + "\n"); + OutputFile!, + (UseShortVersion ? logMessage : logMessage.AsLongString()) + "\n" + ); } - - public async void Log(string message = "", string outputFile = "", Type? source = default, LogType type = LogType.INFO, DateTime throwTime = default) + + public async void Log(string message = "", Type? source = default, LogType type = LogType.INFO, DateTime throwTime = default) { if (!IsEnabled) return; - + if (type < LowestLogLevel) return; if (string.IsNullOrEmpty(message)) return; - if (string.IsNullOrEmpty(outputFile)) outputFile = Config.AppSettings["LogFolder"] + "/" + DateTime.Now.ToString("yyyy-MM-dd") + ".log"; - - if(throwTime == default) throwTime = DateTime.Now; - + if (throwTime == default) throwTime = DateTime.Now; + if (source == default) source = typeof(Log); - - await Log(new Log(message, outputFile, source, type, throwTime)); - + + await Log(new Log(message, source, type, throwTime)); + } public async void Log(Exception exception, LogType logType = LogType.ERROR, Type? source = null) { if (!IsEnabled) return; - + if (logType < LowestLogLevel) return; - await Log(new Log(exception.Message, - Config.AppSettings["LogFolder"] + "/" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", - source, logType, DateTime.Now)); + await Log(new Log(exception.Message, source, logType, DateTime.Now)); } } diff --git a/PluginManager/Others/SettingsDictionary.cs b/PluginManager/Others/SettingsDictionary.cs index 23834de..e913c69 100644 --- a/PluginManager/Others/SettingsDictionary.cs +++ b/PluginManager/Others/SettingsDictionary.cs @@ -5,11 +5,11 @@ using System.Threading.Tasks; namespace PluginManager.Others; -public class SettingsDictionary : IDictionary +public class SettingsDictionary: IDictionary { public string? _file { get; } private IDictionary? _dictionary; - + public SettingsDictionary(string? file) { _file = file; @@ -19,7 +19,7 @@ public class SettingsDictionary : IDictionary SaveToFile(); } } - + public async Task SaveToFile() { if (!string.IsNullOrEmpty(_file)) @@ -36,8 +36,8 @@ public class SettingsDictionary : IDictionary string FileContent = File.ReadAllText(_file); if (string.IsNullOrEmpty(FileContent)) File.WriteAllText(_file, "{}"); - - if(!FileContent.Contains("{") || !FileContent.Contains("}")) + + if (!FileContent.Contains("{") || !FileContent.Contains("}")) File.WriteAllText(_file, "{}"); } else @@ -61,7 +61,7 @@ public class SettingsDictionary : IDictionary IEnumerator IEnumerable.GetEnumerator() { - return ((IEnumerable) _dictionary!).GetEnumerator(); + return ((IEnumerable)_dictionary!).GetEnumerator(); } public void Add(KeyValuePair item) @@ -89,7 +89,7 @@ public class SettingsDictionary : IDictionary return this._dictionary!.Remove(item); } - public int Count => _dictionary!.Count; + public int Count => _dictionary!.Count; public bool IsReadOnly => _dictionary!.IsReadOnly; public void Add(TKey key, TValue value) { @@ -116,9 +116,9 @@ public class SettingsDictionary : IDictionary get { if (this._dictionary!.ContainsKey(key)) - if(this._dictionary[key] is string s && !string.IsNullOrEmpty(s) && !string.IsNullOrWhiteSpace(s)) + if (this._dictionary[key] is string s && !string.IsNullOrEmpty(s) && !string.IsNullOrWhiteSpace(s)) return this._dictionary[key]; - + return default!; } set => this._dictionary![key] = value; @@ -126,4 +126,4 @@ public class SettingsDictionary : IDictionary public ICollection Keys => _dictionary!.Keys; public ICollection Values => _dictionary!.Values; -} \ No newline at end of file +} diff --git a/PluginManager/PluginManager.csproj b/PluginManager/PluginManager.csproj index bc8dbce..4ec873e 100644 --- a/PluginManager/PluginManager.csproj +++ b/PluginManager/PluginManager.csproj @@ -9,10 +9,10 @@ false - + - - + + \ No newline at end of file diff --git a/SethTests/SethTests.csproj b/SethTests/SethTests.csproj index f55c2d1..e2d19d2 100644 --- a/SethTests/SethTests.csproj +++ b/SethTests/SethTests.csproj @@ -22,12 +22,12 @@ - + - - + + From 2280957ea9ce5ec0ccd09ef3cc0e649d66a1bdae Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Tue, 21 Nov 2023 22:07:28 +0200 Subject: [PATCH 07/37] Fixed some warnings --- PluginManager/Others/ArchiveManager.cs | 142 ++++++++++++------------- 1 file changed, 68 insertions(+), 74 deletions(-) diff --git a/PluginManager/Others/ArchiveManager.cs b/PluginManager/Others/ArchiveManager.cs index d2affa9..bb2aefa 100644 --- a/PluginManager/Others/ArchiveManager.cs +++ b/PluginManager/Others/ArchiveManager.cs @@ -8,19 +8,20 @@ namespace PluginManager.Others; public static class ArchiveManager { - private static string? archiveFolder; - public static bool isInitialized { get; private set; } + private static string? _archiveFolder; + private static bool IsInitialized { get; set; } public static void Initialize() { - if (isInitialized) throw new Exception("ArchiveManager is already initialized"); + if (IsInitialized) + throw new Exception("ArchiveManager is already initialized"); if (!Config.AppSettings.ContainsKey("ArchiveFolder")) - Config.AppSettings["ArchiveFolder"] = "./Data/PAKS/"; + Config.AppSettings["ArchiveFolder"] = "./Data/Archives/"; - archiveFolder = Config.AppSettings["ArchiveFolder"]; + _archiveFolder = Config.AppSettings["ArchiveFolder"]; - isInitialized = true; + IsInitialized = true; } /// @@ -29,31 +30,26 @@ public static class ArchiveManager /// The file name in the archive /// The archive location on the disk /// An array of bytes that represents the Stream value from the file that was read inside the archive - public async static Task ReadStreamFromPakAsync(string fileName, string archName) + public static async Task ReadStreamFromPakAsync(string fileName, string archName) { - if (!isInitialized) throw new Exception("ArchiveManager is not initialized"); + if (!IsInitialized) throw new Exception("ArchiveManager is not initialized"); - archName = archiveFolder + archName; + archName = _archiveFolder + archName; if (!File.Exists(archName)) throw new Exception("Failed to load file !"); - byte[]? data = null; + using var zip = ZipFile.OpenRead(archName); + var entry = zip.Entries.FirstOrDefault(entry => entry.FullName == fileName || entry.Name == fileName); + if (entry is null) throw new Exception("File not found in archive"); - using (var zip = ZipFile.OpenRead(archName)) - { - var entry = zip.Entries.FirstOrDefault(entry => entry.FullName == fileName || entry.Name == fileName); - if (entry is null) throw new Exception("File not found in archive"); + await using var memoryStream = new MemoryStream(); + var stream = entry.Open(); + await stream.CopyToAsync(memoryStream); + var data = memoryStream.ToArray(); - var MemoryStream = new MemoryStream(); - - var stream = entry.Open(); - await stream.CopyToAsync(MemoryStream); - data = MemoryStream.ToArray(); - - stream.Close(); - MemoryStream.Close(); - } + stream.Close(); + memoryStream.Close(); return data; } @@ -61,13 +57,13 @@ public static class ArchiveManager /// /// Read data from a file that is inside an archive (ZIP format) /// - /// The file name that is inside the archive or its full path + /// The file name that is inside the archive or its full path /// The archive location from the PAKs folder /// A string that represents the content of the file or null if the file does not exists or it has no content - public static async Task ReadFromPakAsync(string FileName, string archFile) + public static async Task ReadFromPakAsync(string fileName, string archFile) { - if (!isInitialized) throw new Exception("ArchiveManager is not initialized"); - archFile = archiveFolder + archFile; + if (!IsInitialized) throw new Exception("ArchiveManager is not initialized"); + archFile = _archiveFolder + archFile; if (!File.Exists(archFile)) throw new Exception("Failed to load file !"); @@ -78,7 +74,7 @@ public static class ArchiveManager using (var zip = new ZipArchive(fs, ZipArchiveMode.Read)) { foreach (var entry in zip.Entries) - if (entry.Name == FileName || entry.FullName == FileName) + if (entry.Name == fileName || entry.FullName == fileName) using (var s = entry.Open()) using (var reader = new StreamReader(s)) { @@ -95,7 +91,7 @@ public static class ArchiveManager { Config.Logger.Log(message: ex.Message, source: typeof(ArchiveManager), type: LogType.ERROR); // Write the error to a file await Task.Delay(100); - return await ReadFromPakAsync(FileName, archFile); + return await ReadFromPakAsync(fileName, archFile); } } @@ -111,65 +107,63 @@ public static class ArchiveManager string zip, string folder, IProgress progress, UnzipProgressType type) { - if (!isInitialized) throw new Exception("ArchiveManager is not initialized"); + if (!IsInitialized) throw new Exception("ArchiveManager is not initialized"); Directory.CreateDirectory(folder); - using (var archive = ZipFile.OpenRead(zip)) + using var archive = ZipFile.OpenRead(zip); + var totalZipFiles = archive.Entries.Count(); + if (type == UnzipProgressType.PERCENTAGE_FROM_NUMBER_OF_FILES) { - if (type == UnzipProgressType.PERCENTAGE_FROM_NUMBER_OF_FILES) + var currentZipFile = 0; + foreach (var entry in archive.Entries) { - var totalZIPFiles = archive.Entries.Count(); - var currentZIPFile = 0; - foreach (var entry in archive.Entries) - { - if (entry.FullName.EndsWith("/")) // it is a folder - Directory.CreateDirectory(Path.Combine(folder, entry.FullName)); - - else - try - { - entry.ExtractToFile(Path.Combine(folder, entry.FullName), true); - } - catch (Exception ex) - { - Config.Logger.Log(ex.Message, source: typeof(ArchiveManager), type: LogType.ERROR); - } - - currentZIPFile++; - await Task.Delay(10); - if (progress != null) - progress.Report((float)currentZIPFile / totalZIPFiles * 100); - } - } - else if (type == UnzipProgressType.PERCENTAGE_FROM_TOTAL_SIZE) - { - ulong zipSize = 0; - - foreach (var entry in archive.Entries) - zipSize += (ulong)entry.CompressedLength; - - ulong currentSize = 0; - foreach (var entry in archive.Entries) - { - if (entry.FullName.EndsWith("/")) - { - Directory.CreateDirectory(Path.Combine(folder, entry.FullName)); - continue; - } + if (entry.FullName.EndsWith("/")) // it is a folder + Directory.CreateDirectory(Path.Combine(folder, entry.FullName)); + else try { entry.ExtractToFile(Path.Combine(folder, entry.FullName), true); - currentSize += (ulong)entry.CompressedLength; } catch (Exception ex) { Config.Logger.Log(ex.Message, source: typeof(ArchiveManager), type: LogType.ERROR); } - await Task.Delay(10); - if (progress != null) - progress.Report((float)currentSize / zipSize * 100); + currentZipFile++; + await Task.Delay(10); + if (progress != null) + progress.Report((float)currentZipFile / totalZipFiles * 100); + } + } + else if (type == UnzipProgressType.PERCENTAGE_FROM_TOTAL_SIZE) + { + ulong zipSize = 0; + + foreach (var entry in archive.Entries) + zipSize += (ulong)entry.CompressedLength; + + ulong currentSize = 0; + foreach (var entry in archive.Entries) + { + if (entry.FullName.EndsWith("/")) + { + Directory.CreateDirectory(Path.Combine(folder, entry.FullName)); + continue; } + + try + { + entry.ExtractToFile(Path.Combine(folder, entry.FullName), true); + currentSize += (ulong)entry.CompressedLength; + } + catch (Exception ex) + { + Config.Logger.Log(ex.Message, source: typeof(ArchiveManager), type: LogType.ERROR); + } + + await Task.Delay(10); + if (progress != null) + progress.Report((float)currentSize / zipSize * 100); } } } From fe32ebc4d7fd7d6acb131411d8a1632b50780f9d Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Sun, 17 Dec 2023 16:44:52 +0200 Subject: [PATCH 08/37] Fixed bug in linux version for downloading the first plugin only whatever the plugin name was --- DiscordBot/Bot/Actions/Plugin.cs | 3 ++- PluginManager/Online/PluginsManager.cs | 14 ++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/DiscordBot/Bot/Actions/Plugin.cs b/DiscordBot/Bot/Actions/Plugin.cs index 211158c..957ed83 100644 --- a/DiscordBot/Bot/Actions/Plugin.cs +++ b/DiscordBot/Bot/Actions/Plugin.cs @@ -38,7 +38,8 @@ public class Plugin: ICommandAction #if !DEBUG new PluginsManager(); #else - new PluginsManager("tests"); + // new PluginsManager("tests"); + new PluginsManager(); #endif switch (args[0]) diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index 482b398..74b763b 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -148,12 +148,14 @@ public class PluginsManager } else if (Functions.GetOperatingSystem() == OperatingSystem.LINUX && contents[4].Contains("Linux")) { - if (contents.Length == 6) - return new[] { contents[2], contents[3], contents[5] }; - if (contents.Length == 5) - return new[] { contents[2], contents[3], string.Empty }; - throw new Exception("Failed to download plugin. Invalid Argument Length"); - + if (contents[0].ToLowerInvariant() == name.ToLowerInvariant()) + { + if (contents.Length == 6) + return new[] { contents[2], contents[3], contents[5] }; + if (contents.Length == 5) + return new[] { contents[2], contents[3], string.Empty }; + throw new Exception("Failed to download plugin. Invalid Argument Length"); + } } } } From c8480b3c83119628b6f67a30568e42134bd5e4dc Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Sun, 17 Dec 2023 17:14:48 +0200 Subject: [PATCH 09/37] Added Channel to DBCommandExecutingArguments.cs --- DiscordBot/Bot/Actions/Plugin.cs | 4 +- PluginManager/Online/PluginsManager.cs | 52 +++++++++---------- .../Others/DBCommandExecutingArguments.cs | 1 + 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/DiscordBot/Bot/Actions/Plugin.cs b/DiscordBot/Bot/Actions/Plugin.cs index 957ed83..564a239 100644 --- a/DiscordBot/Bot/Actions/Plugin.cs +++ b/DiscordBot/Bot/Actions/Plugin.cs @@ -36,10 +36,10 @@ public class Plugin: ICommandAction PluginsManager manager = #if !DEBUG - new PluginsManager(); + new PluginsManager("releases"); #else // new PluginsManager("tests"); - new PluginsManager(); + new PluginsManager("releases"); #endif switch (args[0]) diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index 74b763b..8417b69 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -10,26 +10,11 @@ namespace PluginManager.Online; public class PluginsManager { - - #if DEBUG - /// - /// The Plugin Manager constructor - /// - /// The link to the file where all plugins are stored - /// The link to the file where all plugin versions are stored - public PluginsManager(string plink, string vlink) - { - PluginsLink = plink; - VersionsLink = vlink; - } - - #endif - /// /// The Plugin Manager constructor. It uses the default links and the default branch. /// /// The main branch from where the plugin manager gets its info - public PluginsManager(string? branch = "releases") + public PluginsManager(string? branch) { PluginsLink = $"https://raw.githubusercontent.com/andreitdr/SethPlugins/{branch}/PluginsList"; VersionsLink = $"https://raw.githubusercontent.com/andreitdr/SethPlugins/{branch}/Versions"; @@ -101,7 +86,7 @@ public class PluginsManager return null; } - public async Task GetVersionOfPackageFromWeb(string pakName) + private async Task GetVersionOfPackageFromWeb(string pakName) { var data = await ServerCom.ReadTextFromURL(VersionsLink); foreach (var item in data) @@ -135,28 +120,41 @@ public class PluginsManager for (var i = 0; i < len; i++) { var contents = lines[i].Split(','); - if (Functions.GetOperatingSystem() == OperatingSystem.WINDOWS && contents[4].Contains("Windows")) + if (contents[0].ToLowerInvariant() == name.ToLowerInvariant()) { - if (contents[0].ToLowerInvariant() == name.ToLowerInvariant()) + if (Functions.GetOperatingSystem() == OperatingSystem.WINDOWS && contents[4].Contains("Windows")) { if (contents.Length == 6) - return new[] { contents[2], contents[3], contents[5] }; + return new[] + { + contents[2], contents[3], contents[5] + }; if (contents.Length == 5) - return new[] { contents[2], contents[3], string.Empty }; + return new[] + { + contents[2], contents[3], string.Empty + }; throw new Exception("Failed to download plugin. Invalid Argument Length"); + } - } - else if (Functions.GetOperatingSystem() == OperatingSystem.LINUX && contents[4].Contains("Linux")) - { - if (contents[0].ToLowerInvariant() == name.ToLowerInvariant()) + + if (Functions.GetOperatingSystem() == OperatingSystem.LINUX && contents[4].Contains("Linux")) { if (contents.Length == 6) - return new[] { contents[2], contents[3], contents[5] }; + return new[] + { + contents[2], contents[3], contents[5] + }; if (contents.Length == 5) - return new[] { contents[2], contents[3], string.Empty }; + return new[] + { + contents[2], contents[3], string.Empty + }; throw new Exception("Failed to download plugin. Invalid Argument Length"); + } } + } } catch (Exception exception) diff --git a/PluginManager/Others/DBCommandExecutingArguments.cs b/PluginManager/Others/DBCommandExecutingArguments.cs index bd8b5e6..ee7da81 100644 --- a/PluginManager/Others/DBCommandExecutingArguments.cs +++ b/PluginManager/Others/DBCommandExecutingArguments.cs @@ -44,4 +44,5 @@ public class DBCommandExecutingArguments public string cleanContent { get; init; } public string commandUsed { get; init; } public string[]? arguments { get; init; } + public ISocketMessageChannel Channel => context.Channel; } From af90ae5fbaeeeda25dc2b96f5692dbeb53fc5604 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Wed, 27 Dec 2023 18:03:26 +0200 Subject: [PATCH 10/37] Added UI support for LINUX KDE Plasma --- DiscordBot/DiscordBot.csproj | 2 +- DiscordBot/Entry.cs | 4 ++ DiscordBot/Installer.cs | 33 +++++++------ DiscordBot/Program.cs | 15 +++--- PluginManager/Bot/Boot.cs | 2 + PluginManager/Config.cs | 21 ++++++++- PluginManager/PluginManager.csproj | 11 ++++- PluginManager/UX/IOutputModel.cs | 29 ++++++++++++ PluginManager/UX/Linux/KDE.cs | 75 ++++++++++++++++++++++++++++++ PluginManager/UX/Other/Console.cs | 51 ++++++++++++++++++++ PluginManager/UX/UxHandler.cs | 42 +++++++++++++++++ 11 files changed, 259 insertions(+), 26 deletions(-) create mode 100644 PluginManager/UX/IOutputModel.cs create mode 100644 PluginManager/UX/Linux/KDE.cs create mode 100644 PluginManager/UX/Other/Console.cs create mode 100644 PluginManager/UX/UxHandler.cs diff --git a/DiscordBot/DiscordBot.csproj b/DiscordBot/DiscordBot.csproj index 3ae8395..868d4d2 100644 --- a/DiscordBot/DiscordBot.csproj +++ b/DiscordBot/DiscordBot.csproj @@ -1,7 +1,7 @@ Exe - net6.0 + net8.0 disable diff --git a/DiscordBot/Entry.cs b/DiscordBot/Entry.cs index eb61106..b9251b1 100644 --- a/DiscordBot/Entry.cs +++ b/DiscordBot/Entry.cs @@ -1,6 +1,10 @@ using System; using System.IO; using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using PluginManager.UX; + namespace DiscordBot; diff --git a/DiscordBot/Installer.cs b/DiscordBot/Installer.cs index e310590..571469e 100644 --- a/DiscordBot/Installer.cs +++ b/DiscordBot/Installer.cs @@ -1,28 +1,33 @@ +using System; using PluginManager; using Spectre.Console; +using System.Threading.Tasks; + namespace DiscordBot; public static class Installer { - public static void GenerateStartupConfig() + public static async Task GenerateStartupConfig() { - AnsiConsole.MarkupLine("Welcome to the [bold]SethBot[/] installer !"); - AnsiConsole.MarkupLine("First, we need to configure the bot. Don't worry, it will be quick !"); - - var token = AnsiConsole.Ask("Please enter the bot [yellow]token[/]:"); - var prefix = AnsiConsole.Ask("Please enter the bot [yellow]prefix[/]:"); - var serverId = AnsiConsole.Ask("Please enter the [yellow]Server ID[/]:"); - + string token = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the bot token:"); + string botPrefix = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the bot prefix:"); + string serverId = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the Server ID:"); + if (string.IsNullOrWhiteSpace(serverId)) serverId = "NULL"; + + if (string.IsNullOrWhiteSpace(token) || string.IsNullOrWhiteSpace(botPrefix)) + { + await PluginManager.UX.UxHandler.ShowMessageBox("SethBot", "Invalid token or prefix !", PluginManager.UX.MessageBoxType.Error); + Environment.Exit(-20); + } + Config.AppSettings.Add("token", token); - Config.AppSettings.Add("prefix", prefix); + Config.AppSettings.Add("prefix", botPrefix); Config.AppSettings.Add("ServerID", serverId); - - Config.AppSettings.SaveToFile(); - - AnsiConsole.MarkupLine("[bold]Config saved ![/]"); - + + await Config.AppSettings.SaveToFile(); + Config.Logger.Log("Config Saved", source: typeof(Installer)); } } diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 42f3437..48e0183 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; @@ -7,6 +8,7 @@ using DiscordBot.Utilities; using PluginManager.Bot; using PluginManager.Others; using PluginManager.Others.Actions; +using PluginManager.UX; using Spectre.Console; using static PluginManager.Config; @@ -24,7 +26,7 @@ public class Program PreLoadComponents(args).Wait(); if (!AppSettings.ContainsKey("ServerID") || !AppSettings.ContainsKey("token") || !AppSettings.ContainsKey("prefix")) - Installer.GenerateStartupConfig(); + Installer.GenerateStartupConfig().Wait(); HandleInput().Wait(); } @@ -87,7 +89,6 @@ public class Program /// /// Handle user input arguments from the startup of the application /// - /// The arguments private static async Task HandleInput() { await StartNoGui(); @@ -100,12 +101,10 @@ public class Program { if (ex.Message == "No process is on the other end of the pipe." || (uint)ex.HResult == 0x800700E9) { - if (AppSettings.ContainsKey("LaunchMessage")) - AppSettings.Add("LaunchMessage", - "An error occured while closing the bot last time. Please consider closing the bot using the &rexit&c method !\n" + - "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !" - ); - + UxHandler.ShowMessageBox("SethBot", "An error occured while closing the bot last time. Please consider closing the bot using the &rexit&c method !\n" + + "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !", MessageBoxType.Error).Wait(); + + Logger.Log("An error occured while closing the bot last time. Please consider closing the bot using the &rexit&c method !\n" + "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !", source: typeof(Program), type: LogType.ERROR diff --git a/PluginManager/Bot/Boot.cs b/PluginManager/Bot/Boot.cs index 5ac16a3..b85ec98 100644 --- a/PluginManager/Bot/Boot.cs +++ b/PluginManager/Bot/Boot.cs @@ -4,6 +4,7 @@ using Discord; using Discord.Commands; using Discord.WebSocket; using PluginManager.Others; +using PluginManager.UX; namespace PluginManager.Bot; @@ -121,6 +122,7 @@ public class Boot private Task Ready() { isReady = true; + UxHandler.ShowNotification("SethBot", "Seth Discord Bot is now up and running !").Wait(); return Task.CompletedTask; } diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index 2b32f52..b23daa5 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -1,9 +1,11 @@ using System; using System.IO; using System.Threading.Tasks; +using Avalonia.Controls.Notifications; using PluginManager.Bot; using PluginManager.Others; using PluginManager.Others.Logger; +using OperatingSystem = System.OperatingSystem; namespace PluginManager; @@ -30,15 +32,30 @@ public class Config AppSettings["LogFolder"] = "./Data/Logs"; + if (OperatingSystem.IsLinux()) + { + var windowManager = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP"); + AppSettings["UI"] = windowManager switch + { + "KDE" => "KDE", + "GNOME" => "GNOME", + _ => "CONSOLE" + }; + } else AppSettings["UI"] = "CONSOLE"; + Logger = new Logger(false, true, AppSettings["LogFolder"] + $"/{DateTime.Today.ToShortDateString().Replace("/", "")}.log" ); ArchiveManager.Initialize(); - + + UX.UxHandler.Init(); _isLoaded = true; - + + Logger.Log(message: "Config initialized", source: typeof(Config)); + + } } diff --git a/PluginManager/PluginManager.csproj b/PluginManager/PluginManager.csproj index 4ec873e..f61b9f8 100644 --- a/PluginManager/PluginManager.csproj +++ b/PluginManager/PluginManager.csproj @@ -1,6 +1,6 @@ - net6.0 + net8.0 enable @@ -12,7 +12,16 @@ + + + + + + + ..\..\..\.nuget\packages\spectre.console\0.47.0\lib\net7.0\Spectre.Console.dll + + \ No newline at end of file diff --git a/PluginManager/UX/IOutputModel.cs b/PluginManager/UX/IOutputModel.cs new file mode 100644 index 0000000..fdd9387 --- /dev/null +++ b/PluginManager/UX/IOutputModel.cs @@ -0,0 +1,29 @@ +using System.Threading.Tasks; + +namespace PluginManager.UX; + +public enum MessageBoxType +{ + Info, + Warning, + Error +} + +public enum MessageBoxButtons +{ + YesNo, + YesNoCancel, + ContinueCancel, +} + +internal interface IOutputModel +{ + + internal Task ShowMessageBox(string title, string message, MessageBoxType type); + internal Task ShowInputBox(string title, string message); + + internal Task ShowMessageBox(string message); + internal Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning); + + internal Task ShowNotification(string title, string message, int timeout_seconds = 5); +} diff --git a/PluginManager/UX/Linux/KDE.cs b/PluginManager/UX/Linux/KDE.cs new file mode 100644 index 0000000..3d3673e --- /dev/null +++ b/PluginManager/UX/Linux/KDE.cs @@ -0,0 +1,75 @@ +using System.Diagnostics; +using System.Threading.Tasks; + +namespace PluginManager.UX.Linux; + +internal class KDE : IOutputModel +{ + + public async Task ShowMessageBox(string title, string message, MessageBoxType type) + { + var process = new Process(); + process.StartInfo.FileName = "kdialog"; + + string typeStr = type switch + { + MessageBoxType.Info => "msgbox", + MessageBoxType.Warning => "sorry", + MessageBoxType.Error => "error", + _ => "info" + }; + + process.StartInfo.Arguments = $"--title \"{title}\" --{typeStr} \"{message}\""; + process.Start(); + await process.WaitForExitAsync(); + } + + public async Task ShowInputBox(string title, string message) + { + var process = new Process(); + process.StartInfo.FileName = "kdialog"; + process.StartInfo.Arguments = $"--title \"{title}\" --inputbox \"{message}\""; + process.StartInfo.RedirectStandardOutput = true; + process.Start(); + + await process.WaitForExitAsync(); + return await process.StandardOutput.ReadToEndAsync(); + } + + public async Task ShowMessageBox(string message) + { + var process = new Process(); + process.StartInfo.FileName = "kdialog"; + process.StartInfo.Arguments = $"--msgbox \"{message}\""; + process.Start(); + await process.WaitForExitAsync(); + } + + public async Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning) + { + var process = new Process(); + process.StartInfo.FileName = "kdialog"; + + string buttonsStr = buttons switch + { + MessageBoxButtons.YesNo => "yesno", + MessageBoxButtons.YesNoCancel => "yesnocancel", + MessageBoxButtons.ContinueCancel => "continuecancel", + _ => "yesno" + }; + string typeStr = isWarning ? "warning" : ""; + process.StartInfo.Arguments = $"--title \"{title}\" --{typeStr}{buttonsStr} \"{message}\""; + process.Start(); + await process.WaitForExitAsync(); + return process.ExitCode; + } + + public async Task ShowNotification(string title, string message, int timeout_seconds = 5) + { + var process = new Process(); + process.StartInfo.FileName = "kdialog"; + process.StartInfo.Arguments = $"--title \"{title}\" --passivepopup \"{message}\" {timeout_seconds}"; + process.Start(); + await process.WaitForExitAsync(); + } +} diff --git a/PluginManager/UX/Other/Console.cs b/PluginManager/UX/Other/Console.cs new file mode 100644 index 0000000..94132e0 --- /dev/null +++ b/PluginManager/UX/Other/Console.cs @@ -0,0 +1,51 @@ + +using System.Threading.Tasks; +using Spectre.Console; + +namespace PluginManager.UX.Other; + + +internal class Console : IOutputModel +{ + + public Task ShowMessageBox(string title, string message, MessageBoxType type) + { + AnsiConsole.Markup(title); + AnsiConsole.Markup(message); + + + return Task.CompletedTask; + } + + public Task ShowInputBox(string title, string message) + { + AnsiConsole.Markup(title); + AnsiConsole.Markup(message); + + string input = AnsiConsole.Ask("Please enter the value:"); + + return Task.FromResult(input); + } + + public Task ShowMessageBox(string message) + { + AnsiConsole.Markup(message); + return Task.CompletedTask; + } + + public Task ShowMessageBox(string title, string message,MessageBoxButtons buttons, bool isWarning) + { + AnsiConsole.Markup(title); + AnsiConsole.Markup(message); + + return Task.FromResult(0); + } + + public Task ShowNotification(string title, string message, int timeout_seconds = 5) + { + AnsiConsole.Markup(title); + AnsiConsole.Markup(message); + + return Task.CompletedTask; + } +} diff --git a/PluginManager/UX/UxHandler.cs b/PluginManager/UX/UxHandler.cs new file mode 100644 index 0000000..d127cf0 --- /dev/null +++ b/PluginManager/UX/UxHandler.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; + +namespace PluginManager.UX; + +public static class UxHandler +{ + private static IOutputModel _model; + + public static void Init() + { + if (Config.AppSettings["UI"] == "KDE") + _model = new Linux.KDE(); + else + _model = new Other.Console(); + } + + public static async Task ShowMessageBox(string title, string message, MessageBoxType type = MessageBoxType.Info) + { + await _model.ShowMessageBox(title, message, type); + } + + public static async Task ShowInputBox(string title, string message) + { + return await _model.ShowInputBox(title, message); + } + + public static async Task ShowMessageBox(string message) + { + await _model.ShowMessageBox(message); + } + + public static async Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning) + { + return await _model.ShowMessageBox(title, message, buttons, isWarning); + } + + public static async Task ShowNotification(string title, string message, int timeout_seconds = 5) + { + await _model.ShowNotification(title, message, timeout_seconds); + } + +} From cc355d7d4f9c401f8c5fae9864e74ac54c34d082 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Wed, 27 Dec 2023 18:24:32 +0200 Subject: [PATCH 11/37] Fixed some names --- PluginManager/Bot/CommandHandler.cs | 34 ++++++++++++++--------------- PluginManager/UX/UxHandler.cs | 11 ++++++---- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/PluginManager/Bot/CommandHandler.cs b/PluginManager/Bot/CommandHandler.cs index 1a8b098..6c3fc72 100644 --- a/PluginManager/Bot/CommandHandler.cs +++ b/PluginManager/Bot/CommandHandler.cs @@ -13,9 +13,9 @@ namespace PluginManager.Bot; internal class CommandHandler { - private readonly string botPrefix; - private readonly DiscordSocketClient client; - private readonly CommandService commandService; + private readonly string _botPrefix; + private readonly DiscordSocketClient _client; + private readonly CommandService _commandService; /// /// Command handler constructor @@ -25,9 +25,9 @@ internal class CommandHandler /// The prefix to watch for public CommandHandler(DiscordSocketClient client, CommandService commandService, string botPrefix) { - this.client = client; - this.commandService = commandService; - this.botPrefix = botPrefix; + this._client = client; + this._commandService = commandService; + this._botPrefix = botPrefix; } /// @@ -36,9 +36,9 @@ internal class CommandHandler /// public async Task InstallCommandsAsync() { - client.MessageReceived += MessageHandler; - client.SlashCommandExecuted += Client_SlashCommandExecuted; - await commandService.AddModulesAsync(Assembly.GetEntryAssembly(), null); + _client.MessageReceived += MessageHandler; + _client.SlashCommandExecuted += Client_SlashCommandExecuted; + await _commandService.AddModulesAsync(Assembly.GetEntryAssembly(), null); } private Task Client_SlashCommandExecuted(SocketSlashCommand arg) @@ -85,19 +85,19 @@ internal class CommandHandler var argPos = 0; - if (!message.Content.StartsWith(botPrefix) && !message.HasMentionPrefix(client.CurrentUser, ref argPos)) + if (!message.Content.StartsWith(_botPrefix) && !message.HasMentionPrefix(_client.CurrentUser, ref argPos)) return; - var context = new SocketCommandContext(client, message); + var context = new SocketCommandContext(_client, message); - await commandService.ExecuteAsync(context, argPos, null); + await _commandService.ExecuteAsync(context, argPos, null); DBCommand? plugin; var cleanMessage = ""; - if (message.HasMentionPrefix(client.CurrentUser, ref argPos)) + if (message.HasMentionPrefix(_client.CurrentUser, ref argPos)) { - var mentionPrefix = "<@" + client.CurrentUser.Id + ">"; + var mentionPrefix = "<@" + _client.CurrentUser.Id + ">"; plugin = PluginLoader.Commands! .FirstOrDefault(plug => plug.Command == @@ -119,14 +119,14 @@ internal class CommandHandler { plugin = PluginLoader.Commands! .FirstOrDefault(p => p.Command == - message.Content.Split(' ')[0].Substring(botPrefix.Length) || + message.Content.Split(' ')[0].Substring(_botPrefix.Length) || (p.Aliases is not null && p.Aliases.Contains( message.Content.Split(' ')[0] - .Substring(botPrefix.Length) + .Substring(_botPrefix.Length) )) ); - cleanMessage = message.Content.Substring(botPrefix.Length); + cleanMessage = message.Content.Substring(_botPrefix.Length); } if (plugin is null) diff --git a/PluginManager/UX/UxHandler.cs b/PluginManager/UX/UxHandler.cs index d127cf0..40bc254 100644 --- a/PluginManager/UX/UxHandler.cs +++ b/PluginManager/UX/UxHandler.cs @@ -8,10 +8,13 @@ public static class UxHandler public static void Init() { - if (Config.AppSettings["UI"] == "KDE") - _model = new Linux.KDE(); - else - _model = new Other.Console(); + _model = Config.AppSettings["UI"] switch + { + "KDE" => new Linux.KDE(), + "Console" => new Other.Console(), + _ => _model + }; + } public static async Task ShowMessageBox(string title, string message, MessageBoxType type = MessageBoxType.Info) From 196fb6d3d1c01161a75ae5cfae539c459a3404a1 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Sat, 24 Feb 2024 23:22:02 +0200 Subject: [PATCH 12/37] Code formatting and renamed DBCommandExecutingArguments to DbCommandExecutingArguments --- DiscordBot/Bot/Actions/Extra/PluginMethods.cs | 4 +- .../Bot/Commands/NormalCommands/Help.cs | 2 +- DiscordBot/Program.cs | 2 +- PluginManager/Bot/CommandHandler.cs | 2 +- PluginManager/Config.cs | 1 - PluginManager/Interfaces/DBCommand.cs | 4 +- .../{IInternalAction.cs => ICommandAction.cs} | 0 PluginManager/Online/PluginsManager.cs | 12 ++--- .../Others/DBCommandExecutingArguments.cs | 11 ++--- PluginManager/Others/Enums.cs | 17 ------- PluginManager/Others/Functions.cs | 12 ----- PluginManager/PluginManager.csproj | 1 + PluginManager/UX/Linux/KDE.cs | 12 +++-- PluginManager/UX/Other/Console.cs | 14 ++---- PluginManager/UX/UxHandler.cs | 6 +-- SethDiscordBot.sln | 6 --- .../PluginManagerTests/AppSettingsTests.cs | 46 ------------------- SethTests/SethTests.csproj | 33 ------------- SethTests/Usings.cs | 1 - 19 files changed, 31 insertions(+), 155 deletions(-) rename PluginManager/Interfaces/{IInternalAction.cs => ICommandAction.cs} (100%) delete mode 100644 SethTests/PluginManagerTests/AppSettingsTests.cs delete mode 100644 SethTests/SethTests.csproj delete mode 100644 SethTests/Usings.cs diff --git a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs index 89da9fe..58be800 100644 --- a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs +++ b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs @@ -151,9 +151,7 @@ internal static class PluginMethods } ); - - - + await RefreshPlugins(false); } diff --git a/DiscordBot/Bot/Commands/NormalCommands/Help.cs b/DiscordBot/Bot/Commands/NormalCommands/Help.cs index 8387dc5..c45d2a0 100644 --- a/DiscordBot/Bot/Commands/NormalCommands/Help.cs +++ b/DiscordBot/Bot/Commands/NormalCommands/Help.cs @@ -38,7 +38,7 @@ internal class Help: DBCommand /// The main body of the command /// /// The command context - public void ExecuteServer(DBCommandExecutingArguments args) + public void ExecuteServer(DbCommandExecutingArguments args) { if (args.arguments is not null) { diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 48e0183..62a20bd 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -69,7 +69,7 @@ public class Program ConsoleUtilities.WriteColorText("&rRemember to close the bot using the ShutDown command (&yexit&r) or some settings won't be saved"); - ConsoleUtilities.WriteColorText($"Running on &m{Functions.GetOperatingSystem()}"); + ConsoleUtilities.WriteColorText($"Running on &m{(System.OperatingSystem.IsWindows() ? "Windows" : "Linux")}"); Console.WriteLine("============================ LOG ============================"); Console.ForegroundColor = ConsoleColor.White; diff --git a/PluginManager/Bot/CommandHandler.cs b/PluginManager/Bot/CommandHandler.cs index 6c3fc72..5fc4256 100644 --- a/PluginManager/Bot/CommandHandler.cs +++ b/PluginManager/Bot/CommandHandler.cs @@ -141,7 +141,7 @@ internal class CommandHandler if (split.Length > 1) argsClean = string.Join(' ', split, 1, split.Length - 1).Split(' '); - DBCommandExecutingArguments cmd = new(context, cleanMessage, split[0], argsClean); + DbCommandExecutingArguments cmd = new(context, cleanMessage, split[0], argsClean); Config.Logger.Log( message: $"User ({context.User.Username}) from Guild \"{context.Guild.Name}\" executed command \"{cmd.cleanContent}\"", diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index b23daa5..5a0d398 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Threading.Tasks; -using Avalonia.Controls.Notifications; using PluginManager.Bot; using PluginManager.Others; using PluginManager.Others.Logger; diff --git a/PluginManager/Interfaces/DBCommand.cs b/PluginManager/Interfaces/DBCommand.cs index 251f103..e25fe15 100644 --- a/PluginManager/Interfaces/DBCommand.cs +++ b/PluginManager/Interfaces/DBCommand.cs @@ -36,7 +36,7 @@ public interface DBCommand /// The main body of the command. This is what is executed when user calls the command in Server /// /// The disocrd Context - void ExecuteServer(DBCommandExecutingArguments args) + void ExecuteServer(DbCommandExecutingArguments args) { } @@ -44,7 +44,7 @@ public interface DBCommand /// The main body of the command. This is what is executed when user calls the command in DM /// /// The disocrd Context - void ExecuteDM(DBCommandExecutingArguments args) + void ExecuteDM(DbCommandExecutingArguments args) { } } diff --git a/PluginManager/Interfaces/IInternalAction.cs b/PluginManager/Interfaces/ICommandAction.cs similarity index 100% rename from PluginManager/Interfaces/IInternalAction.cs rename to PluginManager/Interfaces/ICommandAction.cs diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index 8417b69..285762d 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -1,11 +1,8 @@ using System; using System.Collections.Generic; -using System.Data.Common; using System.Threading.Tasks; using PluginManager.Online.Helpers; using PluginManager.Others; -using OperatingSystem = PluginManager.Others.OperatingSystem; - namespace PluginManager.Online; public class PluginsManager @@ -40,7 +37,6 @@ public class PluginsManager var lines = list.ToArray(); var data = new List(); - var op = Functions.GetOperatingSystem(); var len = lines.Length; for (var i = 0; i < len; i++) @@ -49,7 +45,7 @@ public class PluginsManager continue; var content = lines[i].Split(','); var display = new string[4]; // 4 columns - if (op == OperatingSystem.WINDOWS) + if (System.OperatingSystem.IsWindows()) { if (content[4].Contains("Windows")) { @@ -62,7 +58,7 @@ public class PluginsManager data.Add(display); } } - else if (op == OperatingSystem.LINUX) + else if (System.OperatingSystem.IsLinux()) { if (content[4].Contains("Linux")) { @@ -122,7 +118,7 @@ public class PluginsManager var contents = lines[i].Split(','); if (contents[0].ToLowerInvariant() == name.ToLowerInvariant()) { - if (Functions.GetOperatingSystem() == OperatingSystem.WINDOWS && contents[4].Contains("Windows")) + if (System.OperatingSystem.IsWindows() && contents[4].Contains("Windows")) { if (contents.Length == 6) return new[] @@ -138,7 +134,7 @@ public class PluginsManager } - if (Functions.GetOperatingSystem() == OperatingSystem.LINUX && contents[4].Contains("Linux")) + if (System.OperatingSystem.IsLinux() && contents[4].Contains("Linux")) { if (contents.Length == 6) return new[] diff --git a/PluginManager/Others/DBCommandExecutingArguments.cs b/PluginManager/Others/DBCommandExecutingArguments.cs index ee7da81..7ce0c81 100644 --- a/PluginManager/Others/DBCommandExecutingArguments.cs +++ b/PluginManager/Others/DBCommandExecutingArguments.cs @@ -1,13 +1,12 @@ -using System.Linq; -using Discord.Commands; +using Discord.Commands; using Discord.WebSocket; -using PluginManager.Bot; + namespace PluginManager.Others; -public class DBCommandExecutingArguments +public class DbCommandExecutingArguments { - public DBCommandExecutingArguments( + public DbCommandExecutingArguments( SocketCommandContext context, string cleanContent, string commandUsed, string[]? arguments) { this.context = context; @@ -16,7 +15,7 @@ public class DBCommandExecutingArguments this.arguments = arguments; } - public DBCommandExecutingArguments(SocketUserMessage? message, DiscordSocketClient client) + public DbCommandExecutingArguments(SocketUserMessage? message, DiscordSocketClient client) { this.context = new SocketCommandContext(client, message); int pos = 0; diff --git a/PluginManager/Others/Enums.cs b/PluginManager/Others/Enums.cs index 4f080ad..53a156a 100644 --- a/PluginManager/Others/Enums.cs +++ b/PluginManager/Others/Enums.cs @@ -1,16 +1,5 @@ namespace PluginManager.Others; -/// -/// A list of operating systems -/// -public enum OperatingSystem -{ - WINDOWS, - LINUX, - MAC_OS, - UNKNOWN -} - /// /// The output log type /// @@ -39,9 +28,3 @@ public enum InternalActionRunType ON_STARTUP, ON_CALL } - -internal enum ExceptionExitCode: int -{ - CONFIG_FAILED_TO_LOAD = 1, - CONFIG_KEY_NOT_FOUND = 2, -} diff --git a/PluginManager/Others/Functions.cs b/PluginManager/Others/Functions.cs index 7c71576..6ea23ae 100644 --- a/PluginManager/Others/Functions.cs +++ b/PluginManager/Others/Functions.cs @@ -29,18 +29,6 @@ public static class Functions } } - /// - /// Get the Operating system you are runnin on - /// - /// An Operating system - public static OperatingSystem GetOperatingSystem() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return OperatingSystem.WINDOWS; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return OperatingSystem.LINUX; - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return OperatingSystem.MAC_OS; - return OperatingSystem.UNKNOWN; - } - /// /// Copy one Stream to another /// diff --git a/PluginManager/PluginManager.csproj b/PluginManager/PluginManager.csproj index f61b9f8..1342f6a 100644 --- a/PluginManager/PluginManager.csproj +++ b/PluginManager/PluginManager.csproj @@ -14,6 +14,7 @@ + diff --git a/PluginManager/UX/Linux/KDE.cs b/PluginManager/UX/Linux/KDE.cs index 3d3673e..50ebd00 100644 --- a/PluginManager/UX/Linux/KDE.cs +++ b/PluginManager/UX/Linux/KDE.cs @@ -5,11 +5,12 @@ namespace PluginManager.UX.Linux; internal class KDE : IOutputModel { + internal string KdeDialogApplication { get; } = "kdialog"; public async Task ShowMessageBox(string title, string message, MessageBoxType type) { var process = new Process(); - process.StartInfo.FileName = "kdialog"; + process.StartInfo.FileName = KdeDialogApplication; string typeStr = type switch { @@ -27,9 +28,10 @@ internal class KDE : IOutputModel public async Task ShowInputBox(string title, string message) { var process = new Process(); - process.StartInfo.FileName = "kdialog"; + process.StartInfo.FileName = KdeDialogApplication; process.StartInfo.Arguments = $"--title \"{title}\" --inputbox \"{message}\""; process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardInput = true; process.Start(); await process.WaitForExitAsync(); @@ -39,7 +41,7 @@ internal class KDE : IOutputModel public async Task ShowMessageBox(string message) { var process = new Process(); - process.StartInfo.FileName = "kdialog"; + process.StartInfo.FileName = KdeDialogApplication; process.StartInfo.Arguments = $"--msgbox \"{message}\""; process.Start(); await process.WaitForExitAsync(); @@ -48,7 +50,7 @@ internal class KDE : IOutputModel public async Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning) { var process = new Process(); - process.StartInfo.FileName = "kdialog"; + process.StartInfo.FileName = KdeDialogApplication; string buttonsStr = buttons switch { @@ -67,7 +69,7 @@ internal class KDE : IOutputModel public async Task ShowNotification(string title, string message, int timeout_seconds = 5) { var process = new Process(); - process.StartInfo.FileName = "kdialog"; + process.StartInfo.FileName = KdeDialogApplication; process.StartInfo.Arguments = $"--title \"{title}\" --passivepopup \"{message}\" {timeout_seconds}"; process.Start(); await process.WaitForExitAsync(); diff --git a/PluginManager/UX/Other/Console.cs b/PluginManager/UX/Other/Console.cs index 94132e0..803b1cd 100644 --- a/PluginManager/UX/Other/Console.cs +++ b/PluginManager/UX/Other/Console.cs @@ -19,33 +19,29 @@ internal class Console : IOutputModel public Task ShowInputBox(string title, string message) { - AnsiConsole.Markup(title); - AnsiConsole.Markup(message); + AnsiConsole.MarkupLine(title); - string input = AnsiConsole.Ask("Please enter the value:"); + string input = AnsiConsole.Ask(message); return Task.FromResult(input); } public Task ShowMessageBox(string message) { - AnsiConsole.Markup(message); + AnsiConsole.MarkupLine(message); return Task.CompletedTask; } public Task ShowMessageBox(string title, string message,MessageBoxButtons buttons, bool isWarning) { - AnsiConsole.Markup(title); - AnsiConsole.Markup(message); + AnsiConsole.MarkupLine(title); + AnsiConsole.MarkupLine(message); return Task.FromResult(0); } public Task ShowNotification(string title, string message, int timeout_seconds = 5) { - AnsiConsole.Markup(title); - AnsiConsole.Markup(message); - return Task.CompletedTask; } } diff --git a/PluginManager/UX/UxHandler.cs b/PluginManager/UX/UxHandler.cs index 40bc254..76830ed 100644 --- a/PluginManager/UX/UxHandler.cs +++ b/PluginManager/UX/UxHandler.cs @@ -4,15 +4,15 @@ namespace PluginManager.UX; public static class UxHandler { - private static IOutputModel _model; + private static IOutputModel? _model; public static void Init() { _model = Config.AppSettings["UI"] switch { "KDE" => new Linux.KDE(), - "Console" => new Other.Console(), - _ => _model + "CONSOLE" => new Other.Console(), + _ => null }; } diff --git a/SethDiscordBot.sln b/SethDiscordBot.sln index d355007..a8d9f43 100644 --- a/SethDiscordBot.sln +++ b/SethDiscordBot.sln @@ -15,8 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LevelingSystem", "..\SethPl EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PythonCompatibilityLayer", "..\SethPlugins\PythonCompatibilityLayer\PythonCompatibilityLayer.csproj", "{81ED4953-13E5-4950-96A8-8CEF5FD59559}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SethTests", "SethTests\SethTests.csproj", "{B3044E3C-2F68-4556-9E87-3772702B4CE7}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -43,10 +41,6 @@ Global {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Debug|Any CPU.Build.0 = Debug|Any CPU {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Release|Any CPU.ActiveCfg = Release|Any CPU {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Release|Any CPU.Build.0 = Release|Any CPU - {B3044E3C-2F68-4556-9E87-3772702B4CE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B3044E3C-2F68-4556-9E87-3772702B4CE7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B3044E3C-2F68-4556-9E87-3772702B4CE7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B3044E3C-2F68-4556-9E87-3772702B4CE7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SethTests/PluginManagerTests/AppSettingsTests.cs b/SethTests/PluginManagerTests/AppSettingsTests.cs deleted file mode 100644 index ed18d62..0000000 --- a/SethTests/PluginManagerTests/AppSettingsTests.cs +++ /dev/null @@ -1,46 +0,0 @@ -using PluginManager; -using Xunit.Abstractions; - -namespace SethTests.PluginManagerTests; - -public class AppSettingsTests -{ - private readonly ITestOutputHelper _testOutputHelper; - - public AppSettingsTests(ITestOutputHelper testOutputHelper) - { - _testOutputHelper = testOutputHelper; - } - - [Fact] - public void TestAppSettings_ConstructorInitializeTheClassAndFile() - { - var appSettings = new PluginManager.Others.SettingsDictionary("settings.txt"); - - Assert.NotNull(appSettings); - } - - [Theory] - [InlineData("key1", "value1")] - [InlineData("key2", true)] - public void TestAppSettings_InsertingValueIntoSettings(string keyName, object value) - { - var appSettings = new PluginManager.Others.SettingsDictionary("settings.txt"); - - appSettings[keyName] = value; - Assert.True(appSettings.ContainsKey(keyName)); - } - - [Theory] - //[InlineData("key2", 32)] // fails - [InlineData("key1", "value1")] - public void TestAppSettings_GettingTheValueFromSettings(string keyName, object value) - { - var appSettings = new PluginManager.Others.SettingsDictionary("settings.txt"); - - appSettings[keyName] = value; - - Assert.Same(appSettings[keyName], value); - } - -} \ No newline at end of file diff --git a/SethTests/SethTests.csproj b/SethTests/SethTests.csproj deleted file mode 100644 index e2d19d2..0000000 --- a/SethTests/SethTests.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - net6.0 - enable - enable - - false - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - - - - diff --git a/SethTests/Usings.cs b/SethTests/Usings.cs deleted file mode 100644 index 8c927eb..0000000 --- a/SethTests/Usings.cs +++ /dev/null @@ -1 +0,0 @@ -global using Xunit; \ No newline at end of file From 14f280baefa9f2b696b94d4aa4e981d54f2adc6d Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Mon, 26 Feb 2024 23:36:19 +0200 Subject: [PATCH 13/37] Moved to Json Database for online plugins --- DatabaseCreator/DatabaseCreator.csproj | 14 ++ DatabaseCreator/Program.cs | 68 +++++++ DiscordBot/Bot/Actions/Extra/PluginMethods.cs | 53 ++--- PluginManager/Config.cs | 2 + PluginManager/Interfaces/Updater/IVersion.cs | 14 ++ PluginManager/Interfaces/Updater/Version.cs | 71 +++++++ .../Online/Helpers/ApplicationVersion.cs | 16 ++ PluginManager/Online/Helpers/PluginVersion.cs | 20 ++ PluginManager/Online/Helpers/VersionString.cs | 117 ----------- PluginManager/Online/PluginsManager.cs | 182 ++++-------------- PluginManager/Online/ServerCom.cs | 11 ++ PluginManager/Others/Enums.cs | 13 +- PluginManager/Plugin/OnlineDependencyInfo.cs | 13 ++ PluginManager/Plugin/PluginInfo.cs | 24 +++ PluginManager/Plugin/PluginOnlineInfo.cs | 51 +++++ SethDiscordBot.sln | 6 + 16 files changed, 376 insertions(+), 299 deletions(-) create mode 100644 DatabaseCreator/DatabaseCreator.csproj create mode 100644 DatabaseCreator/Program.cs create mode 100644 PluginManager/Interfaces/Updater/IVersion.cs create mode 100644 PluginManager/Interfaces/Updater/Version.cs create mode 100644 PluginManager/Online/Helpers/ApplicationVersion.cs create mode 100644 PluginManager/Online/Helpers/PluginVersion.cs delete mode 100644 PluginManager/Online/Helpers/VersionString.cs create mode 100644 PluginManager/Plugin/OnlineDependencyInfo.cs create mode 100644 PluginManager/Plugin/PluginInfo.cs create mode 100644 PluginManager/Plugin/PluginOnlineInfo.cs diff --git a/DatabaseCreator/DatabaseCreator.csproj b/DatabaseCreator/DatabaseCreator.csproj new file mode 100644 index 0000000..de0b356 --- /dev/null +++ b/DatabaseCreator/DatabaseCreator.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/DatabaseCreator/Program.cs b/DatabaseCreator/Program.cs new file mode 100644 index 0000000..5a36611 --- /dev/null +++ b/DatabaseCreator/Program.cs @@ -0,0 +1,68 @@ +using System.Diagnostics; +using PluginManager; +using PluginManager.Online.Helpers; +using PluginManager.Others; +using PluginManager.Plugin; + +if (args.Length == 1) +{ + PluginOnlineInfo? result = await JsonManager.ConvertFromJson(args[0]); + // print all rows + Console.WriteLine($"Name: {result.Name}"); + Console.WriteLine($"Version: {result.Version.ToShortString()}"); + Console.WriteLine($"Description: {result.Description}"); + Console.WriteLine($"Download link: {result.DownLoadLink}"); + Console.WriteLine($"Supported OS: {((result.SupportedOS & OSType.WINDOWS) != 0 ? "Windows" : "")} {((result.SupportedOS & OSType.LINUX) != 0 ? "Linux" : "")} {((result.SupportedOS & OSType.MACOSX) != 0 ? "MacOSX" : "")}"); + Console.WriteLine($"Has dependencies: {result.HasDependencies}"); + Console.WriteLine($"Dependencies: {result.Dependencies.Count}"); + + return; +} + + +var _levelingSystem = new PluginOnlineInfo( + "Leveling System", + new PluginVersion(0, 0, 1), + "A simple leveling system for your server", + "https://github.com/andreitdr/SethPlugins/raw/releases/LevelingSystem/LevelingSystem.dll", + OSType.WINDOWS | OSType.LINUX +); + +var _musicPlayerWindows = new PluginOnlineInfo( + "Music Player (Windows)", new PluginVersion(0, 0, 1), + "A simple music player for your server", + "https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/MusicPlayer.dll", + OSType.WINDOWS, + [ + new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/windows/ffmpeg.exe", "ffmpeg.exe"), + new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/windows/libopus.dll", "libopus.dll"), + new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/windows/libsodium.dll", "libsodium.dll"), + new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/windows/opus.dll", "opus.dll"), + new OnlineDependencyInfo("https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_x86.exe", "yt-dlp.exe") + ] +); + +var _musicPlayerLINUX = new PluginOnlineInfo( + "Music Player (Linux)", new PluginVersion(0, 0, 1), + "A simple music player for your server", + "https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/MusicPlayer.dll", + OSType.LINUX, + [ + new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/linux/ffmpeg", "ffmpeg"), + new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/linux/libopus.so", "libopus.so"), + new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/linux/libsodium.so", "libsodium.so"), + new OnlineDependencyInfo("https://github.com/yt-dlp/yt-dlp/releases/download/2023.10.13/yt-dlp", "yt-dlp") + ] +); + +List plugins = +[ + _levelingSystem, + _musicPlayerWindows, + _musicPlayerLINUX +]; + +Directory.CreateDirectory("output"); +await JsonManager.SaveToJsonFile("./output/PluginsList.json", plugins); + +Process.Start("notepad.exe", "./output/PluginsList.json"); \ No newline at end of file diff --git a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs index 58be800..9a1f91d 100644 --- a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs +++ b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs @@ -10,6 +10,7 @@ using PluginManager.Interfaces; using PluginManager.Loaders; using PluginManager.Online; using PluginManager.Others; +using PluginManager.Plugin; using Spectre.Console; namespace DiscordBot.Bot.Actions.Extra; @@ -18,10 +19,10 @@ internal static class PluginMethods { internal static async Task List(PluginsManager manager) { - var data = await ConsoleUtilities.ExecuteWithProgressBar(manager.GetAvailablePlugins(), "Loading plugins..."); + var data = await ConsoleUtilities.ExecuteWithProgressBar(manager.GetPluginsList(), "Loading plugins..."); - TableData tableData = new(new List { "Name", "Description", "Type", "Version" }); - foreach (var plugin in data) tableData.AddRow(plugin); + TableData tableData = new(new List { "Name", "Description", "Version", "Has Dependencies" }); + foreach (var plugin in data) tableData.AddRow([plugin.Name, plugin.Description, plugin.Version.ToString(), plugin.HasDependencies ? "Yes" : "No"]); tableData.HasRoundBorders = false; tableData.PrintAsTable(); @@ -35,16 +36,14 @@ internal static class PluginMethods internal static async Task DownloadPlugin(PluginsManager manager, string pluginName) { - var pluginData = await manager.GetPluginLinkByName(pluginName); - if (pluginData.Length == 0) + var pluginData = await manager.GetPluginDataByName(pluginName); + if (pluginData is null) { 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]; + + var pluginLink = pluginData.DownLoadLink; await AnsiConsole.Progress() @@ -61,7 +60,7 @@ internal static class PluginMethods IProgress progress = new Progress(p => { downloadTask.Value = p; }); - await ServerCom.DownloadFileAsync(pluginLink, $"./Data/{pluginType}s/{pluginName}.dll", progress); + await ServerCom.DownloadFileAsync(pluginLink, $"{Config.AppSettings["PluginFolder"]}/{pluginName}.dll", progress); downloadTask.Increment(100); @@ -69,32 +68,13 @@ internal static class PluginMethods } ); - if (pluginRequirements == string.Empty) + if (!pluginData.HasDependencies) { Console.WriteLine("Finished installing " + pluginName + " successfully"); await RefreshPlugins(false); 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); - - gatherInformationTask.Increment(100); - } - ); + List, string, string>> downloadTasks = new(); await AnsiConsole.Progress() .Columns(new ProgressColumn[] @@ -108,14 +88,9 @@ internal static class PluginMethods { - foreach (var info in requirementsUrLs) + foreach (OnlineDependencyInfo dependency in pluginData.Dependencies) { - if (info.Length < 2) continue; - string[] data = info.Split(','); - string url = data[0]; - string fileName = data[1]; - - var task = ctx.AddTask($"Downloading {fileName}: "); + var task = ctx.AddTask($"Downloading {dependency.DownloadLocation}: "); IProgress progress = new Progress(p => { task.Value = p; @@ -123,7 +98,7 @@ internal static class PluginMethods ); task.IsIndeterminate = true; - downloadTasks.Add(new Tuple, string, string>(task, progress, url, fileName)); + downloadTasks.Add(new Tuple, string, string>(task, progress, dependency.DownloadLink, dependency.DownloadLocation)); } if (!int.TryParse(Config.AppSettings["MaxParallelDownloads"], out int maxParallelDownloads)) diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index 5a0d398..c995e7c 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -30,6 +30,8 @@ public class Config AppSettings = new SettingsDictionary("./Data/Resources/config.json"); AppSettings["LogFolder"] = "./Data/Logs"; + AppSettings["PluginFolder"] = "./Data/Plugins"; + AppSettings["ArchiveFolder"] = "./Data/Archives"; if (OperatingSystem.IsLinux()) { diff --git a/PluginManager/Interfaces/Updater/IVersion.cs b/PluginManager/Interfaces/Updater/IVersion.cs new file mode 100644 index 0000000..327dbf7 --- /dev/null +++ b/PluginManager/Interfaces/Updater/IVersion.cs @@ -0,0 +1,14 @@ +namespace PluginManager.Interfaces.Updater; + +public interface IVersion +{ + public int Major { get; } + public int Minor { get; } + public int Patch { get; } + + public bool IsNewerThan(IVersion version); + public bool IsOlderThan(IVersion version); + public bool IsEqualTo(IVersion version); + + public string ToShortString(); +} diff --git a/PluginManager/Interfaces/Updater/Version.cs b/PluginManager/Interfaces/Updater/Version.cs new file mode 100644 index 0000000..08cb5ff --- /dev/null +++ b/PluginManager/Interfaces/Updater/Version.cs @@ -0,0 +1,71 @@ +using System; + +namespace PluginManager.Interfaces.Updater; + +public abstract class Version : IVersion +{ + public int Major { get; } + public int Minor { get; } + public int Patch { get; } + + protected readonly char _Separator = '.'; + + protected Version(int major, int minor, int patch) + { + this.Major = major; + this.Minor = minor; + this.Patch = patch; + } + + protected Version(string versionAsString) + { + string[] versionParts = versionAsString.Split(_Separator); + + if (versionParts.Length != 3) + { + throw new ArgumentException("Invalid version string"); + } + + this.Major = int.Parse(versionParts[0]); + this.Minor = int.Parse(versionParts[1]); + this.Patch = int.Parse(versionParts[2]); + } + + public bool IsNewerThan(IVersion version) + { + if (this.Major > version.Major) + return true; + + if (this.Major == version.Major && this.Minor > version.Minor) + return true; + + if (this.Major == version.Major && this.Minor == version.Minor && this.Patch > version.Patch) + return true; + + return false; + } + + public bool IsOlderThan(IVersion version) + { + if (this.Major < version.Major) + return true; + + if (this.Major == version.Major && this.Minor < version.Minor) + return true; + + if (this.Major == version.Major && this.Minor == version.Minor && this.Patch < version.Patch) + return true; + + return false; + } + + public bool IsEqualTo(IVersion version) + { + return this.Major == version.Major && this.Minor == version.Minor && this.Patch == version.Patch; + } + + public string ToShortString() + { + return $"{Major}.{Minor}.{Patch}"; + } +} diff --git a/PluginManager/Online/Helpers/ApplicationVersion.cs b/PluginManager/Online/Helpers/ApplicationVersion.cs new file mode 100644 index 0000000..220bce7 --- /dev/null +++ b/PluginManager/Online/Helpers/ApplicationVersion.cs @@ -0,0 +1,16 @@ +using PluginManager.Interfaces.Updater; + +namespace PluginManager.Online.Helpers; + +public class ApplicationVersion : Version +{ + + public ApplicationVersion(int major, int minor, int patch): base(major, minor, patch) + { + } + public ApplicationVersion(string versionAsString): base(versionAsString) + { + } + + +} diff --git a/PluginManager/Online/Helpers/PluginVersion.cs b/PluginManager/Online/Helpers/PluginVersion.cs new file mode 100644 index 0000000..b0bcf92 --- /dev/null +++ b/PluginManager/Online/Helpers/PluginVersion.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; +using PluginManager.Interfaces.Updater; + +namespace PluginManager.Online.Helpers; + +public class PluginVersion : Version +{ + [JsonConstructor] + public PluginVersion(int major, int minor, int patch): base(major, minor, patch) + { + } + public PluginVersion(string versionAsString): base(versionAsString) + { + } + + public override string ToString() + { + return ToShortString(); + } +} diff --git a/PluginManager/Online/Helpers/VersionString.cs b/PluginManager/Online/Helpers/VersionString.cs deleted file mode 100644 index 15812d9..0000000 --- a/PluginManager/Online/Helpers/VersionString.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; - -namespace PluginManager.Online.Helpers; - -public class VersionString -{ - public int PackageCheckVersion; - public int PackageMainVersion; - public int PackageVersionID; - - public VersionString(string version) - { - var data = version.Split('.'); - try - { - if (data.Length == 3) - { - PackageVersionID = int.Parse(data[0]); - PackageMainVersion = int.Parse(data[1]); - PackageCheckVersion = int.Parse(data[2]); - } - else if (data.Length == 4) - { - // ignore the first item data[0] - PackageVersionID = int.Parse(data[1]); - PackageMainVersion = int.Parse(data[2]); - PackageCheckVersion = int.Parse(data[3]); - } - else - { - throw new Exception("Invalid version string"); - } - } - catch (Exception ex) - { - Console.WriteLine(version); - throw new Exception("Failed to write Version", ex); - } - } - - private bool Equals(VersionString other) - { - return PackageCheckVersion == other.PackageCheckVersion && PackageMainVersion == other.PackageMainVersion && - PackageVersionID == other.PackageVersionID; - } - - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((VersionString)obj); - } - - public override int GetHashCode() - { - return HashCode.Combine(PackageCheckVersion, PackageMainVersion, PackageVersionID); - } - - public override string ToString() - { - return "{PackageID: " + PackageVersionID + ", PackageVersion: " + PackageMainVersion + - ", PackageCheckVersion: " + PackageCheckVersion + "}"; - } - - public string ToShortString() - { - if (PackageVersionID == 0 && PackageCheckVersion == 0 && PackageMainVersion == 0) - return "Unknown"; - return $"{PackageVersionID}.{PackageMainVersion}.{PackageCheckVersion}"; - } - - - #region operators - - public static bool operator >(VersionString s1, VersionString s2) - { - if (s1.PackageVersionID > s2.PackageVersionID) return true; - if (s1.PackageVersionID == s2.PackageVersionID) - { - if (s1.PackageMainVersion > s2.PackageMainVersion) return true; - if (s1.PackageMainVersion == s2.PackageMainVersion && - s1.PackageCheckVersion > s2.PackageCheckVersion) return true; - } - - return false; - } - - public static bool operator <(VersionString s1, VersionString s2) - { - return !(s1 > s2) && s1 != s2; - } - - public static bool operator ==(VersionString s1, VersionString s2) - { - if (s1.PackageVersionID == s2.PackageVersionID && s1.PackageMainVersion == s2.PackageMainVersion && - s1.PackageCheckVersion == s2.PackageCheckVersion) return true; - return false; - } - - public static bool operator !=(VersionString s1, VersionString s2) - { - return !(s1 == s2); - } - - public static bool operator <=(VersionString s1, VersionString s2) - { - return s1 < s2 || s1 == s2; - } - - public static bool operator >=(VersionString s1, VersionString s2) - { - return s1 > s2 || s1 == s2; - } - - #endregion -} diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index 285762d..1a96985 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -3,161 +3,59 @@ using System.Collections.Generic; using System.Threading.Tasks; using PluginManager.Online.Helpers; using PluginManager.Others; +using PluginManager.Plugin; + namespace PluginManager.Online; public class PluginsManager { - /// - /// The Plugin Manager constructor. It uses the default links and the default branch. - /// - /// The main branch from where the plugin manager gets its info - public PluginsManager(string? branch) + private static readonly string _DefaultBranch = "releases"; + private static readonly string _DefaultBaseUrl = "https://raw.githubusercontent.com/andreitdr/SethPlugins"; + + private static readonly string _DefaultPluginsLink = "PluginsList.json"; + + + public string Branch { get; init; } + public string BaseUrl { get; init; } + + + private string PluginsLink => $"{BaseUrl}/{Branch}/{_DefaultPluginsLink}"; + + public PluginsManager(Uri baseUrl, string branch) { - PluginsLink = $"https://raw.githubusercontent.com/andreitdr/SethPlugins/{branch}/PluginsList"; - VersionsLink = $"https://raw.githubusercontent.com/andreitdr/SethPlugins/{branch}/Versions"; + this.BaseUrl = baseUrl.ToString(); + this.Branch = branch; + } + + public PluginsManager(string branch) + { + this.BaseUrl = _DefaultBaseUrl; + this.Branch = branch; + } + + public PluginsManager() + { + this.BaseUrl = _DefaultBaseUrl; + this.Branch = _DefaultBranch; } - /// - /// The URL of the server - /// - public string PluginsLink { get; } - - public string VersionsLink { get; } - - /// - /// The method to load all plugins - /// - /// - public async Task> GetAvailablePlugins() + public async Task> GetPluginsList() { - // Config.Logger.Log("Got data from " + VersionsLink, this, LogLevel.INFO); - try - { - var list = await ServerCom.ReadTextFromURL(PluginsLink); - var lines = list.ToArray(); + string jsonText = await ServerCom.GetAllTextFromUrl(PluginsLink); + List result = await JsonManager.ConvertFromJson>(jsonText); + + OSType currentOS = OperatingSystem.IsWindows() ? OSType.WINDOWS : OperatingSystem.IsLinux() ? OSType.LINUX : OSType.MACOSX; - var data = new List(); - - var len = lines.Length; - for (var i = 0; i < len; i++) - { - if (lines[i].Length <= 2) - continue; - var content = lines[i].Split(','); - var display = new string[4]; // 4 columns - if (System.OperatingSystem.IsWindows()) - { - if (content[4].Contains("Windows")) - { - display[0] = content[0]; - display[1] = content[1]; - display[2] = content[2]; - display[3] = - (await GetVersionOfPackageFromWeb(content[0]) ?? new VersionString("0.0.0")) - .ToShortString(); - data.Add(display); - } - } - else if (System.OperatingSystem.IsLinux()) - { - if (content[4].Contains("Linux")) - { - display[0] = content[0]; - display[1] = content[1]; - display[2] = content[2]; - display[3] = - (await GetVersionOfPackageFromWeb(content[0]) ?? new VersionString("0.0.0")) - .ToShortString(); - data.Add(display); - } - } - } - return data; - } - catch (Exception exception) - { - Config.Logger.Log(message: "Failed to execute command: listplugs\nReason: " + exception.Message, source: typeof(PluginsManager), type: LogType.ERROR); - } - - return null; + return result.FindAll(pl => (pl.SupportedOS & currentOS) != 0); } - private async Task GetVersionOfPackageFromWeb(string pakName) + public async Task GetPluginDataByName(string pluginName) { - var data = await ServerCom.ReadTextFromURL(VersionsLink); - foreach (var item in data) - { - if (item.StartsWith("#")) - continue; + List plugins = await GetPluginsList(); + PluginOnlineInfo? result = plugins.Find(p => p.Name == pluginName); - var split = item.Split(','); - if (split[0] == pakName) - { - // Config.Logger.Log("Searched for " + pakName + " and found " + split[1] + " as version.", LogLevel.INFO); - return new VersionString(split[1]); - } - } - - return null; + return result; } - /// - /// The method to get plugin information by its name - /// - /// The plugin name - /// - public async Task GetPluginLinkByName(string name) - { - try - { - var list = await ServerCom.ReadTextFromURL(PluginsLink); - var lines = list.ToArray(); - var len = lines.Length; - for (var i = 0; i < len; i++) - { - var contents = lines[i].Split(','); - if (contents[0].ToLowerInvariant() == name.ToLowerInvariant()) - { - if (System.OperatingSystem.IsWindows() && contents[4].Contains("Windows")) - { - if (contents.Length == 6) - return new[] - { - contents[2], contents[3], contents[5] - }; - if (contents.Length == 5) - return new[] - { - contents[2], contents[3], string.Empty - }; - throw new Exception("Failed to download plugin. Invalid Argument Length"); - - } - - if (System.OperatingSystem.IsLinux() && contents[4].Contains("Linux")) - { - if (contents.Length == 6) - return new[] - { - contents[2], contents[3], contents[5] - }; - if (contents.Length == 5) - return new[] - { - contents[2], contents[3], string.Empty - }; - throw new Exception("Failed to download plugin. Invalid Argument Length"); - - } - } - - } - } - catch (Exception exception) - { - Config.Logger.Log("Failed to execute command: plugin list\nReason: " + exception.Message, source: typeof(PluginsManager), type: LogType.ERROR); - } - - return null; - } + } diff --git a/PluginManager/Online/ServerCom.cs b/PluginManager/Online/ServerCom.cs index 340825b..2b6170d 100644 --- a/PluginManager/Online/ServerCom.cs +++ b/PluginManager/Online/ServerCom.cs @@ -21,6 +21,17 @@ public static class ServerCom var lines = response.Split('\n'); return lines.ToList(); } + + /// + /// Get all text from a file async + /// + /// The link of the file + /// + public static async Task GetAllTextFromUrl(string link) + { + var response = await OnlineFunctions.DownloadStringAsync(link); + return response; + } /// /// Download file from url diff --git a/PluginManager/Others/Enums.cs b/PluginManager/Others/Enums.cs index 53a156a..7802528 100644 --- a/PluginManager/Others/Enums.cs +++ b/PluginManager/Others/Enums.cs @@ -1,4 +1,6 @@ -namespace PluginManager.Others; +using System; + +namespace PluginManager.Others; /// /// The output log type @@ -28,3 +30,12 @@ public enum InternalActionRunType ON_STARTUP, ON_CALL } + +[Flags] +public enum OSType : byte +{ + NONE = 0, + WINDOWS = 1 << 0, + LINUX = 2 << 1, + MACOSX = 3 << 2, +} \ No newline at end of file diff --git a/PluginManager/Plugin/OnlineDependencyInfo.cs b/PluginManager/Plugin/OnlineDependencyInfo.cs new file mode 100644 index 0000000..73f65d4 --- /dev/null +++ b/PluginManager/Plugin/OnlineDependencyInfo.cs @@ -0,0 +1,13 @@ +namespace PluginManager.Plugin; + +public class OnlineDependencyInfo +{ + public string DownloadLink { get; private set; } + public string DownloadLocation { get; private set; } + + public OnlineDependencyInfo(string downloadLink, string downloadLocation) + { + DownloadLink = downloadLink; + DownloadLocation = downloadLocation; + } +} diff --git a/PluginManager/Plugin/PluginInfo.cs b/PluginManager/Plugin/PluginInfo.cs new file mode 100644 index 0000000..8697aa2 --- /dev/null +++ b/PluginManager/Plugin/PluginInfo.cs @@ -0,0 +1,24 @@ +using System.IO; +using PluginManager.Interfaces.Updater; + +namespace PluginManager.Plugin; + +public class PluginInfo +{ + public string PluginName { get; private set; } + public IVersion PluginVersion { get; private set; } + public FileInfo FileData { get; private set; } + + public PluginInfo(string pluginName, IVersion pluginVersion) + { + PluginName = pluginName; + PluginVersion = pluginVersion; + + FileData = new FileInfo($"{Config.AppSettings["PluginFolder"]}/{pluginName}.dll"); + } + + public static PluginInfo FromOnlineInfo(PluginOnlineInfo onlineInfo) + { + return new PluginInfo(onlineInfo.Name, onlineInfo.Version); + } +} diff --git a/PluginManager/Plugin/PluginOnlineInfo.cs b/PluginManager/Plugin/PluginOnlineInfo.cs new file mode 100644 index 0000000..b0c6c49 --- /dev/null +++ b/PluginManager/Plugin/PluginOnlineInfo.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using PluginManager.Online.Helpers; +using PluginManager.Others; + +namespace PluginManager.Plugin; + +public class PluginOnlineInfo +{ + public string Name { get; private set; } + public PluginVersion Version { get; private set; } + public string DownLoadLink { get; private set; } + public string Description { get; private set; } + public List Dependencies { get; private set; } + public OSType SupportedOS { get; private set; } + public bool HasDependencies { get; init; } + + [JsonConstructor] + public PluginOnlineInfo(string name, PluginVersion version, string description, string downLoadLink, OSType supportedOS, List dependencies) + { + Name = name; + Version = version; + Description = description; + DownLoadLink = downLoadLink; + SupportedOS = supportedOS; + Dependencies = dependencies; + HasDependencies = dependencies.Count > 0; + } + + public PluginOnlineInfo(string name, PluginVersion version, string description, string downLoadLink, OSType supportedOS) + { + Name = name; + Version = version; + Description = description; + DownLoadLink = downLoadLink; + SupportedOS = supportedOS; + Dependencies = new List(); + HasDependencies = false; + } + + public static async Task FromRawData(string jsonText) + { + return await JsonManager.ConvertFromJson(jsonText); + } + + public override string ToString() + { + return $"{Name} - {Version} ({Description})"; + } +} diff --git a/SethDiscordBot.sln b/SethDiscordBot.sln index a8d9f43..f855e4a 100644 --- a/SethDiscordBot.sln +++ b/SethDiscordBot.sln @@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LevelingSystem", "..\SethPl EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PythonCompatibilityLayer", "..\SethPlugins\PythonCompatibilityLayer\PythonCompatibilityLayer.csproj", "{81ED4953-13E5-4950-96A8-8CEF5FD59559}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseCreator", "DatabaseCreator\DatabaseCreator.csproj", "{D9BC7451-74A4-4FB3-86CC-A59F6DB889B4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -41,6 +43,10 @@ Global {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Debug|Any CPU.Build.0 = Debug|Any CPU {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Release|Any CPU.ActiveCfg = Release|Any CPU {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Release|Any CPU.Build.0 = Release|Any CPU + {D9BC7451-74A4-4FB3-86CC-A59F6DB889B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9BC7451-74A4-4FB3-86CC-A59F6DB889B4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9BC7451-74A4-4FB3-86CC-A59F6DB889B4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9BC7451-74A4-4FB3-86CC-A59F6DB889B4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From ef7a2c0896603948a1d9695b95a3143f44c93fd0 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Tue, 27 Feb 2024 11:07:27 +0200 Subject: [PATCH 14/37] Formatted code and rebuilt PluginLoader --- DatabaseCreator/DatabaseCreator.csproj | 2 +- DatabaseCreator/Program.cs | 8 +- DiscordBot/Bot/Actions/Exit.cs | 4 +- DiscordBot/Bot/Actions/Extra/PluginMethods.cs | 75 ++++---- DiscordBot/Bot/Actions/Help.cs | 52 ++++- DiscordBot/Bot/Actions/Plugin.cs | 6 +- DiscordBot/Bot/Commands/SlashCommands/Help.cs | 6 +- DiscordBot/Installer.cs | 17 +- DiscordBot/Program.cs | 15 +- DiscordBot/Utilities/Console Utilities.cs | 33 ++-- PluginManager/Bot/Boot.cs | 10 +- PluginManager/Bot/CommandHandler.cs | 32 ++-- PluginManager/Config.cs | 19 +- PluginManager/Database/SqlDatabase.cs | 6 +- PluginManager/Interfaces/Updater/IVersion.cs | 6 +- PluginManager/Interfaces/Updater/Version.cs | 36 ++-- PluginManager/Loaders/FileLoaderResult.cs | 20 ++ PluginManager/Loaders/Loader.cs | 149 +++++---------- PluginManager/Loaders/PluginHandler.cs | 6 + PluginManager/Loaders/PluginLoadResultData.cs | 22 +++ PluginManager/Loaders/PluginLoader.cs | 180 ++++-------------- .../Loaders/PluginLoaderExtensions.cs | 54 ++++++ .../Online/Helpers/ApplicationVersion.cs | 6 +- PluginManager/Online/Helpers/PluginVersion.cs | 2 +- PluginManager/Online/PluginsManager.cs | 45 ++--- PluginManager/Online/ServerCom.cs | 2 +- PluginManager/Others/ArchiveManager.cs | 8 +- .../Others/DBCommandExecutingArguments.cs | 14 +- PluginManager/Others/Enums.cs | 18 +- PluginManager/Others/JsonManager.cs | 6 +- PluginManager/Others/Logger/Log.cs | 10 +- PluginManager/Others/SettingsDictionary.cs | 28 +-- PluginManager/Plugin/OnlineDependencyInfo.cs | 4 +- PluginManager/Plugin/PluginInfo.cs | 10 +- PluginManager/Plugin/PluginOnlineInfo.cs | 32 ++-- PluginManager/PluginManager.csproj | 12 +- PluginManager/UX/IOutputModel.cs | 8 +- PluginManager/UX/Linux/KDE.cs | 44 ++--- PluginManager/UX/Other/Console.cs | 24 ++- PluginManager/UX/UxHandler.cs | 18 +- 40 files changed, 525 insertions(+), 524 deletions(-) create mode 100644 PluginManager/Loaders/FileLoaderResult.cs create mode 100644 PluginManager/Loaders/PluginHandler.cs create mode 100644 PluginManager/Loaders/PluginLoadResultData.cs create mode 100644 PluginManager/Loaders/PluginLoaderExtensions.cs diff --git a/DatabaseCreator/DatabaseCreator.csproj b/DatabaseCreator/DatabaseCreator.csproj index de0b356..438539f 100644 --- a/DatabaseCreator/DatabaseCreator.csproj +++ b/DatabaseCreator/DatabaseCreator.csproj @@ -8,7 +8,7 @@ - + diff --git a/DatabaseCreator/Program.cs b/DatabaseCreator/Program.cs index 5a36611..1d55a8d 100644 --- a/DatabaseCreator/Program.cs +++ b/DatabaseCreator/Program.cs @@ -6,13 +6,15 @@ using PluginManager.Plugin; if (args.Length == 1) { - PluginOnlineInfo? result = await JsonManager.ConvertFromJson(args[0]); + var result = await JsonManager.ConvertFromJson(args[0]); // print all rows Console.WriteLine($"Name: {result.Name}"); Console.WriteLine($"Version: {result.Version.ToShortString()}"); Console.WriteLine($"Description: {result.Description}"); Console.WriteLine($"Download link: {result.DownLoadLink}"); - Console.WriteLine($"Supported OS: {((result.SupportedOS & OSType.WINDOWS) != 0 ? "Windows" : "")} {((result.SupportedOS & OSType.LINUX) != 0 ? "Linux" : "")} {((result.SupportedOS & OSType.MACOSX) != 0 ? "MacOSX" : "")}"); + Console.WriteLine( + $"Supported OS: {((result.SupportedOS & OSType.WINDOWS) != 0 ? "Windows" : "")} {((result.SupportedOS & OSType.LINUX) != 0 ? "Linux" : "")} {((result.SupportedOS & OSType.MACOSX) != 0 ? "MacOSX" : "")}" + ); Console.WriteLine($"Has dependencies: {result.HasDependencies}"); Console.WriteLine($"Dependencies: {result.Dependencies.Count}"); @@ -65,4 +67,4 @@ List plugins = Directory.CreateDirectory("output"); await JsonManager.SaveToJsonFile("./output/PluginsList.json", plugins); -Process.Start("notepad.exe", "./output/PluginsList.json"); \ No newline at end of file +Process.Start("notepad.exe", "./output/PluginsList.json"); diff --git a/DiscordBot/Bot/Actions/Exit.cs b/DiscordBot/Bot/Actions/Exit.cs index fa21edf..631d4e2 100644 --- a/DiscordBot/Bot/Actions/Exit.cs +++ b/DiscordBot/Bot/Actions/Exit.cs @@ -17,7 +17,7 @@ public class Exit: ICommandAction { if (args is null || args.Length == 0) { - Config.Logger.Log("Exiting...", source: typeof(ICommandAction), type: LogType.WARNING); + Config.Logger.Log("Exiting...", typeof(ICommandAction), LogType.WARNING); await Config.AppSettings.SaveToFile(); Environment.Exit(0); } @@ -33,7 +33,7 @@ public class Exit: ICommandAction case "-f": case "force": - Config.Logger.Log("Exiting (FORCE)...", source: typeof(ICommandAction), type: LogType.WARNING); + Config.Logger.Log("Exiting (FORCE)...", typeof(ICommandAction), LogType.WARNING); Environment.Exit(0); break; diff --git a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs index 9a1f91d..67d16b3 100644 --- a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs +++ b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs @@ -21,7 +21,14 @@ internal static class PluginMethods { var data = await ConsoleUtilities.ExecuteWithProgressBar(manager.GetPluginsList(), "Loading plugins..."); - TableData tableData = new(new List { "Name", "Description", "Version", "Has Dependencies" }); + TableData tableData = new(new List + { + "Name", + "Description", + "Version", + "Has Dependencies" + } + ); foreach (var plugin in data) tableData.AddRow([plugin.Name, plugin.Description, plugin.Version.ToString(), plugin.HasDependencies ? "Yes" : "No"]); tableData.HasRoundBorders = false; @@ -42,16 +49,14 @@ internal static class PluginMethods Console.WriteLine($"Plugin {pluginName} not found. Please check the spelling and try again."); return; } - + var pluginLink = pluginData.DownLoadLink; await AnsiConsole.Progress() .Columns(new ProgressColumn[] { - new TaskDescriptionColumn(), - new ProgressBarColumn(), - new PercentageColumn() + new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn() } ) .StartAsync(async ctx => @@ -74,21 +79,19 @@ internal static class PluginMethods await RefreshPlugins(false); return; } - + List, string, string>> downloadTasks = new(); await AnsiConsole.Progress() .Columns(new ProgressColumn[] { - new TaskDescriptionColumn(), - new ProgressBarColumn(), - new PercentageColumn() + new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn() } ) .StartAsync(async ctx => { - foreach (OnlineDependencyInfo dependency in pluginData.Dependencies) + foreach (var dependency in pluginData.Dependencies) { var task = ctx.AddTask($"Downloading {dependency.DownloadLocation}: "); IProgress progress = new Progress(p => @@ -101,7 +104,7 @@ internal static class PluginMethods downloadTasks.Add(new Tuple, string, string>(task, progress, dependency.DownloadLink, dependency.DownloadLocation)); } - if (!int.TryParse(Config.AppSettings["MaxParallelDownloads"], out int maxParallelDownloads)) + if (!int.TryParse(Config.AppSettings["MaxParallelDownloads"], out var maxParallelDownloads)) { maxParallelDownloads = 5; Config.AppSettings.Add("MaxParallelDownloads", "5"); @@ -126,7 +129,7 @@ internal static class PluginMethods } ); - + await RefreshPlugins(false); } @@ -135,74 +138,66 @@ internal static class PluginMethods var loader = new PluginLoader(Config.DiscordBot.client); if (args.Length == 2 && args[1] == "-q") { - loader.LoadPlugins(); + await loader.LoadPlugins(); return true; } var cc = Console.ForegroundColor; - loader.onCMDLoad += (name, typeName, success, exception) => + loader.OnCommandLoaded += (data) => { - if (name == null || name.Length < 2) - name = typeName; - if (success) + if (data.IsSuccess) { - Config.Logger.Log("Successfully loaded command : " + name, source: typeof(ICommandAction), - type: LogType.INFO + Config.Logger.Log("Successfully loaded command : " + data.PluginName, typeof(ICommandAction), + LogType.INFO ); } else { - Config.Logger.Log("Failed to load command : " + name + " because " + exception?.Message, - source: typeof(ICommandAction), type: LogType.ERROR + Config.Logger.Log("Failed to load command : " + data.PluginName + " because " + data.ErrorMessage, + typeof(ICommandAction), LogType.ERROR ); } Console.ForegroundColor = cc; }; - loader.onEVELoad += (name, typeName, success, exception) => + loader.OnEventLoaded += (data) => { - if (name == null || name.Length < 2) - name = typeName; - - if (success) + if (data.IsSuccess) { - Config.Logger.Log("Successfully loaded event : " + name, source: typeof(ICommandAction), - type: LogType.INFO + Config.Logger.Log("Successfully loaded event : " + data.PluginName, typeof(ICommandAction), + LogType.INFO ); } else { - Config.Logger.Log("Failed to load event : " + name + " because " + exception?.Message, - source: typeof(ICommandAction), type: LogType.ERROR + Config.Logger.Log("Failed to load event : " + data.PluginName + " because " + data.ErrorMessage, + typeof(ICommandAction), LogType.ERROR ); } Console.ForegroundColor = cc; }; - loader.onSLSHLoad += (name, typeName, success, exception) => + loader.OnSlashCommandLoaded += (data) => { - if (name == null || name.Length < 2) - name = typeName; - - if (success) + if (data.IsSuccess) { - Config.Logger.Log("Successfully loaded slash command : " + name, source: typeof(ICommandAction), - type: LogType.INFO + Config.Logger.Log("Successfully loaded slash command : " + data.PluginName, typeof(ICommandAction), + LogType.INFO ); } else { - Config.Logger.Log("Failed to load slash command : " + name + " because " + exception?.Message, - source: typeof(ICommandAction), type: LogType.ERROR + Config.Logger.Log("Failed to load slash command : " + data.PluginName + " because " + data.ErrorMessage, + typeof(ICommandAction), LogType.ERROR ); } Console.ForegroundColor = cc; }; - loader.LoadPlugins(); + await loader.LoadPlugins(); Console.ForegroundColor = cc; return true; } diff --git a/DiscordBot/Bot/Actions/Help.cs b/DiscordBot/Bot/Actions/Help.cs index ac8de2a..376d766 100644 --- a/DiscordBot/Bot/Actions/Help.cs +++ b/DiscordBot/Bot/Actions/Help.cs @@ -23,15 +23,32 @@ public class Help: ICommandAction { var items = new List { - new[] { "-", "-", "-" }, - new[] { "Command", "Usage", "Description" }, - new[] { "-", "-", "-" } + new[] + { + "-", "-", "-" + }, + new[] + { + "Command", "Usage", "Description" + }, + new[] + { + "-", "-", "-" + } }; foreach (var a in Program.internalActionManager.Actions) - items.Add(new[] { a.Key, a.Value.Usage, a.Value.Description }); + items.Add(new[] + { + a.Key, a.Value.Usage, a.Value.Description + } + ); - items.Add(new[] { "-", "-", "-" }); + items.Add(new[] + { + "-", "-", "-" + } + ); ConsoleUtilities.FormatAndAlignTable(items, TableFormat.CENTER_EACH_COLUMN_BASED @@ -48,11 +65,26 @@ public class Help: ICommandAction var action = Program.internalActionManager.Actions[args[0]]; var actionData = new List { - new[] { "-", "-", "-" }, - new[] { "Command", "Usage", "Description" }, - new[] { "-", "-", "-" }, - new[] { action.ActionName, action.Usage, action.Description }, - new[] { "-", "-", "-" } + new[] + { + "-", "-", "-" + }, + new[] + { + "Command", "Usage", "Description" + }, + new[] + { + "-", "-", "-" + }, + new[] + { + action.ActionName, action.Usage, action.Description + }, + new[] + { + "-", "-", "-" + } }; ConsoleUtilities.FormatAndAlignTable(actionData, diff --git a/DiscordBot/Bot/Actions/Plugin.cs b/DiscordBot/Bot/Actions/Plugin.cs index 564a239..fc3a304 100644 --- a/DiscordBot/Bot/Actions/Plugin.cs +++ b/DiscordBot/Bot/Actions/Plugin.cs @@ -34,7 +34,7 @@ public class Plugin: ICommandAction return; } - PluginsManager manager = + var manager = #if !DEBUG new PluginsManager("releases"); #else @@ -54,13 +54,13 @@ public class Plugin: ICommandAction case "load": if (pluginsLoaded) { - Config.Logger.Log("Plugins already loaded", source: typeof(ICommandAction), type: LogType.WARNING); + Config.Logger.Log("Plugins already loaded", typeof(ICommandAction), LogType.WARNING); break; } if (Config.DiscordBot is null) { - Config.Logger.Log("DiscordBot is null", source: typeof(ICommandAction), type: LogType.WARNING); + Config.Logger.Log("DiscordBot is null", typeof(ICommandAction), LogType.WARNING); break; } diff --git a/DiscordBot/Bot/Commands/SlashCommands/Help.cs b/DiscordBot/Bot/Commands/SlashCommands/Help.cs index 030d540..7ba6f0a 100644 --- a/DiscordBot/Bot/Commands/SlashCommands/Help.cs +++ b/DiscordBot/Bot/Commands/SlashCommands/Help.cs @@ -40,15 +40,15 @@ public class Help: DBSlashCommand if (options.Count > 0) { - var commandName = options.First().Name; - var slashCommand = slashCommands.FirstOrDefault(x => x.Name == commandName); + var commandName = options.First().Value; + var slashCommand = slashCommands.FirstOrDefault(x => x.Name.TrimEnd() == commandName.ToString()); if (slashCommand is null) { await context.RespondAsync("Unknown Command " + commandName); return; } - embedBuilder.AddField(slashCommand.Name, slashCommand.canUseDM) + embedBuilder.AddField("DM Usable:", slashCommand.canUseDM, true) .WithDescription(slashCommand.Description); } diff --git a/DiscordBot/Installer.cs b/DiscordBot/Installer.cs index 571469e..9cd5f92 100644 --- a/DiscordBot/Installer.cs +++ b/DiscordBot/Installer.cs @@ -1,7 +1,6 @@ using System; using PluginManager; using Spectre.Console; - using System.Threading.Tasks; namespace DiscordBot; @@ -10,10 +9,10 @@ public static class Installer { public static async Task GenerateStartupConfig() { - string token = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the bot token:"); - string botPrefix = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the bot prefix:"); - string serverId = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the Server ID:"); - + var token = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the bot token:"); + var botPrefix = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the bot prefix:"); + var serverId = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the Server ID:"); + if (string.IsNullOrWhiteSpace(serverId)) serverId = "NULL"; if (string.IsNullOrWhiteSpace(token) || string.IsNullOrWhiteSpace(botPrefix)) @@ -21,13 +20,13 @@ public static class Installer await PluginManager.UX.UxHandler.ShowMessageBox("SethBot", "Invalid token or prefix !", PluginManager.UX.MessageBoxType.Error); Environment.Exit(-20); } - + Config.AppSettings.Add("token", token); Config.AppSettings.Add("prefix", botPrefix); Config.AppSettings.Add("ServerID", serverId); - + await Config.AppSettings.SaveToFile(); - - Config.Logger.Log("Config Saved", source: typeof(Installer)); + + Config.Logger.Log("Config Saved", typeof(Installer)); } } diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 62a20bd..0926fa0 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -69,7 +69,7 @@ public class Program ConsoleUtilities.WriteColorText("&rRemember to close the bot using the ShutDown command (&yexit&r) or some settings won't be saved"); - ConsoleUtilities.WriteColorText($"Running on &m{(System.OperatingSystem.IsWindows() ? "Windows" : "Linux")}"); + ConsoleUtilities.WriteColorText($"Running on &m{(OperatingSystem.IsWindows() ? "Windows" : "Linux")}"); Console.WriteLine("============================ LOG ============================"); Console.ForegroundColor = ConsoleColor.White; @@ -82,7 +82,7 @@ public class Program } catch (Exception ex) { - Logger.Log(ex.ToString(), source: typeof(Program), type: LogType.CRITICAL); + Logger.Log(ex.ToString(), typeof(Program), LogType.CRITICAL); } } @@ -102,12 +102,13 @@ public class Program if (ex.Message == "No process is on the other end of the pipe." || (uint)ex.HResult == 0x800700E9) { UxHandler.ShowMessageBox("SethBot", "An error occured while closing the bot last time. Please consider closing the bot using the &rexit&c method !\n" + - "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !", MessageBoxType.Error).Wait(); - - + "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !", MessageBoxType.Error + ).Wait(); + + Logger.Log("An error occured while closing the bot last time. Please consider closing the bot using the &rexit&c method !\n" + "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !", - source: typeof(Program), type: LogType.ERROR + typeof(Program), LogType.ERROR ); } } @@ -119,7 +120,7 @@ public class Program Logger.OnLog += (sender, logMessage) => { - string messageColor = logMessage.Type switch + var messageColor = logMessage.Type switch { LogType.INFO => "[green]", LogType.WARNING => "[yellow]", diff --git a/DiscordBot/Utilities/Console Utilities.cs b/DiscordBot/Utilities/Console Utilities.cs index cd68bd0..bfb1243 100644 --- a/DiscordBot/Utilities/Console Utilities.cs +++ b/DiscordBot/Utilities/Console Utilities.cs @@ -43,9 +43,7 @@ public static class ConsoleUtilities .Columns( new ProgressColumn[] { - new TaskDescriptionColumn(), - new ProgressBarColumn(), - new PercentageColumn(), + new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn() } ) .StartAsync( @@ -67,9 +65,7 @@ public static class ConsoleUtilities await AnsiConsole.Progress() .Columns(new ProgressColumn[] { - new TaskDescriptionColumn(), - new ProgressBarColumn(), - new PercentageColumn(), + new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn() } ) .StartAsync(async ctx => @@ -85,11 +81,21 @@ public static class ConsoleUtilities private static readonly Dictionary Colors = new() { - { 'g', ConsoleColor.Green }, - { 'b', ConsoleColor.Blue }, - { 'r', ConsoleColor.Red }, - { 'm', ConsoleColor.Magenta }, - { 'y', ConsoleColor.Yellow } + { + 'g', ConsoleColor.Green + }, + { + 'b', ConsoleColor.Blue + }, + { + 'r', ConsoleColor.Red + }, + { + 'm', ConsoleColor.Magenta + }, + { + 'y', ConsoleColor.Yellow + } }; private static readonly char ColorPrefix = '&'; @@ -310,7 +316,10 @@ public static class ConsoleUtilities public Spinner() { - Sequence = new[] { "|", "/", "-", "\\" }; + Sequence = new[] + { + "|", "/", "-", "\\" + }; position = 0; } diff --git a/PluginManager/Bot/Boot.cs b/PluginManager/Bot/Boot.cs index b85ec98..df3c07c 100644 --- a/PluginManager/Bot/Boot.cs +++ b/PluginManager/Bot/Boot.cs @@ -106,7 +106,7 @@ public class Boot if (arg.Message.Contains("401")) { Config.AppSettings.Remove("token"); - Config.Logger.Log("The token is invalid. Please restart the bot and enter a valid token.", source: typeof(Boot), type: LogType.CRITICAL); + Config.Logger.Log("The token is invalid. Please restart the bot and enter a valid token.", typeof(Boot), LogType.CRITICAL); await Config.AppSettings.SaveToFile(); await Task.Delay(4000); Environment.Exit(0); @@ -115,7 +115,7 @@ public class Boot private async Task Client_LoggedOut() { - Config.Logger.Log("Successfully Logged Out", source: typeof(Boot)); + Config.Logger.Log("Successfully Logged Out", typeof(Boot)); await Log(new LogMessage(LogSeverity.Info, "Boot", "Successfully logged out from discord !")); } @@ -128,7 +128,7 @@ public class Boot private Task LoggedIn() { - Config.Logger.Log("Successfully Logged In", source: typeof(Boot)); + Config.Logger.Log("Successfully Logged In", typeof(Boot)); return Task.CompletedTask; } @@ -138,12 +138,12 @@ public class Boot { case LogSeverity.Error: case LogSeverity.Critical: - Config.Logger.Log(message.Message, source: typeof(Boot), type: LogType.ERROR); + Config.Logger.Log(message.Message, typeof(Boot), LogType.ERROR); break; case LogSeverity.Info: case LogSeverity.Debug: - Config.Logger.Log(message.Message, source: typeof(Boot), type: LogType.INFO); + Config.Logger.Log(message.Message, typeof(Boot), LogType.INFO); break; diff --git a/PluginManager/Bot/CommandHandler.cs b/PluginManager/Bot/CommandHandler.cs index 5fc4256..d715cb0 100644 --- a/PluginManager/Bot/CommandHandler.cs +++ b/PluginManager/Bot/CommandHandler.cs @@ -25,9 +25,9 @@ internal class CommandHandler /// The prefix to watch for public CommandHandler(DiscordSocketClient client, CommandService commandService, string botPrefix) { - this._client = client; - this._commandService = commandService; - this._botPrefix = botPrefix; + _client = client; + _commandService = commandService; + _botPrefix = botPrefix; } /// @@ -103,12 +103,10 @@ internal class CommandHandler .FirstOrDefault(plug => plug.Command == message.Content.Substring(mentionPrefix.Length + 1) .Split(' ')[0] || - ( - plug.Aliases is not null && - plug.Aliases.Contains(message.CleanContent - .Substring(mentionPrefix.Length + 1) - .Split(' ')[0] - ) + plug.Aliases is not null && + plug.Aliases.Contains(message.CleanContent + .Substring(mentionPrefix.Length + 1) + .Split(' ')[0] ) ); @@ -120,11 +118,11 @@ internal class CommandHandler plugin = PluginLoader.Commands! .FirstOrDefault(p => p.Command == message.Content.Split(' ')[0].Substring(_botPrefix.Length) || - (p.Aliases is not null && - p.Aliases.Contains( - message.Content.Split(' ')[0] - .Substring(_botPrefix.Length) - )) + p.Aliases is not null && + p.Aliases.Contains( + message.Content.Split(' ')[0] + .Substring(_botPrefix.Length) + ) ); cleanMessage = message.Content.Substring(_botPrefix.Length); } @@ -144,9 +142,9 @@ internal class CommandHandler DbCommandExecutingArguments cmd = new(context, cleanMessage, split[0], argsClean); Config.Logger.Log( - message: $"User ({context.User.Username}) from Guild \"{context.Guild.Name}\" executed command \"{cmd.cleanContent}\"", - source: typeof(CommandHandler), - type: LogType.INFO + $"User ({context.User.Username}) from Guild \"{context.Guild.Name}\" executed command \"{cmd.cleanContent}\"", + typeof(CommandHandler), + LogType.INFO ); if (context.Channel is SocketDMChannel) diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index c995e7c..8ebafa3 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -29,8 +29,8 @@ public class Config AppSettings = new SettingsDictionary("./Data/Resources/config.json"); - AppSettings["LogFolder"] = "./Data/Logs"; - AppSettings["PluginFolder"] = "./Data/Plugins"; + AppSettings["LogFolder"] = "./Data/Logs"; + AppSettings["PluginFolder"] = "./Data/Plugins"; AppSettings["ArchiveFolder"] = "./Data/Archives"; if (OperatingSystem.IsLinux()) @@ -42,21 +42,22 @@ public class Config "GNOME" => "GNOME", _ => "CONSOLE" }; - } else AppSettings["UI"] = "CONSOLE"; + } + else AppSettings["UI"] = "CONSOLE"; Logger = new Logger(false, true, AppSettings["LogFolder"] + $"/{DateTime.Today.ToShortDateString().Replace("/", "")}.log" ); ArchiveManager.Initialize(); - + UX.UxHandler.Init(); _isLoaded = true; - - - Logger.Log(message: "Config initialized", source: typeof(Config)); - - + + + Logger.Log("Config initialized", typeof(Config)); + + } } diff --git a/PluginManager/Database/SqlDatabase.cs b/PluginManager/Database/SqlDatabase.cs index 3c9fdd0..943e04f 100644 --- a/PluginManager/Database/SqlDatabase.cs +++ b/PluginManager/Database/SqlDatabase.cs @@ -544,8 +544,10 @@ public class SqlDatabase /// /// The parameter raw inputs. The Key is name and the Value is the value of the parameter /// The SQLiteParameter that has the name, value and DBType set according to your inputs - private SQLiteParameter? CreateParameter(KeyValuePair parameterValues) => - CreateParameter(parameterValues.Key, parameterValues.Value); + private SQLiteParameter? CreateParameter(KeyValuePair parameterValues) + { + return CreateParameter(parameterValues.Key, parameterValues.Value); + } /// /// Execute a query with parameters diff --git a/PluginManager/Interfaces/Updater/IVersion.cs b/PluginManager/Interfaces/Updater/IVersion.cs index 327dbf7..2d86a98 100644 --- a/PluginManager/Interfaces/Updater/IVersion.cs +++ b/PluginManager/Interfaces/Updater/IVersion.cs @@ -5,10 +5,12 @@ public interface IVersion public int Major { get; } public int Minor { get; } public int Patch { get; } - + public bool IsNewerThan(IVersion version); + public bool IsOlderThan(IVersion version); + public bool IsEqualTo(IVersion version); - + public string ToShortString(); } diff --git a/PluginManager/Interfaces/Updater/Version.cs b/PluginManager/Interfaces/Updater/Version.cs index 08cb5ff..7d61402 100644 --- a/PluginManager/Interfaces/Updater/Version.cs +++ b/PluginManager/Interfaces/Updater/Version.cs @@ -2,7 +2,7 @@ using System; namespace PluginManager.Interfaces.Updater; -public abstract class Version : IVersion +public abstract class Version: IVersion { public int Major { get; } public int Minor { get; } @@ -12,34 +12,34 @@ public abstract class Version : IVersion protected Version(int major, int minor, int patch) { - this.Major = major; - this.Minor = minor; - this.Patch = patch; + Major = major; + Minor = minor; + Patch = patch; } protected Version(string versionAsString) { string[] versionParts = versionAsString.Split(_Separator); - + if (versionParts.Length != 3) { throw new ArgumentException("Invalid version string"); } - - this.Major = int.Parse(versionParts[0]); - this.Minor = int.Parse(versionParts[1]); - this.Patch = int.Parse(versionParts[2]); + + Major = int.Parse(versionParts[0]); + Minor = int.Parse(versionParts[1]); + Patch = int.Parse(versionParts[2]); } - + public bool IsNewerThan(IVersion version) { - if (this.Major > version.Major) + if (Major > version.Major) return true; - if (this.Major == version.Major && this.Minor > version.Minor) + if (Major == version.Major && Minor > version.Minor) return true; - if (this.Major == version.Major && this.Minor == version.Minor && this.Patch > version.Patch) + if (Major == version.Major && Minor == version.Minor && Patch > version.Patch) return true; return false; @@ -47,13 +47,13 @@ public abstract class Version : IVersion public bool IsOlderThan(IVersion version) { - if (this.Major < version.Major) + if (Major < version.Major) return true; - if (this.Major == version.Major && this.Minor < version.Minor) + if (Major == version.Major && Minor < version.Minor) return true; - if (this.Major == version.Major && this.Minor == version.Minor && this.Patch < version.Patch) + if (Major == version.Major && Minor == version.Minor && Patch < version.Patch) return true; return false; @@ -61,9 +61,9 @@ public abstract class Version : IVersion public bool IsEqualTo(IVersion version) { - return this.Major == version.Major && this.Minor == version.Minor && this.Patch == version.Patch; + return Major == version.Major && Minor == version.Minor && Patch == version.Patch; } - + public string ToShortString() { return $"{Major}.{Minor}.{Patch}"; diff --git a/PluginManager/Loaders/FileLoaderResult.cs b/PluginManager/Loaders/FileLoaderResult.cs new file mode 100644 index 0000000..c75bf26 --- /dev/null +++ b/PluginManager/Loaders/FileLoaderResult.cs @@ -0,0 +1,20 @@ +namespace PluginManager.Loaders; + +public class FileLoaderResult +{ + public string PluginName { get; init; } + + public string? ErrorMessage { get; init; } + + + public FileLoaderResult(string pluginName, string errorMessage) + { + PluginName = pluginName; + ErrorMessage = errorMessage; + } + + public FileLoaderResult(string pluginName) + { + PluginName = pluginName; + } +} diff --git a/PluginManager/Loaders/Loader.cs b/PluginManager/Loaders/Loader.cs index 946e5de..ef9bc80 100644 --- a/PluginManager/Loaders/Loader.cs +++ b/PluginManager/Loaders/Loader.cs @@ -1,52 +1,40 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using PluginManager.Interfaces; using PluginManager.Others; namespace PluginManager.Loaders; -internal class LoaderArgs: EventArgs -{ - internal string? PluginName { get; init; } - internal string? TypeName { get; init; } - internal bool IsLoaded { get; init; } - internal Exception? Exception { get; init; } - internal object? Plugin { get; init; } -} - internal class Loader { - internal Loader(string path, string extension) + private readonly string _SearchPath; + private readonly string _FileExtension; + + internal delegate void FileLoadedHandler(FileLoaderResult result); + + internal delegate void PluginLoadedHandler(PluginLoadResultData result); + + internal event FileLoadedHandler? OnFileLoadedException; + internal event PluginLoadedHandler? OnPluginLoaded; + + internal Loader(string searchPath, string fileExtension) { - this.Path = path; - this.Extension = extension; + _SearchPath = searchPath; + _FileExtension = fileExtension; } - - private string Path { get; } - private string Extension { get; } - - internal event FileLoadedEventHandler? FileLoaded; - - internal event PluginLoadedEventHandler? PluginLoaded; - - - internal (List?, List?, List?) Load() + internal async Task Load() { - List events = new(); - List slashCommands = new(); - List commands = new(); - - if (!Directory.Exists(Path)) + if (!Directory.Exists(_SearchPath)) { - Directory.CreateDirectory(Path); - return (null, null, null); + Directory.CreateDirectory(_SearchPath); + return; } - var files = Directory.GetFiles(Path, $"*.{Extension}", SearchOption.AllDirectories); + var files = Directory.GetFiles(_SearchPath, $"*.{_FileExtension}", SearchOption.TopDirectoryOnly); foreach (var file in files) { try @@ -55,91 +43,40 @@ internal class Loader } catch { - Config.Logger.Log("PluginName: " + new FileInfo(file).Name.Split('.')[0] + " not loaded", source: typeof(Loader), type: LogType.ERROR); - continue; - } - - if (FileLoaded != null) - { - var args = new LoaderArgs - { - Exception = null, - TypeName = null, - IsLoaded = false, - PluginName = new FileInfo(file).Name.Split('.')[0], - Plugin = null - }; - FileLoaded.Invoke(args); + OnFileLoadedException?.Invoke(new FileLoaderResult(file, "Failed to load file")); } } - - return (LoadItems(), LoadItems(), LoadItems()); + await LoadEverythingOfType(); + await LoadEverythingOfType(); + await LoadEverythingOfType(); } - internal List LoadItems() + private async Task LoadEverythingOfType() { - List list = new(); + var types = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(s => s.GetTypes()) + .Where(p => typeof(T).IsAssignableFrom(p) && !p.IsInterface); - - try + foreach (var type in types) { - var interfaceType = typeof(T); - var types = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(a => a.GetTypes()) - .Where(p => interfaceType.IsAssignableFrom(p) && p.IsClass) - .ToArray(); - - - list.Clear(); - foreach (var type in types) - try + try + { + var plugin = (T)Activator.CreateInstance(type); + var pluginType = plugin switch { - var plugin = (T)Activator.CreateInstance(type)!; - list.Add(plugin); - - - if (PluginLoaded != null) - PluginLoaded.Invoke(new LoaderArgs - { - Exception = null, - IsLoaded = true, - PluginName = type.FullName, - TypeName = typeof(T) == typeof(DBCommand) ? "DBCommand" : - typeof(T) == typeof(DBEvent) ? "DBEvent" : - typeof(T) == typeof(DBSlashCommand) ? "DBSlashCommand" : - null, - Plugin = plugin - } - ); - } - catch (Exception ex) - { - if (PluginLoaded != null) - PluginLoaded.Invoke(new LoaderArgs - { - Exception = ex, - IsLoaded = false, - PluginName = type.FullName, - TypeName = nameof(T) - } - ); - } - - return list; + DBEvent => PluginType.EVENT, + DBCommand => PluginType.COMMAND, + DBSlashCommand => PluginType.SLASH_COMMAND, + _ => PluginType.UNKNOWN + }; + OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, pluginType, true, plugin: plugin)); + } + catch (Exception ex) + { + OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, PluginType.UNKNOWN, false, ex.Message)); + } } - catch (Exception ex) - { - Config.Logger.Log(ex.Message, source: typeof(Loader), type: LogType.ERROR); - - return null; - } - - return null; } - - internal delegate void FileLoadedEventHandler(LoaderArgs args); - - internal delegate void PluginLoadedEventHandler(LoaderArgs args); } diff --git a/PluginManager/Loaders/PluginHandler.cs b/PluginManager/Loaders/PluginHandler.cs new file mode 100644 index 0000000..945ba50 --- /dev/null +++ b/PluginManager/Loaders/PluginHandler.cs @@ -0,0 +1,6 @@ +namespace PluginManager.Loaders; + +public class PluginHandler +{ + +} diff --git a/PluginManager/Loaders/PluginLoadResultData.cs b/PluginManager/Loaders/PluginLoadResultData.cs new file mode 100644 index 0000000..42c3795 --- /dev/null +++ b/PluginManager/Loaders/PluginLoadResultData.cs @@ -0,0 +1,22 @@ +using PluginManager.Others; + +namespace PluginManager.Loaders; + +public class PluginLoadResultData +{ + public string PluginName { get; init; } + public PluginType PluginType { get; init; } + public string? ErrorMessage { get; init; } + public bool IsSuccess { get; init; } + + public object? Plugin { get; init; } + + public PluginLoadResultData(string pluginName, PluginType pluginType, bool isSuccess, string? errorMessage = null, object plugin = null) + { + PluginName = pluginName; + PluginType = pluginType; + IsSuccess = isSuccess; + ErrorMessage = errorMessage; + Plugin = plugin; + } +} diff --git a/PluginManager/Loaders/PluginLoader.cs b/PluginManager/Loaders/PluginLoader.cs index 58e73ff..f82e375 100644 --- a/PluginManager/Loaders/PluginLoader.cs +++ b/PluginManager/Loaders/PluginLoader.cs @@ -1,8 +1,5 @@ -using System; using System.Collections.Generic; -using System.Reflection; using System.Threading.Tasks; -using Discord; using Discord.WebSocket; using PluginManager.Interfaces; using PluginManager.Others; @@ -11,173 +8,78 @@ namespace PluginManager.Loaders; public class PluginLoader { - public delegate void CMDLoaded(string name, string typeName, bool success, Exception? e = null); + internal readonly DiscordSocketClient _Client; - public delegate void EVELoaded(string name, string typeName, bool success, Exception? e = null); + public delegate void CommandLoaded(PluginLoadResultData resultData); - public delegate void SLSHLoaded(string name, string tyypename, bool success, Exception? e = null); + public delegate void EventLoaded(PluginLoadResultData resultData); - private const string pluginFolder = @"./Data/Plugins/"; + public delegate void SlashCommandLoaded(PluginLoadResultData resultData); - internal const string pluginExtension = "dll"; - private readonly DiscordSocketClient _client; + public CommandLoaded? OnCommandLoaded; + public EventLoaded? OnEventLoaded; + public SlashCommandLoaded? OnSlashCommandLoaded; - /// - /// Event that is fired when a is successfully loaded into commands list - /// - public CMDLoaded? onCMDLoad; + public static List? Commands; + public static List? Events; + public static List? SlashCommands; - /// - /// Event that is fired when a is successfully loaded into events list - /// - public EVELoaded? onEVELoad; - - /// - /// Event that is fired when a is successfully loaded into events list - /// - public SLSHLoaded? onSLSHLoad; - - /// - /// The Plugin Loader constructor - /// - /// The discord bot client where the plugins will pe attached to public PluginLoader(DiscordSocketClient discordSocketClient) { - _client = discordSocketClient; + _Client = discordSocketClient; } - - /// - /// A list of commands - /// - public static List? Commands { get; set; } - - /// - /// A list of commands - /// - public static List? Events { get; set; } - - /// - /// A list of commands - /// - public static List? SlashCommands { get; set; } - - public static int PluginsLoaded + public async Task LoadPlugins() { - get - { - var count = 0; - if (Commands is not null) - count += Commands.Count; - if (Events is not null) - count += Events.Count; - if (SlashCommands is not null) - count += SlashCommands.Count; - return count; - } - } - - /// - /// The main mathod that is called to load all events - /// - public async void LoadPlugins() - { - //Load all plugins Commands = new List(); Events = new List(); SlashCommands = new List(); - Config.Logger.Log("Starting plugin loader ... Client: " + _client.CurrentUser.Username, source: typeof(PluginLoader), type: LogType.INFO); + Config.Logger.Log("Loading plugins...", typeof(PluginLoader)); - var loader = new Loader("./Data/Plugins", "dll"); - loader.FileLoaded += args => Config.Logger.Log($"{args.PluginName} file Loaded", source: typeof(PluginLoader), type: LogType.INFO); - loader.PluginLoaded += Loader_PluginLoaded; - var res = loader.Load(); - Events = res.Item1; - Commands = res.Item2; - SlashCommands = res.Item3; + var loader = new Loader(Config.AppSettings["PluginFolder"], "dll"); + + loader.OnFileLoadedException += FileLoadedException; + loader.OnPluginLoaded += OnPluginLoaded; + + await loader.Load(); } - private async void Loader_PluginLoaded(LoaderArgs args) + private void FileLoadedException(FileLoaderResult result) { - switch (args.TypeName) + Config.Logger.Log(result.ErrorMessage, typeof(PluginLoader), LogType.ERROR); + } + + private void OnPluginLoaded(PluginLoadResultData result) + { + switch (result.PluginType) { - case "DBCommand": - onCMDLoad?.Invoke(((DBCommand)args.Plugin!).Command, args.TypeName!, args.IsLoaded, args.Exception); + case PluginType.COMMAND: + Commands.Add((DBCommand)result.Plugin); + OnCommandLoaded?.Invoke(result); break; - case "DBEvent": - try + case PluginType.EVENT: + if (this.TryStartEvent((DBEvent)result.Plugin)) { - if (args.IsLoaded) - ((DBEvent)args.Plugin!).Start(_client); - - onEVELoad?.Invoke(((DBEvent)args.Plugin!).Name, args.TypeName!, args.IsLoaded, args.Exception); - } - catch (Exception ex) - { - Config.Logger.Log(ex.Message, source: typeof(PluginLoader), type: LogType.ERROR); + Events.Add((DBEvent)result.Plugin); + OnEventLoaded?.Invoke(result); } break; - case "DBSlashCommand": - if (args.IsLoaded) + case PluginType.SLASH_COMMAND: + if (this.TryStartSlashCommand((DBSlashCommand)result.Plugin)) { - var slash = (DBSlashCommand)args.Plugin; - var builder = new SlashCommandBuilder(); - builder.WithName(slash.Name); - builder.WithDescription(slash.Description); - builder.WithDMPermission(slash.canUseDM); - builder.Options = slash.Options; - - onSLSHLoad?.Invoke(((DBSlashCommand)args.Plugin!).Name, args.TypeName, args.IsLoaded, - args.Exception - ); - await _client.CreateGlobalApplicationCommandAsync(builder.Build()); + SlashCommands.Add((DBSlashCommand)result.Plugin); + OnSlashCommandLoaded?.Invoke(result); } - + break; + case PluginType.UNKNOWN: + default: + Config.Logger.Log("Unknown plugin type", typeof(PluginLoader), LogType.ERROR); break; } } - public static async Task LoadPluginFromAssembly(Assembly asmb, DiscordSocketClient client) - { - var types = asmb.GetTypes(); - foreach (var type in types) - try - { - if (type.IsClass && typeof(DBEvent).IsAssignableFrom(type)) - { - var instance = (DBEvent)Activator.CreateInstance(type); - instance.Start(client); - Events.Add(instance); - Config.Logger.Log($"[EVENT] Loaded external {type.FullName}!", source: typeof(PluginLoader)); - } - else if (type.IsClass && typeof(DBCommand).IsAssignableFrom(type)) - { - var instance = (DBCommand)Activator.CreateInstance(type); - Commands.Add(instance); - Config.Logger.Log($"[CMD] Instance: {type.FullName} loaded !", source: typeof(PluginLoader)); - } - else if (type.IsClass && typeof(DBSlashCommand).IsAssignableFrom(type)) - { - var instance = (DBSlashCommand)Activator.CreateInstance(type); - var builder = new SlashCommandBuilder(); - builder.WithName(instance.Name); - builder.WithDescription(instance.Description); - builder.WithDMPermission(instance.canUseDM); - builder.Options = instance.Options; - await client.CreateGlobalApplicationCommandAsync(builder.Build()); - SlashCommands.Add(instance); - Config.Logger.Log($"[SLASH] Instance: {type.FullName} loaded !", source: typeof(PluginLoader)); - } - } - catch (Exception ex) - { - //Console.WriteLine(ex.Message); - Config.Logger.Log(ex.Message, source: typeof(PluginLoader), type: LogType.ERROR); - } - - } } diff --git a/PluginManager/Loaders/PluginLoaderExtensions.cs b/PluginManager/Loaders/PluginLoaderExtensions.cs new file mode 100644 index 0000000..01c99e4 --- /dev/null +++ b/PluginManager/Loaders/PluginLoaderExtensions.cs @@ -0,0 +1,54 @@ +using System; +using Discord; +using PluginManager.Interfaces; +using PluginManager.Others; + +namespace PluginManager.Loaders; + +internal static class PluginLoaderExtensions +{ + internal static bool TryStartEvent(this PluginLoader pluginLoader, DBEvent? dbEvent) + { + try + { + if (dbEvent is null) + { + throw new ArgumentNullException(nameof(dbEvent)); + } + + + dbEvent.Start(pluginLoader._Client); + return true; + } + catch (Exception e) + { + Config.Logger.Log($"Error starting event {dbEvent.Name}: {e.Message}", typeof(PluginLoader), LogType.ERROR); + return false; + } + } + + internal static bool TryStartSlashCommand(this PluginLoader pluginLoader, DBSlashCommand? dbSlashCommand) + { + try + { + if (dbSlashCommand is null) + { + throw new ArgumentNullException(nameof(dbSlashCommand)); + } + + var builder = new SlashCommandBuilder(); + builder.WithName(dbSlashCommand.Name); + builder.WithDescription(dbSlashCommand.Description); + builder.WithDMPermission(dbSlashCommand.canUseDM); + builder.Options = dbSlashCommand.Options; + + pluginLoader._Client.CreateGlobalApplicationCommandAsync(builder.Build()); + return true; + } + catch (Exception e) + { + Config.Logger.Log($"Error starting slash command {dbSlashCommand.Name}: {e.Message}", typeof(PluginLoader), LogType.ERROR); + return false; + } + } +} diff --git a/PluginManager/Online/Helpers/ApplicationVersion.cs b/PluginManager/Online/Helpers/ApplicationVersion.cs index 220bce7..89b66dc 100644 --- a/PluginManager/Online/Helpers/ApplicationVersion.cs +++ b/PluginManager/Online/Helpers/ApplicationVersion.cs @@ -2,7 +2,7 @@ using PluginManager.Interfaces.Updater; namespace PluginManager.Online.Helpers; -public class ApplicationVersion : Version +public class ApplicationVersion: Version { public ApplicationVersion(int major, int minor, int patch): base(major, minor, patch) @@ -11,6 +11,6 @@ public class ApplicationVersion : Version public ApplicationVersion(string versionAsString): base(versionAsString) { } - - + + } diff --git a/PluginManager/Online/Helpers/PluginVersion.cs b/PluginManager/Online/Helpers/PluginVersion.cs index b0bcf92..10751cb 100644 --- a/PluginManager/Online/Helpers/PluginVersion.cs +++ b/PluginManager/Online/Helpers/PluginVersion.cs @@ -3,7 +3,7 @@ using PluginManager.Interfaces.Updater; namespace PluginManager.Online.Helpers; -public class PluginVersion : Version +public class PluginVersion: Version { [JsonConstructor] public PluginVersion(int major, int minor, int patch): base(major, minor, patch) diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index 1a96985..b99f787 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -9,53 +9,54 @@ namespace PluginManager.Online; public class PluginsManager { - private static readonly string _DefaultBranch = "releases"; + private static readonly string _DefaultBranch = "releases"; private static readonly string _DefaultBaseUrl = "https://raw.githubusercontent.com/andreitdr/SethPlugins"; - + private static readonly string _DefaultPluginsLink = "PluginsList.json"; - - + + public string Branch { get; init; } public string BaseUrl { get; init; } - - + + private string PluginsLink => $"{BaseUrl}/{Branch}/{_DefaultPluginsLink}"; - + public PluginsManager(Uri baseUrl, string branch) { - this.BaseUrl = baseUrl.ToString(); - this.Branch = branch; + BaseUrl = baseUrl.ToString(); + Branch = branch; } - + public PluginsManager(string branch) { - this.BaseUrl = _DefaultBaseUrl; - this.Branch = branch; + BaseUrl = _DefaultBaseUrl; + Branch = branch; } - + public PluginsManager() { - this.BaseUrl = _DefaultBaseUrl; - this.Branch = _DefaultBranch; + BaseUrl = _DefaultBaseUrl; + Branch = _DefaultBranch; } public async Task> GetPluginsList() { - string jsonText = await ServerCom.GetAllTextFromUrl(PluginsLink); - List result = await JsonManager.ConvertFromJson>(jsonText); - - OSType currentOS = OperatingSystem.IsWindows() ? OSType.WINDOWS : OperatingSystem.IsLinux() ? OSType.LINUX : OSType.MACOSX; + var jsonText = await ServerCom.GetAllTextFromUrl(PluginsLink); + List result = await JsonManager.ConvertFromJson>(jsonText); + + var currentOS = OperatingSystem.IsWindows() ? OSType.WINDOWS : + OperatingSystem.IsLinux() ? OSType.LINUX : OSType.MACOSX; return result.FindAll(pl => (pl.SupportedOS & currentOS) != 0); } public async Task GetPluginDataByName(string pluginName) { - List plugins = await GetPluginsList(); - PluginOnlineInfo? result = plugins.Find(p => p.Name == pluginName); + List plugins = await GetPluginsList(); + var result = plugins.Find(p => p.Name == pluginName); return result; } - + } diff --git a/PluginManager/Online/ServerCom.cs b/PluginManager/Online/ServerCom.cs index 2b6170d..23b3778 100644 --- a/PluginManager/Online/ServerCom.cs +++ b/PluginManager/Online/ServerCom.cs @@ -21,7 +21,7 @@ public static class ServerCom var lines = response.Split('\n'); return lines.ToList(); } - + /// /// Get all text from a file async /// diff --git a/PluginManager/Others/ArchiveManager.cs b/PluginManager/Others/ArchiveManager.cs index bb2aefa..d58704b 100644 --- a/PluginManager/Others/ArchiveManager.cs +++ b/PluginManager/Others/ArchiveManager.cs @@ -13,7 +13,7 @@ public static class ArchiveManager public static void Initialize() { - if (IsInitialized) + if (IsInitialized) throw new Exception("ArchiveManager is already initialized"); if (!Config.AppSettings.ContainsKey("ArchiveFolder")) @@ -89,7 +89,7 @@ public static class ArchiveManager } catch (Exception ex) { - Config.Logger.Log(message: ex.Message, source: typeof(ArchiveManager), type: LogType.ERROR); // Write the error to a file + Config.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.ERROR); // Write the error to a file await Task.Delay(100); return await ReadFromPakAsync(fileName, archFile); } @@ -126,7 +126,7 @@ public static class ArchiveManager } catch (Exception ex) { - Config.Logger.Log(ex.Message, source: typeof(ArchiveManager), type: LogType.ERROR); + Config.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.ERROR); } currentZipFile++; @@ -158,7 +158,7 @@ public static class ArchiveManager } catch (Exception ex) { - Config.Logger.Log(ex.Message, source: typeof(ArchiveManager), type: LogType.ERROR); + Config.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.ERROR); } await Task.Delay(10); diff --git a/PluginManager/Others/DBCommandExecutingArguments.cs b/PluginManager/Others/DBCommandExecutingArguments.cs index 7ce0c81..a891709 100644 --- a/PluginManager/Others/DBCommandExecutingArguments.cs +++ b/PluginManager/Others/DBCommandExecutingArguments.cs @@ -17,26 +17,26 @@ public class DbCommandExecutingArguments public DbCommandExecutingArguments(SocketUserMessage? message, DiscordSocketClient client) { - this.context = new SocketCommandContext(client, message); - int pos = 0; + context = new SocketCommandContext(client, message); + var pos = 0; if (message.HasMentionPrefix(client.CurrentUser, ref pos)) { var mentionPrefix = "<@" + client.CurrentUser.Id + ">"; - this.cleanContent = message.Content.Substring(mentionPrefix.Length + 1); + cleanContent = message.Content.Substring(mentionPrefix.Length + 1); } else { - this.cleanContent = message.Content.Substring(Config.DiscordBot.botPrefix.Length); + cleanContent = message.Content.Substring(Config.DiscordBot.botPrefix.Length); } - var split = this.cleanContent.Split(' '); + var split = cleanContent.Split(' '); string[]? argsClean = null; if (split.Length > 1) argsClean = string.Join(' ', split, 1, split.Length - 1).Split(' '); - this.commandUsed = split[0]; - this.arguments = argsClean; + commandUsed = split[0]; + arguments = argsClean; } public SocketCommandContext context { get; init; } diff --git a/PluginManager/Others/Enums.cs b/PluginManager/Others/Enums.cs index 7802528..50fb888 100644 --- a/PluginManager/Others/Enums.cs +++ b/PluginManager/Others/Enums.cs @@ -32,10 +32,18 @@ public enum InternalActionRunType } [Flags] -public enum OSType : byte +public enum OSType: byte { - NONE = 0, + NONE = 0, WINDOWS = 1 << 0, - LINUX = 2 << 1, - MACOSX = 3 << 2, -} \ No newline at end of file + LINUX = 2 << 1, + MACOSX = 3 << 2 +} + +public enum PluginType +{ + UNKNOWN, + COMMAND, + EVENT, + SLASH_COMMAND +} diff --git a/PluginManager/Others/JsonManager.cs b/PluginManager/Others/JsonManager.cs index 11fc42b..9ad02a8 100644 --- a/PluginManager/Others/JsonManager.cs +++ b/PluginManager/Others/JsonManager.cs @@ -18,7 +18,11 @@ public class JsonManager public static async Task SaveToJsonFile(string file, T Data) { var str = new MemoryStream(); - await JsonSerializer.SerializeAsync(str, Data, typeof(T), new JsonSerializerOptions { WriteIndented = true }); + await JsonSerializer.SerializeAsync(str, Data, typeof(T), new JsonSerializerOptions + { + WriteIndented = true + } + ); await File.WriteAllBytesAsync(file, str.ToArray()); await str.FlushAsync(); str.Close(); diff --git a/PluginManager/Others/Logger/Log.cs b/PluginManager/Others/Logger/Log.cs index 1048004..164a4ab 100644 --- a/PluginManager/Others/Logger/Log.cs +++ b/PluginManager/Others/Logger/Log.cs @@ -43,9 +43,15 @@ public class Log: ILog ThrowTime = DateTime.Now; } - public static implicit operator Log(string message) => new(message); + public static implicit operator Log(string message) + { + return new Log(message); + } - public static implicit operator string(Log log) => $"[{log.ThrowTime}] {log.Message}"; + public static implicit operator string(Log log) + { + return $"[{log.ThrowTime}] {log.Message}"; + } public string AsLongString() { diff --git a/PluginManager/Others/SettingsDictionary.cs b/PluginManager/Others/SettingsDictionary.cs index e913c69..4c2717c 100644 --- a/PluginManager/Others/SettingsDictionary.cs +++ b/PluginManager/Others/SettingsDictionary.cs @@ -33,7 +33,7 @@ public class SettingsDictionary: IDictionary { if (File.Exists(_file)) { - string FileContent = File.ReadAllText(_file); + var FileContent = File.ReadAllText(_file); if (string.IsNullOrEmpty(FileContent)) File.WriteAllText(_file, "{}"); @@ -66,62 +66,62 @@ public class SettingsDictionary: IDictionary public void Add(KeyValuePair item) { - this._dictionary!.Add(item); + _dictionary!.Add(item); } public void Clear() { - this._dictionary!.Clear(); + _dictionary!.Clear(); } public bool Contains(KeyValuePair item) { - return this._dictionary!.Contains(item); + return _dictionary!.Contains(item); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { - this._dictionary!.CopyTo(array, arrayIndex); + _dictionary!.CopyTo(array, arrayIndex); } public bool Remove(KeyValuePair item) { - return this._dictionary!.Remove(item); + return _dictionary!.Remove(item); } public int Count => _dictionary!.Count; public bool IsReadOnly => _dictionary!.IsReadOnly; public void Add(TKey key, TValue value) { - this._dictionary!.Add(key, value); + _dictionary!.Add(key, value); } public bool ContainsKey(TKey key) { - return this._dictionary!.ContainsKey(key); + return _dictionary!.ContainsKey(key); } public bool Remove(TKey key) { - return this._dictionary!.Remove(key); + return _dictionary!.Remove(key); } public bool TryGetValue(TKey key, out TValue value) { - return this._dictionary!.TryGetValue(key, out value); + return _dictionary!.TryGetValue(key, out value); } public TValue this[TKey key] { get { - if (this._dictionary!.ContainsKey(key)) - if (this._dictionary[key] is string s && !string.IsNullOrEmpty(s) && !string.IsNullOrWhiteSpace(s)) - return this._dictionary[key]; + if (_dictionary!.ContainsKey(key)) + if (_dictionary[key] is string s && !string.IsNullOrEmpty(s) && !string.IsNullOrWhiteSpace(s)) + return _dictionary[key]; return default!; } - set => this._dictionary![key] = value; + set => _dictionary![key] = value; } public ICollection Keys => _dictionary!.Keys; diff --git a/PluginManager/Plugin/OnlineDependencyInfo.cs b/PluginManager/Plugin/OnlineDependencyInfo.cs index 73f65d4..6ac49e5 100644 --- a/PluginManager/Plugin/OnlineDependencyInfo.cs +++ b/PluginManager/Plugin/OnlineDependencyInfo.cs @@ -4,10 +4,10 @@ public class OnlineDependencyInfo { public string DownloadLink { get; private set; } public string DownloadLocation { get; private set; } - + public OnlineDependencyInfo(string downloadLink, string downloadLocation) { - DownloadLink = downloadLink; + DownloadLink = downloadLink; DownloadLocation = downloadLocation; } } diff --git a/PluginManager/Plugin/PluginInfo.cs b/PluginManager/Plugin/PluginInfo.cs index 8697aa2..b2221dc 100644 --- a/PluginManager/Plugin/PluginInfo.cs +++ b/PluginManager/Plugin/PluginInfo.cs @@ -6,17 +6,17 @@ namespace PluginManager.Plugin; public class PluginInfo { public string PluginName { get; private set; } - public IVersion PluginVersion { get; private set; } + public IVersion PluginVersion { get; private set; } public FileInfo FileData { get; private set; } - + public PluginInfo(string pluginName, IVersion pluginVersion) { - PluginName = pluginName; + PluginName = pluginName; PluginVersion = pluginVersion; - + FileData = new FileInfo($"{Config.AppSettings["PluginFolder"]}/{pluginName}.dll"); } - + public static PluginInfo FromOnlineInfo(PluginOnlineInfo onlineInfo) { return new PluginInfo(onlineInfo.Name, onlineInfo.Version); diff --git a/PluginManager/Plugin/PluginOnlineInfo.cs b/PluginManager/Plugin/PluginOnlineInfo.cs index b0c6c49..317beb3 100644 --- a/PluginManager/Plugin/PluginOnlineInfo.cs +++ b/PluginManager/Plugin/PluginOnlineInfo.cs @@ -15,35 +15,35 @@ public class PluginOnlineInfo public List Dependencies { get; private set; } public OSType SupportedOS { get; private set; } public bool HasDependencies { get; init; } - + [JsonConstructor] public PluginOnlineInfo(string name, PluginVersion version, string description, string downLoadLink, OSType supportedOS, List dependencies) { - Name = name; - Version = version; - Description = description; - DownLoadLink = downLoadLink; - SupportedOS = supportedOS; - Dependencies = dependencies; + Name = name; + Version = version; + Description = description; + DownLoadLink = downLoadLink; + SupportedOS = supportedOS; + Dependencies = dependencies; HasDependencies = dependencies.Count > 0; } - + public PluginOnlineInfo(string name, PluginVersion version, string description, string downLoadLink, OSType supportedOS) { - Name = name; - Version = version; - Description = description; - DownLoadLink = downLoadLink; - SupportedOS = supportedOS; - Dependencies = new List(); + Name = name; + Version = version; + Description = description; + DownLoadLink = downLoadLink; + SupportedOS = supportedOS; + Dependencies = new List(); HasDependencies = false; } - + public static async Task FromRawData(string jsonText) { return await JsonManager.ConvertFromJson(jsonText); } - + public override string ToString() { return $"{Name} - {Version} ({Description})"; diff --git a/PluginManager/PluginManager.csproj b/PluginManager/PluginManager.csproj index 1342f6a..10780fb 100644 --- a/PluginManager/PluginManager.csproj +++ b/PluginManager/PluginManager.csproj @@ -12,17 +12,17 @@ - + - + - + - - ..\..\..\.nuget\packages\spectre.console\0.47.0\lib\net7.0\Spectre.Console.dll - + + ..\..\..\.nuget\packages\spectre.console\0.47.0\lib\net7.0\Spectre.Console.dll + \ No newline at end of file diff --git a/PluginManager/UX/IOutputModel.cs b/PluginManager/UX/IOutputModel.cs index fdd9387..a202388 100644 --- a/PluginManager/UX/IOutputModel.cs +++ b/PluginManager/UX/IOutputModel.cs @@ -13,17 +13,19 @@ public enum MessageBoxButtons { YesNo, YesNoCancel, - ContinueCancel, + ContinueCancel } internal interface IOutputModel { - + internal Task ShowMessageBox(string title, string message, MessageBoxType type); + internal Task ShowInputBox(string title, string message); internal Task ShowMessageBox(string message); + internal Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning); - + internal Task ShowNotification(string title, string message, int timeout_seconds = 5); } diff --git a/PluginManager/UX/Linux/KDE.cs b/PluginManager/UX/Linux/KDE.cs index 50ebd00..42551a5 100644 --- a/PluginManager/UX/Linux/KDE.cs +++ b/PluginManager/UX/Linux/KDE.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; namespace PluginManager.UX.Linux; -internal class KDE : IOutputModel +internal class KDE: IOutputModel { internal string KdeDialogApplication { get; } = "kdialog"; @@ -11,15 +11,15 @@ internal class KDE : IOutputModel { var process = new Process(); process.StartInfo.FileName = KdeDialogApplication; - - string typeStr = type switch + + var typeStr = type switch { - MessageBoxType.Info => "msgbox", + MessageBoxType.Info => "msgbox", MessageBoxType.Warning => "sorry", - MessageBoxType.Error => "error", - _ => "info" + MessageBoxType.Error => "error", + _ => "info" }; - + process.StartInfo.Arguments = $"--title \"{title}\" --{typeStr} \"{message}\""; process.Start(); await process.WaitForExitAsync(); @@ -28,48 +28,48 @@ internal class KDE : IOutputModel public async Task ShowInputBox(string title, string message) { var process = new Process(); - process.StartInfo.FileName = KdeDialogApplication; - process.StartInfo.Arguments = $"--title \"{title}\" --inputbox \"{message}\""; + process.StartInfo.FileName = KdeDialogApplication; + process.StartInfo.Arguments = $"--title \"{title}\" --inputbox \"{message}\""; process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.RedirectStandardInput = true; + process.StartInfo.RedirectStandardInput = true; process.Start(); - + await process.WaitForExitAsync(); return await process.StandardOutput.ReadToEndAsync(); } - + public async Task ShowMessageBox(string message) { var process = new Process(); - process.StartInfo.FileName = KdeDialogApplication; + process.StartInfo.FileName = KdeDialogApplication; process.StartInfo.Arguments = $"--msgbox \"{message}\""; process.Start(); await process.WaitForExitAsync(); } - + public async Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning) { var process = new Process(); process.StartInfo.FileName = KdeDialogApplication; - - string buttonsStr = buttons switch + + var buttonsStr = buttons switch { - MessageBoxButtons.YesNo => "yesno", - MessageBoxButtons.YesNoCancel => "yesnocancel", + MessageBoxButtons.YesNo => "yesno", + MessageBoxButtons.YesNoCancel => "yesnocancel", MessageBoxButtons.ContinueCancel => "continuecancel", - _ => "yesno" + _ => "yesno" }; - string typeStr = isWarning ? "warning" : ""; + var typeStr = isWarning ? "warning" : ""; process.StartInfo.Arguments = $"--title \"{title}\" --{typeStr}{buttonsStr} \"{message}\""; process.Start(); await process.WaitForExitAsync(); return process.ExitCode; } - + public async Task ShowNotification(string title, string message, int timeout_seconds = 5) { var process = new Process(); - process.StartInfo.FileName = KdeDialogApplication; + process.StartInfo.FileName = KdeDialogApplication; process.StartInfo.Arguments = $"--title \"{title}\" --passivepopup \"{message}\" {timeout_seconds}"; process.Start(); await process.WaitForExitAsync(); diff --git a/PluginManager/UX/Other/Console.cs b/PluginManager/UX/Other/Console.cs index 803b1cd..23757fe 100644 --- a/PluginManager/UX/Other/Console.cs +++ b/PluginManager/UX/Other/Console.cs @@ -1,45 +1,43 @@ - using System.Threading.Tasks; using Spectre.Console; namespace PluginManager.UX.Other; - -internal class Console : IOutputModel +internal class Console: IOutputModel { public Task ShowMessageBox(string title, string message, MessageBoxType type) { AnsiConsole.Markup(title); AnsiConsole.Markup(message); - - + + return Task.CompletedTask; } public Task ShowInputBox(string title, string message) { AnsiConsole.MarkupLine(title); - - string input = AnsiConsole.Ask(message); - + + var input = AnsiConsole.Ask(message); + return Task.FromResult(input); } - + public Task ShowMessageBox(string message) { AnsiConsole.MarkupLine(message); return Task.CompletedTask; } - - public Task ShowMessageBox(string title, string message,MessageBoxButtons buttons, bool isWarning) + + public Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning) { AnsiConsole.MarkupLine(title); AnsiConsole.MarkupLine(message); - + return Task.FromResult(0); } - + public Task ShowNotification(string title, string message, int timeout_seconds = 5) { return Task.CompletedTask; diff --git a/PluginManager/UX/UxHandler.cs b/PluginManager/UX/UxHandler.cs index 76830ed..72372e6 100644 --- a/PluginManager/UX/UxHandler.cs +++ b/PluginManager/UX/UxHandler.cs @@ -2,10 +2,10 @@ using System.Threading.Tasks; namespace PluginManager.UX; -public static class UxHandler +public static class UxHandler { private static IOutputModel? _model; - + public static void Init() { _model = Config.AppSettings["UI"] switch @@ -14,32 +14,32 @@ public static class UxHandler "CONSOLE" => new Other.Console(), _ => null }; - + } - + public static async Task ShowMessageBox(string title, string message, MessageBoxType type = MessageBoxType.Info) { await _model.ShowMessageBox(title, message, type); } - + public static async Task ShowInputBox(string title, string message) { return await _model.ShowInputBox(title, message); } - + public static async Task ShowMessageBox(string message) { await _model.ShowMessageBox(message); } - + public static async Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning) { return await _model.ShowMessageBox(title, message, buttons, isWarning); } - + public static async Task ShowNotification(string title, string message, int timeout_seconds = 5) { await _model.ShowNotification(title, message, timeout_seconds); } - + } From 8c06df9110f71964cca258460fdc266f76057c49 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Tue, 27 Feb 2024 11:09:28 +0200 Subject: [PATCH 15/37] Removed help app --- DatabaseCreator/DatabaseCreator.csproj | 14 ------ DatabaseCreator/Program.cs | 70 -------------------------- SethDiscordBot.sln | 6 --- 3 files changed, 90 deletions(-) delete mode 100644 DatabaseCreator/DatabaseCreator.csproj delete mode 100644 DatabaseCreator/Program.cs diff --git a/DatabaseCreator/DatabaseCreator.csproj b/DatabaseCreator/DatabaseCreator.csproj deleted file mode 100644 index 438539f..0000000 --- a/DatabaseCreator/DatabaseCreator.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - Exe - net8.0 - enable - enable - - - - - - - diff --git a/DatabaseCreator/Program.cs b/DatabaseCreator/Program.cs deleted file mode 100644 index 1d55a8d..0000000 --- a/DatabaseCreator/Program.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Diagnostics; -using PluginManager; -using PluginManager.Online.Helpers; -using PluginManager.Others; -using PluginManager.Plugin; - -if (args.Length == 1) -{ - var result = await JsonManager.ConvertFromJson(args[0]); - // print all rows - Console.WriteLine($"Name: {result.Name}"); - Console.WriteLine($"Version: {result.Version.ToShortString()}"); - Console.WriteLine($"Description: {result.Description}"); - Console.WriteLine($"Download link: {result.DownLoadLink}"); - Console.WriteLine( - $"Supported OS: {((result.SupportedOS & OSType.WINDOWS) != 0 ? "Windows" : "")} {((result.SupportedOS & OSType.LINUX) != 0 ? "Linux" : "")} {((result.SupportedOS & OSType.MACOSX) != 0 ? "MacOSX" : "")}" - ); - Console.WriteLine($"Has dependencies: {result.HasDependencies}"); - Console.WriteLine($"Dependencies: {result.Dependencies.Count}"); - - return; -} - - -var _levelingSystem = new PluginOnlineInfo( - "Leveling System", - new PluginVersion(0, 0, 1), - "A simple leveling system for your server", - "https://github.com/andreitdr/SethPlugins/raw/releases/LevelingSystem/LevelingSystem.dll", - OSType.WINDOWS | OSType.LINUX -); - -var _musicPlayerWindows = new PluginOnlineInfo( - "Music Player (Windows)", new PluginVersion(0, 0, 1), - "A simple music player for your server", - "https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/MusicPlayer.dll", - OSType.WINDOWS, - [ - new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/windows/ffmpeg.exe", "ffmpeg.exe"), - new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/windows/libopus.dll", "libopus.dll"), - new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/windows/libsodium.dll", "libsodium.dll"), - new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/windows/opus.dll", "opus.dll"), - new OnlineDependencyInfo("https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_x86.exe", "yt-dlp.exe") - ] -); - -var _musicPlayerLINUX = new PluginOnlineInfo( - "Music Player (Linux)", new PluginVersion(0, 0, 1), - "A simple music player for your server", - "https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/MusicPlayer.dll", - OSType.LINUX, - [ - new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/linux/ffmpeg", "ffmpeg"), - new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/linux/libopus.so", "libopus.so"), - new OnlineDependencyInfo("https://github.com/andreitdr/SethPlugins/raw/releases/MusicPlayer/libs/linux/libsodium.so", "libsodium.so"), - new OnlineDependencyInfo("https://github.com/yt-dlp/yt-dlp/releases/download/2023.10.13/yt-dlp", "yt-dlp") - ] -); - -List plugins = -[ - _levelingSystem, - _musicPlayerWindows, - _musicPlayerLINUX -]; - -Directory.CreateDirectory("output"); -await JsonManager.SaveToJsonFile("./output/PluginsList.json", plugins); - -Process.Start("notepad.exe", "./output/PluginsList.json"); diff --git a/SethDiscordBot.sln b/SethDiscordBot.sln index f855e4a..a8d9f43 100644 --- a/SethDiscordBot.sln +++ b/SethDiscordBot.sln @@ -15,8 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LevelingSystem", "..\SethPl EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PythonCompatibilityLayer", "..\SethPlugins\PythonCompatibilityLayer\PythonCompatibilityLayer.csproj", "{81ED4953-13E5-4950-96A8-8CEF5FD59559}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseCreator", "DatabaseCreator\DatabaseCreator.csproj", "{D9BC7451-74A4-4FB3-86CC-A59F6DB889B4}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -43,10 +41,6 @@ Global {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Debug|Any CPU.Build.0 = Debug|Any CPU {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Release|Any CPU.ActiveCfg = Release|Any CPU {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Release|Any CPU.Build.0 = Release|Any CPU - {D9BC7451-74A4-4FB3-86CC-A59F6DB889B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D9BC7451-74A4-4FB3-86CC-A59F6DB889B4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D9BC7451-74A4-4FB3-86CC-A59F6DB889B4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D9BC7451-74A4-4FB3-86CC-A59F6DB889B4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From a2179787b9bab0d660c8430230a02e58b40f581f Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Tue, 27 Feb 2024 19:42:59 +0200 Subject: [PATCH 16/37] Plugin Updater --- DiscordBot/Bot/Actions/Extra/PluginMethods.cs | 9 +-- DiscordBot/Bot/Actions/Plugin.cs | 12 +--- PluginManager/Config.cs | 17 +++++- PluginManager/Loaders/Loader.cs | 2 +- PluginManager/Loaders/PluginLoader.cs | 4 +- PluginManager/Online/PluginsManager.cs | 39 +++++++++++++ PluginManager/Plugin/PluginInfo.cs | 9 +-- PluginManager/PluginManager.csproj | 3 + .../Updater/Plugins/PluginUpdater.cs | 56 +++++++++++++++++++ 9 files changed, 127 insertions(+), 24 deletions(-) create mode 100644 PluginManager/Updater/Plugins/PluginUpdater.cs diff --git a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs index 67d16b3..fbf6ad2 100644 --- a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs +++ b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; -using System.Threading; using System.Threading.Tasks; using DiscordBot.Utilities; using PluginManager; @@ -10,7 +7,6 @@ using PluginManager.Interfaces; using PluginManager.Loaders; using PluginManager.Online; using PluginManager.Others; -using PluginManager.Plugin; using Spectre.Console; namespace DiscordBot.Bot.Actions.Extra; @@ -75,6 +71,7 @@ internal static class PluginMethods if (!pluginData.HasDependencies) { + await manager.AppendPluginToDatabase(pluginName, pluginData.Version); Console.WriteLine("Finished installing " + pluginName + " successfully"); await RefreshPlugins(false); return; @@ -129,7 +126,7 @@ internal static class PluginMethods } ); - + await manager.AppendPluginToDatabase(pluginName, pluginData.Version); await RefreshPlugins(false); } @@ -197,7 +194,7 @@ internal static class PluginMethods Console.ForegroundColor = cc; }; - await loader.LoadPlugins(); + await loader. LoadPlugins(); Console.ForegroundColor = cc; return true; } diff --git a/DiscordBot/Bot/Actions/Plugin.cs b/DiscordBot/Bot/Actions/Plugin.cs index fc3a304..59ffc8b 100644 --- a/DiscordBot/Bot/Actions/Plugin.cs +++ b/DiscordBot/Bot/Actions/Plugin.cs @@ -34,14 +34,6 @@ public class Plugin: ICommandAction return; } - var manager = -#if !DEBUG - new PluginsManager("releases"); -#else - // new PluginsManager("tests"); - new PluginsManager("releases"); -#endif - switch (args[0]) { case "refresh": @@ -49,7 +41,7 @@ public class Plugin: ICommandAction break; case "list": - await PluginMethods.List(manager); + await PluginMethods.List(Config.PluginsManager); break; case "load": if (pluginsLoaded) @@ -81,7 +73,7 @@ public class Plugin: ICommandAction } } - await PluginMethods.DownloadPlugin(manager, pluginName); + await PluginMethods.DownloadPlugin(Config.PluginsManager, pluginName); break; } } diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index 8ebafa3..722f83e 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -1,9 +1,12 @@ using System; +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using PluginManager.Bot; +using PluginManager.Online; using PluginManager.Others; using PluginManager.Others.Logger; +using PluginManager.Plugin; using OperatingSystem = System.OperatingSystem; namespace PluginManager; @@ -14,6 +17,8 @@ public class Config public static Logger Logger; public static SettingsDictionary AppSettings; + public static PluginsManager PluginsManager; + internal static Boot? DiscordBotClient; public static Boot? DiscordBot => DiscordBotClient; @@ -32,6 +37,14 @@ public class Config AppSettings["LogFolder"] = "./Data/Logs"; AppSettings["PluginFolder"] = "./Data/Plugins"; AppSettings["ArchiveFolder"] = "./Data/Archives"; + + AppSettings["PluginDatabase"] = "./Data/Resources/plugins.json"; + + if (!File.Exists(AppSettings["PluginDatabase"])) + { + List plugins = new(); + await JsonManager.SaveToJsonFile(AppSettings["PluginDatabase"], plugins); + } if (OperatingSystem.IsLinux()) { @@ -54,10 +67,12 @@ public class Config UX.UxHandler.Init(); _isLoaded = true; + PluginsManager = new PluginsManager("releases"); + + await PluginsManager.CheckForUpdates(); Logger.Log("Config initialized", typeof(Config)); - } } diff --git a/PluginManager/Loaders/Loader.cs b/PluginManager/Loaders/Loader.cs index ef9bc80..c6ee02d 100644 --- a/PluginManager/Loaders/Loader.cs +++ b/PluginManager/Loaders/Loader.cs @@ -43,7 +43,7 @@ internal class Loader } catch { - OnFileLoadedException?.Invoke(new FileLoaderResult(file, "Failed to load file")); + OnFileLoadedException?.Invoke(new FileLoaderResult(file, $"Failed to load file {file}")); } } diff --git a/PluginManager/Loaders/PluginLoader.cs b/PluginManager/Loaders/PluginLoader.cs index f82e375..2e0a0e1 100644 --- a/PluginManager/Loaders/PluginLoader.cs +++ b/PluginManager/Loaders/PluginLoader.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Discord.WebSocket; using PluginManager.Interfaces; using PluginManager.Others; +using PluginManager.Updater.Plugins; namespace PluginManager.Loaders; @@ -31,13 +32,12 @@ public class PluginLoader public async Task LoadPlugins() { - Commands = new List(); Events = new List(); SlashCommands = new List(); Config.Logger.Log("Loading plugins...", typeof(PluginLoader)); - + var loader = new Loader(Config.AppSettings["PluginFolder"], "dll"); loader.OnFileLoadedException += FileLoadedException; diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index b99f787..e531e77 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading.Tasks; using PluginManager.Online.Helpers; using PluginManager.Others; using PluginManager.Plugin; +using PluginManager.Updater.Plugins; namespace PluginManager.Online; @@ -57,6 +59,43 @@ public class PluginsManager return result; } + + public async Task RemovePluginFromDatabase(string pluginName) + { + List installedPlugins = await JsonManager.ConvertFromJson>(await File.ReadAllTextAsync(Config.AppSettings["PluginDatabase"])); + + installedPlugins.RemoveAll(p => p.PluginName == pluginName); + await JsonManager.SaveToJsonFile( Config.AppSettings["PluginDatabase"],installedPlugins); + } + public async Task AppendPluginToDatabase(string pluginName, PluginVersion version) + { + List installedPlugins = await JsonManager.ConvertFromJson>(await File.ReadAllTextAsync(Config.AppSettings["PluginDatabase"])); + + installedPlugins.Add(new PluginInfo(pluginName, version)); + await JsonManager.SaveToJsonFile( Config.AppSettings["PluginDatabase"],installedPlugins); + } + + public async Task> GetInstalledPlugins() + { + return await JsonManager.ConvertFromJson>(await File.ReadAllTextAsync(Config.AppSettings["PluginDatabase"])); + } + + public async Task CheckForUpdates() + { + var pluginUpdater = new PluginUpdater(this); + + List installedPlugins = await GetInstalledPlugins(); + + foreach (var plugin in installedPlugins) + { + if (await pluginUpdater.HasUpdate(plugin.PluginName)) + { + Console.WriteLine($"Updating {plugin.PluginName}..."); + await pluginUpdater.UpdatePlugin(plugin.PluginName); + } + } + } + } diff --git a/PluginManager/Plugin/PluginInfo.cs b/PluginManager/Plugin/PluginInfo.cs index b2221dc..4280e3a 100644 --- a/PluginManager/Plugin/PluginInfo.cs +++ b/PluginManager/Plugin/PluginInfo.cs @@ -1,20 +1,21 @@ using System.IO; using PluginManager.Interfaces.Updater; +using PluginManager.Online.Helpers; namespace PluginManager.Plugin; public class PluginInfo { public string PluginName { get; private set; } - public IVersion PluginVersion { get; private set; } - public FileInfo FileData { get; private set; } + public PluginVersion PluginVersion { get; private set; } + public string FilePath { get; private set; } - public PluginInfo(string pluginName, IVersion pluginVersion) + public PluginInfo(string pluginName, PluginVersion pluginVersion) { PluginName = pluginName; PluginVersion = pluginVersion; - FileData = new FileInfo($"{Config.AppSettings["PluginFolder"]}/{pluginName}.dll"); + FilePath = $"{Config.AppSettings["PluginFolder"]}/{pluginName}.dll"; } public static PluginInfo FromOnlineInfo(PluginOnlineInfo onlineInfo) diff --git a/PluginManager/PluginManager.csproj b/PluginManager/PluginManager.csproj index 10780fb..12af348 100644 --- a/PluginManager/PluginManager.csproj +++ b/PluginManager/PluginManager.csproj @@ -25,4 +25,7 @@ ..\..\..\.nuget\packages\spectre.console\0.47.0\lib\net7.0\Spectre.Console.dll + + + \ No newline at end of file diff --git a/PluginManager/Updater/Plugins/PluginUpdater.cs b/PluginManager/Updater/Plugins/PluginUpdater.cs new file mode 100644 index 0000000..5b23c02 --- /dev/null +++ b/PluginManager/Updater/Plugins/PluginUpdater.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using PluginManager.Online; +using PluginManager.Plugin; + +namespace PluginManager.Updater.Plugins; + +public class PluginUpdater +{ + private readonly PluginsManager _PluginManager; + + public PluginUpdater(PluginsManager pluginManager) + { + _PluginManager = pluginManager; + } + + public async Task GetPluginInfo(string pluginName) + { + var result = await _PluginManager.GetPluginDataByName(pluginName); + return result; + } + + public async Task GetLocalPluginInfo(string pluginName) + { + string pluginsDatabase = File.ReadAllText(Config.AppSettings["PluginDatabase"]); + List installedPlugins = await JsonManager.ConvertFromJson>(pluginsDatabase); + + var result = installedPlugins.Find(p => p.PluginName == pluginName); + + return result; + } + + public async Task UpdatePlugin(string pluginName, IProgress? progressMeter = null) + { + PluginOnlineInfo pluginInfo = await GetPluginInfo(pluginName); + await ServerCom.DownloadFileAsync(pluginInfo.DownLoadLink, $"{Config.AppSettings["PluginFolder"]}/{pluginName}.dll", progressMeter); + + foreach(OnlineDependencyInfo dependency in pluginInfo.Dependencies) + await ServerCom.DownloadFileAsync(dependency.DownloadLocation, dependency.DownloadLocation, progressMeter); + + await _PluginManager.RemovePluginFromDatabase(pluginName); + await _PluginManager.AppendPluginToDatabase(pluginName, pluginInfo.Version); + } + + public async Task HasUpdate(string pluginName) + { + var localPluginInfo = await GetLocalPluginInfo(pluginName); + var pluginInfo = await GetPluginInfo(pluginName); + + return pluginInfo.Version.IsNewerThan(localPluginInfo.PluginVersion); + + } + +} From 3c3c6a13018f8cf84ae06ab200caec024c2ab049 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Tue, 27 Feb 2024 22:20:25 +0200 Subject: [PATCH 17/37] Updated --- DiscordBot/Program.cs | 3 +-- PluginManager/Config.cs | 4 +++- .../Online/Helpers/ApplicationVersion.cs | 16 ---------------- PluginManager/Others/ArchiveManager.cs | 18 ++++++++++++++++++ PluginManager/Others/Logger/Logger.cs | 2 ++ 5 files changed, 24 insertions(+), 19 deletions(-) delete mode 100644 PluginManager/Online/Helpers/ApplicationVersion.cs diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 0926fa0..1971a6a 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; @@ -94,7 +93,7 @@ public class Program await StartNoGui(); try { - internalActionManager = new InternalActionManager("./Data/Plugins", "*.dll"); + internalActionManager = new InternalActionManager(AppSettings["PluginFolder"], "*.dll"); NoGUI(); } catch (IOException ex) diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index 722f83e..0afbed5 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -40,6 +40,8 @@ public class Config AppSettings["PluginDatabase"] = "./Data/Resources/plugins.json"; + ArchiveManager.Initialize(); + if (!File.Exists(AppSettings["PluginDatabase"])) { List plugins = new(); @@ -62,7 +64,7 @@ public class Config AppSettings["LogFolder"] + $"/{DateTime.Today.ToShortDateString().Replace("/", "")}.log" ); - ArchiveManager.Initialize(); + UX.UxHandler.Init(); _isLoaded = true; diff --git a/PluginManager/Online/Helpers/ApplicationVersion.cs b/PluginManager/Online/Helpers/ApplicationVersion.cs deleted file mode 100644 index 89b66dc..0000000 --- a/PluginManager/Online/Helpers/ApplicationVersion.cs +++ /dev/null @@ -1,16 +0,0 @@ -using PluginManager.Interfaces.Updater; - -namespace PluginManager.Online.Helpers; - -public class ApplicationVersion: Version -{ - - public ApplicationVersion(int major, int minor, int patch): base(major, minor, patch) - { - } - public ApplicationVersion(string versionAsString): base(versionAsString) - { - } - - -} diff --git a/PluginManager/Others/ArchiveManager.cs b/PluginManager/Others/ArchiveManager.cs index d58704b..db62acc 100644 --- a/PluginManager/Others/ArchiveManager.cs +++ b/PluginManager/Others/ArchiveManager.cs @@ -23,6 +23,24 @@ public static class ArchiveManager IsInitialized = true; } + + + public static async Task CreateFromFile(string file, string folder) + { + if(!IsInitialized) throw new Exception("ArchiveManager is not initialized"); + + if (!Directory.Exists(folder)) + Directory.CreateDirectory(folder); + + var archiveName = folder + Path.GetFileNameWithoutExtension(file) + ".zip"; + if (File.Exists(archiveName)) + File.Delete(archiveName); + + using(ZipArchive archive = ZipFile.Open(archiveName, ZipArchiveMode.Create)) + { + archive.CreateEntryFromFile(file, Path.GetFileName(file)); + } + } /// /// Read a file from a zip archive. The output is a byte array diff --git a/PluginManager/Others/Logger/Logger.cs b/PluginManager/Others/Logger/Logger.cs index b4f543b..de9ab64 100644 --- a/PluginManager/Others/Logger/Logger.cs +++ b/PluginManager/Others/Logger/Logger.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; using PluginManager.Interfaces.Logger; @@ -31,6 +32,7 @@ public sealed class Logger: ILogger IsEnabled = true; LowestLogLevel = lowestLogLevel; OutputFile = null; + } public event EventHandler? OnLog; From fd9cd49844283ec7e76cd58f45b1d2de0d1195f6 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Wed, 28 Feb 2024 13:57:12 +0200 Subject: [PATCH 18/37] Deleting plugins is now available --- DiscordBot/Bot/Actions/Extra/PluginMethods.cs | 5 +- DiscordBot/Bot/Actions/Plugin.cs | 7 ++ DiscordBot/Entry.cs | 5 +- DiscordBot/Installer.cs | 13 ++-- DiscordBot/Program.cs | 7 -- PluginManager/Bot/Boot.cs | 5 +- PluginManager/Config.cs | 27 ++----- PluginManager/Online/PluginsManager.cs | 43 ++++++++++- .../Others/Actions/InternalActionsManager.cs | 26 ++----- PluginManager/Others/ArchiveManager.cs | 8 +- PluginManager/Plugin/PluginInfo.cs | 24 ++++-- PluginManager/PluginManager.csproj | 57 +++++++------- PluginManager/UX/IOutputModel.cs | 31 -------- PluginManager/UX/Linux/KDE.cs | 77 ------------------- PluginManager/UX/Other/Console.cs | 45 ----------- PluginManager/UX/UxHandler.cs | 45 ----------- .../Updater/Plugins/PluginUpdater.cs | 3 +- 17 files changed, 128 insertions(+), 300 deletions(-) delete mode 100644 PluginManager/UX/IOutputModel.cs delete mode 100644 PluginManager/UX/Linux/KDE.cs delete mode 100644 PluginManager/UX/Other/Console.cs delete mode 100644 PluginManager/UX/UxHandler.cs diff --git a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs index fbf6ad2..98c6b12 100644 --- a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs +++ b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using DiscordBot.Utilities; using PluginManager; @@ -71,7 +72,7 @@ internal static class PluginMethods if (!pluginData.HasDependencies) { - await manager.AppendPluginToDatabase(pluginName, pluginData.Version); + await manager.AppendPluginToDatabase(new PluginManager.Plugin.PluginInfo(pluginName, pluginData.Version, [])); Console.WriteLine("Finished installing " + pluginName + " successfully"); await RefreshPlugins(false); return; @@ -126,7 +127,7 @@ internal static class PluginMethods } ); - await manager.AppendPluginToDatabase(pluginName, pluginData.Version); + await manager.AppendPluginToDatabase(new PluginManager.Plugin.PluginInfo(pluginName, pluginData.Version, pluginData.Dependencies.Select(sep => sep.DownloadLocation).ToList())); await RefreshPlugins(false); } diff --git a/DiscordBot/Bot/Actions/Plugin.cs b/DiscordBot/Bot/Actions/Plugin.cs index 59ffc8b..ea2515c 100644 --- a/DiscordBot/Bot/Actions/Plugin.cs +++ b/DiscordBot/Bot/Actions/Plugin.cs @@ -40,6 +40,13 @@ public class Plugin: ICommandAction await PluginMethods.RefreshPlugins(true); break; + case "uninstall": + string plugName = string.Join(' ', args, 1, args.Length-1); + bool result = await Config.PluginsManager.MarkPluginToUninstall(plugName); + if(result) + Console.WriteLine($"Marked to uninstall plugin {plugName}. Please restart the bot"); + break; + case "list": await PluginMethods.List(Config.PluginsManager); break; diff --git a/DiscordBot/Entry.cs b/DiscordBot/Entry.cs index b9251b1..ede5e0e 100644 --- a/DiscordBot/Entry.cs +++ b/DiscordBot/Entry.cs @@ -1,9 +1,6 @@ using System; using System.IO; using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using PluginManager.UX; namespace DiscordBot; @@ -13,7 +10,7 @@ public static class Entry public static void Main(string[] args) { #if DEBUG - if (args.Length == 1 && args[0] == "/purge_plugins") + if (args.Length == 1 && args[0] == "/purge_plugins" ) { foreach (var plugin in Directory.GetFiles("./Data/Plugins", "*.dll", SearchOption.AllDirectories)) { diff --git a/DiscordBot/Installer.cs b/DiscordBot/Installer.cs index 9cd5f92..3f51ad9 100644 --- a/DiscordBot/Installer.cs +++ b/DiscordBot/Installer.cs @@ -1,7 +1,7 @@ using System; using PluginManager; -using Spectre.Console; using System.Threading.Tasks; +using Spectre.Console; namespace DiscordBot; @@ -9,15 +9,16 @@ public static class Installer { public static async Task GenerateStartupConfig() { - var token = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the bot token:"); - var botPrefix = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the bot prefix:"); - var serverId = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the Server ID:"); + var token = AnsiConsole.Ask("[green]Token:[/]"); + var botPrefix = AnsiConsole.Ask("[yellow]Prefix:[/]"); + var serverId = AnsiConsole.Ask("[deeppink1]Server ID:[/]"); - if (string.IsNullOrWhiteSpace(serverId)) serverId = "NULL"; + if (string.IsNullOrWhiteSpace(serverId)) serverId = string.Empty; if (string.IsNullOrWhiteSpace(token) || string.IsNullOrWhiteSpace(botPrefix)) { - await PluginManager.UX.UxHandler.ShowMessageBox("SethBot", "Invalid token or prefix !", PluginManager.UX.MessageBoxType.Error); + AnsiConsole.MarkupLine("Invalid token or prefix !"); + Environment.Exit(-20); } diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 1971a6a..abf8f01 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -7,7 +7,6 @@ using DiscordBot.Utilities; using PluginManager.Bot; using PluginManager.Others; using PluginManager.Others.Actions; -using PluginManager.UX; using Spectre.Console; using static PluginManager.Config; @@ -100,11 +99,6 @@ public class Program { if (ex.Message == "No process is on the other end of the pipe." || (uint)ex.HResult == 0x800700E9) { - UxHandler.ShowMessageBox("SethBot", "An error occured while closing the bot last time. Please consider closing the bot using the &rexit&c method !\n" + - "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !", MessageBoxType.Error - ).Wait(); - - Logger.Log("An error occured while closing the bot last time. Please consider closing the bot using the &rexit&c method !\n" + "There is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !", typeof(Program), LogType.ERROR @@ -130,7 +124,6 @@ public class Program if (logMessage.Message.Contains('[')) { - // If the message contains a tag, just print it as it is. No need to format it Console.WriteLine(logMessage.Message); return; } diff --git a/PluginManager/Bot/Boot.cs b/PluginManager/Bot/Boot.cs index df3c07c..1e706a8 100644 --- a/PluginManager/Bot/Boot.cs +++ b/PluginManager/Bot/Boot.cs @@ -4,7 +4,7 @@ using Discord; using Discord.Commands; using Discord.WebSocket; using PluginManager.Others; -using PluginManager.UX; + namespace PluginManager.Bot; @@ -91,6 +91,7 @@ public class Boot while (!isReady) ; } + private void CommonTasks() { if (client == null) return; @@ -122,7 +123,7 @@ public class Boot private Task Ready() { isReady = true; - UxHandler.ShowNotification("SethBot", "Seth Discord Bot is now up and running !").Wait(); + // UxHandler.ShowNotification("SethBot", "Seth Discord Bot is now up and running !").Wait(); return Task.CompletedTask; } diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index 0afbed5..87eaf72 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -7,15 +7,14 @@ using PluginManager.Online; using PluginManager.Others; using PluginManager.Others.Logger; using PluginManager.Plugin; -using OperatingSystem = System.OperatingSystem; namespace PluginManager; public class Config { - private static bool _isLoaded; - public static Logger Logger; - public static SettingsDictionary AppSettings; + private static bool _isLoaded; + public static Logger Logger; + public static SettingsDictionary AppSettings; public static PluginsManager PluginsManager; @@ -48,29 +47,15 @@ public class Config await JsonManager.SaveToJsonFile(AppSettings["PluginDatabase"], plugins); } - if (OperatingSystem.IsLinux()) - { - var windowManager = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP"); - AppSettings["UI"] = windowManager switch - { - "KDE" => "KDE", - "GNOME" => "GNOME", - _ => "CONSOLE" - }; - } - else AppSettings["UI"] = "CONSOLE"; - - Logger = new Logger(false, true, - AppSettings["LogFolder"] + $"/{DateTime.Today.ToShortDateString().Replace("/", "")}.log" - ); + Logger = new Logger(false, true, AppSettings["LogFolder"] + $"/{DateTime.Today.ToShortDateString().Replace("/", "")}.log"); - - UX.UxHandler.Init(); _isLoaded = true; PluginsManager = new PluginsManager("releases"); + await PluginsManager.UninstallMarkedPlugins(); + await PluginsManager.CheckForUpdates(); Logger.Log("Config initialized", typeof(Config)); diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index e531e77..e303774 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.IO; +using System.Linq; using System.Threading.Tasks; using PluginManager.Online.Helpers; using PluginManager.Others; @@ -68,11 +70,11 @@ public class PluginsManager await JsonManager.SaveToJsonFile( Config.AppSettings["PluginDatabase"],installedPlugins); } - public async Task AppendPluginToDatabase(string pluginName, PluginVersion version) + public async Task AppendPluginToDatabase(PluginInfo pluginData) { List installedPlugins = await JsonManager.ConvertFromJson>(await File.ReadAllTextAsync(Config.AppSettings["PluginDatabase"])); - installedPlugins.Add(new PluginInfo(pluginName, version)); + installedPlugins.Add(pluginData); await JsonManager.SaveToJsonFile( Config.AppSettings["PluginDatabase"],installedPlugins); } @@ -96,6 +98,43 @@ public class PluginsManager } } } + + public async Task MarkPluginToUninstall(string pluginName) + { + List installedPlugins = await GetInstalledPlugins(); + PluginInfo? info = installedPlugins.Find(info => info.PluginName == pluginName); + + if(info == null) + return false; + + await RemovePluginFromDatabase(pluginName); + info.IsMarkedToUninstall = true; + await AppendPluginToDatabase(info); + + return true; + + } + + public async Task UninstallMarkedPlugins() + { + List installedPlugins = await GetInstalledPlugins(); + foreach(PluginInfo plugin in installedPlugins) + { + if(!plugin.IsMarkedToUninstall) continue; + + await UninstallPlugin(plugin); + } + } + + private async Task UninstallPlugin(PluginInfo pluginInfo) + { + File.Delete(pluginInfo.FilePath); + + foreach(string dependency in pluginInfo.ListOfDependancies) + File.Delete(dependency); + + await RemovePluginFromDatabase(pluginInfo.PluginName); + } } diff --git a/PluginManager/Others/Actions/InternalActionsManager.cs b/PluginManager/Others/Actions/InternalActionsManager.cs index 8c8563b..e752e94 100644 --- a/PluginManager/Others/Actions/InternalActionsManager.cs +++ b/PluginManager/Others/Actions/InternalActionsManager.cs @@ -18,13 +18,12 @@ public class InternalActionManager public async Task Initialize() { - //loader.ActionLoadedEvent += OnActionLoaded; var m_actions = await loader.Load(); - if (m_actions == null) return; + if (m_actions == null) + return; foreach (var action in m_actions) - { Actions.TryAdd(action.ActionName, action); - } + } public async Task Refresh() @@ -33,34 +32,23 @@ public class InternalActionManager await Initialize(); } - // private void OnActionLoaded(string name, string typeName, bool success, Exception? e) - // { - // if (!success) - // { - // Config.Logger.Error(e); - // return; - // } - // - // Config.Logger.Log($"Action {name} loaded successfully", LogLevel.INFO, true); - // } - - public async Task Execute(string actionName, params string[]? args) + public async Task Execute(string actionName, params string[]? args) { if (!Actions.ContainsKey(actionName)) { Config.Logger.Log($"Action {actionName} not found", type: LogType.ERROR, source: typeof(InternalActionManager)); - return "Action not found"; + return false; } try { await Actions[actionName].Execute(args); - return "Action executed"; + return true; } catch (Exception e) { Config.Logger.Log(e.Message, type: LogType.ERROR, source: typeof(InternalActionManager)); - return e.Message; + return false; } } } diff --git a/PluginManager/Others/ArchiveManager.cs b/PluginManager/Others/ArchiveManager.cs index db62acc..ea12787 100644 --- a/PluginManager/Others/ArchiveManager.cs +++ b/PluginManager/Others/ArchiveManager.cs @@ -8,7 +8,7 @@ namespace PluginManager.Others; public static class ArchiveManager { - private static string? _archiveFolder; + private static string? _ArchiveFolder; private static bool IsInitialized { get; set; } public static void Initialize() @@ -19,7 +19,7 @@ public static class ArchiveManager if (!Config.AppSettings.ContainsKey("ArchiveFolder")) Config.AppSettings["ArchiveFolder"] = "./Data/Archives/"; - _archiveFolder = Config.AppSettings["ArchiveFolder"]; + _ArchiveFolder = Config.AppSettings["ArchiveFolder"]; IsInitialized = true; } @@ -52,7 +52,7 @@ public static class ArchiveManager { if (!IsInitialized) throw new Exception("ArchiveManager is not initialized"); - archName = _archiveFolder + archName; + archName = _ArchiveFolder + archName; if (!File.Exists(archName)) throw new Exception("Failed to load file !"); @@ -81,7 +81,7 @@ public static class ArchiveManager public static async Task ReadFromPakAsync(string fileName, string archFile) { if (!IsInitialized) throw new Exception("ArchiveManager is not initialized"); - archFile = _archiveFolder + archFile; + archFile = _ArchiveFolder + archFile; if (!File.Exists(archFile)) throw new Exception("Failed to load file !"); diff --git a/PluginManager/Plugin/PluginInfo.cs b/PluginManager/Plugin/PluginInfo.cs index 4280e3a..9023dfd 100644 --- a/PluginManager/Plugin/PluginInfo.cs +++ b/PluginManager/Plugin/PluginInfo.cs @@ -1,5 +1,6 @@ -using System.IO; -using PluginManager.Interfaces.Updater; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; using PluginManager.Online.Helpers; namespace PluginManager.Plugin; @@ -9,17 +10,30 @@ public class PluginInfo public string PluginName { get; private set; } public PluginVersion PluginVersion { get; private set; } public string FilePath { get; private set; } + public List ListOfDependancies {get; private set;} + public bool IsMarkedToUninstall {get; internal set;} - public PluginInfo(string pluginName, PluginVersion pluginVersion) + [JsonConstructor] + public PluginInfo(string pluginName, PluginVersion pluginVersion, List listOfDependancies, bool isMarkedToUninstall) + { + PluginName = pluginName; + PluginVersion = pluginVersion; + ListOfDependancies = listOfDependancies; + IsMarkedToUninstall = isMarkedToUninstall; + FilePath = $"{Config.AppSettings["PluginFolder"]}/{pluginName}.dll"; + } + + public PluginInfo(string pluginName, PluginVersion pluginVersion, List listOfDependancies) { PluginName = pluginName; PluginVersion = pluginVersion; - + ListOfDependancies = listOfDependancies; + IsMarkedToUninstall = false; FilePath = $"{Config.AppSettings["PluginFolder"]}/{pluginName}.dll"; } public static PluginInfo FromOnlineInfo(PluginOnlineInfo onlineInfo) { - return new PluginInfo(onlineInfo.Name, onlineInfo.Version); + return new PluginInfo(onlineInfo.Name, onlineInfo.Version, onlineInfo.Dependencies.Select(dep => dep.DownloadLocation).ToList()); } } diff --git a/PluginManager/PluginManager.csproj b/PluginManager/PluginManager.csproj index 12af348..35db0a2 100644 --- a/PluginManager/PluginManager.csproj +++ b/PluginManager/PluginManager.csproj @@ -1,31 +1,30 @@ - - net8.0 - enable - - - 512 - none - false - - - - - - - - - - - - - - - - ..\..\..\.nuget\packages\spectre.console\0.47.0\lib\net7.0\Spectre.Console.dll - - - - - + + net8.0 + enable + + + 512 + none + false + + + + + + + + + + + + + + + ..\..\..\.nuget\packages\spectre.console\0.47.0\lib\net7.0\Spectre.Console.dll + + + + + \ No newline at end of file diff --git a/PluginManager/UX/IOutputModel.cs b/PluginManager/UX/IOutputModel.cs deleted file mode 100644 index a202388..0000000 --- a/PluginManager/UX/IOutputModel.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Threading.Tasks; - -namespace PluginManager.UX; - -public enum MessageBoxType -{ - Info, - Warning, - Error -} - -public enum MessageBoxButtons -{ - YesNo, - YesNoCancel, - ContinueCancel -} - -internal interface IOutputModel -{ - - internal Task ShowMessageBox(string title, string message, MessageBoxType type); - - internal Task ShowInputBox(string title, string message); - - internal Task ShowMessageBox(string message); - - internal Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning); - - internal Task ShowNotification(string title, string message, int timeout_seconds = 5); -} diff --git a/PluginManager/UX/Linux/KDE.cs b/PluginManager/UX/Linux/KDE.cs deleted file mode 100644 index 42551a5..0000000 --- a/PluginManager/UX/Linux/KDE.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System.Diagnostics; -using System.Threading.Tasks; - -namespace PluginManager.UX.Linux; - -internal class KDE: IOutputModel -{ - internal string KdeDialogApplication { get; } = "kdialog"; - - public async Task ShowMessageBox(string title, string message, MessageBoxType type) - { - var process = new Process(); - process.StartInfo.FileName = KdeDialogApplication; - - var typeStr = type switch - { - MessageBoxType.Info => "msgbox", - MessageBoxType.Warning => "sorry", - MessageBoxType.Error => "error", - _ => "info" - }; - - process.StartInfo.Arguments = $"--title \"{title}\" --{typeStr} \"{message}\""; - process.Start(); - await process.WaitForExitAsync(); - } - - public async Task ShowInputBox(string title, string message) - { - var process = new Process(); - process.StartInfo.FileName = KdeDialogApplication; - process.StartInfo.Arguments = $"--title \"{title}\" --inputbox \"{message}\""; - process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.RedirectStandardInput = true; - process.Start(); - - await process.WaitForExitAsync(); - return await process.StandardOutput.ReadToEndAsync(); - } - - public async Task ShowMessageBox(string message) - { - var process = new Process(); - process.StartInfo.FileName = KdeDialogApplication; - process.StartInfo.Arguments = $"--msgbox \"{message}\""; - process.Start(); - await process.WaitForExitAsync(); - } - - public async Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning) - { - var process = new Process(); - process.StartInfo.FileName = KdeDialogApplication; - - var buttonsStr = buttons switch - { - MessageBoxButtons.YesNo => "yesno", - MessageBoxButtons.YesNoCancel => "yesnocancel", - MessageBoxButtons.ContinueCancel => "continuecancel", - _ => "yesno" - }; - var typeStr = isWarning ? "warning" : ""; - process.StartInfo.Arguments = $"--title \"{title}\" --{typeStr}{buttonsStr} \"{message}\""; - process.Start(); - await process.WaitForExitAsync(); - return process.ExitCode; - } - - public async Task ShowNotification(string title, string message, int timeout_seconds = 5) - { - var process = new Process(); - process.StartInfo.FileName = KdeDialogApplication; - process.StartInfo.Arguments = $"--title \"{title}\" --passivepopup \"{message}\" {timeout_seconds}"; - process.Start(); - await process.WaitForExitAsync(); - } -} diff --git a/PluginManager/UX/Other/Console.cs b/PluginManager/UX/Other/Console.cs deleted file mode 100644 index 23757fe..0000000 --- a/PluginManager/UX/Other/Console.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Threading.Tasks; -using Spectre.Console; - -namespace PluginManager.UX.Other; - -internal class Console: IOutputModel -{ - - public Task ShowMessageBox(string title, string message, MessageBoxType type) - { - AnsiConsole.Markup(title); - AnsiConsole.Markup(message); - - - return Task.CompletedTask; - } - - public Task ShowInputBox(string title, string message) - { - AnsiConsole.MarkupLine(title); - - var input = AnsiConsole.Ask(message); - - return Task.FromResult(input); - } - - public Task ShowMessageBox(string message) - { - AnsiConsole.MarkupLine(message); - return Task.CompletedTask; - } - - public Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning) - { - AnsiConsole.MarkupLine(title); - AnsiConsole.MarkupLine(message); - - return Task.FromResult(0); - } - - public Task ShowNotification(string title, string message, int timeout_seconds = 5) - { - return Task.CompletedTask; - } -} diff --git a/PluginManager/UX/UxHandler.cs b/PluginManager/UX/UxHandler.cs deleted file mode 100644 index 72372e6..0000000 --- a/PluginManager/UX/UxHandler.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Threading.Tasks; - -namespace PluginManager.UX; - -public static class UxHandler -{ - private static IOutputModel? _model; - - public static void Init() - { - _model = Config.AppSettings["UI"] switch - { - "KDE" => new Linux.KDE(), - "CONSOLE" => new Other.Console(), - _ => null - }; - - } - - public static async Task ShowMessageBox(string title, string message, MessageBoxType type = MessageBoxType.Info) - { - await _model.ShowMessageBox(title, message, type); - } - - public static async Task ShowInputBox(string title, string message) - { - return await _model.ShowInputBox(title, message); - } - - public static async Task ShowMessageBox(string message) - { - await _model.ShowMessageBox(message); - } - - public static async Task ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning) - { - return await _model.ShowMessageBox(title, message, buttons, isWarning); - } - - public static async Task ShowNotification(string title, string message, int timeout_seconds = 5) - { - await _model.ShowNotification(title, message, timeout_seconds); - } - -} diff --git a/PluginManager/Updater/Plugins/PluginUpdater.cs b/PluginManager/Updater/Plugins/PluginUpdater.cs index 5b23c02..9cda048 100644 --- a/PluginManager/Updater/Plugins/PluginUpdater.cs +++ b/PluginManager/Updater/Plugins/PluginUpdater.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; using PluginManager.Online; using PluginManager.Plugin; @@ -41,7 +42,7 @@ public class PluginUpdater await ServerCom.DownloadFileAsync(dependency.DownloadLocation, dependency.DownloadLocation, progressMeter); await _PluginManager.RemovePluginFromDatabase(pluginName); - await _PluginManager.AppendPluginToDatabase(pluginName, pluginInfo.Version); + await _PluginManager.AppendPluginToDatabase(PluginInfo.FromOnlineInfo(pluginInfo)); } public async Task HasUpdate(string pluginName) From 0fccf706a112adb77250f63dabd5f4b31c4d2c7f Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Sun, 3 Mar 2024 15:07:06 +0200 Subject: [PATCH 19/37] Fixed some errors on SettingsDictionary --- PluginManager/Config.cs | 13 ++++++++++--- PluginManager/Others/SettingsDictionary.cs | 11 ++++------- SethDiscordBot.sln | 13 +++++++++---- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index 87eaf72..184b16c 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -32,15 +32,22 @@ public class Config Directory.CreateDirectory("./Data/Logs"); AppSettings = new SettingsDictionary("./Data/Resources/config.json"); + bool response = await AppSettings.LoadFromFile(); + + if (!response) + throw new Exception("Invalid config file"); AppSettings["LogFolder"] = "./Data/Logs"; AppSettings["PluginFolder"] = "./Data/Plugins"; AppSettings["ArchiveFolder"] = "./Data/Archives"; AppSettings["PluginDatabase"] = "./Data/Resources/plugins.json"; + ArchiveManager.Initialize(); + + if (!File.Exists(AppSettings["PluginDatabase"])) { List plugins = new(); @@ -49,15 +56,15 @@ public class Config Logger = new Logger(false, true, AppSettings["LogFolder"] + $"/{DateTime.Today.ToShortDateString().Replace("/", "")}.log"); - - _isLoaded = true; - + PluginsManager = new PluginsManager("releases"); await PluginsManager.UninstallMarkedPlugins(); await PluginsManager.CheckForUpdates(); + _isLoaded = true; + Logger.Log("Config initialized", typeof(Config)); } diff --git a/PluginManager/Others/SettingsDictionary.cs b/PluginManager/Others/SettingsDictionary.cs index 4c2717c..83f0650 100644 --- a/PluginManager/Others/SettingsDictionary.cs +++ b/PluginManager/Others/SettingsDictionary.cs @@ -13,11 +13,6 @@ public class SettingsDictionary: IDictionary public SettingsDictionary(string? file) { _file = file; - if (!LoadFromFile()) - { - _dictionary = new Dictionary(); - SaveToFile(); - } } public async Task SaveToFile() @@ -26,7 +21,7 @@ public class SettingsDictionary: IDictionary await JsonManager.SaveToJsonFile(_file, _dictionary); } - private bool LoadFromFile() + public async Task LoadFromFile() { if (!string.IsNullOrEmpty(_file)) try @@ -42,7 +37,9 @@ public class SettingsDictionary: IDictionary } else File.WriteAllText(_file, "{}"); - _dictionary = JsonManager.ConvertFromJson>(_file).Result; + + + _dictionary = await JsonManager.ConvertFromJson>(_file); return true; } catch diff --git a/SethDiscordBot.sln b/SethDiscordBot.sln index a8d9f43..989c9bd 100644 --- a/SethDiscordBot.sln +++ b/SethDiscordBot.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.1.32421.90 @@ -9,11 +8,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PluginManager", "PluginMana EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SethPlugins", "SethPlugins", "{78B6D390-F61A-453F-B38D-E4C054321615}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MusicPlayer", "..\SethPlugins\MusicPlayer\MusicPlayer.csproj", "{1690CBBC-BDC0-4DD8-B701-F8817189D9D5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MusicPlayer", "..\SethPlugins\MusicPlayer\MusicPlayer.csproj", "{1690CBBC-BDC0-4DD8-B701-F8817189D9D5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LevelingSystem", "..\SethPlugins\LevelingSystem\LevelingSystem.csproj", "{BFE3491C-AC01-4252-B242-6451270FC548}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelingSystem", "..\SethPlugins\LevelingSystem\LevelingSystem.csproj", "{BFE3491C-AC01-4252-B242-6451270FC548}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PythonCompatibilityLayer", "..\SethPlugins\PythonCompatibilityLayer\PythonCompatibilityLayer.csproj", "{81ED4953-13E5-4950-96A8-8CEF5FD59559}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PythonCompatibilityLayer", "..\SethPlugins\PythonCompatibilityLayer\PythonCompatibilityLayer.csproj", "{81ED4953-13E5-4950-96A8-8CEF5FD59559}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordBotUI", "DiscordBotUI\DiscordBotUI.csproj", "{1E781CB6-3EAF-425D-9913-4FE879B1D633}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -41,6 +42,10 @@ Global {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Debug|Any CPU.Build.0 = Debug|Any CPU {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Release|Any CPU.ActiveCfg = Release|Any CPU {81ED4953-13E5-4950-96A8-8CEF5FD59559}.Release|Any CPU.Build.0 = Release|Any CPU + {1E781CB6-3EAF-425D-9913-4FE879B1D633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E781CB6-3EAF-425D-9913-4FE879B1D633}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E781CB6-3EAF-425D-9913-4FE879B1D633}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E781CB6-3EAF-425D-9913-4FE879B1D633}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 90aa5875b53b7bca436ec8e70280e7c685a0a8de Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Sun, 3 Mar 2024 18:00:43 +0200 Subject: [PATCH 20/37] Added Basic UI Functionality --- .gitignore | 3 +- DiscordBotUI/App.axaml | 11 +++ DiscordBotUI/App.axaml.cs | 24 ++++++ DiscordBotUI/Bot/Commands/Help.cs | 90 ++++++++++++++++++++++ DiscordBotUI/Bot/DiscordBot.cs | 83 ++++++++++++++++++++ DiscordBotUI/DiscordBotUI.csproj | 26 +++++++ DiscordBotUI/Program.cs | 23 ++++++ DiscordBotUI/Windows/HomePage.axaml | 40 ++++++++++ DiscordBotUI/Windows/HomePage.axaml.cs | 70 +++++++++++++++++ DiscordBotUI/Windows/PluginsPage.axaml | 24 ++++++ DiscordBotUI/Windows/PluginsPage.axaml.cs | 48 ++++++++++++ DiscordBotUI/Windows/SettingsPage.axaml | 26 +++++++ DiscordBotUI/Windows/SettingsPage.axaml.cs | 44 +++++++++++ DiscordBotUI/app.manifest | 18 +++++ 14 files changed, 529 insertions(+), 1 deletion(-) create mode 100644 DiscordBotUI/App.axaml create mode 100644 DiscordBotUI/App.axaml.cs create mode 100644 DiscordBotUI/Bot/Commands/Help.cs create mode 100644 DiscordBotUI/Bot/DiscordBot.cs create mode 100644 DiscordBotUI/DiscordBotUI.csproj create mode 100644 DiscordBotUI/Program.cs create mode 100644 DiscordBotUI/Windows/HomePage.axaml create mode 100644 DiscordBotUI/Windows/HomePage.axaml.cs create mode 100644 DiscordBotUI/Windows/PluginsPage.axaml create mode 100644 DiscordBotUI/Windows/PluginsPage.axaml.cs create mode 100644 DiscordBotUI/Windows/SettingsPage.axaml create mode 100644 DiscordBotUI/Windows/SettingsPage.axaml.cs create mode 100644 DiscordBotUI/app.manifest diff --git a/.gitignore b/.gitignore index a12e00a..d5c81c9 100644 --- a/.gitignore +++ b/.gitignore @@ -373,4 +373,5 @@ FodyWeavers.xsd /DiscordBot/Updater/ .idea/ DiscordBot/Launcher.exe -DiscordBotUI/* +DiscordBotUI/bin +DiscordBotUI/obj diff --git a/DiscordBotUI/App.axaml b/DiscordBotUI/App.axaml new file mode 100644 index 0000000..cb6daa8 --- /dev/null +++ b/DiscordBotUI/App.axaml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/DiscordBotUI/App.axaml.cs b/DiscordBotUI/App.axaml.cs new file mode 100644 index 0000000..b613a55 --- /dev/null +++ b/DiscordBotUI/App.axaml.cs @@ -0,0 +1,24 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; + +namespace DiscordBotUI +{ + public partial class App : Application + { + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow = new HomePage(); + } + + base.OnFrameworkInitializationCompleted(); + } + } +} \ No newline at end of file diff --git a/DiscordBotUI/Bot/Commands/Help.cs b/DiscordBotUI/Bot/Commands/Help.cs new file mode 100644 index 0000000..8f9ec34 --- /dev/null +++ b/DiscordBotUI/Bot/Commands/Help.cs @@ -0,0 +1,90 @@ +using System.Collections.Generic; +using Discord; +using PluginManager; +using PluginManager.Interfaces; +using PluginManager.Loaders; +using PluginManager.Others; + +namespace DiscordBotUI.Bot.Commands; + +/// +/// The help command +/// +internal class Help: DBCommand +{ + /// + /// Command name + /// + public string Command => "help"; + + public List Aliases => null; + + /// + /// Command Description + /// + public string Description => "This command allows you to check all loaded commands"; + + /// + /// Command usage + /// + public string Usage => "help "; + + /// + /// Check if the command require administrator to be executed + /// + public bool requireAdmin => false; + + /// + /// The main body of the command + /// + /// The command context + public void ExecuteServer(DbCommandExecutingArguments args) + { + if (args.arguments is not null) + { + var e = GenerateHelpCommand(args.arguments[0]); + if (e is null) + args.context.Channel.SendMessageAsync("Unknown Command " + args.arguments[0]); + else + args.context.Channel.SendMessageAsync(embed: e.Build()); + + + return; + } + + var embedBuilder = new EmbedBuilder(); + + var adminCommands = ""; + var normalCommands = ""; + + foreach (var cmd in PluginLoader.Commands) + if (cmd.requireAdmin) + adminCommands += cmd.Command + " "; + else + normalCommands += cmd.Command + " "; + + + if (adminCommands.Length > 0) + embedBuilder.AddField("Admin Commands", adminCommands); + if (normalCommands.Length > 0) + embedBuilder.AddField("Normal Commands", normalCommands); + args.context.Channel.SendMessageAsync(embed: embedBuilder.Build()); + } + + private EmbedBuilder GenerateHelpCommand(string command) + { + var embedBuilder = new EmbedBuilder(); + var cmd = PluginLoader.Commands.Find(p => p.Command == command || + p.Aliases is not null && p.Aliases.Contains(command) + ); + if (cmd == null) return null; + + embedBuilder.AddField("Usage", Config.AppSettings["prefix"] + cmd.Usage); + embedBuilder.AddField("Description", cmd.Description); + if (cmd.Aliases is null) + return embedBuilder; + embedBuilder.AddField("Alias", cmd.Aliases.Count == 0 ? "-" : string.Join(", ", cmd.Aliases)); + + return embedBuilder; + } +} diff --git a/DiscordBotUI/Bot/DiscordBot.cs b/DiscordBotUI/Bot/DiscordBot.cs new file mode 100644 index 0000000..5bf5cec --- /dev/null +++ b/DiscordBotUI/Bot/DiscordBot.cs @@ -0,0 +1,83 @@ +using System.Threading.Tasks; + +using PluginManager; +using PluginManager.Interfaces; +using PluginManager.Loaders; +using PluginManager.Others; + +namespace DiscordBotUI.Bot +{ + internal class DiscordBot + { + private readonly string[] _StartArguments; + + public DiscordBot(string[] args) + { + this._StartArguments = args; + } + + public async Task InitializeBot() + { + string token = Config.AppSettings["token"]; + string prefix = Config.AppSettings["prefix"]; + PluginManager.Bot.Boot discordBooter = new PluginManager.Bot.Boot(token, prefix); + await discordBooter.Awake(); + } + + public async Task LoadPlugins() + { + var loader = new PluginLoader(Config.DiscordBot.client); + + loader.OnCommandLoaded += (data) => + { + if (data.IsSuccess) + { + Config.Logger.Log("Successfully loaded command : " + data.PluginName, typeof(ICommandAction), + LogType.INFO + ); + } + + else + { + Config.Logger.Log("Failed to load command : " + data.PluginName + " because " + data.ErrorMessage, + typeof(ICommandAction), LogType.ERROR + ); + } + }; + loader.OnEventLoaded += (data) => + { + if (data.IsSuccess) + { + Config.Logger.Log("Successfully loaded event : " + data.PluginName, typeof(ICommandAction), + LogType.INFO + ); + } + else + { + Config.Logger.Log("Failed to load event : " + data.PluginName + " because " + data.ErrorMessage, + typeof(ICommandAction), LogType.ERROR + ); + } + }; + + loader.OnSlashCommandLoaded += (data) => + { + if (data.IsSuccess) + { + Config.Logger.Log("Successfully loaded slash command : " + data.PluginName, typeof(ICommandAction), + LogType.INFO + ); + } + else + { + Config.Logger.Log("Failed to load slash command : " + data.PluginName + " because " + data.ErrorMessage, + typeof(ICommandAction), LogType.ERROR + ); + } + }; + + await loader.LoadPlugins(); + } + + } +} diff --git a/DiscordBotUI/DiscordBotUI.csproj b/DiscordBotUI/DiscordBotUI.csproj new file mode 100644 index 0000000..eb95467 --- /dev/null +++ b/DiscordBotUI/DiscordBotUI.csproj @@ -0,0 +1,26 @@ + + + WinExe + net8.0 + enable + true + app.manifest + true + + + + + + + + + + + + + + + + + + diff --git a/DiscordBotUI/Program.cs b/DiscordBotUI/Program.cs new file mode 100644 index 0000000..9090e15 --- /dev/null +++ b/DiscordBotUI/Program.cs @@ -0,0 +1,23 @@ +using System; + +using Avalonia; + +namespace DiscordBotUI +{ + internal class Program + { + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace(); + } +} diff --git a/DiscordBotUI/Windows/HomePage.axaml b/DiscordBotUI/Windows/HomePage.axaml new file mode 100644 index 0000000..c1b71e0 --- /dev/null +++ b/DiscordBotUI/Windows/HomePage.axaml @@ -0,0 +1,40 @@ + + + + + + + + + + +