Formatted code and rebuilt PluginLoader

This commit is contained in:
2024-02-27 11:07:27 +02:00
parent 14f280baef
commit ef7a2c0896
40 changed files with 525 additions and 524 deletions

View File

@@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\PluginManager\PluginManager.csproj" /> <ProjectReference Include="..\PluginManager\PluginManager.csproj"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -6,13 +6,15 @@ using PluginManager.Plugin;
if (args.Length == 1) if (args.Length == 1)
{ {
PluginOnlineInfo? result = await JsonManager.ConvertFromJson<PluginOnlineInfo>(args[0]); var result = await JsonManager.ConvertFromJson<PluginOnlineInfo>(args[0]);
// print all rows // print all rows
Console.WriteLine($"Name: {result.Name}"); Console.WriteLine($"Name: {result.Name}");
Console.WriteLine($"Version: {result.Version.ToShortString()}"); Console.WriteLine($"Version: {result.Version.ToShortString()}");
Console.WriteLine($"Description: {result.Description}"); Console.WriteLine($"Description: {result.Description}");
Console.WriteLine($"Download link: {result.DownLoadLink}"); 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($"Has dependencies: {result.HasDependencies}");
Console.WriteLine($"Dependencies: {result.Dependencies.Count}"); Console.WriteLine($"Dependencies: {result.Dependencies.Count}");
@@ -65,4 +67,4 @@ List<PluginOnlineInfo> plugins =
Directory.CreateDirectory("output"); Directory.CreateDirectory("output");
await JsonManager.SaveToJsonFile("./output/PluginsList.json", plugins); await JsonManager.SaveToJsonFile("./output/PluginsList.json", plugins);
Process.Start("notepad.exe", "./output/PluginsList.json"); Process.Start("notepad.exe", "./output/PluginsList.json");

View File

@@ -17,7 +17,7 @@ public class Exit: ICommandAction
{ {
if (args is null || args.Length == 0) 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(); await Config.AppSettings.SaveToFile();
Environment.Exit(0); Environment.Exit(0);
} }
@@ -33,7 +33,7 @@ public class Exit: ICommandAction
case "-f": case "-f":
case "force": 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); Environment.Exit(0);
break; break;

View File

@@ -21,7 +21,14 @@ internal static class PluginMethods
{ {
var data = await ConsoleUtilities.ExecuteWithProgressBar(manager.GetPluginsList(), "Loading plugins..."); var data = await ConsoleUtilities.ExecuteWithProgressBar(manager.GetPluginsList(), "Loading plugins...");
TableData tableData = new(new List<string> { "Name", "Description", "Version", "Has Dependencies" }); TableData tableData = new(new List<string>
{
"Name",
"Description",
"Version",
"Has Dependencies"
}
);
foreach (var plugin in data) tableData.AddRow([plugin.Name, plugin.Description, plugin.Version.ToString(), plugin.HasDependencies ? "Yes" : "No"]); foreach (var plugin in data) tableData.AddRow([plugin.Name, plugin.Description, plugin.Version.ToString(), plugin.HasDependencies ? "Yes" : "No"]);
tableData.HasRoundBorders = false; tableData.HasRoundBorders = false;
@@ -42,16 +49,14 @@ internal static class PluginMethods
Console.WriteLine($"Plugin {pluginName} not found. Please check the spelling and try again."); Console.WriteLine($"Plugin {pluginName} not found. Please check the spelling and try again.");
return; return;
} }
var pluginLink = pluginData.DownLoadLink; var pluginLink = pluginData.DownLoadLink;
await AnsiConsole.Progress() await AnsiConsole.Progress()
.Columns(new ProgressColumn[] .Columns(new ProgressColumn[]
{ {
new TaskDescriptionColumn(), new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()
new ProgressBarColumn(),
new PercentageColumn()
} }
) )
.StartAsync(async ctx => .StartAsync(async ctx =>
@@ -74,21 +79,19 @@ internal static class PluginMethods
await RefreshPlugins(false); await RefreshPlugins(false);
return; return;
} }
List<Tuple<ProgressTask, IProgress<float>, string, string>> downloadTasks = new(); List<Tuple<ProgressTask, IProgress<float>, string, string>> downloadTasks = new();
await AnsiConsole.Progress() await AnsiConsole.Progress()
.Columns(new ProgressColumn[] .Columns(new ProgressColumn[]
{ {
new TaskDescriptionColumn(), new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()
new ProgressBarColumn(),
new PercentageColumn()
} }
) )
.StartAsync(async ctx => .StartAsync(async ctx =>
{ {
foreach (OnlineDependencyInfo dependency in pluginData.Dependencies) foreach (var dependency in pluginData.Dependencies)
{ {
var task = ctx.AddTask($"Downloading {dependency.DownloadLocation}: "); var task = ctx.AddTask($"Downloading {dependency.DownloadLocation}: ");
IProgress<float> progress = new Progress<float>(p => IProgress<float> progress = new Progress<float>(p =>
@@ -101,7 +104,7 @@ internal static class PluginMethods
downloadTasks.Add(new Tuple<ProgressTask, IProgress<float>, string, string>(task, progress, dependency.DownloadLink, dependency.DownloadLocation)); downloadTasks.Add(new Tuple<ProgressTask, IProgress<float>, 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; maxParallelDownloads = 5;
Config.AppSettings.Add("MaxParallelDownloads", "5"); Config.AppSettings.Add("MaxParallelDownloads", "5");
@@ -126,7 +129,7 @@ internal static class PluginMethods
} }
); );
await RefreshPlugins(false); await RefreshPlugins(false);
} }
@@ -135,74 +138,66 @@ internal static class PluginMethods
var loader = new PluginLoader(Config.DiscordBot.client); var loader = new PluginLoader(Config.DiscordBot.client);
if (args.Length == 2 && args[1] == "-q") if (args.Length == 2 && args[1] == "-q")
{ {
loader.LoadPlugins(); await loader.LoadPlugins();
return true; return true;
} }
var cc = Console.ForegroundColor; var cc = Console.ForegroundColor;
loader.onCMDLoad += (name, typeName, success, exception) => loader.OnCommandLoaded += (data) =>
{ {
if (name == null || name.Length < 2) if (data.IsSuccess)
name = typeName;
if (success)
{ {
Config.Logger.Log("Successfully loaded command : " + name, source: typeof(ICommandAction), Config.Logger.Log("Successfully loaded command : " + data.PluginName, typeof(ICommandAction),
type: LogType.INFO LogType.INFO
); );
} }
else else
{ {
Config.Logger.Log("Failed to load command : " + name + " because " + exception?.Message, Config.Logger.Log("Failed to load command : " + data.PluginName + " because " + data.ErrorMessage,
source: typeof(ICommandAction), type: LogType.ERROR typeof(ICommandAction), LogType.ERROR
); );
} }
Console.ForegroundColor = cc; Console.ForegroundColor = cc;
}; };
loader.onEVELoad += (name, typeName, success, exception) => loader.OnEventLoaded += (data) =>
{ {
if (name == null || name.Length < 2) if (data.IsSuccess)
name = typeName;
if (success)
{ {
Config.Logger.Log("Successfully loaded event : " + name, source: typeof(ICommandAction), Config.Logger.Log("Successfully loaded event : " + data.PluginName, typeof(ICommandAction),
type: LogType.INFO LogType.INFO
); );
} }
else else
{ {
Config.Logger.Log("Failed to load event : " + name + " because " + exception?.Message, Config.Logger.Log("Failed to load event : " + data.PluginName + " because " + data.ErrorMessage,
source: typeof(ICommandAction), type: LogType.ERROR typeof(ICommandAction), LogType.ERROR
); );
} }
Console.ForegroundColor = cc; Console.ForegroundColor = cc;
}; };
loader.onSLSHLoad += (name, typeName, success, exception) => loader.OnSlashCommandLoaded += (data) =>
{ {
if (name == null || name.Length < 2) if (data.IsSuccess)
name = typeName;
if (success)
{ {
Config.Logger.Log("Successfully loaded slash command : " + name, source: typeof(ICommandAction), Config.Logger.Log("Successfully loaded slash command : " + data.PluginName, typeof(ICommandAction),
type: LogType.INFO LogType.INFO
); );
} }
else else
{ {
Config.Logger.Log("Failed to load slash command : " + name + " because " + exception?.Message, Config.Logger.Log("Failed to load slash command : " + data.PluginName + " because " + data.ErrorMessage,
source: typeof(ICommandAction), type: LogType.ERROR typeof(ICommandAction), LogType.ERROR
); );
} }
Console.ForegroundColor = cc; Console.ForegroundColor = cc;
}; };
loader.LoadPlugins(); await loader.LoadPlugins();
Console.ForegroundColor = cc; Console.ForegroundColor = cc;
return true; return true;
} }

View File

@@ -23,15 +23,32 @@ public class Help: ICommandAction
{ {
var items = new List<string[]> var items = new List<string[]>
{ {
new[] { "-", "-", "-" }, new[]
new[] { "Command", "Usage", "Description" }, {
new[] { "-", "-", "-" } "-", "-", "-"
},
new[]
{
"Command", "Usage", "Description"
},
new[]
{
"-", "-", "-"
}
}; };
foreach (var a in Program.internalActionManager.Actions) 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, ConsoleUtilities.FormatAndAlignTable(items,
TableFormat.CENTER_EACH_COLUMN_BASED TableFormat.CENTER_EACH_COLUMN_BASED
@@ -48,11 +65,26 @@ public class Help: ICommandAction
var action = Program.internalActionManager.Actions[args[0]]; var action = Program.internalActionManager.Actions[args[0]];
var actionData = new List<string[]> var actionData = new List<string[]>
{ {
new[] { "-", "-", "-" }, new[]
new[] { "Command", "Usage", "Description" }, {
new[] { "-", "-", "-" }, "-", "-", "-"
new[] { action.ActionName, action.Usage, action.Description }, },
new[] { "-", "-", "-" } new[]
{
"Command", "Usage", "Description"
},
new[]
{
"-", "-", "-"
},
new[]
{
action.ActionName, action.Usage, action.Description
},
new[]
{
"-", "-", "-"
}
}; };
ConsoleUtilities.FormatAndAlignTable(actionData, ConsoleUtilities.FormatAndAlignTable(actionData,

View File

@@ -34,7 +34,7 @@ public class Plugin: ICommandAction
return; return;
} }
PluginsManager manager = var manager =
#if !DEBUG #if !DEBUG
new PluginsManager("releases"); new PluginsManager("releases");
#else #else
@@ -54,13 +54,13 @@ public class Plugin: ICommandAction
case "load": case "load":
if (pluginsLoaded) 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; break;
} }
if (Config.DiscordBot is null) 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; break;
} }

View File

@@ -40,15 +40,15 @@ public class Help: DBSlashCommand
if (options.Count > 0) if (options.Count > 0)
{ {
var commandName = options.First().Name; var commandName = options.First().Value;
var slashCommand = slashCommands.FirstOrDefault(x => x.Name == commandName); var slashCommand = slashCommands.FirstOrDefault(x => x.Name.TrimEnd() == commandName.ToString());
if (slashCommand is null) if (slashCommand is null)
{ {
await context.RespondAsync("Unknown Command " + commandName); await context.RespondAsync("Unknown Command " + commandName);
return; return;
} }
embedBuilder.AddField(slashCommand.Name, slashCommand.canUseDM) embedBuilder.AddField("DM Usable:", slashCommand.canUseDM, true)
.WithDescription(slashCommand.Description); .WithDescription(slashCommand.Description);
} }

View File

@@ -1,7 +1,6 @@
using System; using System;
using PluginManager; using PluginManager;
using Spectre.Console; using Spectre.Console;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace DiscordBot; namespace DiscordBot;
@@ -10,10 +9,10 @@ public static class Installer
{ {
public static async Task GenerateStartupConfig() public static async Task GenerateStartupConfig()
{ {
string token = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the bot token:"); var 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:"); var 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 serverId = await PluginManager.UX.UxHandler.ShowInputBox("SethBot", "Please enter the Server ID:");
if (string.IsNullOrWhiteSpace(serverId)) serverId = "NULL"; if (string.IsNullOrWhiteSpace(serverId)) serverId = "NULL";
if (string.IsNullOrWhiteSpace(token) || string.IsNullOrWhiteSpace(botPrefix)) 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); await PluginManager.UX.UxHandler.ShowMessageBox("SethBot", "Invalid token or prefix !", PluginManager.UX.MessageBoxType.Error);
Environment.Exit(-20); Environment.Exit(-20);
} }
Config.AppSettings.Add("token", token); Config.AppSettings.Add("token", token);
Config.AppSettings.Add("prefix", botPrefix); Config.AppSettings.Add("prefix", botPrefix);
Config.AppSettings.Add("ServerID", serverId); Config.AppSettings.Add("ServerID", serverId);
await Config.AppSettings.SaveToFile(); await Config.AppSettings.SaveToFile();
Config.Logger.Log("Config Saved", source: typeof(Installer)); Config.Logger.Log("Config Saved", typeof(Installer));
} }
} }

View File

@@ -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("&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.WriteLine("============================ LOG ============================");
Console.ForegroundColor = ConsoleColor.White; Console.ForegroundColor = ConsoleColor.White;
@@ -82,7 +82,7 @@ public class Program
} }
catch (Exception ex) 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) 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" + 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" + 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 !", "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) => Logger.OnLog += (sender, logMessage) =>
{ {
string messageColor = logMessage.Type switch var messageColor = logMessage.Type switch
{ {
LogType.INFO => "[green]", LogType.INFO => "[green]",
LogType.WARNING => "[yellow]", LogType.WARNING => "[yellow]",

View File

@@ -43,9 +43,7 @@ public static class ConsoleUtilities
.Columns( .Columns(
new ProgressColumn[] new ProgressColumn[]
{ {
new TaskDescriptionColumn(), new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()
new ProgressBarColumn(),
new PercentageColumn(),
} }
) )
.StartAsync( .StartAsync(
@@ -67,9 +65,7 @@ public static class ConsoleUtilities
await AnsiConsole.Progress() await AnsiConsole.Progress()
.Columns(new ProgressColumn[] .Columns(new ProgressColumn[]
{ {
new TaskDescriptionColumn(), new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()
new ProgressBarColumn(),
new PercentageColumn(),
} }
) )
.StartAsync(async ctx => .StartAsync(async ctx =>
@@ -85,11 +81,21 @@ public static class ConsoleUtilities
private static readonly Dictionary<char, ConsoleColor> Colors = new() private static readonly Dictionary<char, ConsoleColor> Colors = new()
{ {
{ 'g', ConsoleColor.Green }, {
{ 'b', ConsoleColor.Blue }, 'g', ConsoleColor.Green
{ 'r', ConsoleColor.Red }, },
{ 'm', ConsoleColor.Magenta }, {
{ 'y', ConsoleColor.Yellow } 'b', ConsoleColor.Blue
},
{
'r', ConsoleColor.Red
},
{
'm', ConsoleColor.Magenta
},
{
'y', ConsoleColor.Yellow
}
}; };
private static readonly char ColorPrefix = '&'; private static readonly char ColorPrefix = '&';
@@ -310,7 +316,10 @@ public static class ConsoleUtilities
public Spinner() public Spinner()
{ {
Sequence = new[] { "|", "/", "-", "\\" }; Sequence = new[]
{
"|", "/", "-", "\\"
};
position = 0; position = 0;
} }

View File

@@ -106,7 +106,7 @@ public class Boot
if (arg.Message.Contains("401")) if (arg.Message.Contains("401"))
{ {
Config.AppSettings.Remove("token"); 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 Config.AppSettings.SaveToFile();
await Task.Delay(4000); await Task.Delay(4000);
Environment.Exit(0); Environment.Exit(0);
@@ -115,7 +115,7 @@ public class Boot
private async Task Client_LoggedOut() 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 !")); await Log(new LogMessage(LogSeverity.Info, "Boot", "Successfully logged out from discord !"));
} }
@@ -128,7 +128,7 @@ public class Boot
private Task LoggedIn() private Task LoggedIn()
{ {
Config.Logger.Log("Successfully Logged In", source: typeof(Boot)); Config.Logger.Log("Successfully Logged In", typeof(Boot));
return Task.CompletedTask; return Task.CompletedTask;
} }
@@ -138,12 +138,12 @@ public class Boot
{ {
case LogSeverity.Error: case LogSeverity.Error:
case LogSeverity.Critical: case LogSeverity.Critical:
Config.Logger.Log(message.Message, source: typeof(Boot), type: LogType.ERROR); Config.Logger.Log(message.Message, typeof(Boot), LogType.ERROR);
break; break;
case LogSeverity.Info: case LogSeverity.Info:
case LogSeverity.Debug: case LogSeverity.Debug:
Config.Logger.Log(message.Message, source: typeof(Boot), type: LogType.INFO); Config.Logger.Log(message.Message, typeof(Boot), LogType.INFO);
break; break;

View File

@@ -25,9 +25,9 @@ internal class CommandHandler
/// <param name="botPrefix">The prefix to watch for</param> /// <param name="botPrefix">The prefix to watch for</param>
public CommandHandler(DiscordSocketClient client, CommandService commandService, string botPrefix) public CommandHandler(DiscordSocketClient client, CommandService commandService, string botPrefix)
{ {
this._client = client; _client = client;
this._commandService = commandService; _commandService = commandService;
this._botPrefix = botPrefix; _botPrefix = botPrefix;
} }
/// <summary> /// <summary>
@@ -103,12 +103,10 @@ internal class CommandHandler
.FirstOrDefault(plug => plug.Command == .FirstOrDefault(plug => plug.Command ==
message.Content.Substring(mentionPrefix.Length + 1) message.Content.Substring(mentionPrefix.Length + 1)
.Split(' ')[0] || .Split(' ')[0] ||
( plug.Aliases is not null &&
plug.Aliases is not null && plug.Aliases.Contains(message.CleanContent
plug.Aliases.Contains(message.CleanContent .Substring(mentionPrefix.Length + 1)
.Substring(mentionPrefix.Length + 1) .Split(' ')[0]
.Split(' ')[0]
)
) )
); );
@@ -120,11 +118,11 @@ internal class CommandHandler
plugin = PluginLoader.Commands! plugin = PluginLoader.Commands!
.FirstOrDefault(p => p.Command == .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 is not null &&
p.Aliases.Contains( p.Aliases.Contains(
message.Content.Split(' ')[0] message.Content.Split(' ')[0]
.Substring(_botPrefix.Length) .Substring(_botPrefix.Length)
)) )
); );
cleanMessage = message.Content.Substring(_botPrefix.Length); cleanMessage = message.Content.Substring(_botPrefix.Length);
} }
@@ -144,9 +142,9 @@ internal class CommandHandler
DbCommandExecutingArguments cmd = new(context, cleanMessage, split[0], argsClean); DbCommandExecutingArguments cmd = new(context, cleanMessage, split[0], argsClean);
Config.Logger.Log( Config.Logger.Log(
message: $"User ({context.User.Username}) from Guild \"{context.Guild.Name}\" executed command \"{cmd.cleanContent}\"", $"User ({context.User.Username}) from Guild \"{context.Guild.Name}\" executed command \"{cmd.cleanContent}\"",
source: typeof(CommandHandler), typeof(CommandHandler),
type: LogType.INFO LogType.INFO
); );
if (context.Channel is SocketDMChannel) if (context.Channel is SocketDMChannel)

View File

@@ -29,8 +29,8 @@ public class Config
AppSettings = new SettingsDictionary<string, string>("./Data/Resources/config.json"); AppSettings = new SettingsDictionary<string, string>("./Data/Resources/config.json");
AppSettings["LogFolder"] = "./Data/Logs"; AppSettings["LogFolder"] = "./Data/Logs";
AppSettings["PluginFolder"] = "./Data/Plugins"; AppSettings["PluginFolder"] = "./Data/Plugins";
AppSettings["ArchiveFolder"] = "./Data/Archives"; AppSettings["ArchiveFolder"] = "./Data/Archives";
if (OperatingSystem.IsLinux()) if (OperatingSystem.IsLinux())
@@ -42,21 +42,22 @@ public class Config
"GNOME" => "GNOME", "GNOME" => "GNOME",
_ => "CONSOLE" _ => "CONSOLE"
}; };
} else AppSettings["UI"] = "CONSOLE"; }
else AppSettings["UI"] = "CONSOLE";
Logger = new Logger(false, true, Logger = new Logger(false, true,
AppSettings["LogFolder"] + $"/{DateTime.Today.ToShortDateString().Replace("/", "")}.log" AppSettings["LogFolder"] + $"/{DateTime.Today.ToShortDateString().Replace("/", "")}.log"
); );
ArchiveManager.Initialize(); ArchiveManager.Initialize();
UX.UxHandler.Init(); UX.UxHandler.Init();
_isLoaded = true; _isLoaded = true;
Logger.Log(message: "Config initialized", source: typeof(Config)); Logger.Log("Config initialized", typeof(Config));
} }
} }

View File

@@ -544,8 +544,10 @@ public class SqlDatabase
/// </summary> /// </summary>
/// <param name="parameterValues">The parameter raw inputs. The Key is name and the Value is the value of the parameter</param> /// <param name="parameterValues">The parameter raw inputs. The Key is name and the Value is the value of the parameter</param>
/// <returns>The SQLiteParameter that has the name, value and DBType set according to your inputs</returns> /// <returns>The SQLiteParameter that has the name, value and DBType set according to your inputs</returns>
private SQLiteParameter? CreateParameter(KeyValuePair<string, object> parameterValues) => private SQLiteParameter? CreateParameter(KeyValuePair<string, object> parameterValues)
CreateParameter(parameterValues.Key, parameterValues.Value); {
return CreateParameter(parameterValues.Key, parameterValues.Value);
}
/// <summary> /// <summary>
/// Execute a query with parameters /// Execute a query with parameters

View File

@@ -5,10 +5,12 @@ public interface IVersion
public int Major { get; } public int Major { get; }
public int Minor { get; } public int Minor { get; }
public int Patch { get; } public int Patch { get; }
public bool IsNewerThan(IVersion version); public bool IsNewerThan(IVersion version);
public bool IsOlderThan(IVersion version); public bool IsOlderThan(IVersion version);
public bool IsEqualTo(IVersion version); public bool IsEqualTo(IVersion version);
public string ToShortString(); public string ToShortString();
} }

View File

@@ -2,7 +2,7 @@ using System;
namespace PluginManager.Interfaces.Updater; namespace PluginManager.Interfaces.Updater;
public abstract class Version : IVersion public abstract class Version: IVersion
{ {
public int Major { get; } public int Major { get; }
public int Minor { get; } public int Minor { get; }
@@ -12,34 +12,34 @@ public abstract class Version : IVersion
protected Version(int major, int minor, int patch) protected Version(int major, int minor, int patch)
{ {
this.Major = major; Major = major;
this.Minor = minor; Minor = minor;
this.Patch = patch; Patch = patch;
} }
protected Version(string versionAsString) protected Version(string versionAsString)
{ {
string[] versionParts = versionAsString.Split(_Separator); string[] versionParts = versionAsString.Split(_Separator);
if (versionParts.Length != 3) if (versionParts.Length != 3)
{ {
throw new ArgumentException("Invalid version string"); throw new ArgumentException("Invalid version string");
} }
this.Major = int.Parse(versionParts[0]); Major = int.Parse(versionParts[0]);
this.Minor = int.Parse(versionParts[1]); Minor = int.Parse(versionParts[1]);
this.Patch = int.Parse(versionParts[2]); Patch = int.Parse(versionParts[2]);
} }
public bool IsNewerThan(IVersion version) public bool IsNewerThan(IVersion version)
{ {
if (this.Major > version.Major) if (Major > version.Major)
return true; return true;
if (this.Major == version.Major && this.Minor > version.Minor) if (Major == version.Major && Minor > version.Minor)
return true; 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 true;
return false; return false;
@@ -47,13 +47,13 @@ public abstract class Version : IVersion
public bool IsOlderThan(IVersion version) public bool IsOlderThan(IVersion version)
{ {
if (this.Major < version.Major) if (Major < version.Major)
return true; return true;
if (this.Major == version.Major && this.Minor < version.Minor) if (Major == version.Major && Minor < version.Minor)
return true; 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 true;
return false; return false;
@@ -61,9 +61,9 @@ public abstract class Version : IVersion
public bool IsEqualTo(IVersion version) 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() public string ToShortString()
{ {
return $"{Major}.{Minor}.{Patch}"; return $"{Major}.{Minor}.{Patch}";

View File

@@ -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;
}
}

View File

@@ -1,52 +1,40 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using PluginManager.Interfaces; using PluginManager.Interfaces;
using PluginManager.Others; using PluginManager.Others;
namespace PluginManager.Loaders; 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 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; _SearchPath = searchPath;
this.Extension = extension; _FileExtension = fileExtension;
} }
internal async Task Load()
private string Path { get; }
private string Extension { get; }
internal event FileLoadedEventHandler? FileLoaded;
internal event PluginLoadedEventHandler? PluginLoaded;
internal (List<DBEvent>?, List<DBCommand>?, List<DBSlashCommand>?) Load()
{ {
List<DBEvent> events = new(); if (!Directory.Exists(_SearchPath))
List<DBSlashCommand> slashCommands = new();
List<DBCommand> commands = new();
if (!Directory.Exists(Path))
{ {
Directory.CreateDirectory(Path); Directory.CreateDirectory(_SearchPath);
return (null, null, null); return;
} }
var files = Directory.GetFiles(Path, $"*.{Extension}", SearchOption.AllDirectories); var files = Directory.GetFiles(_SearchPath, $"*.{_FileExtension}", SearchOption.TopDirectoryOnly);
foreach (var file in files) foreach (var file in files)
{ {
try try
@@ -55,91 +43,40 @@ internal class Loader
} }
catch catch
{ {
Config.Logger.Log("PluginName: " + new FileInfo(file).Name.Split('.')[0] + " not loaded", source: typeof(Loader), type: LogType.ERROR); OnFileLoadedException?.Invoke(new FileLoaderResult(file, "Failed to load file"));
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);
} }
} }
await LoadEverythingOfType<DBEvent>();
return (LoadItems<DBEvent>(), LoadItems<DBCommand>(), LoadItems<DBSlashCommand>()); await LoadEverythingOfType<DBCommand>();
await LoadEverythingOfType<DBSlashCommand>();
} }
internal List<T> LoadItems<T>() private async Task LoadEverythingOfType<T>()
{ {
List<T> list = new(); var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => typeof(T).IsAssignableFrom(p) && !p.IsInterface);
foreach (var type in types)
try
{ {
var interfaceType = typeof(T); try
var types = AppDomain.CurrentDomain.GetAssemblies() {
.SelectMany(a => a.GetTypes()) var plugin = (T)Activator.CreateInstance(type);
.Where(p => interfaceType.IsAssignableFrom(p) && p.IsClass) var pluginType = plugin switch
.ToArray();
list.Clear();
foreach (var type in types)
try
{ {
var plugin = (T)Activator.CreateInstance(type)!; DBEvent => PluginType.EVENT,
list.Add(plugin); DBCommand => PluginType.COMMAND,
DBSlashCommand => PluginType.SLASH_COMMAND,
_ => PluginType.UNKNOWN
if (PluginLoaded != null) };
PluginLoaded.Invoke(new LoaderArgs OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, pluginType, true, plugin: plugin));
{ }
Exception = null, catch (Exception ex)
IsLoaded = true, {
PluginName = type.FullName, OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, PluginType.UNKNOWN, false, ex.Message));
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;
} }
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);
} }

View File

@@ -0,0 +1,6 @@
namespace PluginManager.Loaders;
public class PluginHandler
{
}

View File

@@ -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;
}
}

View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord;
using Discord.WebSocket; using Discord.WebSocket;
using PluginManager.Interfaces; using PluginManager.Interfaces;
using PluginManager.Others; using PluginManager.Others;
@@ -11,173 +8,78 @@ namespace PluginManager.Loaders;
public class PluginLoader 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"; public CommandLoaded? OnCommandLoaded;
private readonly DiscordSocketClient _client; public EventLoaded? OnEventLoaded;
public SlashCommandLoaded? OnSlashCommandLoaded;
/// <summary> public static List<DBCommand>? Commands;
/// Event that is fired when a <see cref="DBCommand" /> is successfully loaded into commands list public static List<DBEvent>? Events;
/// </summary> public static List<DBSlashCommand>? SlashCommands;
public CMDLoaded? onCMDLoad;
/// <summary>
/// Event that is fired when a <see cref="DBEvent" /> is successfully loaded into events list
/// </summary>
public EVELoaded? onEVELoad;
/// <summary>
/// Event that is fired when a <see cref="DBEvent" /> is successfully loaded into events list
/// </summary>
public SLSHLoaded? onSLSHLoad;
/// <summary>
/// The Plugin Loader constructor
/// </summary>
/// <param name="discordSocketClient">The discord bot client where the plugins will pe attached to</param>
public PluginLoader(DiscordSocketClient discordSocketClient) public PluginLoader(DiscordSocketClient discordSocketClient)
{ {
_client = discordSocketClient; _Client = discordSocketClient;
} }
public async Task LoadPlugins()
/// <summary>
/// A list of <see cref="DBCommand" /> commands
/// </summary>
public static List<DBCommand>? Commands { get; set; }
/// <summary>
/// A list of <see cref="DBEvent" /> commands
/// </summary>
public static List<DBEvent>? Events { get; set; }
/// <summary>
/// A list of <see cref="DBSlashCommand" /> commands
/// </summary>
public static List<DBSlashCommand>? SlashCommands { get; set; }
public static int PluginsLoaded
{ {
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;
}
}
/// <summary>
/// The main mathod that is called to load all events
/// </summary>
public async void LoadPlugins()
{
//Load all plugins
Commands = new List<DBCommand>(); Commands = new List<DBCommand>();
Events = new List<DBEvent>(); Events = new List<DBEvent>();
SlashCommands = new List<DBSlashCommand>(); SlashCommands = new List<DBSlashCommand>();
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"); var loader = new Loader(Config.AppSettings["PluginFolder"], "dll");
loader.FileLoaded += args => Config.Logger.Log($"{args.PluginName} file Loaded", source: typeof(PluginLoader), type: LogType.INFO);
loader.PluginLoaded += Loader_PluginLoaded; loader.OnFileLoadedException += FileLoadedException;
var res = loader.Load(); loader.OnPluginLoaded += OnPluginLoaded;
Events = res.Item1;
Commands = res.Item2; await loader.Load();
SlashCommands = res.Item3;
} }
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": case PluginType.COMMAND:
onCMDLoad?.Invoke(((DBCommand)args.Plugin!).Command, args.TypeName!, args.IsLoaded, args.Exception); Commands.Add((DBCommand)result.Plugin);
OnCommandLoaded?.Invoke(result);
break; break;
case "DBEvent": case PluginType.EVENT:
try if (this.TryStartEvent((DBEvent)result.Plugin))
{ {
if (args.IsLoaded) Events.Add((DBEvent)result.Plugin);
((DBEvent)args.Plugin!).Start(_client); OnEventLoaded?.Invoke(result);
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);
} }
break; break;
case "DBSlashCommand": case PluginType.SLASH_COMMAND:
if (args.IsLoaded) if (this.TryStartSlashCommand((DBSlashCommand)result.Plugin))
{ {
var slash = (DBSlashCommand)args.Plugin; SlashCommands.Add((DBSlashCommand)result.Plugin);
var builder = new SlashCommandBuilder(); OnSlashCommandLoaded?.Invoke(result);
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());
} }
break;
case PluginType.UNKNOWN:
default:
Config.Logger.Log("Unknown plugin type", typeof(PluginLoader), LogType.ERROR);
break; 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);
}
}
} }

View File

@@ -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;
}
}
}

View File

@@ -2,7 +2,7 @@ using PluginManager.Interfaces.Updater;
namespace PluginManager.Online.Helpers; namespace PluginManager.Online.Helpers;
public class ApplicationVersion : Version public class ApplicationVersion: Version
{ {
public ApplicationVersion(int major, int minor, int patch): base(major, minor, patch) 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) public ApplicationVersion(string versionAsString): base(versionAsString)
{ {
} }
} }

View File

@@ -3,7 +3,7 @@ using PluginManager.Interfaces.Updater;
namespace PluginManager.Online.Helpers; namespace PluginManager.Online.Helpers;
public class PluginVersion : Version public class PluginVersion: Version
{ {
[JsonConstructor] [JsonConstructor]
public PluginVersion(int major, int minor, int patch): base(major, minor, patch) public PluginVersion(int major, int minor, int patch): base(major, minor, patch)

View File

@@ -9,53 +9,54 @@ namespace PluginManager.Online;
public class PluginsManager 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 _DefaultBaseUrl = "https://raw.githubusercontent.com/andreitdr/SethPlugins";
private static readonly string _DefaultPluginsLink = "PluginsList.json"; private static readonly string _DefaultPluginsLink = "PluginsList.json";
public string Branch { get; init; } public string Branch { get; init; }
public string BaseUrl { get; init; } public string BaseUrl { get; init; }
private string PluginsLink => $"{BaseUrl}/{Branch}/{_DefaultPluginsLink}"; private string PluginsLink => $"{BaseUrl}/{Branch}/{_DefaultPluginsLink}";
public PluginsManager(Uri baseUrl, string branch) public PluginsManager(Uri baseUrl, string branch)
{ {
this.BaseUrl = baseUrl.ToString(); BaseUrl = baseUrl.ToString();
this.Branch = branch; Branch = branch;
} }
public PluginsManager(string branch) public PluginsManager(string branch)
{ {
this.BaseUrl = _DefaultBaseUrl; BaseUrl = _DefaultBaseUrl;
this.Branch = branch; Branch = branch;
} }
public PluginsManager() public PluginsManager()
{ {
this.BaseUrl = _DefaultBaseUrl; BaseUrl = _DefaultBaseUrl;
this.Branch = _DefaultBranch; Branch = _DefaultBranch;
} }
public async Task<List<PluginOnlineInfo?>> GetPluginsList() public async Task<List<PluginOnlineInfo?>> GetPluginsList()
{ {
string jsonText = await ServerCom.GetAllTextFromUrl(PluginsLink); var jsonText = await ServerCom.GetAllTextFromUrl(PluginsLink);
List<PluginOnlineInfo?> result = await JsonManager.ConvertFromJson<List<PluginOnlineInfo?>>(jsonText); List<PluginOnlineInfo?> result = await JsonManager.ConvertFromJson<List<PluginOnlineInfo?>>(jsonText);
OSType currentOS = OperatingSystem.IsWindows() ? OSType.WINDOWS : OperatingSystem.IsLinux() ? OSType.LINUX : OSType.MACOSX; var currentOS = OperatingSystem.IsWindows() ? OSType.WINDOWS :
OperatingSystem.IsLinux() ? OSType.LINUX : OSType.MACOSX;
return result.FindAll(pl => (pl.SupportedOS & currentOS) != 0); return result.FindAll(pl => (pl.SupportedOS & currentOS) != 0);
} }
public async Task<PluginOnlineInfo?> GetPluginDataByName(string pluginName) public async Task<PluginOnlineInfo?> GetPluginDataByName(string pluginName)
{ {
List<PluginOnlineInfo?> plugins = await GetPluginsList(); List<PluginOnlineInfo?> plugins = await GetPluginsList();
PluginOnlineInfo? result = plugins.Find(p => p.Name == pluginName); var result = plugins.Find(p => p.Name == pluginName);
return result; return result;
} }
} }

View File

@@ -21,7 +21,7 @@ public static class ServerCom
var lines = response.Split('\n'); var lines = response.Split('\n');
return lines.ToList(); return lines.ToList();
} }
/// <summary> /// <summary>
/// Get all text from a file async /// Get all text from a file async
/// </summary> /// </summary>

View File

@@ -13,7 +13,7 @@ public static class ArchiveManager
public static void Initialize() public static void Initialize()
{ {
if (IsInitialized) if (IsInitialized)
throw new Exception("ArchiveManager is already initialized"); throw new Exception("ArchiveManager is already initialized");
if (!Config.AppSettings.ContainsKey("ArchiveFolder")) if (!Config.AppSettings.ContainsKey("ArchiveFolder"))
@@ -89,7 +89,7 @@ public static class ArchiveManager
} }
catch (Exception ex) 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); await Task.Delay(100);
return await ReadFromPakAsync(fileName, archFile); return await ReadFromPakAsync(fileName, archFile);
} }
@@ -126,7 +126,7 @@ public static class ArchiveManager
} }
catch (Exception ex) catch (Exception ex)
{ {
Config.Logger.Log(ex.Message, source: typeof(ArchiveManager), type: LogType.ERROR); Config.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.ERROR);
} }
currentZipFile++; currentZipFile++;
@@ -158,7 +158,7 @@ public static class ArchiveManager
} }
catch (Exception ex) 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); await Task.Delay(10);

View File

@@ -17,26 +17,26 @@ public class DbCommandExecutingArguments
public DbCommandExecutingArguments(SocketUserMessage? message, DiscordSocketClient client) public DbCommandExecutingArguments(SocketUserMessage? message, DiscordSocketClient client)
{ {
this.context = new SocketCommandContext(client, message); context = new SocketCommandContext(client, message);
int pos = 0; var pos = 0;
if (message.HasMentionPrefix(client.CurrentUser, ref pos)) if (message.HasMentionPrefix(client.CurrentUser, ref pos))
{ {
var mentionPrefix = "<@" + client.CurrentUser.Id + ">"; var mentionPrefix = "<@" + client.CurrentUser.Id + ">";
this.cleanContent = message.Content.Substring(mentionPrefix.Length + 1); cleanContent = message.Content.Substring(mentionPrefix.Length + 1);
} }
else 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; string[]? argsClean = null;
if (split.Length > 1) if (split.Length > 1)
argsClean = string.Join(' ', split, 1, split.Length - 1).Split(' '); argsClean = string.Join(' ', split, 1, split.Length - 1).Split(' ');
this.commandUsed = split[0]; commandUsed = split[0];
this.arguments = argsClean; arguments = argsClean;
} }
public SocketCommandContext context { get; init; } public SocketCommandContext context { get; init; }

View File

@@ -32,10 +32,18 @@ public enum InternalActionRunType
} }
[Flags] [Flags]
public enum OSType : byte public enum OSType: byte
{ {
NONE = 0, NONE = 0,
WINDOWS = 1 << 0, WINDOWS = 1 << 0,
LINUX = 2 << 1, LINUX = 2 << 1,
MACOSX = 3 << 2, MACOSX = 3 << 2
} }
public enum PluginType
{
UNKNOWN,
COMMAND,
EVENT,
SLASH_COMMAND
}

View File

@@ -18,7 +18,11 @@ public class JsonManager
public static async Task SaveToJsonFile<T>(string file, T Data) public static async Task SaveToJsonFile<T>(string file, T Data)
{ {
var str = new MemoryStream(); 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 File.WriteAllBytesAsync(file, str.ToArray());
await str.FlushAsync(); await str.FlushAsync();
str.Close(); str.Close();

View File

@@ -43,9 +43,15 @@ public class Log: ILog
ThrowTime = DateTime.Now; 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() public string AsLongString()
{ {

View File

@@ -33,7 +33,7 @@ public class SettingsDictionary<TKey, TValue>: IDictionary<TKey, TValue>
{ {
if (File.Exists(_file)) if (File.Exists(_file))
{ {
string FileContent = File.ReadAllText(_file); var FileContent = File.ReadAllText(_file);
if (string.IsNullOrEmpty(FileContent)) if (string.IsNullOrEmpty(FileContent))
File.WriteAllText(_file, "{}"); File.WriteAllText(_file, "{}");
@@ -66,62 +66,62 @@ public class SettingsDictionary<TKey, TValue>: IDictionary<TKey, TValue>
public void Add(KeyValuePair<TKey, TValue> item) public void Add(KeyValuePair<TKey, TValue> item)
{ {
this._dictionary!.Add(item); _dictionary!.Add(item);
} }
public void Clear() public void Clear()
{ {
this._dictionary!.Clear(); _dictionary!.Clear();
} }
public bool Contains(KeyValuePair<TKey, TValue> item) public bool Contains(KeyValuePair<TKey, TValue> item)
{ {
return this._dictionary!.Contains(item); return _dictionary!.Contains(item);
} }
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{ {
this._dictionary!.CopyTo(array, arrayIndex); _dictionary!.CopyTo(array, arrayIndex);
} }
public bool Remove(KeyValuePair<TKey, TValue> item) public bool Remove(KeyValuePair<TKey, TValue> item)
{ {
return this._dictionary!.Remove(item); return _dictionary!.Remove(item);
} }
public int Count => _dictionary!.Count; public int Count => _dictionary!.Count;
public bool IsReadOnly => _dictionary!.IsReadOnly; public bool IsReadOnly => _dictionary!.IsReadOnly;
public void Add(TKey key, TValue value) public void Add(TKey key, TValue value)
{ {
this._dictionary!.Add(key, value); _dictionary!.Add(key, value);
} }
public bool ContainsKey(TKey key) public bool ContainsKey(TKey key)
{ {
return this._dictionary!.ContainsKey(key); return _dictionary!.ContainsKey(key);
} }
public bool Remove(TKey key) public bool Remove(TKey key)
{ {
return this._dictionary!.Remove(key); return _dictionary!.Remove(key);
} }
public bool TryGetValue(TKey key, out TValue value) 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] public TValue this[TKey key]
{ {
get get
{ {
if (this._dictionary!.ContainsKey(key)) if (_dictionary!.ContainsKey(key))
if (this._dictionary[key] is string s && !string.IsNullOrEmpty(s) && !string.IsNullOrWhiteSpace(s)) if (_dictionary[key] is string s && !string.IsNullOrEmpty(s) && !string.IsNullOrWhiteSpace(s))
return this._dictionary[key]; return _dictionary[key];
return default!; return default!;
} }
set => this._dictionary![key] = value; set => _dictionary![key] = value;
} }
public ICollection<TKey> Keys => _dictionary!.Keys; public ICollection<TKey> Keys => _dictionary!.Keys;

View File

@@ -4,10 +4,10 @@ public class OnlineDependencyInfo
{ {
public string DownloadLink { get; private set; } public string DownloadLink { get; private set; }
public string DownloadLocation { get; private set; } public string DownloadLocation { get; private set; }
public OnlineDependencyInfo(string downloadLink, string downloadLocation) public OnlineDependencyInfo(string downloadLink, string downloadLocation)
{ {
DownloadLink = downloadLink; DownloadLink = downloadLink;
DownloadLocation = downloadLocation; DownloadLocation = downloadLocation;
} }
} }

View File

@@ -6,17 +6,17 @@ namespace PluginManager.Plugin;
public class PluginInfo public class PluginInfo
{ {
public string PluginName { get; private set; } 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 FileInfo FileData { get; private set; }
public PluginInfo(string pluginName, IVersion pluginVersion) public PluginInfo(string pluginName, IVersion pluginVersion)
{ {
PluginName = pluginName; PluginName = pluginName;
PluginVersion = pluginVersion; PluginVersion = pluginVersion;
FileData = new FileInfo($"{Config.AppSettings["PluginFolder"]}/{pluginName}.dll"); FileData = new FileInfo($"{Config.AppSettings["PluginFolder"]}/{pluginName}.dll");
} }
public static PluginInfo FromOnlineInfo(PluginOnlineInfo onlineInfo) public static PluginInfo FromOnlineInfo(PluginOnlineInfo onlineInfo)
{ {
return new PluginInfo(onlineInfo.Name, onlineInfo.Version); return new PluginInfo(onlineInfo.Name, onlineInfo.Version);

View File

@@ -15,35 +15,35 @@ public class PluginOnlineInfo
public List<OnlineDependencyInfo> Dependencies { get; private set; } public List<OnlineDependencyInfo> Dependencies { get; private set; }
public OSType SupportedOS { get; private set; } public OSType SupportedOS { get; private set; }
public bool HasDependencies { get; init; } public bool HasDependencies { get; init; }
[JsonConstructor] [JsonConstructor]
public PluginOnlineInfo(string name, PluginVersion version, string description, string downLoadLink, OSType supportedOS, List<OnlineDependencyInfo> dependencies) public PluginOnlineInfo(string name, PluginVersion version, string description, string downLoadLink, OSType supportedOS, List<OnlineDependencyInfo> dependencies)
{ {
Name = name; Name = name;
Version = version; Version = version;
Description = description; Description = description;
DownLoadLink = downLoadLink; DownLoadLink = downLoadLink;
SupportedOS = supportedOS; SupportedOS = supportedOS;
Dependencies = dependencies; Dependencies = dependencies;
HasDependencies = dependencies.Count > 0; HasDependencies = dependencies.Count > 0;
} }
public PluginOnlineInfo(string name, PluginVersion version, string description, string downLoadLink, OSType supportedOS) public PluginOnlineInfo(string name, PluginVersion version, string description, string downLoadLink, OSType supportedOS)
{ {
Name = name; Name = name;
Version = version; Version = version;
Description = description; Description = description;
DownLoadLink = downLoadLink; DownLoadLink = downLoadLink;
SupportedOS = supportedOS; SupportedOS = supportedOS;
Dependencies = new List<OnlineDependencyInfo>(); Dependencies = new List<OnlineDependencyInfo>();
HasDependencies = false; HasDependencies = false;
} }
public static async Task<PluginOnlineInfo> FromRawData(string jsonText) public static async Task<PluginOnlineInfo> FromRawData(string jsonText)
{ {
return await JsonManager.ConvertFromJson<PluginOnlineInfo>(jsonText); return await JsonManager.ConvertFromJson<PluginOnlineInfo>(jsonText);
} }
public override string ToString() public override string ToString()
{ {
return $"{Name} - {Version} ({Description})"; return $"{Name} - {Version} ({Description})";

View File

@@ -12,17 +12,17 @@
<None Remove="BlankWindow1.xaml"/> <None Remove="BlankWindow1.xaml"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.6" /> <PackageReference Include="Avalonia" Version="11.0.6"/>
<PackageReference Include="Discord.Net" Version="3.11.0"/> <PackageReference Include="Discord.Net" Version="3.11.0"/>
<PackageReference Include="Spectre.Console" Version="0.47.0" /> <PackageReference Include="Spectre.Console" Version="0.47.0"/>
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.118"/> <PackageReference Include="System.Data.SQLite.Core" Version="1.0.118"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<UpToDateCheckInput Remove="UI\Controls\MessageBox.axaml" /> <UpToDateCheckInput Remove="UI\Controls\MessageBox.axaml"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Spectre.Console"> <Reference Include="Spectre.Console">
<HintPath>..\..\..\.nuget\packages\spectre.console\0.47.0\lib\net7.0\Spectre.Console.dll</HintPath> <HintPath>..\..\..\.nuget\packages\spectre.console\0.47.0\lib\net7.0\Spectre.Console.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -13,17 +13,19 @@ public enum MessageBoxButtons
{ {
YesNo, YesNo,
YesNoCancel, YesNoCancel,
ContinueCancel, ContinueCancel
} }
internal interface IOutputModel internal interface IOutputModel
{ {
internal Task ShowMessageBox(string title, string message, MessageBoxType type); internal Task ShowMessageBox(string title, string message, MessageBoxType type);
internal Task<string> ShowInputBox(string title, string message); internal Task<string> ShowInputBox(string title, string message);
internal Task ShowMessageBox(string message); internal Task ShowMessageBox(string message);
internal Task<int> ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning); internal Task<int> ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning);
internal Task ShowNotification(string title, string message, int timeout_seconds = 5); internal Task ShowNotification(string title, string message, int timeout_seconds = 5);
} }

View File

@@ -3,7 +3,7 @@ using System.Threading.Tasks;
namespace PluginManager.UX.Linux; namespace PluginManager.UX.Linux;
internal class KDE : IOutputModel internal class KDE: IOutputModel
{ {
internal string KdeDialogApplication { get; } = "kdialog"; internal string KdeDialogApplication { get; } = "kdialog";
@@ -11,15 +11,15 @@ internal class KDE : IOutputModel
{ {
var process = new Process(); var process = new Process();
process.StartInfo.FileName = KdeDialogApplication; process.StartInfo.FileName = KdeDialogApplication;
string typeStr = type switch var typeStr = type switch
{ {
MessageBoxType.Info => "msgbox", MessageBoxType.Info => "msgbox",
MessageBoxType.Warning => "sorry", MessageBoxType.Warning => "sorry",
MessageBoxType.Error => "error", MessageBoxType.Error => "error",
_ => "info" _ => "info"
}; };
process.StartInfo.Arguments = $"--title \"{title}\" --{typeStr} \"{message}\""; process.StartInfo.Arguments = $"--title \"{title}\" --{typeStr} \"{message}\"";
process.Start(); process.Start();
await process.WaitForExitAsync(); await process.WaitForExitAsync();
@@ -28,48 +28,48 @@ internal class KDE : IOutputModel
public async Task<string> ShowInputBox(string title, string message) public async Task<string> ShowInputBox(string title, string message)
{ {
var process = new Process(); var process = new Process();
process.StartInfo.FileName = KdeDialogApplication; process.StartInfo.FileName = KdeDialogApplication;
process.StartInfo.Arguments = $"--title \"{title}\" --inputbox \"{message}\""; process.StartInfo.Arguments = $"--title \"{title}\" --inputbox \"{message}\"";
process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true; process.StartInfo.RedirectStandardInput = true;
process.Start(); process.Start();
await process.WaitForExitAsync(); await process.WaitForExitAsync();
return await process.StandardOutput.ReadToEndAsync(); return await process.StandardOutput.ReadToEndAsync();
} }
public async Task ShowMessageBox(string message) public async Task ShowMessageBox(string message)
{ {
var process = new Process(); var process = new Process();
process.StartInfo.FileName = KdeDialogApplication; process.StartInfo.FileName = KdeDialogApplication;
process.StartInfo.Arguments = $"--msgbox \"{message}\""; process.StartInfo.Arguments = $"--msgbox \"{message}\"";
process.Start(); process.Start();
await process.WaitForExitAsync(); await process.WaitForExitAsync();
} }
public async Task<int> ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning) public async Task<int> ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning)
{ {
var process = new Process(); var process = new Process();
process.StartInfo.FileName = KdeDialogApplication; process.StartInfo.FileName = KdeDialogApplication;
string buttonsStr = buttons switch var buttonsStr = buttons switch
{ {
MessageBoxButtons.YesNo => "yesno", MessageBoxButtons.YesNo => "yesno",
MessageBoxButtons.YesNoCancel => "yesnocancel", MessageBoxButtons.YesNoCancel => "yesnocancel",
MessageBoxButtons.ContinueCancel => "continuecancel", MessageBoxButtons.ContinueCancel => "continuecancel",
_ => "yesno" _ => "yesno"
}; };
string typeStr = isWarning ? "warning" : ""; var typeStr = isWarning ? "warning" : "";
process.StartInfo.Arguments = $"--title \"{title}\" --{typeStr}{buttonsStr} \"{message}\""; process.StartInfo.Arguments = $"--title \"{title}\" --{typeStr}{buttonsStr} \"{message}\"";
process.Start(); process.Start();
await process.WaitForExitAsync(); await process.WaitForExitAsync();
return process.ExitCode; return process.ExitCode;
} }
public async Task ShowNotification(string title, string message, int timeout_seconds = 5) public async Task ShowNotification(string title, string message, int timeout_seconds = 5)
{ {
var process = new Process(); var process = new Process();
process.StartInfo.FileName = KdeDialogApplication; process.StartInfo.FileName = KdeDialogApplication;
process.StartInfo.Arguments = $"--title \"{title}\" --passivepopup \"{message}\" {timeout_seconds}"; process.StartInfo.Arguments = $"--title \"{title}\" --passivepopup \"{message}\" {timeout_seconds}";
process.Start(); process.Start();
await process.WaitForExitAsync(); await process.WaitForExitAsync();

View File

@@ -1,45 +1,43 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Spectre.Console; using Spectre.Console;
namespace PluginManager.UX.Other; namespace PluginManager.UX.Other;
internal class Console: IOutputModel
internal class Console : IOutputModel
{ {
public Task ShowMessageBox(string title, string message, MessageBoxType type) public Task ShowMessageBox(string title, string message, MessageBoxType type)
{ {
AnsiConsole.Markup(title); AnsiConsole.Markup(title);
AnsiConsole.Markup(message); AnsiConsole.Markup(message);
return Task.CompletedTask; return Task.CompletedTask;
} }
public Task<string> ShowInputBox(string title, string message) public Task<string> ShowInputBox(string title, string message)
{ {
AnsiConsole.MarkupLine(title); AnsiConsole.MarkupLine(title);
string input = AnsiConsole.Ask<string>(message); var input = AnsiConsole.Ask<string>(message);
return Task.FromResult(input); return Task.FromResult(input);
} }
public Task ShowMessageBox(string message) public Task ShowMessageBox(string message)
{ {
AnsiConsole.MarkupLine(message); AnsiConsole.MarkupLine(message);
return Task.CompletedTask; return Task.CompletedTask;
} }
public Task<int> ShowMessageBox(string title, string message,MessageBoxButtons buttons, bool isWarning) public Task<int> ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning)
{ {
AnsiConsole.MarkupLine(title); AnsiConsole.MarkupLine(title);
AnsiConsole.MarkupLine(message); AnsiConsole.MarkupLine(message);
return Task.FromResult(0); return Task.FromResult(0);
} }
public Task ShowNotification(string title, string message, int timeout_seconds = 5) public Task ShowNotification(string title, string message, int timeout_seconds = 5)
{ {
return Task.CompletedTask; return Task.CompletedTask;

View File

@@ -2,10 +2,10 @@ using System.Threading.Tasks;
namespace PluginManager.UX; namespace PluginManager.UX;
public static class UxHandler public static class UxHandler
{ {
private static IOutputModel? _model; private static IOutputModel? _model;
public static void Init() public static void Init()
{ {
_model = Config.AppSettings["UI"] switch _model = Config.AppSettings["UI"] switch
@@ -14,32 +14,32 @@ public static class UxHandler
"CONSOLE" => new Other.Console(), "CONSOLE" => new Other.Console(),
_ => null _ => null
}; };
} }
public static async Task ShowMessageBox(string title, string message, MessageBoxType type = MessageBoxType.Info) public static async Task ShowMessageBox(string title, string message, MessageBoxType type = MessageBoxType.Info)
{ {
await _model.ShowMessageBox(title, message, type); await _model.ShowMessageBox(title, message, type);
} }
public static async Task<string> ShowInputBox(string title, string message) public static async Task<string> ShowInputBox(string title, string message)
{ {
return await _model.ShowInputBox(title, message); return await _model.ShowInputBox(title, message);
} }
public static async Task ShowMessageBox(string message) public static async Task ShowMessageBox(string message)
{ {
await _model.ShowMessageBox(message); await _model.ShowMessageBox(message);
} }
public static async Task<int> ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning) public static async Task<int> ShowMessageBox(string title, string message, MessageBoxButtons buttons, bool isWarning)
{ {
return await _model.ShowMessageBox(title, message, buttons, isWarning); return await _model.ShowMessageBox(title, message, buttons, isWarning);
} }
public static async Task ShowNotification(string title, string message, int timeout_seconds = 5) public static async Task ShowNotification(string title, string message, int timeout_seconds = 5)
{ {
await _model.ShowNotification(title, message, timeout_seconds); await _model.ShowNotification(title, message, timeout_seconds);
} }
} }