Fixed some text and added some missing texts to commands. Added new command to clear screen and formated code.

This commit is contained in:
2023-07-03 14:39:50 +03:00
parent 4a6a12baae
commit 298e557260
36 changed files with 1503 additions and 1542 deletions

View File

@@ -0,0 +1,20 @@
using System;
using System.Threading.Tasks;
using PluginManager.Interfaces;
using PluginManager.Others;
namespace DiscordBot.Bot.Actions;
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 Task Execute(string[] args)
{
Console.Clear();
return Task.CompletedTask;
}
}

View File

@@ -8,15 +8,16 @@ namespace DiscordBot.Bot.Actions;
public class Exit : ICommandAction public class Exit : ICommandAction
{ {
public string ActionName => "exit"; public string ActionName => "exit";
public string Description => "Exits the bot and saves the config. Use exit help for more info."; public string Description => "Exits the bot and saves the config. Use exit help for more info.";
public string Usage => "exit [help|force]"; public string Usage => "exit [help|force]";
public InternalActionRunType RunType => InternalActionRunType.ON_CALL; public InternalActionRunType RunType => InternalActionRunType.ON_CALL;
public async Task Execute(string[] args) public async Task Execute(string[] args)
{ {
if (args is null || args.Length == 0) if (args is null || args.Length == 0)
{ {
Config.Logger.Log("Exiting...", "Exit", LogLevel.INFO); Config.Logger.Log("Exiting...", "Exit");
Config.Data.Save(); Config.Data.Save();
Environment.Exit(0); Environment.Exit(0);
} }
@@ -31,7 +32,7 @@ public class Exit : ICommandAction
break; break;
case "force": case "force":
Config.Logger.Log("Exiting...", "Exit", LogLevel.INFO); Config.Logger.Log("Exiting...", "Exit");
Environment.Exit(0); Environment.Exit(0);
break; break;

View File

@@ -1,62 +1,60 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordBot.Utilities;
using PluginManager.Others;
using PluginManager.Interfaces; using PluginManager.Interfaces;
using PluginManager.Others;
namespace DiscordBot.Bot.Actions namespace DiscordBot.Bot.Actions;
public class Help : ICommandAction
{ {
public class Help : ICommandAction public string ActionName => "help";
public string Description => "Shows the list of commands and their usage";
public string Usage => "help [command]";
public InternalActionRunType RunType => InternalActionRunType.ON_CALL;
public async Task Execute(string[] args)
{ {
public string ActionName => "help"; if (args == null || args.Length == 0)
public string Description => "Shows the list of commands and their usage";
public string Usage => "help [command]";
public InternalActionRunType RunType => InternalActionRunType.ON_CALL;
public async Task Execute(string[] args)
{ {
if (args == null || args.Length == 0) var items = new List<string[]>
{ {
var items = new List<string[]> new[] { "-", "-", "-" },
{ new[] { "Command", "Usage", "Description" },
new[] { "-", "-", "-" }, 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[] { "-", "-", "-" });
DiscordBot.Utilities.Utilities.FormatAndAlignTable(items, Utilities.TableFormat.CENTER_EACH_COLUMN_BASED); Utilities.Utilities.FormatAndAlignTable(items,
return; TableFormat.CENTER_EACH_COLUMN_BASED);
} return;
if (!Program.internalActionManager.Actions.ContainsKey(args[0]))
{
Console.WriteLine("Command not found");
return;
}
var action = Program.internalActionManager.Actions[args[0]];
var actionData = new List<string[]>
{
new[] { "-", "-", "-" },
new[] { "Command", "Usage", "Description" },
new[] { "-", "-", "-"},
new[] { action.ActionName, action.Usage, action.Description },
new[] { "-", "-", "-" }
};
DiscordBot.Utilities.Utilities.FormatAndAlignTable(actionData, Utilities.TableFormat.CENTER_EACH_COLUMN_BASED);
} }
if (!Program.internalActionManager.Actions.ContainsKey(args[0]))
{
Console.WriteLine("Command not found");
return;
}
var action = Program.internalActionManager.Actions[args[0]];
var actionData = new List<string[]>
{
new[] { "-", "-", "-" },
new[] { "Command", "Usage", "Description" },
new[] { "-", "-", "-" },
new[] { action.ActionName, action.Usage, action.Description },
new[] { "-", "-", "-" }
};
Utilities.Utilities.FormatAndAlignTable(actionData,
TableFormat.CENTER_EACH_COLUMN_BASED);
} }
} }

View File

@@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordBot.Utilities;
using PluginManager;
using PluginManager.Interfaces; using PluginManager.Interfaces;
using PluginManager.Loaders; using PluginManager.Loaders;
using PluginManager.Online; using PluginManager.Online;
@@ -10,12 +12,11 @@ namespace DiscordBot.Bot.Actions;
public class Plugin : ICommandAction public class Plugin : ICommandAction
{ {
public string ActionName => "plugin"; private bool pluginsLoaded;
public string Description => "Manages plugins. Use plugin help for more info."; public string ActionName => "plugin";
public string Usage => "plugin [help|list|load|install]"; public string Description => "Manages plugins. Use plugin help for more info.";
public InternalActionRunType RunType => InternalActionRunType.ON_CALL; public string Usage => "plugin [help|list|load|install]";
public InternalActionRunType RunType => InternalActionRunType.ON_CALL;
private bool pluginsLoaded = false;
public async Task Execute(string[] args) public async Task Execute(string[] args)
{ {
@@ -33,32 +34,30 @@ public class Plugin : ICommandAction
switch (args[0]) switch (args[0])
{ {
case "list": case "list":
var manager = new PluginManager.Online.PluginsManager(Program.URLs["PluginList"], Program.URLs["PluginVersions"]); var manager =
new PluginsManager(Program.URLs["PluginList"], Program.URLs["PluginVersions"]);
var data = await manager.GetAvailablePlugins(); var data = await manager.GetAvailablePlugins();
var items = new List<string[]> var items = new List<string[]>
{ {
new[] { "-", "-", "-", "-" }, new[] { "-", "-", "-", "-" },
new[] { "Name", "Type", "Description", "Required" }, new[] { "Name", "Description", "Type", "Version" },
new[] { "-", "-", "-", "-" } new[] { "-", "-", "-", "-" }
}; };
foreach (var plugin in data) foreach (var plugin in data) items.Add(new[] { plugin[0], plugin[1], plugin[2], plugin[3] });
{
items.Add(new[] { plugin[0], plugin[1], plugin[2], plugin[3] });
}
items.Add(new[] { "-", "-", "-", "-" }); items.Add(new[] { "-", "-", "-", "-" });
Utilities.Utilities.FormatAndAlignTable(items, Utilities.TableFormat.DEFAULT); Utilities.Utilities.FormatAndAlignTable(items, TableFormat.DEFAULT);
break; break;
case "load": case "load":
if (pluginsLoaded) if (pluginsLoaded)
break; break;
var loader = new PluginLoader(PluginManager.Config.DiscordBot.client); var loader = new PluginLoader(Config.DiscordBot.client);
var cc = Console.ForegroundColor; var cc = Console.ForegroundColor;
loader.onCMDLoad += (name, typeName, success, exception) => loader.onCMDLoad += (name, typeName, success, exception) =>
{ {
if (name == null || name.Length < 2) if (name == null || name.Length < 2)
@@ -122,33 +121,34 @@ public class Plugin : ICommandAction
loader.LoadPlugins(); loader.LoadPlugins();
Console.ForegroundColor = cc; Console.ForegroundColor = cc;
pluginsLoaded = true; pluginsLoaded = true;
break; break;
case "install": case "install":
string pluginName = string.Join(' ', args, 1, args.Length-1); var pluginName = string.Join(' ', args, 1, args.Length - 1);
if (string.IsNullOrEmpty(pluginName)|| pluginName.Length < 2) if (string.IsNullOrEmpty(pluginName) || pluginName.Length < 2)
{ {
Console.WriteLine("Please specify a plugin name"); Console.WriteLine("Please specify a plugin name");
break; break;
} }
var pluginManager = new PluginManager.Online.PluginsManager(Program.URLs["PluginList"], Program.URLs["PluginVersions"]); var pluginManager =
string[] pluginData = await pluginManager.GetPluginLinkByName(pluginName); new PluginsManager(Program.URLs["PluginList"], Program.URLs["PluginVersions"]);
var pluginData = await pluginManager.GetPluginLinkByName(pluginName);
if (pluginData == null || pluginData.Length == 0) if (pluginData == null || pluginData.Length == 0)
{ {
Console.WriteLine("Plugin not found"); Console.WriteLine("Plugin not found");
break; break;
} }
string pluginType = pluginData[0]; var pluginType = pluginData[0];
string pluginLink = pluginData[1]; var pluginLink = pluginData[1];
string pluginRequirements = pluginData[2]; var pluginRequirements = pluginData[2];
Console.WriteLine("Downloading plugin..."); Console.WriteLine("Downloading plugin...");
//download plugin progress bar for linux and windows terminals //download plugin progress bar for linux and windows terminals
Utilities.Utilities.Spinner spinner = new Utilities.Utilities.Spinner(); var spinner = new Utilities.Utilities.Spinner();
spinner.Start(); spinner.Start();
await ServerCom.DownloadFileAsync(pluginLink, $"./Data/{pluginType}s/{pluginName}.dll", null); await ServerCom.DownloadFileAsync(pluginLink, $"./Data/{pluginType}s/{pluginName}.dll", null);
spinner.Stop(); spinner.Stop();
@@ -161,15 +161,15 @@ public class Plugin : ICommandAction
} }
Console.WriteLine("Downloading plugin requirements..."); Console.WriteLine("Downloading plugin requirements...");
List<string> requirementsURLs = await ServerCom.ReadTextFromURL(pluginRequirements); var requirementsURLs = await ServerCom.ReadTextFromURL(pluginRequirements);
foreach (var requirement in requirementsURLs) foreach (var requirement in requirementsURLs)
{ {
if(requirement.Length < 2) if (requirement.Length < 2)
continue; continue;
string[] reqdata = requirement.Split(','); var reqdata = requirement.Split(',');
string url = reqdata[0]; var url = reqdata[0];
string filename = reqdata[1]; var filename = reqdata[1];
Console.WriteLine($"Downloading {filename}... "); Console.WriteLine($"Downloading {filename}... ");
spinner.Start(); spinner.Start();

View File

@@ -1,7 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using Discord; using Discord;
using PluginManager; using PluginManager;
using PluginManager.Interfaces; using PluginManager.Interfaces;
using PluginManager.Loaders; using PluginManager.Loaders;
@@ -56,7 +54,7 @@ internal class Help : DBCommand
var embedBuilder = new EmbedBuilder(); var embedBuilder = new EmbedBuilder();
var adminCommands = ""; var adminCommands = "";
var normalCommands = ""; var normalCommands = "";
foreach (var cmd in PluginLoader.Commands) foreach (var cmd in PluginLoader.Commands)
@@ -77,7 +75,7 @@ internal class Help : DBCommand
{ {
var embedBuilder = new EmbedBuilder(); var embedBuilder = new EmbedBuilder();
var cmd = PluginLoader.Commands.Find(p => p.Command == command || var cmd = PluginLoader.Commands.Find(p => p.Command == command ||
(p.Aliases is not null && p.Aliases.Contains(command))); (p.Aliases is not null && p.Aliases.Contains(command)));
if (cmd == null) return null; if (cmd == null) return null;
embedBuilder.AddField("Usage", Config.Data["prefix"] + cmd.Usage); embedBuilder.AddField("Usage", Config.Data["prefix"] + cmd.Usage);

View File

@@ -1,30 +1,28 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Discord; using Discord;
using Discord.WebSocket; using Discord.WebSocket;
using PluginManager.Interfaces; using PluginManager.Interfaces;
using PluginManager.Loaders;
using PluginManager.Others; using PluginManager.Others;
namespace DiscordBot.Bot.Commands.SlashCommands; 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 string Description => "This command allows you to check all loaded commands";
public bool canUseDM => true; public bool canUseDM => true;
public List<SlashCommandOptionBuilder> Options => new() public List<SlashCommandOptionBuilder> Options =>
{ new()
new SlashCommandOptionBuilder() {
.WithName("command") new SlashCommandOptionBuilder()
.WithDescription("The command you want to get help for") .WithName("command")
.WithRequired(false) .WithDescription("The command you want to get help for")
.WithType(ApplicationCommandOptionType.String) .WithRequired(false)
}; .WithType(ApplicationCommandOptionType.String)
};
public async void ExecuteServer(SocketSlashCommand context) public async void ExecuteServer(SocketSlashCommand context)
{ {
@@ -32,21 +30,17 @@ public class Help : DBSlashCommand
embedBuilder.WithTitle("Help Command"); embedBuilder.WithTitle("Help Command");
embedBuilder.WithColor(Functions.RandomColor); embedBuilder.WithColor(Functions.RandomColor);
var slashCommands = PluginManager.Loaders.PluginLoader.SlashCommands; var slashCommands = PluginLoader.SlashCommands;
var options = context.Data.Options; var options = context.Data.Options;
//Console.WriteLine("Options: " + options.Count); //Console.WriteLine("Options: " + options.Count);
if (options is null || options.Count == 0) if (options is null || options.Count == 0)
{
foreach (var slashCommand in slashCommands) foreach (var slashCommand in slashCommands)
{
embedBuilder.AddField(slashCommand.Name, slashCommand.Description, true); embedBuilder.AddField(slashCommand.Name, slashCommand.Description, true);
}
}
if (options.Count > 0) if (options.Count > 0)
{ {
string commandName = options.First().Name; var commandName = options.First().Name;
var slashCommand = slashCommands.FirstOrDefault(x => x.Name == commandName); var slashCommand = slashCommands.FirstOrDefault(x => x.Name == commandName);
if (slashCommand is null) if (slashCommand is null)
{ {
@@ -54,7 +48,8 @@ public class Help : DBSlashCommand
return; return;
} }
embedBuilder.AddField(slashCommand.Name, slashCommand.canUseDM,true).WithDescription(slashCommand.Description); embedBuilder.AddField(slashCommand.Name, slashCommand.canUseDM, true)
.WithDescription(slashCommand.Description);
} }
await context.RespondAsync(embed: embedBuilder.Build()); await context.RespondAsync(embed: embedBuilder.Build());

View File

@@ -1,39 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Nullable>disable</Nullable> <Nullable>disable</Nullable>
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
<SignAssembly>False</SignAssembly> <SignAssembly>False</SignAssembly>
<IsPublishable>True</IsPublishable> <IsPublishable>True</IsPublishable>
<AssemblyVersion>1.0.2.2</AssemblyVersion> <AssemblyVersion>1.0.2.2</AssemblyVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>none</DebugType> <DebugType>none</DebugType>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>none</DebugType> <DebugType>none</DebugType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Remove="Data\**" /> <Compile Remove="Data\**" />
<Compile Remove="obj\**" /> <Compile Remove="obj\**" />
<Compile Remove="Output\**" /> <Compile Remove="Output\**" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Remove="Data\**" /> <EmbeddedResource Remove="Data\**" />
<EmbeddedResource Remove="obj\**" /> <EmbeddedResource Remove="obj\**" />
<EmbeddedResource Remove="Output\**" /> <EmbeddedResource Remove="Output\**" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="Data\**" /> <None Remove="Data\**" />
<None Remove="obj\**" /> <None Remove="obj\**" />
<None Remove="Output\**" /> <None Remove="Output\**" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Discord.Net" Version="3.10.0" /> <PackageReference Include="Discord.Net" Version="3.10.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\PluginManager\PluginManager.csproj" /> <ProjectReference Include="..\PluginManager\PluginManager.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -1,32 +1,27 @@
using PluginManager.Others; using System;
using System;
using System.IO; using System.IO;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
namespace DiscordBot namespace DiscordBot;
public class Entry
{ {
public static void Main(string[] args)
public class Entry
{ {
public static void Main(string[] args) var currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += LoadFromSameFolder;
static Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
{ {
AppDomain currentDomain = AppDomain.CurrentDomain; var folderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
currentDomain.AssemblyResolve += new ResolveEventHandler(LoadFromSameFolder); "./Libraries");
var assemblyPath = Path.Combine(folderPath, new AssemblyName(args.Name).Name + ".dll");
static Assembly LoadFromSameFolder(object sender, ResolveEventArgs args) if (!File.Exists(assemblyPath)) return null;
{ var assembly = Assembly.LoadFrom(assemblyPath);
string folderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "./Libraries");
string assemblyPath = Path.Combine(folderPath, new AssemblyName(args.Name).Name + ".dll");
if (!File.Exists(assemblyPath)) return null;
Assembly assembly = Assembly.LoadFrom(assemblyPath);
return assembly;
}
Program.Startup(args);
return assembly;
} }
Program.Startup(args);
} }
} }

View File

@@ -1,96 +1,89 @@
using System.Diagnostics;
using System.IO;
using System; using System;
using System.Collections.Generic; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using PluginManager; using PluginManager;
using PluginManager.Others;
using PluginManager.Online; using PluginManager.Online;
namespace DiscordBot namespace DiscordBot;
public static class Installer
{ {
public static class Installer public static void GenerateStartupConfig()
{ {
Console.WriteLine("Welcome to the SethBot installer !");
Console.WriteLine("First, we need to configure the bot. Don't worry, it will be quick !");
Console.WriteLine("The following information will be stored in the config.json file in the ./Data/Resources folder. You can change it later from there.");
Console.WriteLine("The bot token is required to run the bot. You can get it from the Discord Developer Portal. (https://discord.com/developers/applications)");
public static void GenerateStartupConfig() if (!Config.Data.ContainsKey("token"))
{ {
Console.WriteLine("Welcome to the SethBot installer !"); Console.WriteLine("Please enter the bot token :");
Console.WriteLine("First, we need to configure the bot. Don't worry, it will be quick !"); var token = Console.ReadLine();
Console.WriteLine("The following information will be stored in the config.json file in the ./Data/Resources folder. You can change it later from there."); Config.Data.Add("token", token);
Console.WriteLine("The bot token is required to run the bot. You can get it from the Discord Developer Portal. (https://discord.com/developers/applications)");
if (!Config.Data.ContainsKey("token"))
{
Console.WriteLine("Please enter the bot token :");
var token = Console.ReadLine();
Config.Data.Add("token", token);
}
if (!Config.Data.ContainsKey("prefix"))
{
Console.WriteLine("Please enter the bot prefix :");
var prefix = Console.ReadLine();
Config.Data.Add("prefix", prefix);
}
if (!Config.Data.ContainsKey("ServerID"))
{
Console.WriteLine("Please enter the Server ID :");
var serverId = Console.ReadLine();
Config.Data.Add("ServerID", serverId);
}
Config.Logger.Log("Config Saved", "Installer", LogLevel.INFO);
Config.Data.Save();
Console.WriteLine("Config saved !");
} }
public static async Task SetupPluginDatabase() if (!Config.Data.ContainsKey("prefix"))
{ {
Console.WriteLine("The plugin database is required to run the bot but there is nothing configured yet."); Console.WriteLine("Please enter the bot prefix :");
Console.WriteLine("Please select one option : "); var prefix = Console.ReadLine();
Console.WriteLine("1. Download the official database file"); Config.Data.Add("prefix", prefix);
Console.WriteLine("2. Create a new (CUSTOM) database file"); }
int choice = 0;
Console.Write("Choice : "); if (!Config.Data.ContainsKey("ServerID"))
choice = int.Parse(Console.ReadLine()); {
if (choice != 1 && choice != 2) Console.WriteLine("Please enter the Server ID :");
var serverId = Console.ReadLine();
Config.Data.Add("ServerID", serverId);
}
Config.Logger.Log("Config Saved", "Installer");
Config.Data.Save();
Console.WriteLine("Config saved !");
}
public static async Task SetupPluginDatabase()
{
Console.WriteLine("The plugin database is required to run the bot but there is nothing configured yet.");
Console.WriteLine("Please select one option : ");
Console.WriteLine("1. Download the official database file");
Console.WriteLine("2. Create a new (CUSTOM) database file");
var choice = 0;
Console.Write("Choice : ");
choice = int.Parse(Console.ReadLine());
if (choice != 1 && choice != 2)
{
Console.WriteLine("Invalid choice !");
Console.WriteLine("Please restart the installer !");
Console.ReadKey();
Environment.Exit(0);
}
if (choice == 1)
await DownloadPluginDatabase();
if (choice == 2)
{
Console.WriteLine("Do you have a url to a valid database file ? (y/n)");
var answer = Console.ReadLine();
if (answer == "y")
{ {
Console.WriteLine("Invalid choice !"); Console.WriteLine("Please enter the url :");
Console.WriteLine("Please restart the installer !"); var url = Console.ReadLine();
Console.ReadKey(); await DownloadPluginDatabase(url);
Environment.Exit(0); return;
} }
if (choice == 1) Console.WriteLine("Do you want to create a new database file ? (y/n)");
await DownloadPluginDatabase(); answer = Console.ReadLine();
if (answer == "y")
if (choice == 2)
{ {
Console.WriteLine("Do you have a url to a valid database file ? (y/n)"); Console.WriteLine("A new file will be generated at ./Data/Resources/URLs.json");
var answer = Console.ReadLine(); Console.WriteLine("Please edit the file and restart the bot !");
if (answer == "y") Directory.CreateDirectory("./Data/Resources");
{ await File.WriteAllTextAsync("./Data/Resources/URLs.json",
Console.WriteLine("Please enter the url :"); @"
var url = Console.ReadLine();
await DownloadPluginDatabase(url);
return;
}
Console.WriteLine("Do you want to create a new database file ? (y/n)");
answer = Console.ReadLine();
if (answer == "y")
{
Console.WriteLine("A new file will be generated at ./Data/Resources/URLs.json");
System.Console.WriteLine("Please edit the file and restart the bot !");
Directory.CreateDirectory("./Data/Resources");
await File.WriteAllTextAsync("./Data/Resources/URLs.json",
@"
{ {
""PluginList"": """", ""PluginList"": """",
""PluginVersions"": """", ""PluginVersions"": """",
@@ -102,21 +95,20 @@ namespace DiscordBot
""WindowsLauncher"": """", ""WindowsLauncher"": """",
} }
".Replace(" ", "")); ".Replace(" ", ""));
Environment.Exit(0); Environment.Exit(0);
return;
}
} }
} }
}
private static async Task DownloadPluginDatabase(string url = "https://raw.githubusercontent.com/Wizzy69/SethDiscordBot/gh-pages/defaultURLs.json") private static async Task DownloadPluginDatabase(
{ string url = "https://raw.githubusercontent.com/andreitdr/SethDiscordBot/gh-pages/defaultURLs.json")
string path = "./Data/Resources/URLs.json"; {
var path = "./Data/Resources/URLs.json";
Directory.CreateDirectory("./Data/Resources"); Directory.CreateDirectory("./Data/Resources");
Utilities.Utilities.Spinner spinner = new Utilities.Utilities.Spinner(); var spinner = new Utilities.Utilities.Spinner();
spinner.Start(); spinner.Start();
await ServerCom.DownloadFileAsync(url, path, null); await ServerCom.DownloadFileAsync(url, path, null);
spinner.Stop(); spinner.Stop();
}
} }
} }

View File

@@ -1,26 +1,22 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Linq;
using PluginManager;
using PluginManager.Bot; using PluginManager.Bot;
using PluginManager.Online; using PluginManager.Online;
using PluginManager.Online.Helpers; using PluginManager.Online.Helpers;
using PluginManager.Others; using PluginManager.Others;
using PluginManager.Others.Actions;
using DiscordBot.Utilities;
using static PluginManager.Config; using static PluginManager.Config;
using PluginManager.Interfaces;
namespace DiscordBot; namespace DiscordBot;
public class Program public class Program
{ {
public static Json<string, string> URLs; public static Json<string, string> URLs;
public static PluginManager.Others.Actions.InternalActionManager internalActionManager; public static InternalActionManager internalActionManager;
/// <summary> /// <summary>
/// The main entry point for the application. /// The main entry point for the application.
@@ -30,15 +26,13 @@ public class Program
{ {
PreLoadComponents(args).Wait(); PreLoadComponents(args).Wait();
if (!Config.Data.ContainsKey("ServerID") || !Config.Data.ContainsKey("token") || if (!Data.ContainsKey("ServerID") || !Data.ContainsKey("token") ||
Config.Data["token"] == null || Data["token"] == null ||
(Config.Data["token"]?.Length != 70 && Config.Data["token"]?.Length != 59) || (Data["token"]?.Length != 70 && Data["token"]?.Length != 59) ||
!Config.Data.ContainsKey("prefix") || Config.Data["prefix"] == null || !Data.ContainsKey("prefix") || Data["prefix"] == null ||
Config.Data["prefix"]?.Length != 1 || Data["prefix"]?.Length != 1 ||
(args.Length == 1 && args[0] == "/reset")) (args.Length == 1 && args[0] == "/reset"))
{
Installer.GenerateStartupConfig(); Installer.GenerateStartupConfig();
}
HandleInput(args.ToList()).Wait(); HandleInput(args.ToList()).Wait();
} }
@@ -55,11 +49,11 @@ public class Program
while (true) while (true)
{ {
var cmd = Console.ReadLine(); string cmd = Console.ReadLine();
string[] args = cmd.Split(' '); string[] args = cmd.Split(' ');
string command = args[0]; string command = args[0];
args = args.Skip(1).ToArray(); args = args.Skip(1).ToArray();
if(args.Length == 0) if (args.Length == 0)
args = null; args = null;
internalActionManager.Execute(command, args).Wait(); // Execute the command internalActionManager.Execute(command, args).Wait(); // Execute the command
@@ -82,40 +76,40 @@ public class Program
Console.WriteLine(message); Console.WriteLine(message);
Console.WriteLine( Console.WriteLine(
$"Running on version: {Assembly.GetExecutingAssembly().GetName().Version}"); $"Running on version: {Assembly.GetExecutingAssembly().GetName().Version}");
Console.WriteLine($"Git URL: {Config.Data["GitURL"]}"); Console.WriteLine($"Git URL: {Data["GitURL"]}");
Utilities.Utilities.WriteColorText( Utilities.Utilities.WriteColorText(
"&rRemember to close the bot using the ShutDown command (&ysd&r) or some settings won't be saved\n"); "&rRemember to close the bot using the ShutDown command (&ysd&r) or some settings won't be saved\n");
Console.ForegroundColor = ConsoleColor.White; Console.ForegroundColor = ConsoleColor.White;
if (Config.Data.ContainsKey("LaunchMessage")) if (Data.ContainsKey("LaunchMessage"))
Utilities.Utilities.WriteColorText(Config.Data["LaunchMessage"]); Utilities.Utilities.WriteColorText(Data["LaunchMessage"]);
Utilities.Utilities.WriteColorText( Utilities.Utilities.WriteColorText(
"Please note that the bot saves a backup save file every time you are using the shudown command (&ysd&c)"); "Please note that the bot saves a backup save file every time you are using the shudown command (&ysd&c)");
Console.WriteLine("Running on " + Functions.GetOperatingSystem().ToString()); Console.WriteLine("Running on " + Functions.GetOperatingSystem());
Console.WriteLine("============================ LOG ============================"); Console.WriteLine("============================ LOG ============================");
try try
{ {
string token = ""; var token = "";
#if DEBUG #if DEBUG
if (File.Exists("./Data/Resources/token.txt")) token = File.ReadAllText("./Data/Resources/token.txt"); if (File.Exists("./Data/Resources/token.txt")) token = File.ReadAllText("./Data/Resources/token.txt");
else token = Config.Data["token"]; else token = Data["token"];
#else #else
token = Config.Data["token"]; token = Config.Data["token"];
#endif #endif
var prefix = Config.Data["prefix"]; var prefix = Data["prefix"];
var discordbooter = new Boot(token, prefix); var discordbooter = new Boot(token, prefix);
await discordbooter.Awake(); await discordbooter.Awake();
return discordbooter; return discordbooter;
} }
catch (Exception ex) catch (Exception ex)
{ {
Config.Logger.Log(ex.ToString(), "Bot", LogLevel.ERROR); Logger.Log(ex.ToString(), "Bot", LogLevel.ERROR);
return null; return null;
} }
} }
@@ -126,12 +120,11 @@ public class Program
/// <param name="args">The arguments</param> /// <param name="args">The arguments</param>
private static async Task HandleInput(List<string> args) private static async Task HandleInput(List<string> args)
{ {
Console.WriteLine("Loading Core ..."); Console.WriteLine("Loading Core ...");
//Handle arguments here: //Handle arguments here:
if(args.Contains("--gui")) if (args.Contains("--gui"))
{ {
// GUI not implemented yet // GUI not implemented yet
Console.WriteLine("GUI not implemented yet"); Console.WriteLine("GUI not implemented yet");
@@ -143,7 +136,7 @@ public class Program
var b = await StartNoGui(); var b = await StartNoGui();
try try
{ {
internalActionManager = new PluginManager.Others.Actions.InternalActionManager("./Data/Actions", "*.dll"); internalActionManager = new InternalActionManager("./Data/Actions", "*.dll");
await internalActionManager.Initialize(); await internalActionManager.Initialize();
NoGUI(); NoGUI();
@@ -152,42 +145,40 @@ 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)
{ {
if (Config.Data.ContainsKey("LaunchMessage")) if (Data.ContainsKey("LaunchMessage"))
Config.Data.Add("LaunchMessage", Data.Add("LaunchMessage",
"An error occured while closing the bot last time. Please consider closing the bot using the &rsd&c method !\nThere 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 &rsd&c method !\nThere is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !");
Config.Logger.Log("An error occured while closing the bot last time. Please consider closing the bot using the &rsd&c method !\nThere is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !", "Bot", LogLevel.ERROR); Logger
.Log("An error occured while closing the bot last time. Please consider closing the bot using the &rsd&c method !\nThere is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !",
"Bot", LogLevel.ERROR);
} }
} }
return;
} }
private static async Task PreLoadComponents(string[] args) private static async Task PreLoadComponents(string[] args)
{ {
await Initialize();
await Config.Initialize();
if (!Directory.Exists("./Data/Resources") || !File.Exists("./Data/Resources/URLs.json")) if (!Directory.Exists("./Data/Resources") || !File.Exists("./Data/Resources/URLs.json"))
{
await Installer.SetupPluginDatabase(); await Installer.SetupPluginDatabase();
}
URLs = new Json<string, string>("./Data/Resources/URLs.json"); URLs = new Json<string, string>("./Data/Resources/URLs.json");
Config.Logger.LogEvent += (message, type) => { Console.WriteLine(message); }; Logger.LogEvent += (message, type) => { Console.WriteLine(message); };
Console.WriteLine("Loading resources ..."); Console.WriteLine("Loading resources ...");
if (Config.Data.ContainsKey("DeleteLogsAtStartup")) if (Data.ContainsKey("DeleteLogsAtStartup"))
if (Config.Data["DeleteLogsAtStartup"] == "true") if (Data["DeleteLogsAtStartup"] == "true")
foreach (var file in Directory.GetFiles("./Output/Logs/")) foreach (var file in Directory.GetFiles("./Output/Logs/"))
File.Delete(file); File.Delete(file);
var OnlineDefaultKeys = var OnlineDefaultKeys =
await ServerCom.ReadTextFromURL(URLs["SetupKeys"]); await ServerCom.ReadTextFromURL(URLs["SetupKeys"]);
Config.Data["Version"] = Assembly.GetExecutingAssembly().GetName().Version.ToString(); Data["Version"] = Assembly.GetExecutingAssembly().GetName().Version.ToString();
foreach (var key in OnlineDefaultKeys) foreach (var key in OnlineDefaultKeys)
{ {
@@ -195,11 +186,11 @@ public class Program
var s = key.Split(' '); var s = key.Split(' ');
try try
{ {
Config.Data[s[0]] = s[1]; Data[s[0]] = s[1];
} }
catch (Exception ex) catch (Exception ex)
{ {
Config.Logger.Log(ex.ToString(), "Bot", LogLevel.ERROR); Logger.Log(ex.ToString(), "Bot", LogLevel.ERROR);
} }
} }
@@ -213,27 +204,27 @@ public class Program
switch (s[0]) switch (s[0])
{ {
case "CurrentVersion": case "CurrentVersion":
var currentVersion = Config.Data["Version"]; var currentVersion = Data["Version"];
var newVersion = s[1]; var newVersion = s[1];
if(new VersionString(newVersion) != new VersionString(newVersion)) if (new VersionString(newVersion) != new VersionString(newVersion))
{ {
Console.WriteLine("A new updated was found. Check the changelog for more information."); Console.WriteLine("A new updated was found. Check the changelog for more information.");
List<string> changeLog = await ServerCom.ReadTextFromURL(URLs["Changelog"]); var changeLog = await ServerCom.ReadTextFromURL(URLs["Changelog"]);
foreach (var item in changeLog) foreach (var item in changeLog)
Utilities.Utilities.WriteColorText(item); Utilities.Utilities.WriteColorText(item);
Console.WriteLine("Current version: " + currentVersion); Console.WriteLine("Current version: " + currentVersion);
Console.WriteLine("Latest version: " + newVersion); Console.WriteLine("Latest version: " + newVersion);
Console.WriteLine($"Download from here: https://github.com/andreitdr/SethDiscordBot/releases"); Console.WriteLine("Download from here: https://github.com/andreitdr/SethDiscordBot/releases");
Console.WriteLine("Press any key to continue ..."); Console.WriteLine("Press any key to continue ...");
Console.ReadKey(); Console.ReadKey();
} }
break;
} break;
}
} }
Console.Clear(); Console.Clear();
} }
} }

View File

@@ -1,25 +1,21 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using PluginManager;
namespace DiscordBot.Utilities; namespace DiscordBot.Utilities;
public static class Utilities public static class Utilities
{ {
private static Dictionary<char, ConsoleColor> Colors = new() private static readonly Dictionary<char, ConsoleColor> Colors = new()
{ {
{ 'g', ConsoleColor.Green }, { 'g', ConsoleColor.Green },
{ 'b', ConsoleColor.Blue }, { 'b', ConsoleColor.Blue },
{ 'r', ConsoleColor.Red }, { 'r', ConsoleColor.Red },
{ 'm', ConsoleColor.Magenta }, { 'm', ConsoleColor.Magenta },
{ 'y', ConsoleColor.Yellow } { 'y', ConsoleColor.Yellow }
}; };
private static char ColorPrefix = '&'; private static readonly char ColorPrefix = '&';
private static bool CanAproximateTo(this float f, float y) private static bool CanAproximateTo(this float f, float y)
@@ -36,9 +32,9 @@ public static class Utilities
{ {
if (format == TableFormat.CENTER_EACH_COLUMN_BASED) if (format == TableFormat.CENTER_EACH_COLUMN_BASED)
{ {
var tableLine = '-'; var tableLine = '-';
var tableCross = '+'; var tableCross = '+';
var tableWall = '|'; var tableWall = '|';
var len = new int[data[0].Length]; var len = new int[data[0].Length];
foreach (var line in data) foreach (var line in data)
@@ -144,7 +140,7 @@ public static class Utilities
if (format == TableFormat.DEFAULT) if (format == TableFormat.DEFAULT)
{ {
var widths = new int[data[0].Length]; var widths = new int[data[0].Length];
var space_between_columns = 3; var space_between_columns = 3;
for (var i = 0; i < data.Count; i++) for (var i = 0; i < data.Count; i++)
for (var j = 0; j < data[i].Length; j++) for (var j = 0; j < data[i].Length; j++)
@@ -174,7 +170,7 @@ public static class Utilities
public static void WriteColorText(string text, bool appendNewLineAtEnd = true) public static void WriteColorText(string text, bool appendNewLineAtEnd = true)
{ {
var initialForeGround = Console.ForegroundColor; var initialForeGround = Console.ForegroundColor;
var input = text.ToCharArray(); var input = text.ToCharArray();
for (var i = 0; i < input.Length; i++) for (var i = 0; i < input.Length; i++)
if (input[i] == ColorPrefix) if (input[i] == ColorPrefix)
{ {
@@ -203,25 +199,25 @@ public static class Utilities
} }
public class Spinner public class Spinner
{ {
private Thread thread;
private bool isRunning;
private readonly string[] Sequence; private readonly string[] Sequence;
private int position; private bool isRunning;
private int position;
private Thread thread;
public Spinner() public Spinner()
{ {
Sequence = new[] {"|", "/", "-", "\\"}; Sequence = new[] { "|", "/", "-", "\\" };
position = 0; position = 0;
} }
public void Start() public void Start()
{ {
Console.CursorVisible = false; Console.CursorVisible = false;
isRunning=true; isRunning = true;
thread = new Thread(() => { thread = new Thread(() =>
{
while (isRunning) while (isRunning)
{ {
Console.Write("\r" + Sequence[position]); Console.Write("\r" + Sequence[position]);
@@ -233,14 +229,12 @@ public static class Utilities
}); });
thread.Start(); thread.Start();
} }
public void Stop() public void Stop()
{ {
isRunning=false; isRunning = false;
Console.CursorVisible = true; Console.CursorVisible = true;
} }
} }
} }

View File

@@ -1,15 +1,8 @@
using System; namespace DiscordBot.Utilities;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DiscordBot.Utilities public enum TableFormat
{ {
public enum TableFormat CENTER_EACH_COLUMN_BASED,
{ CENTER_OVERALL_LENGTH,
CENTER_EACH_COLUMN_BASED, DEFAULT
CENTER_OVERALL_LENGTH,
DEFAULT
}
} }

View File

@@ -1,11 +1,9 @@
using System.Net.Mime;
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using PluginManager.Others;
namespace PluginManager.Bot; namespace PluginManager.Bot;
@@ -44,35 +42,37 @@ public class Boot
public Boot(string botToken, string botPrefix) public Boot(string botToken, string botPrefix)
{ {
this.botPrefix = botPrefix; this.botPrefix = botPrefix;
this.botToken = botToken; this.botToken = botToken;
} }
/// <summary> /// <summary>
/// Checks if the bot is ready /// Checks if the bot is ready
/// </summary> /// </summary>
/// <value> true if the bot is ready, othwerwise false </value> /// <value> true if the bot is ready, otherwise false </value>
public bool isReady { get; private set; } public bool isReady { get; private set; }
/// <summary> /// <summary>
/// The start method for the bot. This method is used to load the bot /// The start method for the bot. This method is used to load the bot
/// </summary> /// </summary>
/// <param name="config">The discord socket config. If null then the default one will be applied (AlwaysDownloadUsers=true, UseInteractionSnowflakeDate=false, GatewayIntents=GatewayIntents.All)</param> /// <param name="config">
/// The discord socket config. If null then the default one will be applied (AlwaysDownloadUsers=true,
/// UseInteractionSnowflakeDate=false, GatewayIntents=GatewayIntents.All)
/// </param>
/// <returns>Task</returns> /// <returns>Task</returns>
public async Task Awake(DiscordSocketConfig? config = null) public async Task Awake(DiscordSocketConfig? config = null)
{ {
if (config is null) if (config is null)
config = new DiscordSocketConfig config = new DiscordSocketConfig
{ {
AlwaysDownloadUsers = true, AlwaysDownloadUsers = true,
//Disable system clock checkup (for responses at slash commands) //Disable system clock checkup (for responses at slash commands)
UseInteractionSnowflakeDate = false, UseInteractionSnowflakeDate = false,
GatewayIntents = GatewayIntents.All GatewayIntents = GatewayIntents.All
}; };
client = new DiscordSocketClient(config); client = new DiscordSocketClient(config);
service = new CommandService(); service = new CommandService();
CommonTasks(); CommonTasks();
@@ -86,7 +86,6 @@ public class Boot
await commandServiceHandler.InstallCommandsAsync(); await commandServiceHandler.InstallCommandsAsync();
await Task.Delay(2000); await Task.Delay(2000);
Config._DiscordBotClient = this; Config._DiscordBotClient = this;
@@ -97,10 +96,10 @@ public class Boot
private void CommonTasks() private void CommonTasks()
{ {
if (client == null) return; if (client == null) return;
client.LoggedOut += Client_LoggedOut; client.LoggedOut += Client_LoggedOut;
client.Log += Log; client.Log += Log;
client.LoggedIn += LoggedIn; client.LoggedIn += LoggedIn;
client.Ready += Ready; client.Ready += Ready;
client.Disconnected += Client_Disconnected; client.Disconnected += Client_Disconnected;
} }
@@ -109,7 +108,8 @@ public class Boot
if (arg.Message.Contains("401")) if (arg.Message.Contains("401"))
{ {
Config.Data.Remove("token"); Config.Data.Remove("token");
Config.Logger.Log("The token is invalid. Please restart the bot and enter a valid token.", this, Others.LogLevel.ERROR); Config.Logger.Log("The token is invalid. Please restart the bot and enter a valid token.", this,
LogLevel.ERROR);
Config.Data.Save(); Config.Data.Save();
await Task.Delay(4000); await Task.Delay(4000);
Environment.Exit(0); Environment.Exit(0);
@@ -140,7 +140,7 @@ public class Boot
{ {
case LogSeverity.Error: case LogSeverity.Error:
case LogSeverity.Critical: case LogSeverity.Critical:
Config.Logger.Log(message.Message, this, Others.LogLevel.ERROR); Config.Logger.Log(message.Message, this, LogLevel.ERROR);
break; break;

View File

@@ -2,7 +2,6 @@ using System;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.Commands; using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using PluginManager.Interfaces; using PluginManager.Interfaces;
@@ -14,9 +13,9 @@ namespace PluginManager.Bot;
internal class CommandHandler internal class CommandHandler
{ {
private readonly string botPrefix; private readonly string botPrefix;
private readonly DiscordSocketClient client; private readonly DiscordSocketClient client;
private readonly CommandService commandService; private readonly CommandService commandService;
/// <summary> /// <summary>
/// Command handler constructor /// Command handler constructor
@@ -26,10 +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; this.client = client;
this.commandService = commandService; this.commandService = commandService;
this.botPrefix = botPrefix; this.botPrefix = botPrefix;
} }
/// <summary> /// <summary>
@@ -38,7 +36,7 @@ internal class CommandHandler
/// <returns></returns> /// <returns></returns>
public async Task InstallCommandsAsync() public async Task InstallCommandsAsync()
{ {
client.MessageReceived += MessageHandler; client.MessageReceived += MessageHandler;
client.SlashCommandExecuted += Client_SlashCommandExecuted; client.SlashCommandExecuted += Client_SlashCommandExecuted;
await commandService.AddModulesAsync(Assembly.GetEntryAssembly(), null); await commandService.AddModulesAsync(Assembly.GetEntryAssembly(), null);
} }
@@ -63,7 +61,6 @@ internal class CommandHandler
} }
return Task.CompletedTask; return Task.CompletedTask;
} }
/// <summary> /// <summary>
@@ -73,7 +70,6 @@ internal class CommandHandler
/// <returns></returns> /// <returns></returns>
private async Task MessageHandler(SocketMessage Message) private async Task MessageHandler(SocketMessage Message)
{ {
try try
{ {
if (Message.Author.IsBot) if (Message.Author.IsBot)
@@ -97,18 +93,22 @@ internal class CommandHandler
await commandService.ExecuteAsync(context, argPos, null); await commandService.ExecuteAsync(context, argPos, null);
DBCommand? plugin; DBCommand? plugin;
string cleanMessage = ""; var cleanMessage = "";
if (message.HasMentionPrefix(client.CurrentUser, ref argPos)) if (message.HasMentionPrefix(client.CurrentUser, ref argPos))
{ {
string mentionPrefix = "<@" + client.CurrentUser.Id + ">"; var mentionPrefix = "<@" + client.CurrentUser.Id + ">";
plugin = PluginLoader.Commands! plugin = PluginLoader.Commands!
.FirstOrDefault(plug => plug.Command == message.Content.Substring(mentionPrefix.Length+1).Split(' ')[0] || .FirstOrDefault(plug => plug.Command ==
( message.Content.Substring(mentionPrefix.Length + 1)
plug.Aliases is not null && .Split(' ')[0] ||
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])
));
cleanMessage = message.Content.Substring(mentionPrefix.Length + 1); cleanMessage = message.Content.Substring(mentionPrefix.Length + 1);
} }
@@ -116,23 +116,27 @@ internal class CommandHandler
else else
{ {
plugin = PluginLoader.Commands! plugin = PluginLoader.Commands!
.FirstOrDefault(p => p.Command == message.Content.Split(' ')[0].Substring(botPrefix.Length) || .FirstOrDefault(p => p.Command ==
(p.Aliases is not null && message.Content.Split(' ')[0].Substring(botPrefix.Length) ||
p.Aliases.Contains( (p.Aliases is not null &&
message.Content.Split(' ')[0].Substring(botPrefix.Length)))); p.Aliases.Contains(
message.Content.Split(' ')[0]
.Substring(botPrefix.Length))));
cleanMessage = message.Content.Substring(botPrefix.Length); cleanMessage = message.Content.Substring(botPrefix.Length);
} }
if (plugin is null) if (plugin is null)
throw new Exception($"Failed to run command ! " + message.CleanContent + " (user: " + context.Message.Author.Username + " - " + context.Message.Author.Id + ")"); throw new Exception("Failed to run command ! " + message.CleanContent + " (user: " +
context.Message.Author.Username + " - " + context.Message.Author.Id + ")");
if (plugin.requireAdmin && !context.Message.Author.isAdmin()) if (plugin.requireAdmin && !context.Message.Author.isAdmin())
return; return;
string[] split = cleanMessage.Split(' '); var split = cleanMessage.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(' ');
DBCommandExecutingArguments cmd = new(context, cleanMessage, split[0], argsClean); DBCommandExecutingArguments cmd = new(context, cleanMessage, split[0], argsClean);

View File

@@ -1,27 +1,24 @@
using System; using System;
using System.Threading.Tasks;
using System.IO;
using System.Collections.Generic;
using PluginManager.Others;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using PluginManager.Bot;
using PluginManager.Others;
using PluginManager.Others.Logger; using PluginManager.Others.Logger;
namespace PluginManager; namespace PluginManager;
public class Config public class Config
{ {
private static bool IsLoaded = false; private static bool IsLoaded;
public static DBLogger Logger; public static DBLogger Logger;
public static Json<string, string> Data; public static Json<string, string>? Data;
public static Json<string, string> Plugins; public static Json<string, string>? Plugins;
internal static Bot.Boot? _DiscordBotClient; internal static Boot? _DiscordBotClient;
public static Bot.Boot? DiscordBot public static Boot? DiscordBot => _DiscordBotClient;
{
get => _DiscordBotClient;
}
public static async Task Initialize() public static async Task Initialize()
{ {
@@ -34,11 +31,11 @@ public class Config
Directory.CreateDirectory("./Data/Logs/Logs"); Directory.CreateDirectory("./Data/Logs/Logs");
Directory.CreateDirectory("./Data/Logs/Errors"); Directory.CreateDirectory("./Data/Logs/Errors");
Data = new Json<string, string>("./Data/Resources/config.json"); Data = new Json<string, string>("./Data/Resources/config.json");
Plugins = new Json<string, string>("./Data/Resources/Plugins.json"); Plugins = new Json<string, string>("./Data/Resources/Plugins.json");
Config.Data["LogFolder"] = "./Data/Logs/Logs"; Data["LogFolder"] = "./Data/Logs/Logs";
Config.Data["ErrorFolder"] = "./Data/Logs/Errors"; Data["ErrorFolder"] = "./Data/Logs/Errors";
Logger = new DBLogger(); Logger = new DBLogger();
@@ -51,11 +48,11 @@ public class Config
public class Json<TKey, TValue> : IDictionary<TKey, TValue> public class Json<TKey, TValue> : IDictionary<TKey, TValue>
{ {
protected IDictionary<TKey, TValue> _dictionary; private readonly string _file = "";
private readonly string _file = ""; private readonly IDictionary<TKey, TValue>? _dictionary;
/// <summary> /// <summary>
/// Empty constructor /// Empty constructor
/// </summary> /// </summary>
public Json() public Json()
{ {
@@ -65,13 +62,7 @@ public class Config
public Json(string file) public Json(string file)
{ {
_dictionary = PrivateReadConfig(file).GetAwaiter().GetResult(); _dictionary = PrivateReadConfig(file).GetAwaiter().GetResult();
this._file = file; _file = file;
}
public async void Save()
{
if(!string.IsNullOrEmpty(_file))
await Functions.SaveToJsonFile(_file, _dictionary);
} }
public virtual void Add(TKey key, TValue value) public virtual void Add(TKey key, TValue value)
@@ -101,9 +92,9 @@ public class Config
{ {
get get
{ {
if (_dictionary.TryGetValue(key, out TValue value)) return value; if (_dictionary.TryGetValue(key, out var value)) return value;
throw new Exception("Key not found in dictionary " + key.ToString() + " (Json )" + this.GetType().Name + ")"); throw new Exception("Key not found in dictionary " + key + " (Json )" + GetType().Name +
")");
} }
set set
{ {
@@ -118,30 +109,6 @@ public class Config
return _dictionary.TryGetValue(key, out value); return _dictionary.TryGetValue(key, out value);
} }
private async Task<Dictionary<TKey, TValue>> PrivateReadConfig(string file)
{
if (!File.Exists(file))
{
var dictionary = new Dictionary<TKey, TValue>();
await Functions.SaveToJsonFile(file, _dictionary);
return dictionary;
}
try
{
var d = await Functions.ConvertFromJson<Dictionary<TKey, TValue>>(file);
if (d is null)
throw new Exception("Failed to read config file");
return d;
}catch (Exception ex)
{
File.Delete(file);
return new Dictionary<TKey, TValue>();
}
}
public bool Remove(TKey key) public bool Remove(TKey key)
{ {
return _dictionary.Remove(key); return _dictionary.Remove(key);
@@ -176,6 +143,35 @@ public class Config
{ {
return ((IEnumerable)_dictionary).GetEnumerator(); return ((IEnumerable)_dictionary).GetEnumerator();
} }
}
public async void Save()
{
if (!string.IsNullOrEmpty(_file))
await Functions.SaveToJsonFile(_file, _dictionary);
}
private async Task<Dictionary<TKey, TValue>> PrivateReadConfig(string file)
{
if (!File.Exists(file))
{
var dictionary = new Dictionary<TKey, TValue>();
await Functions.SaveToJsonFile(file, _dictionary);
return dictionary;
}
try
{
var d = await Functions.ConvertFromJson<Dictionary<TKey, TValue>>(file);
if (d is null)
throw new Exception("Failed to read config file");
return d;
}
catch (Exception ex)
{
File.Delete(file);
return new Dictionary<TKey, TValue>();
}
}
}
} }

View File

@@ -1,489 +1,483 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite; using System.Data.SQLite;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PluginManager.Database namespace PluginManager.Database;
public class SqlDatabase
{ {
public class SqlDatabase private readonly SQLiteConnection Connection;
private readonly string ConnectionString;
/// <summary>
/// Initialize a SQL connection by specifing its private path
/// </summary>
/// <param name="fileName">The path to the database (it is starting from ./Data/Resources/)</param>
public SqlDatabase(string fileName)
{ {
private string ConnectionString; if (!fileName.StartsWith("./Data/Resources/"))
private SQLiteConnection Connection; fileName = Path.Combine("./Data/Resources", fileName);
if (!File.Exists(fileName))
SQLiteConnection.CreateFile(fileName);
ConnectionString = $"URI=file:{fileName}";
Connection = new SQLiteConnection(ConnectionString);
}
/// <summary>
/// Initialize a SQL connection by specifing its private path /// <summary>
/// </summary> /// Open the SQL Connection. To close use the Stop() method
/// <param name="fileName">The path to the database (it is starting from ./Data/Resources/)</param> /// </summary>
public SqlDatabase(string fileName) /// <returns></returns>
public async Task Open()
{
await Connection.OpenAsync();
}
/// <summary>
/// <para>
/// Insert into a specified table some values
/// </para>
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="values">The values to be inserted (in the correct order and number)</param>
/// <returns></returns>
public async Task InsertAsync(string tableName, params string[] values)
{
var query = $"INSERT INTO {tableName} VALUES (";
for (var i = 0; i < values.Length; i++)
{ {
if (!fileName.StartsWith("./Data/Resources/")) query += $"'{values[i]}'";
fileName = Path.Combine("./Data/Resources", fileName); if (i != values.Length - 1)
if (!File.Exists(fileName)) query += ", ";
SQLiteConnection.CreateFile(fileName);
ConnectionString = $"URI=file:{fileName}";
Connection = new SQLiteConnection(ConnectionString);
} }
query += ")";
/// <summary> var command = new SQLiteCommand(query, Connection);
/// Open the SQL Connection. To close use the Stop() method await command.ExecuteNonQueryAsync();
/// </summary> }
/// <returns></returns>
public async Task Open() /// <summary>
/// <para>
/// Insert into a specified table some values
/// </para>
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="values">The values to be inserted (in the correct order and number)</param>
/// <returns></returns>
public void Insert(string tableName, params string[] values)
{
var query = $"INSERT INTO {tableName} VALUES (";
for (var i = 0; i < values.Length; i++)
{ {
query += $"'{values[i]}'";
if (i != values.Length - 1)
query += ", ";
}
query += ")";
var command = new SQLiteCommand(query, Connection);
command.ExecuteNonQuery();
}
/// <summary>
/// Remove every row in a table that has a certain propery
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="KeyName">The column name that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the specified column</param>
/// <returns></returns>
public async Task RemoveKeyAsync(string tableName, string KeyName, string KeyValue)
{
var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'";
var command = new SQLiteCommand(query, Connection);
await command.ExecuteNonQueryAsync();
}
/// <summary>
/// Remove every row in a table that has a certain propery
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="KeyName">The column name that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the specified column</param>
/// <returns></returns>
public void RemoveKey(string tableName, string KeyName, string KeyValue)
{
var query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'";
var command = new SQLiteCommand(query, Connection);
command.ExecuteNonQuery();
}
/// <summary>
/// Check if the key exists in the table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="keyName">The column that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the specified column</param>
/// <returns></returns>
public async Task<bool> KeyExistsAsync(string tableName, string keyName, string KeyValue)
{
var query = $"SELECT * FROM {tableName} where {keyName} = '{KeyValue}'";
if (await ReadDataAsync(query) is not null)
return true;
return false;
}
/// <summary>
/// Check if the key exists in the table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="keyName">The column that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the specified column</param>
/// <returns></returns>
public bool KeyExists(string tableName, string keyName, string KeyValue)
{
var query = $"SELECT * FROM {tableName} where {keyName} = '{KeyValue}'";
if (ReadData(query) is not null)
return true;
return false;
}
/// <summary>
/// Set value of a column in a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="keyName">The column that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the column specified</param>
/// <param name="ResultColumnName">The column that has to be modified</param>
/// <param name="ResultColumnValue">The new value that will replace the old value from the column specified</param>
public async Task SetValueAsync(
string tableName, string keyName, string KeyValue, string ResultColumnName,
string ResultColumnValue)
{
if (!await TableExistsAsync(tableName))
throw new Exception($"Table {tableName} does not exist");
await ExecuteAsync(
$"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'");
}
/// <summary>
/// Set value of a column in a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="keyName">The column that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the column specified</param>
/// <param name="ResultColumnName">The column that has to be modified</param>
/// <param name="ResultColumnValue">The new value that will replace the old value from the column specified</param>
public void SetValue(
string tableName, string keyName, string KeyValue, string ResultColumnName,
string ResultColumnValue)
{
if (!TableExists(tableName))
throw new Exception($"Table {tableName} does not exist");
Execute($"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'");
}
/// <summary>
/// Get value from a column in a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="keyName">The column that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the specified column</param>
/// <param name="ResultColumnName">The column that has the result</param>
/// <returns>A string that has the requested value (can be null if nothing found)</returns>
public async Task<string?> GetValueAsync(
string tableName, string keyName, string KeyValue,
string ResultColumnName)
{
if (!await TableExistsAsync(tableName))
throw new Exception($"Table {tableName} does not exist");
return await ReadDataAsync($"SELECT {ResultColumnName} FROM {tableName} WHERE {keyName}='{KeyValue}'");
}
/// <summary>
/// Get value from a column in a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="keyName">The column that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the specified column</param>
/// <param name="ResultColumnName">The column that has the result</param>
/// <returns>A string that has the requested value (can be null if nothing found)</returns>
public string? GetValue(string tableName, string keyName, string KeyValue, string ResultColumnName)
{
if (!TableExists(tableName))
throw new Exception($"Table {tableName} does not exist");
return ReadData($"SELECT {ResultColumnName} FROM {tableName} WHERE {keyName}='{KeyValue}'");
}
/// <summary>
/// Stop the connection to the SQL Database
/// </summary>
/// <returns></returns>
public async void Stop()
{
await Connection.CloseAsync();
}
/// <summary>
/// Change the structure of a table by adding new columns
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="columns">The columns to be added</param>
/// <param name="TYPE">The type of the columns (TEXT, INTEGER, FLOAT, etc)</param>
/// <returns></returns>
public async Task AddColumnsToTableAsync(string tableName, string[] columns, string TYPE = "TEXT")
{
var command = Connection.CreateCommand();
command.CommandText = $"SELECT * FROM {tableName}";
var reader = await command.ExecuteReaderAsync();
var tableColumns = new List<string>();
for (var i = 0; i < reader.FieldCount; i++)
tableColumns.Add(reader.GetName(i));
foreach (var column in columns)
if (!tableColumns.Contains(column))
{
command.CommandText = $"ALTER TABLE {tableName} ADD COLUMN {column} {TYPE}";
await command.ExecuteNonQueryAsync();
}
}
/// <summary>
/// Change the structure of a table by adding new columns
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="columns">The columns to be added</param>
/// <param name="TYPE">The type of the columns (TEXT, INTEGER, FLOAT, etc)</param>
/// <returns></returns>
public void AddColumnsToTable(string tableName, string[] columns, string TYPE = "TEXT")
{
var command = Connection.CreateCommand();
command.CommandText = $"SELECT * FROM {tableName}";
var reader = command.ExecuteReader();
var tableColumns = new List<string>();
for (var i = 0; i < reader.FieldCount; i++)
tableColumns.Add(reader.GetName(i));
foreach (var column in columns)
if (!tableColumns.Contains(column))
{
command.CommandText = $"ALTER TABLE {tableName} ADD COLUMN {column} {TYPE}";
command.ExecuteNonQuery();
}
}
/// <summary>
/// Check if a table exists
/// </summary>
/// <param name="tableName">The table name</param>
/// <returns>True if the table exists, false if not</returns>
public async Task<bool> TableExistsAsync(string tableName)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'";
var result = await cmd.ExecuteScalarAsync();
if (result == null)
return false;
return true;
}
/// <summary>
/// Check if a table exists
/// </summary>
/// <param name="tableName">The table name</param>
/// <returns>True if the table exists, false if not</returns>
public bool TableExists(string tableName)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'";
var result = cmd.ExecuteScalar();
if (result == null)
return false;
return true;
}
/// <summary>
/// Create a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="columns">The columns of the table</param>
/// <returns></returns>
public async Task CreateTableAsync(string tableName, params string[] columns)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})";
await cmd.ExecuteNonQueryAsync();
}
/// <summary>
/// Create a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="columns">The columns of the table</param>
/// <returns></returns>
public void CreateTable(string tableName, params string[] columns)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})";
cmd.ExecuteNonQuery();
}
/// <summary>
/// Execute a custom query
/// </summary>
/// <param name="query">The query</param>
/// <returns>The number of rows that the query modified</returns>
public async Task<int> ExecuteAsync(string query)
{
if (!Connection.State.HasFlag(ConnectionState.Open))
await Connection.OpenAsync(); await Connection.OpenAsync();
var command = new SQLiteCommand(query, Connection);
var answer = await command.ExecuteNonQueryAsync();
return answer;
}
/// <summary>
/// Execute a custom query
/// </summary>
/// <param name="query">The query</param>
/// <returns>The number of rows that the query modified</returns>
public int Execute(string query)
{
if (!Connection.State.HasFlag(ConnectionState.Open))
Connection.Open();
var command = new SQLiteCommand(query, Connection);
var r = command.ExecuteNonQuery();
return r;
}
/// <summary>
/// Read data from the result table and return the first row
/// </summary>
/// <param name="query">The query</param>
/// <returns>The result is a string that has all values separated by space character</returns>
public async Task<string?> ReadDataAsync(string query)
{
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())
{
reader.GetValues(values);
return string.Join<object>(" ", values);
} }
/// <summary> return null;
/// <para> }
/// Insert into a specified table some values
/// </para> /// <summary>
/// </summary> /// Read data from the result table and return the first row
/// <param name="tableName">The table name</param> /// </summary>
/// <param name="values">The values to be inserted (in the correct order and number)</param> /// <param name="query">The query</param>
/// <returns></returns> /// <returns>The result is a string that has all values separated by space character</returns>
public async Task InsertAsync(string tableName, params string[] values) public string? ReadData(string query)
{
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())
{ {
string query = $"INSERT INTO {tableName} VALUES ("; reader.GetValues(values);
for (int i = 0; i < values.Length; i++) return string.Join<object>(" ", values);
{
query += $"'{values[i]}'";
if (i != values.Length - 1)
query += ", ";
}
query += ")";
SQLiteCommand command = new SQLiteCommand(query, Connection);
await command.ExecuteNonQueryAsync();
} }
/// <summary> return null;
/// <para> }
/// Insert into a specified table some values
/// </para> /// <summary>
/// </summary> /// Read data from the result table and return the first row
/// <param name="tableName">The table name</param> /// </summary>
/// <param name="values">The values to be inserted (in the correct order and number)</param> /// <param name="query">The query</param>
/// <returns></returns> /// <returns>The first row as separated items</returns>
public void Insert(string tableName, params string[] values) public async Task<object[]?> ReadDataArrayAsync(string query)
{
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())
{ {
string query = $"INSERT INTO {tableName} VALUES ("; reader.GetValues(values);
for (int i = 0; i < values.Length; i++) return values;
{
query += $"'{values[i]}'";
if (i != values.Length - 1)
query += ", ";
}
query += ")";
SQLiteCommand command = new SQLiteCommand(query, Connection);
command.ExecuteNonQuery();
} }
/// <summary> return null;
/// Remove every row in a table that has a certain propery }
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="KeyName">The column name that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the specified column</param>
/// <returns></returns>
public async Task RemoveKeyAsync(string tableName, string KeyName, string KeyValue)
{
string query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'";
SQLiteCommand command = new SQLiteCommand(query, Connection);
await command.ExecuteNonQueryAsync(); /// <summary>
/// Read data from the result table and return the first row
/// </summary>
/// <param name="query">The query</param>
/// <returns>The first row as separated items</returns>
public object[]? ReadDataArray(string query)
{
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())
{
reader.GetValues(values);
return values;
} }
/// <summary> return null;
/// Remove every row in a table that has a certain propery }
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="KeyName">The column name that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the specified column</param>
/// <returns></returns>
public void RemoveKey(string tableName, string KeyName, string KeyValue)
{
string query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'";
SQLiteCommand command = new SQLiteCommand(query, Connection); /// <summary>
command.ExecuteNonQuery(); /// Read all rows from the result table and return them as a list of string arrays. The string arrays contain the
} /// values of each row
/// </summary>
/// <summary> /// <param name="query">The query</param>
/// Check if the key exists in the table /// <returns>A list of string arrays representing the values that the query returns</returns>
/// </summary> public async Task<List<string[]>?> ReadAllRowsAsync(string query)
/// <param name="tableName">The table name</param> {
/// <param name="keyName">The column that the search is made by</param> if (!Connection.State.HasFlag(ConnectionState.Open))
/// <param name="KeyValue">The value that is searched in the specified column</param> await Connection.OpenAsync();
/// <returns></returns> var command = new SQLiteCommand(query, Connection);
public async Task<bool> KeyExistsAsync(string tableName, string keyName, string KeyValue) var reader = await command.ExecuteReaderAsync();
{
string query = $"SELECT * FROM {tableName} where {keyName} = '{KeyValue}'";
if (await ReadDataAsync(query) is not null)
return true;
return false;
}
/// <summary>
/// Check if the key exists in the table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="keyName">The column that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the specified column</param>
/// <returns></returns>
public bool KeyExists(string tableName, string keyName, string KeyValue)
{
string query = $"SELECT * FROM {tableName} where {keyName} = '{KeyValue}'";
if (ReadData(query) is not null)
return true;
return false;
}
/// <summary>
/// Set value of a column in a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="keyName">The column that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the column specified</param>
/// <param name="ResultColumnName">The column that has to be modified</param>
/// <param name="ResultColumnValue">The new value that will replace the old value from the column specified</param>
public async Task SetValueAsync(string tableName, string keyName, string KeyValue, string ResultColumnName,
string ResultColumnValue)
{
if (!await TableExistsAsync(tableName))
throw new System.Exception($"Table {tableName} does not exist");
await ExecuteAsync(
$"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'");
}
/// <summary>
/// Set value of a column in a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="keyName">The column that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the column specified</param>
/// <param name="ResultColumnName">The column that has to be modified</param>
/// <param name="ResultColumnValue">The new value that will replace the old value from the column specified</param>
public void SetValue(string tableName, string keyName, string KeyValue, string ResultColumnName,
string ResultColumnValue)
{
if (!TableExists(tableName))
throw new System.Exception($"Table {tableName} does not exist");
Execute($"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'");
}
/// <summary>
/// Get value from a column in a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="keyName">The column that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the specified column</param>
/// <param name="ResultColumnName">The column that has the result</param>
/// <returns>A string that has the requested value (can be null if nothing found)</returns>
public async Task<string?> GetValueAsync(string tableName, string keyName, string KeyValue,
string ResultColumnName)
{
if (!await TableExistsAsync(tableName))
throw new System.Exception($"Table {tableName} does not exist");
return await ReadDataAsync($"SELECT {ResultColumnName} FROM {tableName} WHERE {keyName}='{KeyValue}'");
}
/// <summary>
/// Get value from a column in a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="keyName">The column that the search is made by</param>
/// <param name="KeyValue">The value that is searched in the specified column</param>
/// <param name="ResultColumnName">The column that has the result</param>
/// <returns>A string that has the requested value (can be null if nothing found)</returns>
public string? GetValue(string tableName, string keyName, string KeyValue, string ResultColumnName)
{
if (!TableExists(tableName))
throw new System.Exception($"Table {tableName} does not exist");
return ReadData($"SELECT {ResultColumnName} FROM {tableName} WHERE {keyName}='{KeyValue}'");
}
/// <summary>
/// Stop the connection to the SQL Database
/// </summary>
/// <returns></returns>
public async void Stop()
{
await Connection.CloseAsync();
}
/// <summary>
/// Change the structure of a table by adding new columns
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="columns">The columns to be added</param>
/// <param name="TYPE">The type of the columns (TEXT, INTEGER, FLOAT, etc)</param>
/// <returns></returns>
public async Task AddColumnsToTableAsync(string tableName, string[] columns, string TYPE = "TEXT")
{
var command = Connection.CreateCommand();
command.CommandText = $"SELECT * FROM {tableName}";
var reader = await command.ExecuteReaderAsync();
var tableColumns = new List<string>();
for (int i = 0; i < reader.FieldCount; i++)
tableColumns.Add(reader.GetName(i));
foreach (var column in columns)
{
if (!tableColumns.Contains(column))
{
command.CommandText = $"ALTER TABLE {tableName} ADD COLUMN {column} {TYPE}";
await command.ExecuteNonQueryAsync();
}
}
}
/// <summary>
/// Change the structure of a table by adding new columns
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="columns">The columns to be added</param>
/// <param name="TYPE">The type of the columns (TEXT, INTEGER, FLOAT, etc)</param>
/// <returns></returns>
public void AddColumnsToTable(string tableName, string[] columns, string TYPE = "TEXT")
{
var command = Connection.CreateCommand();
command.CommandText = $"SELECT * FROM {tableName}";
var reader = command.ExecuteReader();
var tableColumns = new List<string>();
for (int i = 0; i < reader.FieldCount; i++)
tableColumns.Add(reader.GetName(i));
foreach (var column in columns)
{
if (!tableColumns.Contains(column))
{
command.CommandText = $"ALTER TABLE {tableName} ADD COLUMN {column} {TYPE}";
command.ExecuteNonQuery();
}
}
}
/// <summary>
/// Check if a table exists
/// </summary>
/// <param name="tableName">The table name</param>
/// <returns>True if the table exists, false if not</returns>
public async Task<bool> TableExistsAsync(string tableName)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'";
var result = await cmd.ExecuteScalarAsync();
if (result == null)
return false;
return true;
}
/// <summary>
/// Check if a table exists
/// </summary>
/// <param name="tableName">The table name</param>
/// <returns>True if the table exists, false if not</returns>
public bool TableExists(string tableName)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'";
var result = cmd.ExecuteScalar();
if (result == null)
return false;
return true;
}
/// <summary>
/// Create a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="columns">The columns of the table</param>
/// <returns></returns>
public async Task CreateTableAsync(string tableName, params string[] columns)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})";
await cmd.ExecuteNonQueryAsync();
}
/// <summary>
/// Create a table
/// </summary>
/// <param name="tableName">The table name</param>
/// <param name="columns">The columns of the table</param>
/// <returns></returns>
public void CreateTable(string tableName, params string[] columns)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})";
cmd.ExecuteNonQuery();
}
/// <summary>
/// Execute a custom query
/// </summary>
/// <param name="query">The query</param>
/// <returns>The number of rows that the query modified</returns>
public async Task<int> ExecuteAsync(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
await Connection.OpenAsync();
var command = new SQLiteCommand(query, Connection);
int answer = await command.ExecuteNonQueryAsync();
return answer;
}
/// <summary>
/// Execute a custom query
/// </summary>
/// <param name="query">The query</param>
/// <returns>The number of rows that the query modified</returns>
public int Execute(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
Connection.Open();
var command = new SQLiteCommand(query, Connection);
int r = command.ExecuteNonQuery();
return r;
}
/// <summary>
/// Read data from the result table and return the first row
/// </summary>
/// <param name="query">The query</param>
/// <returns>The result is a string that has all values separated by space character</returns>
public async Task<string?> ReadDataAsync(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
await Connection.OpenAsync();
var command = new SQLiteCommand(query, Connection);
var reader = await command.ExecuteReaderAsync();
object[] values = new object[reader.FieldCount];
if (reader.Read())
{
reader.GetValues(values);
return string.Join<object>(" ", values);
}
if (!reader.HasRows)
return null; return null;
}
/// <summary> List<string[]> rows = new();
/// Read data from the result table and return the first row while (await reader.ReadAsync())
/// </summary>
/// <param name="query">The query</param>
/// <returns>The result is a string that has all values separated by space character</returns>
public string? ReadData(string query)
{ {
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open)) var values = new string[reader.FieldCount];
Connection.Open(); reader.GetValues(values);
var command = new SQLiteCommand(query, Connection); rows.Add(values);
var reader = command.ExecuteReader();
object[] values = new object[reader.FieldCount];
if (reader.Read())
{
reader.GetValues(values);
return string.Join<object>(" ", values);
}
return null;
} }
/// <summary> if (rows.Count == 0) return null;
/// Read data from the result table and return the first row
/// </summary>
/// <param name="query">The query</param>
/// <returns>The first row as separated items</returns>
public async Task<object[]?> ReadDataArrayAsync(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
await Connection.OpenAsync();
var command = new SQLiteCommand(query, Connection);
var reader = await command.ExecuteReaderAsync();
object[] values = new object[reader.FieldCount]; return rows;
if (reader.Read())
{
reader.GetValues(values);
return values;
}
return null;
}
/// <summary>
/// Read data from the result table and return the first row
/// </summary>
/// <param name="query">The query</param>
/// <returns>The first row as separated items</returns>
public object[]? ReadDataArray(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
Connection.Open();
var command = new SQLiteCommand(query, Connection);
var reader = command.ExecuteReader();
object[] values = new object[reader.FieldCount];
if (reader.Read())
{
reader.GetValues(values);
return values;
}
return null;
}
/// <summary>
/// Read all rows from the result table and return them as a list of string arrays. The string arrays contain the values of each row
/// </summary>
/// <param name="query">The query</param>
/// <returns>A list of string arrays representing the values that the query returns</returns>
public async Task<List<string[]>?> ReadAllRowsAsync(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
await Connection.OpenAsync();
var command = new SQLiteCommand(query, Connection);
var reader = await command.ExecuteReaderAsync();
if (!reader.HasRows)
return null;
List<string[]> rows = new();
while (await reader.ReadAsync())
{
string[] values = new string[reader.FieldCount];
reader.GetValues(values);
rows.Add(values);
}
if (rows.Count == 0) return null;
return rows;
}
} }
} }

View File

@@ -1,25 +1,21 @@
using System.Collections.Generic; using System.Collections.Generic;
using Discord; using Discord;
using Discord.WebSocket; using Discord.WebSocket;
namespace PluginManager.Interfaces namespace PluginManager.Interfaces;
public interface DBSlashCommand
{ {
public interface DBSlashCommand string Name { get; }
string Description { get; }
bool canUseDM { get; }
List<SlashCommandOptionBuilder> Options { get; }
void ExecuteServer(SocketSlashCommand context)
{ {
string Name { get; }
string Description { get; }
bool canUseDM { get; }
List<SlashCommandOptionBuilder> Options { get; }
void ExecuteServer(SocketSlashCommand context)
{
}
void ExecuteDM(SocketSlashCommand context) { }
} }
void ExecuteDM(SocketSlashCommand context) { }
} }

View File

@@ -1,23 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using PluginManager.Others; using PluginManager.Others;
namespace PluginManager.Interfaces namespace PluginManager.Interfaces;
public interface ICommandAction
{ {
public interface ICommandAction public string ActionName { get; }
{
public string ActionName { get; }
public string? Description { get; } public string? Description { get; }
public string? Usage { get; } public string? Usage { get; }
public InternalActionRunType RunType { get; } public InternalActionRunType RunType { get; }
public Task Execute(string[]? args); public Task Execute(string[]? args);
}
} }

View File

@@ -1,76 +1,72 @@
using System.IO;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Reflection; using System.Reflection;
using PluginManager.Others.Actions; using System.Threading.Tasks;
using PluginManager.Interfaces; using PluginManager.Interfaces;
using System.Collections; using PluginManager.Others;
namespace PluginManager.Loaders namespace PluginManager.Loaders;
public class ActionsLoader
{ {
public class ActionsLoader public delegate void ActionLoaded(string name, string typeName, bool success, Exception? e = null);
private readonly string actionExtension = "dll";
private readonly string actionFolder = @"./Data/Actions/";
public ActionsLoader(string path, string extension)
{ {
public delegate void ActionLoaded(string name, string typeName, bool success, Exception? e = null); actionFolder = path;
public event ActionLoaded? ActionLoadedEvent; actionExtension = extension;
}
private string actionFolder = @"./Data/Actions/"; public event ActionLoaded? ActionLoadedEvent;
private string actionExtension = "dll";
public ActionsLoader(string path, string extension) public async Task<List<ICommandAction>?> Load()
{ {
actionFolder = path; Directory.CreateDirectory(actionFolder);
actionExtension = extension; var files = Directory.GetFiles(actionFolder, $"*.{actionExtension}", SearchOption.AllDirectories);
}
public async Task<List<ICommandAction>?> Load() var actions = new List<ICommandAction>();
{
Directory.CreateDirectory(actionFolder);
var files = Directory.GetFiles(actionFolder, $"*.{actionExtension}", SearchOption.AllDirectories);
List<ICommandAction> actions = new List<ICommandAction>(); foreach (var file in files)
try
foreach (var file in files)
{ {
try Assembly.LoadFrom(file);
{ }
Assembly.LoadFrom(file); catch (Exception e)
} {
catch (Exception e) ActionLoadedEvent?.Invoke(file, "", false, e);
{
ActionLoadedEvent?.Invoke(file, "", false, e);
}
} }
var types = AppDomain.CurrentDomain.GetAssemblies() var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes()) .SelectMany(s => s.GetTypes())
.Where(p => typeof(ICommandAction).IsAssignableFrom(p) && !p.IsInterface); .Where(p => typeof(ICommandAction).IsAssignableFrom(p) && !p.IsInterface);
foreach (var type in types) foreach (var type in types)
try
{ {
try var action = (ICommandAction)Activator.CreateInstance(type);
if (action.ActionName == null)
{ {
var action = (ICommandAction) Activator.CreateInstance(type); ActionLoadedEvent?.Invoke(action.ActionName, type.Name, false);
if (action.ActionName == null) continue;
{
ActionLoadedEvent?.Invoke(action.ActionName, type.Name, false);
continue;
}
if(action.RunType == PluginManager.Others.InternalActionRunType.ON_STARTUP)
await action.Execute(null);
ActionLoadedEvent?.Invoke(action.ActionName, type.Name, true);
actions.Add(action);
}
catch (Exception e)
{
ActionLoadedEvent?.Invoke(type.Name, type.Name, false, e);
} }
if (action.RunType == InternalActionRunType.ON_STARTUP)
await action.Execute(null);
ActionLoadedEvent?.Invoke(action.ActionName, type.Name, true);
actions.Add(action);
}
catch (Exception e)
{
ActionLoadedEvent?.Invoke(type.Name, type.Name, false, e);
} }
return actions; return actions;
}
} }
} }

View File

@@ -3,143 +3,143 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using PluginManager.Interfaces; using PluginManager.Interfaces;
using PluginManager.Others;
namespace PluginManager.Loaders 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 class Loader
{
internal Loader(string path, string extension)
{ {
internal string? PluginName { get; init; } this.path = path;
internal string? TypeName { get; init; } this.extension = extension;
internal bool IsLoaded { get; init; }
internal Exception? Exception { get; init; }
internal object? Plugin { get; init; }
} }
internal class Loader
private string path { get; }
private string extension { get; }
internal event FileLoadedEventHandler? FileLoaded;
internal event PluginLoadedEventHandler? PluginLoaded;
internal (List<DBEvent>?, List<DBCommand>?, List<DBSlashCommand>?) Load()
{ {
internal Loader(string path, string extension) List<DBEvent> events = new();
List<DBSlashCommand> slashCommands = new();
List<DBCommand> commands = new();
if (!Directory.Exists(path))
{ {
this.path = path; Directory.CreateDirectory(path);
this.extension = extension; return (null, null, null);
} }
var files = Directory.GetFiles(path, $"*.{extension}", SearchOption.AllDirectories);
private string path { get; } foreach (var file in files)
private string extension { get; }
internal event FileLoadedEventHandler? FileLoaded;
internal event PluginLoadedEventHandler? PluginLoaded;
internal delegate void FileLoadedEventHandler(LoaderArgs args);
internal delegate void PluginLoadedEventHandler(LoaderArgs args);
internal (List<DBEvent>?, List<DBCommand>?, List<DBSlashCommand>?) Load()
{ {
List<DBEvent> events = new();
List<DBSlashCommand> slashCommands = new();
List<DBCommand> commands = new();
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
return (null, null, null);
}
var files = Directory.GetFiles(path, $"*.{extension}", SearchOption.AllDirectories);
foreach (var file in files)
{
try
{
Assembly.LoadFrom(file);
}
catch (Exception ex)
{
Config.Logger.Log("PluginName: " + new FileInfo(file).Name.Split('.')[0] + " not loaded", this, Others.LogLevel.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);
}
}
return (LoadItems<DBEvent>(), LoadItems<DBCommand>(), LoadItems<DBSlashCommand>());
}
internal List<T> LoadItems<T>()
{
List<T> list = new();
try try
{ {
var interfaceType = typeof(T); Assembly.LoadFrom(file);
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
{
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;
} }
catch (Exception ex) catch (Exception ex)
{ {
Config.Logger.Log(ex.Message, this, Others.LogLevel.ERROR); Config.Logger.Log("PluginName: " + new FileInfo(file).Name.Split('.')[0] + " not loaded", this,
LogLevel.ERROR);
return null; 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);
}
}
return (LoadItems<DBEvent>(), LoadItems<DBCommand>(), LoadItems<DBSlashCommand>());
}
internal List<T> LoadItems<T>()
{
List<T> list = new();
try
{
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
{
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;
}
catch (Exception ex)
{
Config.Logger.Log(ex.Message, this, LogLevel.ERROR);
return null; return null;
} }
return null;
} }
internal delegate void FileLoadedEventHandler(LoaderArgs args);
internal delegate void PluginLoadedEventHandler(LoaderArgs args);
} }

View File

@@ -1,14 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord; using Discord;
using Discord.WebSocket; using Discord.WebSocket;
using PluginManager.Interfaces; using PluginManager.Interfaces;
using PluginManager.Online;
using PluginManager.Others; using PluginManager.Others;
namespace PluginManager.Loaders; namespace PluginManager.Loaders;
@@ -23,7 +19,7 @@ public class PluginLoader
private const string pluginFolder = @"./Data/Plugins/"; private const string pluginFolder = @"./Data/Plugins/";
internal const string pluginExtension = "dll"; internal const string pluginExtension = "dll";
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
/// <summary> /// <summary>
@@ -62,20 +58,24 @@ public class PluginLoader
public static List<DBEvent>? Events { get; set; } public static List<DBEvent>? Events { get; set; }
/// <summary> /// <summary>
/// A list of <see cref="DBSlashCommand"/> commands /// A list of <see cref="DBSlashCommand" /> commands
/// </summary> /// </summary>
public static List<DBSlashCommand>? SlashCommands { get; set; } public static List<DBSlashCommand>? SlashCommands { get; set; }
public static int PluginsLoaded { get { public static int PluginsLoaded
var count = 0; {
if (Commands is not null) get
count += Commands.Count; {
if (Events is not null) var count = 0;
count += Events.Count; if (Commands is not null)
if (SlashCommands is not null) count += Commands.Count;
count += SlashCommands.Count; if (Events is not null)
return count; count += Events.Count;
}} if (SlashCommands is not null)
count += SlashCommands.Count;
return count;
}
}
/// <summary> /// <summary>
/// The main mathod that is called to load all events /// The main mathod that is called to load all events
@@ -84,24 +84,24 @@ public class PluginLoader
{ {
//Load all plugins //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, this, Others.LogLevel.INFO); Config.Logger.Log("Starting plugin loader ... Client: " + _client.CurrentUser.Username, this,
LogLevel.INFO);
var loader = new Loader("./Data/Plugins", "dll"); var loader = new Loader("./Data/Plugins", "dll");
loader.FileLoaded += (args) => Config.Logger.Log($"{args.PluginName} file Loaded", this , Others.LogLevel.INFO); loader.FileLoaded += args => Config.Logger.Log($"{args.PluginName} file Loaded", this, LogLevel.INFO);
loader.PluginLoaded += Loader_PluginLoaded; loader.PluginLoaded += Loader_PluginLoaded;
var res = loader.Load(); var res = loader.Load();
Events = res.Item1; Events = res.Item1;
Commands = res.Item2; Commands = res.Item2;
SlashCommands = res.Item3; SlashCommands = res.Item3;
} }
private async void Loader_PluginLoaded(LoaderArgs args) private async void Loader_PluginLoaded(LoaderArgs args)
{ {
switch (args.TypeName) switch (args.TypeName)
{ {
case "DBCommand": case "DBCommand":
@@ -117,27 +117,29 @@ public class PluginLoader
} }
catch (Exception ex) catch (Exception ex)
{ {
Config.Logger.Log(ex.Message, this, Others.LogLevel.ERROR); Config.Logger.Log(ex.Message, this, LogLevel.ERROR);
} }
break; break;
case "DBSlashCommand": case "DBSlashCommand":
if (args.IsLoaded) if (args.IsLoaded)
{ {
var slash = (DBSlashCommand)args.Plugin; var slash = (DBSlashCommand)args.Plugin;
SlashCommandBuilder builder = new SlashCommandBuilder(); var builder = new SlashCommandBuilder();
builder.WithName(slash.Name); builder.WithName(slash.Name);
builder.WithDescription(slash.Description); builder.WithDescription(slash.Description);
builder.WithDMPermission(slash.canUseDM); builder.WithDMPermission(slash.canUseDM);
builder.Options = slash.Options; builder.Options = slash.Options;
onSLSHLoad?.Invoke(((DBSlashCommand)args.Plugin!).Name, args.TypeName, args.IsLoaded, args.Exception); onSLSHLoad?.Invoke(((DBSlashCommand)args.Plugin!).Name, args.TypeName, args.IsLoaded,
args.Exception);
await _client.CreateGlobalApplicationCommandAsync(builder.Build()); await _client.CreateGlobalApplicationCommandAsync(builder.Build());
} }
break; break;
} }
} }
public static async Task LoadPluginFromAssembly(Assembly asmb, DiscordSocketClient client) public static async Task LoadPluginFromAssembly(Assembly asmb, DiscordSocketClient client)
{ {
var types = asmb.GetTypes(); var types = asmb.GetTypes();
@@ -146,28 +148,27 @@ public class PluginLoader
{ {
var instance = (DBEvent)Activator.CreateInstance(type); var instance = (DBEvent)Activator.CreateInstance(type);
instance.Start(client); instance.Start(client);
PluginLoader.Events.Add(instance); Events.Add(instance);
Config.Logger.Log($"[EVENT] Loaded external {type.FullName}!", Others.LogLevel.INFO); Config.Logger.Log($"[EVENT] Loaded external {type.FullName}!", LogLevel.INFO);
} }
else if (type.IsClass && typeof(DBCommand).IsAssignableFrom(type)) else if (type.IsClass && typeof(DBCommand).IsAssignableFrom(type))
{ {
var instance = (DBCommand)Activator.CreateInstance(type); var instance = (DBCommand)Activator.CreateInstance(type);
PluginLoader.Commands.Add(instance); Commands.Add(instance);
Config.Logger.Log($"[CMD] Instance: {type.FullName} loaded !", Others.LogLevel.INFO); Config.Logger.Log($"[CMD] Instance: {type.FullName} loaded !", LogLevel.INFO);
} }
else if (type.IsClass && typeof(DBSlashCommand).IsAssignableFrom(type)) else if (type.IsClass && typeof(DBSlashCommand).IsAssignableFrom(type))
{ {
var instance = (DBSlashCommand)Activator.CreateInstance(type); var instance = (DBSlashCommand)Activator.CreateInstance(type);
SlashCommandBuilder builder = new SlashCommandBuilder(); var builder = new SlashCommandBuilder();
builder.WithName(instance.Name); builder.WithName(instance.Name);
builder.WithDescription(instance.Description); builder.WithDescription(instance.Description);
builder.WithDMPermission(instance.canUseDM); builder.WithDMPermission(instance.canUseDM);
builder.Options = instance.Options; builder.Options = instance.Options;
await client.CreateGlobalApplicationCommandAsync(builder.Build()); await client.CreateGlobalApplicationCommandAsync(builder.Build());
PluginLoader.SlashCommands.Add(instance); SlashCommands.Add(instance);
Config.Logger.Log($"[SLASH] Instance: {type.FullName} loaded !", Others.LogLevel.INFO); Config.Logger.Log($"[SLASH] Instance: {type.FullName} loaded !", LogLevel.INFO);
} }
} }
} }

View File

@@ -3,7 +3,6 @@ using System.IO;
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using PluginManager.Others; using PluginManager.Others;
namespace PluginManager.Online.Helpers; namespace PluginManager.Online.Helpers;
@@ -19,10 +18,11 @@ internal static class OnlineFunctions
/// <param name="progress">The <see cref="IProgress{T}" /> that is used to track the download progress</param> /// <param name="progress">The <see cref="IProgress{T}" /> that is used to track the download progress</param>
/// <param name="cancellation">The cancellation token</param> /// <param name="cancellation">The cancellation token</param>
/// <returns></returns> /// <returns></returns>
internal static async Task DownloadFileAsync(this HttpClient client, string url, Stream destination, internal static async Task DownloadFileAsync(
IProgress<float>? progress = null, this HttpClient client, string url, Stream destination,
IProgress<long>? downloadedBytes = null, int bufferSize = 81920, IProgress<float>? progress = null,
CancellationToken cancellation = default) IProgress<long>? downloadedBytes = null, int bufferSize = 81920,
CancellationToken cancellation = default)
{ {
using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellation)) using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellation))
{ {
@@ -40,11 +40,12 @@ internal static class OnlineFunctions
// Convert absolute progress (bytes downloaded) into relative progress (0% - 100%) // Convert absolute progress (bytes downloaded) into relative progress (0% - 100%)
var relativeProgress = new Progress<long>(totalBytes => var relativeProgress = new Progress<long>(totalBytes =>
{ {
progress?.Report((float)totalBytes / contentLength.Value * 100); progress?.Report((float)totalBytes / contentLength.Value *
downloadedBytes?.Report(totalBytes); 100);
} downloadedBytes?.Report(totalBytes);
); }
);
// Use extension method to report progress while downloading // Use extension method to report progress while downloading
await download.CopyToOtherStreamAsync(destination, bufferSize, relativeProgress, cancellation); await download.CopyToOtherStreamAsync(destination, bufferSize, relativeProgress, cancellation);

View File

@@ -4,24 +4,6 @@ namespace PluginManager.Online.Helpers;
public class VersionString public class VersionString
{ {
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() != this.GetType()) return false;
return Equals((VersionString)obj);
}
public override int GetHashCode()
{
return HashCode.Combine(PackageCheckVersion, PackageMainVersion, PackageVersionID);
}
public int PackageCheckVersion; public int PackageCheckVersion;
public int PackageMainVersion; public int PackageMainVersion;
public int PackageVersionID; public int PackageVersionID;
@@ -33,20 +15,21 @@ public class VersionString
{ {
if (data.Length == 3) if (data.Length == 3)
{ {
PackageVersionID = int.Parse(data[0]); PackageVersionID = int.Parse(data[0]);
PackageMainVersion = int.Parse(data[1]); PackageMainVersion = int.Parse(data[1]);
PackageCheckVersion = int.Parse(data[2]); PackageCheckVersion = int.Parse(data[2]);
} }
else if (data.Length == 4) else if (data.Length == 4)
{ {
// ignore the first item data[0] // ignore the first item data[0]
PackageVersionID = int.Parse(data[1]); PackageVersionID = int.Parse(data[1]);
PackageMainVersion = int.Parse(data[2]); PackageMainVersion = int.Parse(data[2]);
PackageCheckVersion = int.Parse(data[3]); PackageCheckVersion = int.Parse(data[3]);
} }
else else
{
throw new Exception("Invalid version string"); throw new Exception("Invalid version string");
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -55,6 +38,25 @@ public class VersionString
} }
} }
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() public override string ToString()
{ {
return "{PackageID: " + PackageVersionID + ", PackageVersion: " + PackageMainVersion + return "{PackageID: " + PackageVersionID + ", PackageVersion: " + PackageMainVersion +

View File

@@ -1,10 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using PluginManager.Online.Helpers; using PluginManager.Online.Helpers;
using PluginManager.Others; using PluginManager.Others;
using OperatingSystem = PluginManager.Others.OperatingSystem; using OperatingSystem = PluginManager.Others.OperatingSystem;
namespace PluginManager.Online; namespace PluginManager.Online;
@@ -18,7 +16,7 @@ public class PluginsManager
/// <param name="vlink">The link to the file where all plugin versions are stored</param> /// <param name="vlink">The link to the file where all plugin versions are stored</param>
public PluginsManager(string plink, string vlink) public PluginsManager(string plink, string vlink)
{ {
PluginsLink = plink; PluginsLink = plink;
VersionsLink = vlink; VersionsLink = vlink;
} }
@@ -26,7 +24,8 @@ public class PluginsManager
/// The URL of the server /// The URL of the server
/// </summary> /// </summary>
public string PluginsLink { get; } public string PluginsLink { get; }
public string VersionsLink {get; }
public string VersionsLink { get; }
/// <summary> /// <summary>
/// The method to load all plugins /// The method to load all plugins
@@ -36,11 +35,11 @@ public class PluginsManager
{ {
try try
{ {
var list = await ServerCom.ReadTextFromURL(PluginsLink); var list = await ServerCom.ReadTextFromURL(PluginsLink);
var lines = list.ToArray(); var lines = list.ToArray();
var data = new List<string[]>(); var data = new List<string[]>();
var op = Functions.GetOperatingSystem(); var op = Functions.GetOperatingSystem();
var len = lines.Length; var len = lines.Length;
for (var i = 0; i < len; i++) for (var i = 0; i < len; i++)
@@ -58,7 +57,7 @@ public class PluginsManager
display[2] = content[2]; display[2] = content[2];
display[3] = display[3] =
(await GetVersionOfPackageFromWeb(content[0]) ?? new VersionString("0.0.0")) (await GetVersionOfPackageFromWeb(content[0]) ?? new VersionString("0.0.0"))
.ToShortString(); .ToShortString();
data.Add(display); data.Add(display);
} }
} }
@@ -71,7 +70,7 @@ public class PluginsManager
display[2] = content[2]; display[2] = content[2];
display[3] = display[3] =
(await GetVersionOfPackageFromWeb(content[0]) ?? new VersionString("0.0.0")) (await GetVersionOfPackageFromWeb(content[0]) ?? new VersionString("0.0.0"))
.ToShortString(); .ToShortString();
data.Add(display); data.Add(display);
} }
} }
@@ -83,7 +82,8 @@ public class PluginsManager
} }
catch (Exception exception) catch (Exception exception)
{ {
Config.Logger.Log("Failed to execute command: listplugs\nReason: " + exception.Message, this, LogLevel.ERROR); Config.Logger.Log("Failed to execute command: listplugs\nReason: " + exception.Message, this,
LogLevel.ERROR);
} }
return null; return null;
@@ -97,14 +97,15 @@ public class PluginsManager
if (item.StartsWith("#")) if (item.StartsWith("#"))
continue; continue;
string[] split = item.Split(','); var split = item.Split(',');
if (split[0] == pakName) if (split[0] == pakName)
{ {
Console.WriteLine("Searched for " + pakName + " and found " + split[1] + " as version.\nUsed url: " + VersionsLink); Console.WriteLine("Searched for " + pakName + " and found " + split[1] + " as version.\nUsed url: " +
VersionsLink);
return new VersionString(split[1]); return new VersionString(split[1]);
} }
} }
return null; return null;
} }
@@ -117,9 +118,9 @@ public class PluginsManager
{ {
try try
{ {
var list = await ServerCom.ReadTextFromURL(PluginsLink); var list = await ServerCom.ReadTextFromURL(PluginsLink);
var lines = list.ToArray(); var lines = list.ToArray();
var len = lines.Length; var len = lines.Length;
for (var i = 0; i < len; i++) for (var i = 0; i < len; i++)
{ {
var contents = lines[i].Split(','); var contents = lines[i].Split(',');
@@ -135,7 +136,8 @@ public class PluginsManager
} }
catch (Exception exception) catch (Exception exception)
{ {
Config.Logger.Log("Failed to execute command: listplugs\nReason: " + exception.Message, this, LogLevel.ERROR); Config.Logger.Log("Failed to execute command: listplugs\nReason: " + exception.Message, this,
LogLevel.ERROR);
} }
return null; return null;

View File

@@ -1,13 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Generic;
using PluginManager.Online.Helpers; using PluginManager.Online.Helpers;
using PluginManager.Others;
namespace PluginManager.Online; namespace PluginManager.Online;
@@ -21,7 +18,7 @@ public static class ServerCom
public static async Task<List<string>> ReadTextFromURL(string link) public static async Task<List<string>> ReadTextFromURL(string link)
{ {
var response = await OnlineFunctions.DownloadStringAsync(link); var response = await OnlineFunctions.DownloadStringAsync(link);
var lines = response.Split('\n'); var lines = response.Split('\n');
return lines.ToList(); return lines.ToList();
} }
@@ -32,8 +29,9 @@ public static class ServerCom
/// <param name="location">The location where to store the downloaded data</param> /// <param name="location">The location where to store the downloaded data</param>
/// <param name="progress">The <see cref="IProgress{T}" /> to track the download</param> /// <param name="progress">The <see cref="IProgress{T}" /> to track the download</param>
/// <returns></returns> /// <returns></returns>
public static async Task DownloadFileAsync(string URL, string location, IProgress<float> progress, public static async Task DownloadFileAsync(
IProgress<long>? downloadedBytes) string URL, string location, IProgress<float> progress,
IProgress<long>? downloadedBytes)
{ {
using (var client = new HttpClient()) using (var client = new HttpClient())
{ {

View File

@@ -1,57 +1,58 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using PluginManager.Interfaces; using PluginManager.Interfaces;
using PluginManager.Loaders; using PluginManager.Loaders;
namespace PluginManager.Others.Actions namespace PluginManager.Others.Actions;
public class InternalActionManager
{ {
public class InternalActionManager public Dictionary<string, ICommandAction> Actions = new();
public ActionsLoader loader;
public InternalActionManager(string path, string extension)
{ {
public ActionsLoader loader; loader = new ActionsLoader(path, extension);
public Dictionary<string, ICommandAction> Actions = new Dictionary<string, ICommandAction>(); }
public InternalActionManager(string path, string extension) public async Task Initialize()
{
loader.ActionLoadedEvent += OnActionLoaded;
var m_actions = await loader.Load();
if (m_actions == null) return;
foreach (var action in m_actions)
Actions.Add(action.ActionName, action);
}
private void OnActionLoaded(string name, string typeName, bool success, Exception? e)
{
if (!success)
{ {
loader = new ActionsLoader(path, extension); Config.Logger.Error(e);
return;
} }
public async Task Initialize() Config.Logger.Log($"Action {name} loaded successfully", typeName);
}
public async Task<string> Execute(string actionName, params string[]? args)
{
if (!Actions.ContainsKey(actionName))
{ {
loader.ActionLoadedEvent += OnActionLoaded; Config.Logger.Log($"Action {actionName} not found", "InternalActionManager", LogLevel.WARNING);
var m_actions = await loader.Load(); return "Action not found";
if(m_actions == null) return;
foreach(var action in m_actions)
Actions.Add(action.ActionName, action);
} }
private void OnActionLoaded(string name, string typeName, bool success, Exception? e) try
{ {
if (!success) await Actions[actionName].Execute(args);
{ return "Action executed";
Config.Logger.Error(e);
return;
}
Config.Logger.Log($"Action {name} loaded successfully", typeName, LogLevel.INFO);
} }
catch (Exception e)
public async Task<string> Execute(string actionName, params string[]? args)
{ {
if (!Actions.ContainsKey(actionName)) Config.Logger.Log(e.Message, "InternalActionManager", LogLevel.ERROR);
{ return e.Message;
Config.Logger.Log($"Action {actionName} not found", "InternalActionManager", LogLevel.WARNING);
return "Action not found";
}
try{
await Actions[actionName].Execute(args);
return "Action executed";
}catch(Exception e){
Config.Logger.Log(e.Message, "InternalActionManager", LogLevel.ERROR);
return e.Message;
}
} }
} }
} }

View File

@@ -4,136 +4,138 @@ using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PluginManager.Others namespace PluginManager.Others;
public static class ArchiveManager
{ {
public static class ArchiveManager private static string? archiveFolder;
public static bool isInitialized { get; private set; }
public static void Initialize()
{ {
public static bool isInitialized { get; private set; } if (isInitialized) throw new Exception("ArchiveManager is already initialized");
private static string? archiveFolder;
public static void Initialize() if (!Config.Data.ContainsKey("ArchiveFolder"))
Config.Data["ArchiveFolder"] = "./Data/PAKS/";
archiveFolder = Config.Data["ArchiveFolder"];
isInitialized = true;
}
/// <summary>
/// Read data from a file that is inside an archive (ZIP format)
/// </summary>
/// <param name="FileName">The file name that is inside the archive or its full path</param>
/// <param name="archFile">The archive location from the PAKs folder</param>
/// <returns>A string that represents the content of the file or null if the file does not exists or it has no content</returns>
public static async Task<string?> ReadFromPakAsync(string FileName, string archFile)
{
if (!isInitialized) throw new Exception("ArchiveManager is not initialized");
archFile = archiveFolder + archFile;
if (!File.Exists(archFile))
throw new Exception("Failed to load file !");
try
{ {
if (isInitialized) throw new Exception("ArchiveManager is already initialized"); string? textValue = null;
using (var fs = new FileStream(archFile, FileMode.Open))
if (!Config.Data.ContainsKey("ArchiveFolder"))
Config.Data["ArchiveFolder"] = "./Data/PAKS/";
archiveFolder = Config.Data["ArchiveFolder"];
isInitialized = true;
}
/// <summary>
/// Read data from a file that is inside an archive (ZIP format)
/// </summary>
/// <param name="FileName">The file name that is inside the archive or its full path</param>
/// <param name="archFile">The archive location from the PAKs folder</param>
/// <returns>A string that represents the content of the file or null if the file does not exists or it has no content</returns>
public static async Task<string?> ReadFromPakAsync(string FileName, string archFile)
{
if (!isInitialized) throw new Exception("ArchiveManager is not initialized");
archFile = archiveFolder + archFile;
if (!File.Exists(archFile))
throw new Exception("Failed to load file !");
try
{
string? textValue = null;
using (var fs = new FileStream(archFile, FileMode.Open))
using (var zip = new ZipArchive(fs, ZipArchiveMode.Read)) using (var zip = new ZipArchive(fs, ZipArchiveMode.Read))
{ {
foreach (var entry in zip.Entries) 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 s = entry.Open())
using (var reader = new StreamReader(s)) using (var reader = new StreamReader(s))
{ {
textValue = await reader.ReadToEndAsync(); textValue = await reader.ReadToEndAsync();
reader.Close(); reader.Close();
s.Close(); s.Close();
fs.Close(); fs.Close();
} }
} }
return textValue; return textValue;
}
catch (Exception ex)
{
Config.Logger.Log(ex.Message, "Archive Manager", LogLevel.ERROR); // Write the error to a file
await Task.Delay(100);
return await ReadFromPakAsync(FileName, archFile);
}
} }
catch (Exception ex)
/// <summary>
/// Extract zip to location
/// </summary>
/// <param name="zip">The zip location</param>
/// <param name="folder">The target location</param>
/// <param name="progress">The progress that is updated as a file is processed</param>
/// <param name="type">The type of progress</param>
/// <returns></returns>
public static async Task ExtractArchive(string zip, string folder, IProgress<float> progress,
UnzipProgressType type)
{ {
if (!isInitialized) throw new Exception("ArchiveManager is not initialized"); Config.Logger.Log(ex.Message, "Archive Manager", LogLevel.ERROR); // Write the error to a file
Directory.CreateDirectory(folder); await Task.Delay(100);
using (var archive = ZipFile.OpenRead(zip)) return await ReadFromPakAsync(FileName, archFile);
}
}
/// <summary>
/// Extract zip to location
/// </summary>
/// <param name="zip">The zip location</param>
/// <param name="folder">The target location</param>
/// <param name="progress">The progress that is updated as a file is processed</param>
/// <param name="type">The type of progress</param>
/// <returns></returns>
public static async Task ExtractArchive(
string zip, string folder, IProgress<float> progress,
UnzipProgressType type)
{
if (!isInitialized) throw new Exception("ArchiveManager is not initialized");
Directory.CreateDirectory(folder);
using (var archive = ZipFile.OpenRead(zip))
{
if (type == UnzipProgressType.PERCENTAGE_FROM_NUMBER_OF_FILES)
{ {
if (type == UnzipProgressType.PERCENTAGE_FROM_NUMBER_OF_FILES) var totalZIPFiles = archive.Entries.Count();
var currentZIPFile = 0;
foreach (var entry in archive.Entries)
{ {
var totalZIPFiles = archive.Entries.Count(); if (entry.FullName.EndsWith("/")) // it is a folder
var currentZIPFile = 0; Directory.CreateDirectory(Path.Combine(folder, entry.FullName));
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($"Failed to extract {entry.Name}. Exception: {ex.Message}", "Archive Manager", LogLevel.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;
}
else
try try
{ {
entry.ExtractToFile(Path.Combine(folder, entry.FullName), true); entry.ExtractToFile(Path.Combine(folder, entry.FullName), true);
currentSize += (ulong)entry.CompressedLength;
} }
catch (Exception ex) catch (Exception ex)
{ {
Config.Logger.Log($"Failed to extract {entry.Name}. Exception: {ex.Message}", "Archive Manager", LogLevel.ERROR); Config.Logger.Log($"Failed to extract {entry.Name}. Exception: {ex.Message}",
"Archive Manager", LogLevel.ERROR);
} }
await Task.Delay(10); currentZIPFile++;
if (progress != null) await Task.Delay(10);
progress.Report((float)currentSize / zipSize * 100); 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($"Failed to extract {entry.Name}. Exception: {ex.Message}",
"Archive Manager", LogLevel.ERROR);
}
await Task.Delay(10);
if (progress != null)
progress.Report((float)currentSize / zipSize * 100);
} }
} }
} }

View File

@@ -1,27 +1,20 @@
using Discord.Commands; using Discord.Commands;
using Discord.WebSocket;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PluginManager.Others namespace PluginManager.Others;
public class DBCommandExecutingArguments
{ {
public class DBCommandExecutingArguments public DBCommandExecutingArguments(
SocketCommandContext context, string cleanContent, string commandUsed, string[]? arguments)
{ {
public SocketCommandContext context { get; init; } this.context = context;
public string cleanContent { get; init; } this.cleanContent = cleanContent;
public string commandUsed { get;init; } this.commandUsed = commandUsed;
public string[]? arguments { get;init; } this.arguments = arguments;
public DBCommandExecutingArguments(SocketCommandContext context, string cleanContent, string commandUsed, string[]? arguments)
{
this.context = context;
this.cleanContent = cleanContent;
this.commandUsed = commandUsed;
this.arguments = arguments;
}
} }
public SocketCommandContext context { get; init; }
public string cleanContent { get; init; }
public string commandUsed { get; init; }
public string[]? arguments { get; init; }
} }

View File

@@ -19,6 +19,15 @@ public static class Functions
/// </summary> /// </summary>
public static readonly string dataFolder = @"./Data/Resources/"; public static readonly string dataFolder = @"./Data/Resources/";
public static Color RandomColor
{
get
{
var random = new Random();
return new Color(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));
}
}
/// <summary> /// <summary>
/// Get the Operating system you are runnin on /// Get the Operating system you are runnin on
/// </summary> /// </summary>
@@ -43,9 +52,10 @@ public static class Functions
/// <exception cref="ArgumentOutOfRangeException">Triggered if <paramref name="bufferSize" /> is less then or equal to 0</exception> /// <exception cref="ArgumentOutOfRangeException">Triggered if <paramref name="bufferSize" /> is less then or equal to 0</exception>
/// <exception cref="InvalidOperationException">Triggered if <paramref name="stream" /> is not readable</exception> /// <exception cref="InvalidOperationException">Triggered if <paramref name="stream" /> is not readable</exception>
/// <exception cref="ArgumentException">Triggered in <paramref name="destination" /> is not writable</exception> /// <exception cref="ArgumentException">Triggered in <paramref name="destination" /> is not writable</exception>
public static async Task CopyToOtherStreamAsync(this Stream stream, Stream destination, int bufferSize, public static async Task CopyToOtherStreamAsync(
IProgress<long>? progress = null, this Stream stream, Stream destination, int bufferSize,
CancellationToken cancellationToken = default) IProgress<long>? progress = null,
CancellationToken cancellationToken = default)
{ {
if (stream == null) throw new ArgumentNullException(nameof(stream)); if (stream == null) throw new ArgumentNullException(nameof(stream));
if (destination == null) throw new ArgumentNullException(nameof(destination)); if (destination == null) throw new ArgumentNullException(nameof(destination));
@@ -54,10 +64,11 @@ public static class Functions
if (!destination.CanWrite) if (!destination.CanWrite)
throw new ArgumentException("Destination stream is not writable", nameof(destination)); throw new ArgumentException("Destination stream is not writable", nameof(destination));
var buffer = new byte[bufferSize]; var buffer = new byte[bufferSize];
long totalBytesRead = 0; long totalBytesRead = 0;
int bytesRead; int bytesRead;
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0) while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)
.ConfigureAwait(false)) != 0)
{ {
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
@@ -102,9 +113,9 @@ public static class Functions
return (obj ?? default)!; return (obj ?? default)!;
} }
public static T SelectRandomValueOf<T> () public static T SelectRandomValueOf<T>()
{ {
var enums = Enum.GetValues(typeof(T)); var enums = Enum.GetValues(typeof(T));
var random = new Random(); var random = new Random();
return (T)enums.GetValue(random.Next(enums.Length)); return (T)enums.GetValue(random.Next(enums.Length));
} }
@@ -114,13 +125,4 @@ public static class Functions
Random random = new(); Random random = new();
return values[random.Next(values.Length)]; return values[random.Next(values.Length)];
} }
public static Discord.Color RandomColor
{
get
{
Random random = new Random();
return new Discord.Color(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));
}
}
} }

View File

@@ -1,53 +1,60 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PluginManager.Others.Logger namespace PluginManager.Others.Logger;
public class DBLogger
{ {
public class DBLogger public delegate void LogHandler(string message, LogLevel logType);
private readonly string _errFolder;
private readonly string _logFolder;
private readonly List<LogMessage> ErrorHistory = new();
private readonly List<LogMessage> LogHistory = new();
public DBLogger()
{ {
_logFolder = Config.Data["LogFolder"];
_errFolder = Config.Data["ErrorFolder"];
}
private List<LogMessage> LogHistory = new List<LogMessage>(); public IReadOnlyList<LogMessage> Logs => LogHistory;
private List<LogMessage> ErrorHistory = new List<LogMessage>(); public IReadOnlyList<LogMessage> Errors => ErrorHistory;
public IReadOnlyList<LogMessage> Logs => LogHistory; public event LogHandler LogEvent;
public IReadOnlyList<LogMessage> Errors => ErrorHistory;
public delegate void LogHandler(string message, LogLevel logType); public void Log(string message, string sender = "unknown", LogLevel type = LogLevel.INFO)
public event LogHandler LogEvent; {
Log(new LogMessage(message, type, sender));
}
private string _logFolder; public void Error(Exception? e)
private string _errFolder; {
Log(e.Message, e.Source, LogLevel.ERROR);
}
public DBLogger() public void Log(LogMessage message)
{ {
_logFolder = Config.Data["LogFolder"]; if (LogEvent is not null)
_errFolder = Config.Data["ErrorFolder"]; LogEvent?.Invoke(message.Message, message.Type);
}
public void Log(string message, string sender = "unknown", LogLevel type = LogLevel.INFO) => Log(new LogMessage(message, type, sender)); if (message.Type != LogLevel.ERROR && message.Type != LogLevel.CRITICAL)
public void Error(Exception? e) => Log(e.Message, e.Source, LogLevel.ERROR); LogHistory.Add(message);
else
ErrorHistory.Add(message);
}
public void Log(LogMessage message) public void Log(string message, object sender, LogLevel type = LogLevel.NONE)
{ {
if(LogEvent is not null) Log(message, sender.GetType().Name, type);
LogEvent?.Invoke(message.Message, message.Type); }
if (message.Type != LogLevel.ERROR && message.Type != LogLevel.CRITICAL) public async void SaveToFile()
LogHistory.Add(message); {
else await Functions.SaveToJsonFile(_logFolder + "/" + DateTime.Now.ToString("yyyy-MM-dd") + ".json",
ErrorHistory.Add(message); LogHistory);
} await Functions.SaveToJsonFile(_errFolder + "/" + DateTime.Now.ToString("yyyy-MM-dd") + ".json",
ErrorHistory);
public void Log(string message, object sender, LogLevel type = LogLevel.NONE) => Log(message, sender.GetType().Name, type);
public async void SaveToFile()
{
await Functions.SaveToJsonFile(_logFolder + "/" + DateTime.Now.ToString("yyyy-MM-dd") + ".json", LogHistory);
await Functions.SaveToJsonFile(_errFolder + "/" + DateTime.Now.ToString("yyyy-MM-dd") + ".json", ErrorHistory);
}
} }
} }

View File

@@ -1,47 +1,43 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PluginManager.Others.Logger namespace PluginManager.Others.Logger;
public class LogMessage
{ {
public class LogMessage public LogMessage(string message, LogLevel type)
{ {
public string Message { get; set; } Message = message;
public LogLevel Type { get; set; } Type = type;
public string Time { get; set; } Time = DateTime.Now.ToString("HH:mm:ss");
public string Sender { get; set; } }
public LogMessage(string message, LogLevel type)
{
Message = message;
Type = type;
Time = DateTime.Now.ToString("HH:mm:ss");
}
public LogMessage(string message, LogLevel type, string sender) : this(message, type) public LogMessage(string message, LogLevel type, string sender) : this(message, type)
{ {
Sender = sender; Sender = sender;
} }
public override string ToString() public string Message { get; set; }
{ public LogLevel Type { get; set; }
return $"[{Time}] {Message}"; public string Time { get; set; }
} public string Sender { get; set; }
public static explicit operator LogMessage(string message) public override string ToString()
{ {
return new LogMessage(message, LogLevel.INFO); return $"[{Time}] {Message}";
} }
public static explicit operator LogMessage((string message, LogLevel type) tuple) public static explicit operator LogMessage(string message)
{ {
return new LogMessage(tuple.message, tuple.type); return new LogMessage(message, LogLevel.INFO);
} }
public static explicit operator LogMessage((string message, LogLevel type, string sender) tuple) public static explicit operator LogMessage((string message, LogLevel type) tuple)
{ {
return new LogMessage(tuple.message, tuple.type, tuple.sender); return new LogMessage(tuple.message, tuple.type);
} }
public static explicit operator LogMessage((string message, LogLevel type, string sender) tuple)
{
return new LogMessage(tuple.message, tuple.type, tuple.sender);
} }
} }

View File

@@ -1,5 +1,4 @@
using System.Linq; using System.Linq;
using Discord; using Discord;
using Discord.WebSocket; using Discord.WebSocket;

View File

@@ -1,18 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<DebugType>none</DebugType> <DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols> <DebugSymbols>false</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Remove="BlankWindow1.xaml" /> <None Remove="BlankWindow1.xaml"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Discord.Net" Version="3.10.0" /> <PackageReference Include="Discord.Net" Version="3.10.0"/>
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.118" /> <PackageReference Include="System.Data.SQLite.Core" Version="1.0.118"/>
</ItemGroup> </ItemGroup>
</Project> </Project>