Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f3c3c7939c | |||
| 361ed37362 | |||
| ed3128b940 | |||
| 6bbd68a135 | |||
| 06d322b5b3 | |||
| 5497ee9119 | |||
| 0aa78e3560 | |||
| 41ad37b3bb | |||
| 0104d09509 | |||
| b4f5e40f12 | |||
| 7107b17f19 | |||
| 42e1fd917e | |||
| 9e6fcdbe6f | |||
| a24d8aa222 | |||
| 0e5c9ff14b | |||
| f8977d8840 | |||
| bb9768f3a1 | |||
| b3d6930142 | |||
| 5254be44be | |||
| 207e0d6abd | |||
| 968d23380f | |||
| fff9e2e897 | |||
| 3e4e777d8d | |||
| 7f906d400f | |||
| c1161a3bca | |||
| ac512e3a27 | |||
| 730b628fe3 | |||
| 701edc5c6a | |||
| e7688762b8 | |||
| a7a71bf49a | |||
| ac7212ca00 | |||
| 298e557260 | |||
| 7ba791f906 | |||
| 4a6a12baae | |||
| f1dda5da3c | |||
| 3ab96e2d0d | |||
| 970c519a32 | |||
| 188920ec7f | |||
| dcfc4ea32f | |||
| a8c02176d3 | |||
| 1665d47a25 | |||
| 0b2f1e6ab6 | |||
| bcd9245502 | |||
| 59da9b295b | |||
| 99d7d5e7e7 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -372,5 +372,5 @@ FodyWeavers.xsd
|
|||||||
/DiscordBot/Data/
|
/DiscordBot/Data/
|
||||||
/DiscordBot/Updater/
|
/DiscordBot/Updater/
|
||||||
.idea/
|
.idea/
|
||||||
/DiscordBotWeb/
|
|
||||||
DiscordBot/Launcher.exe
|
DiscordBot/Launcher.exe
|
||||||
|
DiscordBotUI/*
|
||||||
|
|||||||
24
DiscordBot/Bot/Actions/Clear.cs
Normal file
24
DiscordBot/Bot/Actions/Clear.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using PluginManager;
|
||||||
|
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();
|
||||||
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
Console.WriteLine("===== Seth Discord Bot =====");
|
||||||
|
Console.ResetColor();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
47
DiscordBot/Bot/Actions/Exit.cs
Normal file
47
DiscordBot/Bot/Actions/Exit.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using PluginManager;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
using PluginManager.Others;
|
||||||
|
|
||||||
|
namespace DiscordBot.Bot.Actions;
|
||||||
|
|
||||||
|
public class Exit : ICommandAction
|
||||||
|
{
|
||||||
|
public string ActionName => "exit";
|
||||||
|
public string Description => "Exits the bot and saves the config. Use exit help for more info.";
|
||||||
|
public string Usage => "exit [help|force (-f)]";
|
||||||
|
public InternalActionRunType RunType => InternalActionRunType.ON_CALL;
|
||||||
|
|
||||||
|
public async Task Execute(string[] args)
|
||||||
|
{
|
||||||
|
if (args is null || args.Length == 0)
|
||||||
|
{
|
||||||
|
Config.Logger.Log("Exiting...", "Exit", isInternal: false);
|
||||||
|
await Config.AppSettings.SaveToFile();
|
||||||
|
await Config.Logger.SaveToFile();
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch ( args[0] )
|
||||||
|
{
|
||||||
|
case "help":
|
||||||
|
Console.WriteLine("Usage : exit [help|force]");
|
||||||
|
Console.WriteLine("help : Displays this message");
|
||||||
|
Console.WriteLine("force | -f : Exits the bot without saving the config");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "-f":
|
||||||
|
case "force":
|
||||||
|
Config.Logger.Log("Exiting (FORCE)...", "Exit", LogLevel.WARNING, false);
|
||||||
|
Environment.Exit(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Console.WriteLine("Invalid argument !");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
DiscordBot/Bot/Actions/Help.cs
Normal file
62
DiscordBot/Bot/Actions/Help.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using DiscordBot.Utilities;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
using PluginManager.Others;
|
||||||
|
|
||||||
|
namespace DiscordBot.Bot.Actions;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (args == null || args.Length == 0)
|
||||||
|
{
|
||||||
|
var items = new List<string[]>
|
||||||
|
{
|
||||||
|
new[] { "-", "-", "-" },
|
||||||
|
new[] { "Command", "Usage", "Description" },
|
||||||
|
new[] { "-", "-", "-" }
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var a in Program.internalActionManager.Actions)
|
||||||
|
items.Add(new[] { a.Key, a.Value.Usage, a.Value.Description });
|
||||||
|
|
||||||
|
items.Add(new[] { "-", "-", "-" });
|
||||||
|
|
||||||
|
Utilities.Utilities.FormatAndAlignTable(items,
|
||||||
|
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[] { "-", "-", "-" }
|
||||||
|
};
|
||||||
|
|
||||||
|
Utilities.Utilities.FormatAndAlignTable(actionData,
|
||||||
|
TableFormat.CENTER_EACH_COLUMN_BASED
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
197
DiscordBot/Bot/Actions/Plugin.cs
Normal file
197
DiscordBot/Bot/Actions/Plugin.cs
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using DiscordBot.Utilities;
|
||||||
|
using PluginManager;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
using PluginManager.Loaders;
|
||||||
|
using PluginManager.Online;
|
||||||
|
using PluginManager.Others;
|
||||||
|
|
||||||
|
namespace DiscordBot.Bot.Actions;
|
||||||
|
|
||||||
|
public class Plugin : ICommandAction
|
||||||
|
{
|
||||||
|
private bool pluginsLoaded;
|
||||||
|
public string ActionName => "plugin";
|
||||||
|
public string Description => "Manages plugins. Use plugin help for more info.";
|
||||||
|
public string Usage => "plugin [help|list|load|install]";
|
||||||
|
public InternalActionRunType RunType => InternalActionRunType.ON_CALL;
|
||||||
|
|
||||||
|
public async Task Execute(string[] args)
|
||||||
|
{
|
||||||
|
if (args is null || args.Length == 0 || args[0] == "help")
|
||||||
|
{
|
||||||
|
Console.WriteLine("Usage : plugin [help|list|load|install]");
|
||||||
|
Console.WriteLine("help : Displays this message");
|
||||||
|
Console.WriteLine("list : Lists all plugins");
|
||||||
|
Console.WriteLine("load : Loads all plugins");
|
||||||
|
Console.WriteLine("install : Installs a plugin");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( args[0] )
|
||||||
|
{
|
||||||
|
case "list":
|
||||||
|
var manager =
|
||||||
|
new PluginsManager(Program.URLs["PluginList"], Program.URLs["PluginVersions"]);
|
||||||
|
|
||||||
|
var data = await manager.GetAvailablePlugins();
|
||||||
|
var items = new List<string[]>
|
||||||
|
{
|
||||||
|
new[] { "-", "-", "-", "-" },
|
||||||
|
new[] { "Name", "Description", "Type", "Version" },
|
||||||
|
new[] { "-", "-", "-", "-" }
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var plugin in data) items.Add(new[] { plugin[0], plugin[1], plugin[2], plugin[3] });
|
||||||
|
|
||||||
|
items.Add(new[] { "-", "-", "-", "-" });
|
||||||
|
|
||||||
|
Utilities.Utilities.FormatAndAlignTable(items, TableFormat.DEFAULT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case "load":
|
||||||
|
if (pluginsLoaded)
|
||||||
|
break;
|
||||||
|
var loader = new PluginLoader(Config.DiscordBot.client);
|
||||||
|
var cc = Console.ForegroundColor;
|
||||||
|
loader.onCMDLoad += (name, typeName, success, exception) =>
|
||||||
|
{
|
||||||
|
if (name == null || name.Length < 2)
|
||||||
|
name = typeName;
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
Console.WriteLine("[CMD] Successfully loaded command : " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
if (exception is null)
|
||||||
|
Console.WriteLine("An error occured while loading: " + name);
|
||||||
|
else
|
||||||
|
Console.WriteLine("[CMD] Failed to load command : " + name + " because " +
|
||||||
|
exception!.Message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.ForegroundColor = cc;
|
||||||
|
};
|
||||||
|
loader.onEVELoad += (name, typeName, success, exception) =>
|
||||||
|
{
|
||||||
|
if (name == null || name.Length < 2)
|
||||||
|
name = typeName;
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
Console.WriteLine("[EVENT] Successfully loaded event : " + name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine("[EVENT] Failed to load event : " + name + " because " + exception!.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.ForegroundColor = cc;
|
||||||
|
};
|
||||||
|
|
||||||
|
loader.onSLSHLoad += (name, typeName, success, exception) =>
|
||||||
|
{
|
||||||
|
if (name == null || name.Length < 2)
|
||||||
|
name = typeName;
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
Console.WriteLine("[SLASH] Successfully loaded command : " + name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine("[SLASH] Failed to load command : " + name + " because " +
|
||||||
|
exception!.Message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.ForegroundColor = cc;
|
||||||
|
};
|
||||||
|
|
||||||
|
loader.LoadPlugins();
|
||||||
|
Console.ForegroundColor = cc;
|
||||||
|
pluginsLoaded = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "install":
|
||||||
|
var pluginName = string.Join(' ', args, 1, args.Length - 1);
|
||||||
|
if (string.IsNullOrEmpty(pluginName) || pluginName.Length < 2)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Please specify a plugin name");
|
||||||
|
Console.Write("Plugin name : ");
|
||||||
|
pluginName = Console.ReadLine();
|
||||||
|
if (string.IsNullOrEmpty(pluginName) || pluginName.Length < 2)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Invalid plugin name");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var pluginManager =
|
||||||
|
new PluginsManager(Program.URLs["PluginList"], Program.URLs["PluginVersions"]);
|
||||||
|
var pluginData = await pluginManager.GetPluginLinkByName(pluginName);
|
||||||
|
if (pluginData == null || pluginData.Length == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Plugin {pluginName} not found. Please check the spelling and try again.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pluginType = pluginData[0];
|
||||||
|
var pluginLink = pluginData[1];
|
||||||
|
var pluginRequirements = pluginData[2];
|
||||||
|
|
||||||
|
|
||||||
|
Console.WriteLine("Downloading plugin...");
|
||||||
|
//download plugin progress bar for linux and windows terminals
|
||||||
|
var spinner = new Utilities.Utilities.Spinner();
|
||||||
|
spinner.Start();
|
||||||
|
IProgress<float> progress = new Progress<float>(p => { spinner.Message = $"Downloading {pluginName}... {Math.Round(p, 2)}% "; });
|
||||||
|
await ServerCom.DownloadFileAsync(pluginLink, $"./Data/{pluginType}s/{pluginName}.dll", progress);
|
||||||
|
spinner.Stop();
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
if (pluginRequirements == string.Empty)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Plugin installed successfully");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Downloading plugin requirements...");
|
||||||
|
var requirementsURLs = await ServerCom.ReadTextFromURL(pluginRequirements);
|
||||||
|
|
||||||
|
foreach (var requirement in requirementsURLs)
|
||||||
|
{
|
||||||
|
if (requirement.Length < 2)
|
||||||
|
continue;
|
||||||
|
var reqdata = requirement.Split(',');
|
||||||
|
var url = reqdata[0];
|
||||||
|
var filename = reqdata[1];
|
||||||
|
|
||||||
|
Console.WriteLine($"Downloading {filename}... ");
|
||||||
|
spinner.Start();
|
||||||
|
|
||||||
|
await ServerCom.DownloadFileAsync(url, $"./{filename}.dll", null);
|
||||||
|
spinner.Stop();
|
||||||
|
await Task.Delay(1000);
|
||||||
|
Console.WriteLine("Downloaded " + filename + " successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Finished installing " + pluginName + " successfully");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
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;
|
||||||
using PluginManager.Others;
|
using PluginManager.Others;
|
||||||
|
|
||||||
namespace DiscordBot.Discord.Commands;
|
namespace DiscordBot.Bot.Commands;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The help command
|
/// The help command
|
||||||
@@ -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,10 +75,11 @@ 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.AppSettings["prefix"] + cmd.Usage);
|
||||||
embedBuilder.AddField("Description", cmd.Description);
|
embedBuilder.AddField("Description", cmd.Description);
|
||||||
if (cmd.Aliases is null)
|
if (cmd.Aliases is null)
|
||||||
return embedBuilder;
|
return embedBuilder;
|
||||||
57
DiscordBot/Bot/Commands/SlashCommands/Help.cs
Normal file
57
DiscordBot/Bot/Commands/SlashCommands/Help.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
using PluginManager.Loaders;
|
||||||
|
using PluginManager.Others;
|
||||||
|
|
||||||
|
namespace DiscordBot.Bot.Commands.SlashCommands;
|
||||||
|
|
||||||
|
public class Help : DBSlashCommand
|
||||||
|
{
|
||||||
|
public string Name => "help";
|
||||||
|
public string Description => "This command allows you to check all loaded commands";
|
||||||
|
public bool canUseDM => true;
|
||||||
|
|
||||||
|
public List<SlashCommandOptionBuilder> Options =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
new SlashCommandOptionBuilder()
|
||||||
|
.WithName("command")
|
||||||
|
.WithDescription("The command you want to get help for")
|
||||||
|
.WithRequired(false)
|
||||||
|
.WithType(ApplicationCommandOptionType.String)
|
||||||
|
};
|
||||||
|
|
||||||
|
public async void ExecuteServer(SocketSlashCommand context)
|
||||||
|
{
|
||||||
|
EmbedBuilder embedBuilder = new();
|
||||||
|
|
||||||
|
embedBuilder.WithTitle("Help Command");
|
||||||
|
embedBuilder.WithColor(Functions.RandomColor);
|
||||||
|
var slashCommands = PluginLoader.SlashCommands;
|
||||||
|
var options = context.Data.Options;
|
||||||
|
|
||||||
|
//Console.WriteLine("Options: " + options.Count);
|
||||||
|
if (options is null || options.Count == 0)
|
||||||
|
foreach (var slashCommand in slashCommands)
|
||||||
|
embedBuilder.AddField(slashCommand.Name, slashCommand.Description);
|
||||||
|
|
||||||
|
if (options.Count > 0)
|
||||||
|
{
|
||||||
|
var commandName = options.First().Name;
|
||||||
|
var slashCommand = slashCommands.FirstOrDefault(x => x.Name == commandName);
|
||||||
|
if (slashCommand is null)
|
||||||
|
{
|
||||||
|
await context.RespondAsync("Unknown Command " + commandName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
embedBuilder.AddField(slashCommand.Name, slashCommand.canUseDM)
|
||||||
|
.WithDescription(slashCommand.Description);
|
||||||
|
}
|
||||||
|
|
||||||
|
await context.RespondAsync(embed: embedBuilder.Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,39 +1,42 @@
|
|||||||
<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.1</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>
|
<None Remove="builder.bat" />
|
||||||
<ItemGroup>
|
<None Remove="builder.sh" />
|
||||||
<PackageReference Include="Discord.Net" Version="3.9.0" />
|
</ItemGroup>
|
||||||
</ItemGroup>
|
<ItemGroup>
|
||||||
<ItemGroup>
|
<PackageReference Include="Discord.Net" Version="3.11.0"/>
|
||||||
<ProjectReference Include="..\PluginManager\PluginManager.csproj" />
|
<PackageReference Include="Sodium.Core" Version="1.3.3"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\PluginManager\PluginManager.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,31 +1,28 @@
|
|||||||
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"
|
||||||
|
);
|
||||||
static Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
|
var assemblyPath = Path.Combine(folderPath, new AssemblyName(args.Name).Name + ".dll");
|
||||||
{
|
if (!File.Exists(assemblyPath)) return null;
|
||||||
string folderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "./Libraries");
|
var assembly = Assembly.LoadFrom(assemblyPath);
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +1,64 @@
|
|||||||
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 void GenerateStartupConfig()
|
public static class Installer
|
||||||
|
{
|
||||||
|
public static void GenerateStartupConfig()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Welcome to the SethBot installer !");
|
||||||
|
Console.WriteLine("First, we need to configure the bot. Don't worry, it will be quick !");
|
||||||
|
Console.WriteLine("The following information will be stored in the config.json file in the ./Data/Resources folder. You can change it later from there.");
|
||||||
|
Console.WriteLine("The bot token is required to run the bot. You can get it from the Discord Developer Portal. (https://discord.com/developers/applications)");
|
||||||
|
|
||||||
|
if (!Config.AppSettings.ContainsKey("token"))
|
||||||
{
|
{
|
||||||
Console.WriteLine("Welcome to the SethBot installer !");
|
|
||||||
Console.WriteLine("First, we need to configure the bot. Don't worry, it will be quick !");
|
|
||||||
Console.WriteLine("The following information will be stored in the config.json file in the ./Data/Resources folder. You can change it later from there.");
|
|
||||||
Console.WriteLine("The bot tokn is required to run the bot. You can get it from the Discord Developer Portal. (https://discord.com/developers/applications)");
|
|
||||||
Console.WriteLine("Please enter the bot token :");
|
Console.WriteLine("Please enter the bot token :");
|
||||||
var token = Console.ReadLine();
|
var token = Console.ReadLine();
|
||||||
|
Config.AppSettings.Add("token", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Config.AppSettings.ContainsKey("prefix"))
|
||||||
|
{
|
||||||
Console.WriteLine("Please enter the bot prefix :");
|
Console.WriteLine("Please enter the bot prefix :");
|
||||||
var prefix = Console.ReadLine();
|
var prefix = Console.ReadLine();
|
||||||
|
Config.AppSettings.Add("prefix", prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Config.AppSettings.ContainsKey("ServerID"))
|
||||||
|
{
|
||||||
Console.WriteLine("Please enter the Server ID :");
|
Console.WriteLine("Please enter the Server ID :");
|
||||||
var serverId = Console.ReadLine();
|
var serverId = Console.ReadLine();
|
||||||
|
Config.AppSettings.Add("ServerID", serverId);
|
||||||
Config.Data.Add("token", token);
|
|
||||||
Config.Data.Add("prefix", prefix);
|
|
||||||
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()
|
Config.Logger.Log("Config Saved", "Installer", isInternal: true);
|
||||||
{
|
|
||||||
Console.WriteLine("The plugin database is required to run the bot but there is nothing configured yet.");
|
|
||||||
Console.WriteLine("Please select one option : ");
|
|
||||||
Console.WriteLine("1. Download the official database file");
|
|
||||||
Console.WriteLine("2. Create a new (CUSTOM) database file");
|
|
||||||
int choice = 0;
|
|
||||||
Console.Write("Choice : ");
|
|
||||||
choice = int.Parse(Console.ReadLine());
|
|
||||||
if (choice != 1 && choice != 2)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Invalid choice !");
|
|
||||||
Console.WriteLine("Please restart the installer !");
|
|
||||||
Console.ReadKey();
|
|
||||||
Environment.Exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (choice == 1)
|
Config.AppSettings.SaveToFile();
|
||||||
await DownloadPluginDatabase();
|
|
||||||
|
|
||||||
if (choice == 2)
|
Console.WriteLine("Config saved !");
|
||||||
{
|
}
|
||||||
Console.WriteLine("Do you have a url to a valid database file ? (y/n)");
|
|
||||||
var answer = Console.ReadLine();
|
|
||||||
if (answer == "y")
|
|
||||||
{
|
|
||||||
Console.WriteLine("Please enter the url :");
|
|
||||||
var url = Console.ReadLine();
|
|
||||||
await DownloadPluginDatabase(url);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Do you want to create a new database file ? (y/n)");
|
public static async Task SetupPluginDatabase()
|
||||||
answer = Console.ReadLine();
|
{
|
||||||
if (answer == "y")
|
Console.WriteLine("The plugin database is required to run the bot but there is nothing configured yet.");
|
||||||
{
|
Console.WriteLine("Downloading the default database...");
|
||||||
Console.WriteLine("A new file will be generated at ./Data/Resources/URLs.json");
|
await DownloadPluginDatabase();
|
||||||
System.Console.WriteLine("Please edit the file and restart the bot !");
|
}
|
||||||
Directory.CreateDirectory("./Data/Resources");
|
|
||||||
await File.WriteAllTextAsync("./Data/Resources/URLs.json",
|
|
||||||
@"
|
|
||||||
{
|
|
||||||
""PluginList"": """",
|
|
||||||
""PluginVersions"": """",
|
|
||||||
""StartupMessage"": """",
|
|
||||||
""SetupKeys"": """",
|
|
||||||
""Versions"": """",
|
|
||||||
""Changelog"": """",
|
|
||||||
""LinuxBot"": """",
|
|
||||||
""WindowsLauncher"": """",
|
|
||||||
}
|
|
||||||
".Replace(" ", ""));
|
|
||||||
Environment.Exit(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task DownloadPluginDatabase(string url = "https://raw.githubusercontent.com/Wizzy69/SethDiscordBot/gh-pages/defaultURLs.json")
|
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.ProgressBar bar = new Utilities.Utilities.ProgressBar(Utilities.ProgressBarType.NORMAL){
|
var spinner = new Utilities.Utilities.Spinner();
|
||||||
Max = 100,
|
spinner.Start();
|
||||||
Color = ConsoleColor.Green,
|
await ServerCom.DownloadFileAsync(url, path, null);
|
||||||
NoColor = true
|
spinner.Stop();
|
||||||
};
|
|
||||||
IProgress<float> downloadProgress = new Progress<float>(p => bar.Update(p));
|
|
||||||
await ServerCom.DownloadFileAsync(url, path, downloadProgress, null);
|
|
||||||
bar.Update(bar.Max);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,30 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using PluginManager;
|
using System.Threading.Tasks;
|
||||||
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 Microsoft.VisualBasic.CompilerServices;
|
|
||||||
using OperatingSystem = PluginManager.Others.OperatingSystem;
|
|
||||||
using static PluginManager.Config;
|
using static PluginManager.Config;
|
||||||
|
|
||||||
namespace DiscordBot;
|
namespace DiscordBot;
|
||||||
|
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static Json<string, string> URLs;
|
public static SettingsDictionary<string, string> URLs;
|
||||||
private static bool loadPluginsOnStartup = false;
|
public static InternalActionManager internalActionManager;
|
||||||
private static ConsoleCommandsHandler consoleCommandsHandler;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The main entry point for the application.
|
/// The main entry point for the application.
|
||||||
@@ -34,15 +26,13 @@ public class Program
|
|||||||
{
|
{
|
||||||
PreLoadComponents(args).Wait();
|
PreLoadComponents(args).Wait();
|
||||||
|
|
||||||
if (!Config.Data.ContainsKey("ServerID") || !Config.Data.ContainsKey("token") ||
|
if (!AppSettings.ContainsKey("ServerID") || !AppSettings.ContainsKey("token") ||
|
||||||
Config.Data["token"] == null ||
|
AppSettings["token"] == null ||
|
||||||
(Config.Data["token"]?.Length != 70 && Config.Data["token"]?.Length != 59) ||
|
AppSettings["token"]?.Length != 70 && AppSettings["token"]?.Length != 59 ||
|
||||||
!Config.Data.ContainsKey("prefix") || Config.Data["prefix"] == null ||
|
!AppSettings.ContainsKey("prefix") || AppSettings["prefix"] == null ||
|
||||||
Config.Data["prefix"]?.Length != 1 ||
|
AppSettings["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();
|
||||||
}
|
}
|
||||||
@@ -54,21 +44,19 @@ public class Program
|
|||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Console.WriteLine("Debug mode enabled");
|
Console.WriteLine("Debug mode enabled");
|
||||||
|
internalActionManager.Execute("plugin", "load").Wait(); // Load plugins at startup
|
||||||
#endif
|
#endif
|
||||||
if (loadPluginsOnStartup)
|
|
||||||
consoleCommandsHandler.HandleCommand("lp");
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var cmd = Console.ReadLine();
|
var cmd = Console.ReadLine();
|
||||||
if (!consoleCommandsHandler.HandleCommand(cmd!
|
var args = cmd.Split(' ');
|
||||||
#if DEBUG
|
var command = args[0];
|
||||||
, false
|
args = args.Skip(1).ToArray();
|
||||||
#endif
|
if (args.Length == 0)
|
||||||
|
args = null;
|
||||||
|
|
||||||
) && cmd.Length > 0)
|
internalActionManager.Execute(command, args).Wait(); // Execute the command
|
||||||
Console.WriteLine("Failed to run command " + cmd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,40 +76,43 @@ 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: {AppSettings["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 (AppSettings.ContainsKey("LaunchMessage"))
|
||||||
Utilities.Utilities.WriteColorText(Config.Data["LaunchMessage"]);
|
Utilities.Utilities.WriteColorText(AppSettings["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 = AppSettings["token"];
|
||||||
#else
|
#else
|
||||||
token = Config.Data["token"];
|
token = AppSettings["token"];
|
||||||
#endif
|
#endif
|
||||||
var prefix = Config.Data["prefix"];
|
var prefix = AppSettings["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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,63 +123,80 @@ 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:
|
||||||
|
|
||||||
|
if (args.Contains("--gui"))
|
||||||
|
{
|
||||||
|
// GUI not implemented yet
|
||||||
|
Console.WriteLine("GUI not implemented yet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starting bot after all arguments are handled
|
||||||
|
|
||||||
var b = await StartNoGui();
|
var b = await StartNoGui();
|
||||||
consoleCommandsHandler = new ConsoleCommandsHandler(b.client);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if(args.Contains("--gui"))
|
internalActionManager = new InternalActionManager("./Data/Actions", "*.dll");
|
||||||
{
|
await internalActionManager.Initialize();
|
||||||
// GUI not implemented yet
|
|
||||||
Console.WriteLine("GUI not implemented yet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NoGUI();
|
NoGUI();
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch ( IOException ex )
|
||||||
{
|
{
|
||||||
if (ex.Message == "No process is on the other end of the pipe." || (uint)ex.HResult == 0x800700E9)
|
if (ex.Message == "No process is on the other end of the pipe." || (uint)ex.HResult == 0x800700E9)
|
||||||
{
|
{
|
||||||
if (Config.Data.ContainsKey("LaunchMessage"))
|
if (AppSettings.ContainsKey("LaunchMessage"))
|
||||||
Config.Data.Add("LaunchMessage",
|
AppSettings.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();
|
Logger.LogEvent += (message, type, isInternal) =>
|
||||||
|
{
|
||||||
|
if (type == LogLevel.INFO)
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
else if (type == LogLevel.WARNING)
|
||||||
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
|
else if (type == LogLevel.ERROR)
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
else if (type == LogLevel.CRITICAL)
|
||||||
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
||||||
|
|
||||||
|
Console.WriteLine($"[{type.ToString()}] {message}");
|
||||||
|
Console.ResetColor();
|
||||||
|
};
|
||||||
|
|
||||||
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 SettingsDictionary<string, string>("./Data/Resources/URLs.json");
|
||||||
|
|
||||||
Config.Logger.LogEvent += (message, type) => { Console.WriteLine(message); };
|
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine("Loading resources ...");
|
Console.WriteLine("Loading resources ...");
|
||||||
var main = new Utilities.Utilities.ProgressBar(ProgressBarType.NO_END);
|
|
||||||
main.Start();
|
|
||||||
|
|
||||||
if (Config.Data.ContainsKey("DeleteLogsAtStartup"))
|
if (AppSettings.ContainsKey("DeleteLogsAtStartup"))
|
||||||
if (Config.Data["DeleteLogsAtStartup"] == "true")
|
if (AppSettings["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 =
|
|
||||||
await ServerCom.ReadTextFromURL(URLs["SetupKeys"]);
|
var OnlineDefaultKeys = await ServerCom.ReadTextFromURL(URLs["SetupKeys"]);
|
||||||
|
|
||||||
|
|
||||||
Config.Data["Version"] = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
AppSettings["Version"] = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||||
|
|
||||||
foreach (var key in OnlineDefaultKeys)
|
foreach (var key in OnlineDefaultKeys)
|
||||||
{
|
{
|
||||||
@@ -196,127 +204,38 @@ public class Program
|
|||||||
var s = key.Split(' ');
|
var s = key.Split(' ');
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Config.Data[s[0]] = s[1];
|
AppSettings[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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var onlineSettingsList = await ServerCom.ReadTextFromURL(URLs["Versions"]);
|
var onlineSettingsList = await ServerCom.ReadTextFromURL(URLs["Versions"]);
|
||||||
main.Stop("Loaded online settings. Loading updates ...");
|
|
||||||
foreach (var key in onlineSettingsList)
|
foreach (var key in onlineSettingsList)
|
||||||
{
|
{
|
||||||
if (key.Length <= 3 || !key.Contains(' ')) continue;
|
if (key.Length <= 3 || !key.Contains(' ')) continue;
|
||||||
|
|
||||||
var s = key.Split(' ');
|
var s = key.Split(' ');
|
||||||
switch (s[0])
|
switch ( s[0] )
|
||||||
{
|
{
|
||||||
case "CurrentVersion":
|
case "CurrentVersion":
|
||||||
var newVersion = s[1];
|
var currentVersion = AppSettings["Version"];
|
||||||
var currentVersion = Config.Data["Version"];
|
var newVersion = s[1];
|
||||||
if (!newVersion.Equals(currentVersion))
|
if (new VersionString(newVersion) != new VersionString(newVersion))
|
||||||
{
|
{
|
||||||
var nVer = new VersionString(newVersion.Substring(2));
|
Console.WriteLine("A new updated was found. Check the changelog for more information.");
|
||||||
var cVer = new VersionString((Config.Data["Version"]).Substring(2));
|
var changeLog = await ServerCom.ReadTextFromURL(URLs["Changelog"]);
|
||||||
if (cVer > nVer)
|
|
||||||
{
|
|
||||||
Config.Data["Version"] = "1." + cVer.ToShortString() + " (Beta)";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OperatingSystem.WINDOWS == Functions.GetOperatingSystem())
|
|
||||||
{
|
|
||||||
Console.Clear();
|
|
||||||
Console.WriteLine("A new update was found !");
|
|
||||||
Console.WriteLine("Run the launcher to update");
|
|
||||||
Console.WriteLine("Current version: " + currentVersion);
|
|
||||||
Console.WriteLine("Latest version: " + s[1]);
|
|
||||||
|
|
||||||
File.WriteAllText("version.txt", currentVersion);
|
|
||||||
|
|
||||||
await Task.Delay(3000);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.Clear();
|
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
|
||||||
Console.WriteLine("A new version of the bot is available !");
|
|
||||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
|
||||||
Console.WriteLine("Current version : " +
|
|
||||||
Assembly.GetExecutingAssembly().GetName().Version.ToString());
|
|
||||||
Console.ForegroundColor = ConsoleColor.Green;
|
|
||||||
Console.WriteLine("New version : " + newVersion);
|
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
|
||||||
|
|
||||||
File.WriteAllText("version.txt", newVersion);
|
|
||||||
|
|
||||||
Console.WriteLine("Changelog :");
|
|
||||||
|
|
||||||
List<string> 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("Do you want to update the bot ? (y/n)");
|
Console.WriteLine("Current version: " + currentVersion);
|
||||||
if (Console.ReadKey().Key == ConsoleKey.Y)
|
Console.WriteLine("Latest version: " + newVersion);
|
||||||
{
|
|
||||||
var url = URLs["LinuxBot"].Replace("{0}", newVersion);
|
|
||||||
Config.Logger.Log($"executing: download_file {url}");
|
|
||||||
|
|
||||||
await ServerCom.DownloadFileAsync(url, "./update.zip", new Progress<float>(percent => { Console.WriteLine($"\rProgress: {percent}% "); }));
|
Console.WriteLine("Download from here: https://github.com/andreitdr/SethDiscordBot/releases");
|
||||||
await File.WriteAllTextAsync("Install.sh",
|
|
||||||
"#!/bin/bash\nunzip -qq -o update.zip \nrm update.zip\nchmod a+x DiscordBot");
|
|
||||||
|
|
||||||
try
|
Console.WriteLine("Press any key to continue ...");
|
||||||
{
|
Console.ReadKey();
|
||||||
Console.WriteLine("executing: chmod a+x Install.sh");
|
|
||||||
Process.Start("chmod", "a+x Install.sh").WaitForExit();
|
|
||||||
Process.Start("Install.sh").WaitForExit();
|
|
||||||
|
|
||||||
Console.WriteLine("executing: rm Install.sh");
|
|
||||||
Process.Start("rm", "Install.sh").WaitForExit();
|
|
||||||
|
|
||||||
Config.Logger.Log("The new version of the bot has been installed.");
|
|
||||||
Console.WriteLine("Please restart the bot.");
|
|
||||||
Environment.Exit(0);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Config.Logger.Log(ex.Message, "Updater", LogLevel.ERROR);
|
|
||||||
if (ex.Message.Contains("Access de"))
|
|
||||||
Config.Logger.Log("Please run the bot as root.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case "LauncherVersion":
|
|
||||||
var updaternewversion = s[1];
|
|
||||||
//File.WriteAllText(updaternewversion + ".txt", updaternewversion);
|
|
||||||
if (Functions.GetOperatingSystem() == OperatingSystem.LINUX)
|
|
||||||
break;
|
|
||||||
|
|
||||||
Directory.CreateDirectory(Functions.dataFolder + "Applications");
|
|
||||||
if (!Config.Data.ContainsKey("LauncherVersion"))
|
|
||||||
Config.Data["LauncherVersion"] = "0.0.0.0";
|
|
||||||
if (Config.Data["LauncherVersion"] != updaternewversion ||
|
|
||||||
!File.Exists("./Launcher.exe"))
|
|
||||||
{
|
|
||||||
Console.Clear();
|
|
||||||
Console.WriteLine("Installing a new Launcher ...\nDo NOT close the bot during update !");
|
|
||||||
var bar = new Utilities.Utilities.ProgressBar(ProgressBarType.NO_END);
|
|
||||||
bar.Start();
|
|
||||||
await ServerCom.DownloadFileAsync(URLs["WindowsLauncher"], $"./Launcher.exe", null);
|
|
||||||
//await ArchiveManager.ExtractArchive("./Updater.zip", "./", null,
|
|
||||||
// UnzipProgressType.PercentageFromTotalSize);
|
|
||||||
Config.Data["LauncherVersion"] = updaternewversion;
|
|
||||||
// File.Delete("Updater.zip");
|
|
||||||
bar.Stop("The launcher has been updated !");
|
|
||||||
Console.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Discord.Commands;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
|
|
||||||
namespace DiscordBot.Utilities;
|
|
||||||
|
|
||||||
public class ConsoleCommand
|
|
||||||
{
|
|
||||||
public string? CommandName { get; init; }
|
|
||||||
public string? Description { get; init; }
|
|
||||||
public string? Usage { get; init; }
|
|
||||||
public Action<string[]>? Action { get; init; }
|
|
||||||
}
|
|
||||||
@@ -1,24 +1,21 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
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)
|
||||||
@@ -35,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)
|
||||||
@@ -143,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++)
|
||||||
@@ -173,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)
|
||||||
{
|
{
|
||||||
@@ -201,199 +198,46 @@ public static class Utilities
|
|||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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;
|
||||||
|
public string Message;
|
||||||
|
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]);
|
{
|
||||||
position++;
|
Console.SetCursorPosition(0, Console.CursorTop);
|
||||||
if (position >= Sequence.Length)
|
Console.Write(" " + Sequence[position] + " " + Message + " ");
|
||||||
position = 0;
|
position++;
|
||||||
Thread.Sleep(100);
|
if (position >= Sequence.Length)
|
||||||
}
|
position = 0;
|
||||||
});
|
Thread.Sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
thread.Start();
|
thread.Start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
isRunning=false;
|
isRunning = false;
|
||||||
Console.CursorVisible = true;
|
Console.CursorVisible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Progress bar object
|
|
||||||
/// </summary>
|
|
||||||
public class ProgressBar
|
|
||||||
{
|
|
||||||
private readonly int BarLength = 32;
|
|
||||||
|
|
||||||
private bool isRunning;
|
|
||||||
private int position = 1;
|
|
||||||
private bool positive = true;
|
|
||||||
|
|
||||||
public ProgressBar(ProgressBarType type)
|
|
||||||
{
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Max { get; init; }
|
|
||||||
public ConsoleColor Color { get; init; }
|
|
||||||
public bool NoColor { get; init; }
|
|
||||||
public ProgressBarType type { get; set; }
|
|
||||||
|
|
||||||
public int TotalLength { get; private set; }
|
|
||||||
|
|
||||||
|
|
||||||
public async void Start()
|
|
||||||
{
|
|
||||||
Console.WriteLine();
|
|
||||||
if (type != ProgressBarType.NO_END)
|
|
||||||
throw new Exception("Only NO_END progress bar can use this method");
|
|
||||||
if (isRunning)
|
|
||||||
throw new Exception("This progress bar is already running");
|
|
||||||
|
|
||||||
isRunning = true;
|
|
||||||
while (isRunning)
|
|
||||||
{
|
|
||||||
UpdateNoEnd();
|
|
||||||
await Task.Delay(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Start(string message)
|
|
||||||
{
|
|
||||||
if (type != ProgressBarType.NO_END)
|
|
||||||
throw new Exception("Only NO_END progress bar can use this method");
|
|
||||||
if (isRunning)
|
|
||||||
throw new Exception("This progress bar is already running");
|
|
||||||
|
|
||||||
isRunning = true;
|
|
||||||
|
|
||||||
TotalLength = message.Length + BarLength + 5;
|
|
||||||
while (isRunning)
|
|
||||||
{
|
|
||||||
UpdateNoEnd(message);
|
|
||||||
await Task.Delay(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
if (type != ProgressBarType.NO_END)
|
|
||||||
throw new Exception("Only NO_END progress bar can use this method");
|
|
||||||
if (!isRunning)
|
|
||||||
throw new Exception("Can not stop a progressbar that did not start");
|
|
||||||
isRunning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop(string message)
|
|
||||||
{
|
|
||||||
Stop();
|
|
||||||
|
|
||||||
if (message is not null)
|
|
||||||
{
|
|
||||||
Console.CursorLeft = 0;
|
|
||||||
for (var i = 0; i < BarLength + message.Length + 1; i++)
|
|
||||||
Console.Write(" ");
|
|
||||||
Console.CursorLeft = 0;
|
|
||||||
Console.WriteLine(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update(float progress)
|
|
||||||
{
|
|
||||||
if (type == ProgressBarType.NO_END)
|
|
||||||
throw new Exception("This function is for progress bars with end");
|
|
||||||
|
|
||||||
UpdateNormal(progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateNoEnd(string message)
|
|
||||||
{
|
|
||||||
Console.CursorLeft = 0;
|
|
||||||
Console.Write("[");
|
|
||||||
for (var i = 1; i <= position; i++)
|
|
||||||
Console.Write(" ");
|
|
||||||
Console.Write("<==()==>");
|
|
||||||
position += positive ? 1 : -1;
|
|
||||||
for (var i = position; i <= BarLength - 1 - (positive ? 0 : 2); i++)
|
|
||||||
Console.Write(" ");
|
|
||||||
Console.Write("] " + message);
|
|
||||||
|
|
||||||
|
|
||||||
if (position == BarLength - 1 || position == 1)
|
|
||||||
positive = !positive;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateNoEnd()
|
|
||||||
{
|
|
||||||
Console.CursorLeft = 0;
|
|
||||||
Console.Write("[");
|
|
||||||
for (var i = 1; i <= position; i++)
|
|
||||||
Console.Write(" ");
|
|
||||||
Console.Write("<==()==>");
|
|
||||||
position += positive ? 1 : -1;
|
|
||||||
for (var i = position; i <= BarLength - 1 - (positive ? 0 : 2); i++)
|
|
||||||
Console.Write(" ");
|
|
||||||
Console.Write("]");
|
|
||||||
|
|
||||||
|
|
||||||
if (position == BarLength - 1 || position == 1)
|
|
||||||
positive = !positive;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateNormal(float progress)
|
|
||||||
{
|
|
||||||
Console.CursorLeft = 0;
|
|
||||||
Console.Write("[");
|
|
||||||
Console.CursorLeft = BarLength;
|
|
||||||
Console.Write("]");
|
|
||||||
Console.CursorLeft = 1;
|
|
||||||
var onechunk = 30.0f / Max;
|
|
||||||
|
|
||||||
var position = 1;
|
|
||||||
|
|
||||||
for (var i = 0; i < onechunk * progress; i++)
|
|
||||||
{
|
|
||||||
Console.BackgroundColor = NoColor ? ConsoleColor.Black : Color;
|
|
||||||
Console.CursorLeft = position++;
|
|
||||||
Console.Write("#");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = position; i < BarLength; i++)
|
|
||||||
{
|
|
||||||
Console.BackgroundColor = NoColor ? ConsoleColor.Black : ConsoleColor.DarkGray;
|
|
||||||
Console.CursorLeft = position++;
|
|
||||||
Console.Write(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.CursorLeft = BarLength + 4;
|
|
||||||
Console.BackgroundColor = ConsoleColor.Black;
|
|
||||||
if (progress.CanAproximateTo(Max))
|
|
||||||
Console.Write(progress + " % ✓");
|
|
||||||
else
|
|
||||||
Console.Write(MathF.Round(progress, 2) + " % ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,439 +0,0 @@
|
|||||||
using System.Threading;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Discord.WebSocket;
|
|
||||||
|
|
||||||
using PluginManager;
|
|
||||||
using PluginManager.Loaders;
|
|
||||||
using PluginManager.Online;
|
|
||||||
using PluginManager.Others;
|
|
||||||
|
|
||||||
using OperatingSystem = PluginManager.Others.OperatingSystem;
|
|
||||||
|
|
||||||
namespace DiscordBot.Utilities;
|
|
||||||
|
|
||||||
public class ConsoleCommandsHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
public static ConsoleCommandsHandler handler;
|
|
||||||
private readonly PluginsManager manager;
|
|
||||||
|
|
||||||
private readonly List<ConsoleCommand> commandList = new();
|
|
||||||
|
|
||||||
|
|
||||||
private bool isDownloading;
|
|
||||||
private bool pluginsLoaded;
|
|
||||||
private DiscordSocketClient client;
|
|
||||||
|
|
||||||
public ConsoleCommandsHandler(DiscordSocketClient client)
|
|
||||||
{
|
|
||||||
this.client = client;
|
|
||||||
|
|
||||||
manager = new PluginsManager(Program.URLs["PluginList"], Program.URLs["PluginVersions"]);
|
|
||||||
InitializeBasicCommands();
|
|
||||||
Console.WriteLine("Done");
|
|
||||||
|
|
||||||
if (handler == null)
|
|
||||||
handler = this;
|
|
||||||
else
|
|
||||||
throw new Exception("ConsoleCommandsHandler already initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeBasicCommands()
|
|
||||||
{
|
|
||||||
commandList.Clear();
|
|
||||||
|
|
||||||
AddCommand("help", "Show help", "help <command>", args =>
|
|
||||||
{
|
|
||||||
if (args.Length <= 1)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Available commands:");
|
|
||||||
var items = new List<string[]>
|
|
||||||
{
|
|
||||||
new[] { "-", "-", "-" },
|
|
||||||
new[] { "Command", "Description", "Usage" },
|
|
||||||
new[] { " ", " ", "Argument type: <optional> [required]" },
|
|
||||||
new[] { "-", "-", "-" }
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var command in commandList)
|
|
||||||
{
|
|
||||||
if (!command.CommandName.StartsWith("_"))
|
|
||||||
items.Add(new[] { command.CommandName, command.Description, command.Usage });
|
|
||||||
}
|
|
||||||
|
|
||||||
items.Add(new[] { "-", "-", "-" });
|
|
||||||
Utilities.FormatAndAlignTable(items, TableFormat.DEFAULT);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var command in commandList)
|
|
||||||
if (command.CommandName == args[1])
|
|
||||||
{
|
|
||||||
Console.WriteLine("Command description: " + command.Description);
|
|
||||||
Console.WriteLine("Command execution format:" + command.Usage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Command not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
AddCommand("lp", "Load plugins", () =>
|
|
||||||
{
|
|
||||||
if (pluginsLoaded)
|
|
||||||
return;
|
|
||||||
var loader = new PluginLoader(client!);
|
|
||||||
var cc = Console.ForegroundColor;
|
|
||||||
loader.onCMDLoad += (name, typeName, success, exception) =>
|
|
||||||
{
|
|
||||||
if (name == null || name.Length < 2)
|
|
||||||
name = typeName;
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
Console.ForegroundColor = ConsoleColor.Green;
|
|
||||||
Console.WriteLine("[CMD] Successfully loaded command : " + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
|
||||||
if (exception is null)
|
|
||||||
Console.WriteLine("An error occured while loading: " + name);
|
|
||||||
else
|
|
||||||
Console.WriteLine("[CMD] Failed to load command : " + name + " because " + exception!.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.ForegroundColor = cc;
|
|
||||||
};
|
|
||||||
loader.onEVELoad += (name, typeName, success, exception) =>
|
|
||||||
{
|
|
||||||
if (name == null || name.Length < 2)
|
|
||||||
name = typeName;
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
Console.ForegroundColor = ConsoleColor.Green;
|
|
||||||
Console.WriteLine("[EVENT] Successfully loaded event : " + name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
|
||||||
Console.WriteLine("[EVENT] Failed to load event : " + name + " because " + exception!.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.ForegroundColor = cc;
|
|
||||||
};
|
|
||||||
|
|
||||||
loader.onSLSHLoad += (name, typeName, success, exception) =>
|
|
||||||
{
|
|
||||||
if (name == null || name.Length < 2)
|
|
||||||
name = typeName;
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
Console.ForegroundColor = ConsoleColor.Green;
|
|
||||||
Console.WriteLine("[SLASH] Successfully loaded command : " + name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
|
||||||
Console.WriteLine("[SLASH] Failed to load command : " + name + " because " + exception!.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.ForegroundColor = cc;
|
|
||||||
};
|
|
||||||
|
|
||||||
loader.LoadPlugins();
|
|
||||||
Console.ForegroundColor = cc;
|
|
||||||
pluginsLoaded = true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
AddCommand("listplugs", "list available plugins", async () => {
|
|
||||||
if(manager == null)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Plugin manager is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var data = await manager.GetAvailablePlugins();
|
|
||||||
var items = new List<string[]>
|
|
||||||
{
|
|
||||||
new[] { "-", "-", "-", "-" },
|
|
||||||
new[] { "Name", "Type", "Description", "Required" },
|
|
||||||
new[] { "-", "-", "-", "-" }
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var plugin in data)
|
|
||||||
{
|
|
||||||
items.Add(new[] { plugin[0], plugin[1], plugin[2], plugin[3] });
|
|
||||||
}
|
|
||||||
|
|
||||||
items.Add(new[] { "-", "-", "-", "-" });
|
|
||||||
Utilities.FormatAndAlignTable(items, TableFormat.DEFAULT);
|
|
||||||
});
|
|
||||||
|
|
||||||
AddCommand("dwplug", "download plugin", "dwplug [name]", async args =>
|
|
||||||
{
|
|
||||||
isDownloading = true;
|
|
||||||
Utilities.Spinner spinner = new Utilities.Spinner();
|
|
||||||
if (args.Length == 1)
|
|
||||||
{
|
|
||||||
isDownloading = false;
|
|
||||||
Console.WriteLine("Please specify plugin name");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var name = string.Join(' ', args, 1, args.Length - 1);
|
|
||||||
// info[0] = plugin type
|
|
||||||
// info[1] = plugin link
|
|
||||||
// info[2] = if others are required, or string.Empty if none
|
|
||||||
var info = await manager.GetPluginLinkByName(name);
|
|
||||||
if (info[1] == null) // link is null
|
|
||||||
{
|
|
||||||
if (name == "")
|
|
||||||
{
|
|
||||||
isDownloading = false;
|
|
||||||
Utilities.WriteColorText("Name is invalid");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isDownloading = false;
|
|
||||||
Utilities.WriteColorText($"Failed to find plugin &b{name} &c!" +
|
|
||||||
" Use &glistplugs &ccommand to display all available plugins !");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
spinner.Start();
|
|
||||||
|
|
||||||
string path;
|
|
||||||
if (info[0] == "Plugin")
|
|
||||||
path = "./Data/Plugins/" + name + ".dll";
|
|
||||||
else
|
|
||||||
path = $"./{info[1].Split('/')[info[1].Split('/').Length - 1]}";
|
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine($"Downloading plugin {name} from {info[1]} to {path}");
|
|
||||||
await ServerCom.DownloadFileAsync(info[1], path, null);
|
|
||||||
|
|
||||||
Console.WriteLine("\n");
|
|
||||||
|
|
||||||
// check requirements if any
|
|
||||||
|
|
||||||
if (info.Length == 3 && info[2] != string.Empty && info[2] != null)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Downloading requirements for plugin : {name}");
|
|
||||||
|
|
||||||
var lines = await ServerCom.ReadTextFromURL(info[2]);
|
|
||||||
|
|
||||||
foreach (var line in lines)
|
|
||||||
{
|
|
||||||
if (!(line.Length > 0 && line.Contains(",")))
|
|
||||||
continue;
|
|
||||||
var split = line.Split(',');
|
|
||||||
Console.WriteLine($"\nDownloading item: {split[1]}");
|
|
||||||
if (File.Exists("./" + split[1])) File.Delete("./" + split[1]);
|
|
||||||
await ServerCom.DownloadFileAsync(split[0], "./" + split[1], null);
|
|
||||||
|
|
||||||
Console.WriteLine("Item " + split[1] + " downloaded !");
|
|
||||||
|
|
||||||
Console.WriteLine();
|
|
||||||
if (split[0].EndsWith(".pak"))
|
|
||||||
{
|
|
||||||
File.Move("./" + split[1], "./Data/PAKS/" + split[1], true);
|
|
||||||
}
|
|
||||||
else if (split[0].EndsWith(".zip") || split[0].EndsWith(".pkg"))
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Extracting {split[1]} ...");
|
|
||||||
await ArchiveManager.ExtractArchive("./" + split[1], "./", null,
|
|
||||||
UnzipProgressType.PERCENTAGE_FROM_TOTAL_SIZE);
|
|
||||||
Console.WriteLine("\n");
|
|
||||||
File.Delete("./" + split[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine();
|
|
||||||
}
|
|
||||||
spinner.Stop();
|
|
||||||
|
|
||||||
var ver = await manager.GetVersionOfPackageFromWeb(name);
|
|
||||||
if (ver is null) throw new Exception("Incorrect version");
|
|
||||||
Config.Plugins[name] = ver.ToShortString();
|
|
||||||
|
|
||||||
isDownloading = false;
|
|
||||||
|
|
||||||
|
|
||||||
Config.Logger.Log("Plugin installed !", this, LogLevel.INFO);
|
|
||||||
|
|
||||||
//await ExecuteCommad("localload " + name);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
AddCommand("value", "read value from VariableStack", "value [key]", args =>
|
|
||||||
{
|
|
||||||
if (args.Length != 2)
|
|
||||||
return;
|
|
||||||
if (!Config.Data.ContainsKey(args[1]))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var data = Config.Data[args[1]];
|
|
||||||
Console.WriteLine($"{args[1]} => {data}");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
AddCommand("add", "add variable to the system variables", "add [key] [value]", args =>
|
|
||||||
{
|
|
||||||
if (args.Length < 4)
|
|
||||||
return;
|
|
||||||
var key = args[1];
|
|
||||||
var value = args[2];
|
|
||||||
var isReadOnly = args[3].Equals("true", StringComparison.CurrentCultureIgnoreCase);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Config.Data[key] = value;
|
|
||||||
Console.WriteLine($"Updated config file with the following command: {args[1]} => {value}");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
AddCommand("remv", "remove variable from system variables", "remv [key]", args =>
|
|
||||||
{
|
|
||||||
if (args.Length < 2)
|
|
||||||
return;
|
|
||||||
Config.Data.Remove(args[1]);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
AddCommand("sd", "Shuts down the discord bot", async () =>
|
|
||||||
{
|
|
||||||
if (client is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
await Functions.SaveToJsonFile(Functions.dataFolder + "config.json", Config.Data);
|
|
||||||
await Functions.SaveToJsonFile(Functions.dataFolder + "Plugins.json", Config.Plugins);
|
|
||||||
await client.StopAsync();
|
|
||||||
await client.DisposeAsync();
|
|
||||||
|
|
||||||
Config.Logger.SaveToFile();
|
|
||||||
await Task.Delay(1000);
|
|
||||||
Environment.Exit(0);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
AddCommand("import", "Load an external command", "import [pluginName]", async args =>
|
|
||||||
{
|
|
||||||
if (args.Length <= 1) return;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var pName = string.Join(' ', args, 1, args.Length - 1);
|
|
||||||
using (var client = new HttpClient())
|
|
||||||
{
|
|
||||||
var url = (await manager.GetPluginLinkByName(pName))[1];
|
|
||||||
if (url is null) throw new Exception($"Invalid plugin name {pName}.");
|
|
||||||
var s = await client.GetStreamAsync(url);
|
|
||||||
var str = new MemoryStream();
|
|
||||||
await s.CopyToAsync(str);
|
|
||||||
var asmb = Assembly.Load(str.ToArray());
|
|
||||||
|
|
||||||
await PluginLoader.LoadPluginFromAssembly(asmb, this.client);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
AddCommand("localload", "Load a local command", "local [pluginName]", async args =>
|
|
||||||
{
|
|
||||||
if (args.Length <= 1) return;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var pName = string.Join(' ', args, 1, args.Length - 1);
|
|
||||||
var asmb = Assembly.LoadFile(Path.GetFullPath("./Data/Plugins/" + pName + ".dll"));
|
|
||||||
|
|
||||||
await PluginLoader.LoadPluginFromAssembly(asmb, this.client);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
Config.Logger.Log(ex.Message, this, LogLevel.ERROR);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
commandList.Sort((x, y) => x.CommandName.CompareTo(y.CommandName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddCommand(string command, string description, string usage, Action<string[]> action)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Adding command {command} ...");
|
|
||||||
commandList.Add(new ConsoleCommand
|
|
||||||
{ CommandName = command, Description = description, Action = action, Usage = usage });
|
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
|
||||||
Utilities.WriteColorText($"Command &r{command} &cadded to the list of commands");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddCommand(string command, string description, Action action)
|
|
||||||
{
|
|
||||||
AddCommand(command, description, command, args => action());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveCommand(string command)
|
|
||||||
{
|
|
||||||
commandList.RemoveAll(x => x.CommandName == command);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CommandExists(string command)
|
|
||||||
{
|
|
||||||
return GetCommand(command) is not null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConsoleCommand? GetCommand(string command)
|
|
||||||
{
|
|
||||||
return commandList.FirstOrDefault(t => t.CommandName == command);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HandleCommand(string command, bool removeCommandExecution = true)
|
|
||||||
{
|
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
|
||||||
var args = command.Split(' ');
|
|
||||||
foreach (var item in commandList.ToList())
|
|
||||||
if (item.CommandName == args[0])
|
|
||||||
{
|
|
||||||
if (args[0].StartsWith("_"))
|
|
||||||
throw new Exception("This command is reserved for internal worker and can not be executed manually !");
|
|
||||||
|
|
||||||
if (removeCommandExecution)
|
|
||||||
{
|
|
||||||
Console.SetCursorPosition(0, Console.CursorTop - 1);
|
|
||||||
for (var i = 0; i < command.Length + 30; i++)
|
|
||||||
Console.Write(" ");
|
|
||||||
Console.SetCursorPosition(0, Console.CursorTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine();
|
|
||||||
item.Action(args);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +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
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ProgressBarType
|
|
||||||
{
|
|
||||||
NORMAL,
|
|
||||||
NO_END
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
35
DiscordBot/builder.bat
Normal file
35
DiscordBot/builder.bat
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
@echo off
|
||||||
|
echo "Building..."
|
||||||
|
|
||||||
|
echo "Building linux-x64 not self-contained"
|
||||||
|
dotnet publish -r linux-x64 -p:PublishSingleFile=false --self-contained true -c Release -o ../publish/linux-x64
|
||||||
|
|
||||||
|
echo "Building win-x64 not self-contained"
|
||||||
|
dotnet publish -r win-x64 -p:PublishSingleFile=false --self-contained true -c Release -o ../publish/win-x64
|
||||||
|
|
||||||
|
echo "Building osx-x64 not self-contained"
|
||||||
|
dotnet publish -r osx-x64 -p:PublishSingleFile=false --self-contained true -c Release -o ../publish/osx-x64
|
||||||
|
|
||||||
|
|
||||||
|
echo "Building linux-x64 self-contained"
|
||||||
|
dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained true -c Release -o ../publish/linux-x64-selfcontained
|
||||||
|
|
||||||
|
echo "Building win-x64 self-contained"
|
||||||
|
dotnet publish -r win-x64 -p:PublishSingleFile=true --self-contained true -c Release -o ../publish/win-x64-selfcontained
|
||||||
|
|
||||||
|
echo "Building osx-x64 self-contained"
|
||||||
|
dotnet publish -r osx-x64 -p:PublishSingleFile=true --self-contained true -c Release -o ../publish/osx-x64-selfcontained
|
||||||
|
|
||||||
|
echo "Zipping..."
|
||||||
|
mkdir ../publish/zip
|
||||||
|
|
||||||
|
|
||||||
|
zip -r ../publish/zip/linux-x64.zip ../publish/linux-x64
|
||||||
|
zip -r ../publish/zip/win-x64.zip ../publish/win-x64
|
||||||
|
zip -r ../publish/zip/osx-x64.zip ../publish/osx-x64
|
||||||
|
|
||||||
|
zip -r ../publish/zip/linux-x64-selfcontained.zip ../publish/linux-x64-selfcontained
|
||||||
|
zip -r ../publish/zip/win-x64-selfcontained.zip ../publish/win-x64-selfcontained
|
||||||
|
zip -r ../publish/zip/osx-x64-selfcontained.zip ../publish/osx-x64-selfcontained
|
||||||
|
|
||||||
|
echo "Done!"
|
||||||
6
builder.sh → DiscordBot/builder.sh
Executable file → Normal file
6
builder.sh → DiscordBot/builder.sh
Executable file → Normal file
@@ -3,13 +3,13 @@
|
|||||||
echo "Building..."
|
echo "Building..."
|
||||||
|
|
||||||
echo "Building linux-x64 not self-contained"
|
echo "Building linux-x64 not self-contained"
|
||||||
dotnet publish -r linux-x64 -p:PublishSingleFile=false --self-contained false -c Release -o ./publish/linux-x64
|
dotnet publish -r linux-x64 -p:PublishSingleFile=false --self-contained true -c Release -o ./publish/linux-x64
|
||||||
|
|
||||||
echo "Building win-x64 not self-contained"
|
echo "Building win-x64 not self-contained"
|
||||||
dotnet publish -r win-x64 -p:PublishSingleFile=false --self-contained false -c Release -o ./publish/win-x64
|
dotnet publish -r win-x64 -p:PublishSingleFile=false --self-contained true -c Release -o ./publish/win-x64
|
||||||
|
|
||||||
echo "Building osx-x64 not self-contained"
|
echo "Building osx-x64 not self-contained"
|
||||||
dotnet publish -r osx-x64 -p:PublishSingleFile=false --self-contained false -c Release -o ./publish/osx-x64
|
dotnet publish -r osx-x64 -p:PublishSingleFile=false --self-contained true -c Release -o ./publish/osx-x64
|
||||||
|
|
||||||
#One file per platform
|
#One file per platform
|
||||||
echo "Building linux-x64 self-contained"
|
echo "Building linux-x64 self-contained"
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using System.Net.Mime;
|
|
||||||
using System;
|
using System;
|
||||||
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;
|
||||||
|
|
||||||
@@ -43,36 +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,18 +86,20 @@ public class Boot
|
|||||||
await commandServiceHandler.InstallCommandsAsync();
|
await commandServiceHandler.InstallCommandsAsync();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
await Task.Delay(2000);
|
await Task.Delay(2000);
|
||||||
|
|
||||||
|
Config._DiscordBotClient = this;
|
||||||
|
|
||||||
while (!isReady) ;
|
while (!isReady) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,8 +107,10 @@ public class Boot
|
|||||||
{
|
{
|
||||||
if (arg.Message.Contains("401"))
|
if (arg.Message.Contains("401"))
|
||||||
{
|
{
|
||||||
Config.Data.Remove("token");
|
Config.AppSettings.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);
|
||||||
|
await Config.AppSettings.SaveToFile();
|
||||||
await Task.Delay(4000);
|
await Task.Delay(4000);
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
@@ -136,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;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -47,9 +45,7 @@ internal class CommandHandler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var plugin = PluginLoader.SlashCommands!
|
var plugin = PluginLoader.SlashCommands!.FirstOrDefault(p => p.Name == arg.Data.Name);
|
||||||
.Where(p => p.Name == arg.Data.Name)
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
if (plugin is null)
|
if (plugin is null)
|
||||||
throw new Exception("Failed to run command. !");
|
throw new Exception("Failed to run command. !");
|
||||||
@@ -65,7 +61,6 @@ internal class CommandHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -75,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)
|
||||||
@@ -98,19 +92,23 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -118,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);
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,25 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Collections.Generic;
|
using PluginManager.Bot;
|
||||||
using PluginManager.Others;
|
using PluginManager.Others;
|
||||||
using System.Collections;
|
|
||||||
using PluginManager.Online.Helpers;
|
|
||||||
using PluginManager.Others.Logger;
|
using PluginManager.Others.Logger;
|
||||||
|
|
||||||
namespace PluginManager;
|
namespace PluginManager;
|
||||||
|
|
||||||
public static class Config
|
public class Config
|
||||||
{
|
{
|
||||||
private static bool IsLoaded = false;
|
private static bool IsLoaded;
|
||||||
|
public static DBLogger Logger;
|
||||||
|
public static SettingsDictionary<string, string>? AppSettings;
|
||||||
|
|
||||||
public static DBLogger Logger;
|
internal static Boot? _DiscordBotClient;
|
||||||
public static Json<string, string> Data;
|
|
||||||
public static Json<string, string> Plugins;
|
public static Boot? DiscordBot => _DiscordBotClient;
|
||||||
|
|
||||||
public static async Task Initialize()
|
public static async Task Initialize()
|
||||||
{
|
{
|
||||||
if (IsLoaded)
|
if (IsLoaded) return;
|
||||||
return;
|
|
||||||
|
|
||||||
Directory.CreateDirectory("./Data/Resources");
|
Directory.CreateDirectory("./Data/Resources");
|
||||||
Directory.CreateDirectory("./Data/Plugins");
|
Directory.CreateDirectory("./Data/Plugins");
|
||||||
@@ -29,11 +27,10 @@ public static 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");
|
AppSettings = new SettingsDictionary<string, string>("./Data/Resources/config.json");
|
||||||
Plugins = new Json<string, string>("./Data/Resources/Plugins.json");
|
|
||||||
|
|
||||||
Config.Data["LogFolder"] = "./Data/Logs/Logs";
|
AppSettings["LogFolder"] = "./Data/Logs/Logs";
|
||||||
Config.Data["ErrorFolder"] = "./Data/Logs/Errors";
|
AppSettings["ErrorFolder"] = "./Data/Logs/Errors";
|
||||||
|
|
||||||
Logger = new DBLogger();
|
Logger = new DBLogger();
|
||||||
|
|
||||||
@@ -44,124 +41,4 @@ public static class Config
|
|||||||
Logger.Log("Config initialized", LogLevel.INFO);
|
Logger.Log("Config initialized", LogLevel.INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Json<TKey, TValue> : IDictionary<TKey, TValue>
|
|
||||||
{
|
|
||||||
protected IDictionary<TKey, TValue> _dictionary;
|
|
||||||
private readonly string _file = "";
|
|
||||||
|
|
||||||
public Json(string file)
|
|
||||||
{
|
|
||||||
_dictionary = PrivateReadConfig(file).GetAwaiter().GetResult();
|
|
||||||
this._file = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Save()
|
|
||||||
{
|
|
||||||
await Functions.SaveToJsonFile(_file, _dictionary);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Add(TKey key, TValue value)
|
|
||||||
{
|
|
||||||
_dictionary.Add(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear() { _dictionary.Clear(); }
|
|
||||||
|
|
||||||
public bool ContainsKey(TKey key)
|
|
||||||
{
|
|
||||||
if (_dictionary == null)
|
|
||||||
throw new Exception("Dictionary is null");
|
|
||||||
|
|
||||||
return _dictionary.ContainsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual ICollection<TKey> Keys => _dictionary.Keys;
|
|
||||||
|
|
||||||
public virtual ICollection<TValue> Values => _dictionary.Values;
|
|
||||||
|
|
||||||
public int Count => _dictionary.Count;
|
|
||||||
|
|
||||||
public bool IsReadOnly => _dictionary.IsReadOnly;
|
|
||||||
|
|
||||||
public virtual TValue this[TKey key]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_dictionary.TryGetValue(key, out TValue value)) return value;
|
|
||||||
throw new Exception("Key not found in dictionary " + key.ToString() + " (Json )" + this.GetType().Name + ")");
|
|
||||||
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_dictionary.ContainsKey(key))
|
|
||||||
_dictionary[key] = value;
|
|
||||||
else _dictionary.Add(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool TryGetValue(TKey key, out TValue 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)
|
|
||||||
{
|
|
||||||
return _dictionary.Remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
_dictionary.Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
return _dictionary.Contains(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
_dictionary.CopyTo(array, arrayIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
return _dictionary.Remove(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
|
||||||
{
|
|
||||||
return _dictionary.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return ((IEnumerable)_dictionary).GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,489 +1,482 @@
|
|||||||
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;
|
||||||
|
|
||||||
|
/// <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);
|
||||||
|
var 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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) { }
|
||||||
}
|
}
|
||||||
|
|||||||
17
PluginManager/Interfaces/Exceptions/IException.cs
Normal file
17
PluginManager/Interfaces/Exceptions/IException.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace PluginManager.Interfaces.Exceptions;
|
||||||
|
|
||||||
|
public interface IException
|
||||||
|
{
|
||||||
|
public List<string> Messages { get; set; }
|
||||||
|
public bool isFatal { get; }
|
||||||
|
public string GenerateFullMessage();
|
||||||
|
public void HandleException();
|
||||||
|
|
||||||
|
public IException AppendError(string message);
|
||||||
|
|
||||||
|
public IException AppendError(List<string> messages);
|
||||||
|
public IException IsFatal(bool isFatal = true);
|
||||||
|
|
||||||
|
}
|
||||||
17
PluginManager/Interfaces/IInternalAction.cs
Normal file
17
PluginManager/Interfaces/IInternalAction.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using PluginManager.Others;
|
||||||
|
|
||||||
|
namespace PluginManager.Interfaces;
|
||||||
|
|
||||||
|
public interface ICommandAction
|
||||||
|
{
|
||||||
|
public string ActionName { get; }
|
||||||
|
|
||||||
|
public string? Description { get; }
|
||||||
|
|
||||||
|
public string? Usage { get; }
|
||||||
|
|
||||||
|
public InternalActionRunType RunType { get; }
|
||||||
|
|
||||||
|
public Task Execute(string[]? args);
|
||||||
|
}
|
||||||
72
PluginManager/Loaders/ActionsLoader.cs
Normal file
72
PluginManager/Loaders/ActionsLoader.cs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
using PluginManager.Others;
|
||||||
|
|
||||||
|
namespace PluginManager.Loaders;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
actionFolder = path;
|
||||||
|
actionExtension = extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event ActionLoaded? ActionLoadedEvent;
|
||||||
|
|
||||||
|
public async Task<List<ICommandAction>?> Load()
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(actionFolder);
|
||||||
|
var files = Directory.GetFiles(actionFolder, $"*.{actionExtension}", SearchOption.AllDirectories);
|
||||||
|
|
||||||
|
var actions = new List<ICommandAction>();
|
||||||
|
|
||||||
|
foreach (var file in files)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Assembly.LoadFrom(file);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
ActionLoadedEvent?.Invoke(file, "", false, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
var types = AppDomain.CurrentDomain.GetAssemblies()
|
||||||
|
.SelectMany(s => s.GetTypes())
|
||||||
|
.Where(p => typeof(ICommandAction).IsAssignableFrom(p) && !p.IsInterface);
|
||||||
|
|
||||||
|
foreach (var type in types)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var action = (ICommandAction)Activator.CreateInstance(type);
|
||||||
|
if (action.ActionName == null)
|
||||||
|
{
|
||||||
|
ActionLoadedEvent?.Invoke(action.ActionName, type.Name, false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,140 +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" : "DBSlashCommand",
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
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;
|
||||||
|
|
||||||
namespace PluginManager.Loaders;
|
namespace PluginManager.Loaders;
|
||||||
|
|
||||||
@@ -22,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>
|
||||||
@@ -61,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
|
||||||
@@ -83,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":
|
||||||
@@ -116,57 +117,67 @@ 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();
|
||||||
foreach (var type in types)
|
foreach (var type in types)
|
||||||
if (type.IsClass && typeof(DBEvent).IsAssignableFrom(type))
|
try
|
||||||
{
|
{
|
||||||
var instance = (DBEvent)Activator.CreateInstance(type);
|
if (type.IsClass && typeof(DBEvent).IsAssignableFrom(type))
|
||||||
instance.Start(client);
|
{
|
||||||
PluginLoader.Events.Add(instance);
|
var instance = (DBEvent)Activator.CreateInstance(type);
|
||||||
Config.Logger.Log($"[EVENT] Loaded external {type.FullName}!", Others.LogLevel.INFO);
|
instance.Start(client);
|
||||||
}
|
Events.Add(instance);
|
||||||
else if (type.IsClass && typeof(DBCommand).IsAssignableFrom(type))
|
Config.Logger.Log($"[EVENT] Loaded external {type.FullName}!", LogLevel.INFO);
|
||||||
{
|
}
|
||||||
var instance = (DBCommand)Activator.CreateInstance(type);
|
else if (type.IsClass && typeof(DBCommand).IsAssignableFrom(type))
|
||||||
PluginLoader.Commands.Add(instance);
|
{
|
||||||
Config.Logger.Log($"[CMD] Instance: {type.FullName} loaded !", Others.LogLevel.INFO);
|
var instance = (DBCommand)Activator.CreateInstance(type);
|
||||||
}
|
Commands.Add(instance);
|
||||||
else if (type.IsClass && typeof(DBSlashCommand).IsAssignableFrom(type))
|
Config.Logger.Log($"[CMD] Instance: {type.FullName} loaded !", LogLevel.INFO);
|
||||||
{
|
}
|
||||||
var instance = (DBSlashCommand)Activator.CreateInstance(type);
|
else if (type.IsClass && typeof(DBSlashCommand).IsAssignableFrom(type))
|
||||||
SlashCommandBuilder builder = new SlashCommandBuilder();
|
{
|
||||||
builder.WithName(instance.Name);
|
var instance = (DBSlashCommand)Activator.CreateInstance(type);
|
||||||
builder.WithDescription(instance.Description);
|
var builder = new SlashCommandBuilder();
|
||||||
builder.WithDMPermission(instance.canUseDM);
|
builder.WithName(instance.Name);
|
||||||
builder.Options = instance.Options;
|
builder.WithDescription(instance.Description);
|
||||||
|
builder.WithDMPermission(instance.canUseDM);
|
||||||
await client.CreateGlobalApplicationCommandAsync(builder.Build());
|
builder.Options = instance.Options;
|
||||||
PluginLoader.SlashCommands.Add(instance);
|
|
||||||
Config.Logger.Log($"[SLASH] Instance: {type.FullName} loaded !", Others.LogLevel.INFO);
|
|
||||||
|
|
||||||
|
await client.CreateGlobalApplicationCommandAsync(builder.Build());
|
||||||
|
SlashCommands.Add(instance);
|
||||||
|
Config.Logger.Log($"[SLASH] Instance: {type.FullName} loaded !", LogLevel.INFO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
//Console.WriteLine(ex.Message);
|
||||||
|
Config.Logger.Error(ex);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -13,9 +13,23 @@ public class VersionString
|
|||||||
var data = version.Split('.');
|
var data = version.Split('.');
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PackageVersionID = int.Parse(data[0]);
|
if (data.Length == 3)
|
||||||
PackageMainVersion = int.Parse(data[1]);
|
{
|
||||||
PackageCheckVersion = int.Parse(data[2]);
|
PackageVersionID = int.Parse(data[0]);
|
||||||
|
PackageMainVersion = int.Parse(data[1]);
|
||||||
|
PackageCheckVersion = int.Parse(data[2]);
|
||||||
|
}
|
||||||
|
else if (data.Length == 4)
|
||||||
|
{
|
||||||
|
// ignore the first item data[0]
|
||||||
|
PackageVersionID = int.Parse(data[1]);
|
||||||
|
PackageMainVersion = int.Parse(data[2]);
|
||||||
|
PackageCheckVersion = int.Parse(data[3]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid version string");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -24,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 +
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -34,13 +33,14 @@ public class PluginsManager
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<List<string[]>> GetAvailablePlugins()
|
public async Task<List<string[]>> GetAvailablePlugins()
|
||||||
{
|
{
|
||||||
|
Config.Logger.Log("Got data from " + VersionsLink, this, LogLevel.INFO);
|
||||||
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 +58,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 +71,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 +83,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 +98,14 @@ 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);
|
Config.Logger.Log("Searched for " + pakName + " and found " + split[1] + " as version.", LogLevel.INFO);
|
||||||
return new VersionString(split[1]);
|
return new VersionString(split[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,13 +118,13 @@ 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(',');
|
||||||
if (contents[0] == name)
|
if (contents[0].ToLowerInvariant() == name.ToLowerInvariant())
|
||||||
{
|
{
|
||||||
if (contents.Length == 6)
|
if (contents.Length == 6)
|
||||||
return new[] { contents[2], contents[3], contents[5] };
|
return new[] { contents[2], contents[3], contents[5] };
|
||||||
@@ -135,9 +136,10 @@ 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 new string[] { null!, null!, null! };
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace PluginManager.Others.Actions
|
|
||||||
{
|
|
||||||
public class ActionManager
|
|
||||||
{
|
|
||||||
public List<InternalAction> Actions { get; private set; }
|
|
||||||
|
|
||||||
private bool _isInitialized = false;
|
|
||||||
|
|
||||||
public ActionManager()
|
|
||||||
{
|
|
||||||
if(_isInitialized) return;
|
|
||||||
|
|
||||||
Actions = new List<InternalAction>();
|
|
||||||
|
|
||||||
_isInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ActionExists(string name)
|
|
||||||
{
|
|
||||||
if(!_isInitialized) throw new Exception("ActionManager is not initialized");
|
|
||||||
return Actions.Any(x => x.Name == name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddAction(InternalAction action)
|
|
||||||
{
|
|
||||||
if(!_isInitialized) throw new Exception("ActionManager is not initialized");
|
|
||||||
Actions.Add(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ExecuteAction(string name, string[] args)
|
|
||||||
{
|
|
||||||
if(!_isInitialized) throw new Exception("ActionManager is not initialized");
|
|
||||||
var action = Actions.FirstOrDefault(x => x.Name == name);
|
|
||||||
if(action == null) throw new Exception($"Action {name} not found");
|
|
||||||
action.Invoke(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ExecuteActionAsync(string name, string[] args)
|
|
||||||
{
|
|
||||||
if(!_isInitialized) throw new Exception("ActionManager is not initialized");
|
|
||||||
var action = Actions.FirstOrDefault(x => x.Name == name);
|
|
||||||
if(action == null) throw new Exception($"Action {name} not found");
|
|
||||||
await action.InvokeAsync(args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace PluginManager.Others.Actions
|
|
||||||
{
|
|
||||||
public class InternalAction
|
|
||||||
{
|
|
||||||
public string? Name { get; init; }
|
|
||||||
public Action<string[]> Action { get; init; }
|
|
||||||
|
|
||||||
public InternalAction(string name, Action<string[]> action)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
Action = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InternalAction(string name, Action action)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
Action = (o) =>
|
|
||||||
{
|
|
||||||
action();
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Invoke(string[] args)
|
|
||||||
{
|
|
||||||
Action(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InvokeAsync(string[] args)
|
|
||||||
{
|
|
||||||
await Task.Run(() => Action(args));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
58
PluginManager/Others/Actions/InternalActionsManager.cs
Normal file
58
PluginManager/Others/Actions/InternalActionsManager.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using PluginManager.Interfaces;
|
||||||
|
using PluginManager.Loaders;
|
||||||
|
|
||||||
|
namespace PluginManager.Others.Actions;
|
||||||
|
|
||||||
|
public class InternalActionManager
|
||||||
|
{
|
||||||
|
public Dictionary<string, ICommandAction> Actions = new();
|
||||||
|
public ActionsLoader loader;
|
||||||
|
|
||||||
|
public InternalActionManager(string path, string extension)
|
||||||
|
{
|
||||||
|
loader = new ActionsLoader(path, 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)
|
||||||
|
{
|
||||||
|
Config.Logger.Error(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.Logger.Log($"Action {name} loaded successfully", LogLevel.INFO, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> Execute(string actionName, params string[]? args)
|
||||||
|
{
|
||||||
|
if (!Actions.ContainsKey(actionName))
|
||||||
|
{
|
||||||
|
Config.Logger.Log($"Action {actionName} not found", "InternalActionManager", LogLevel.WARNING, true);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,138 +2,176 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization.Formatters.Binary;
|
||||||
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.AppSettings.ContainsKey("ArchiveFolder"))
|
||||||
|
Config.AppSettings["ArchiveFolder"] = "./Data/PAKS/";
|
||||||
|
|
||||||
|
archiveFolder = Config.AppSettings["ArchiveFolder"];
|
||||||
|
|
||||||
|
isInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read a file from a zip archive. The output is a byte array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileName">The file name in the archive</param>
|
||||||
|
/// <param name="archName">The archive location on the disk</param>
|
||||||
|
/// <returns>An array of bytes that represents the Stream value from the file that was read inside the archive</returns>
|
||||||
|
public async static Task<byte[]?> ReadStreamFromPakAsync(string fileName, string archName)
|
||||||
|
{
|
||||||
|
if (!isInitialized) throw new Exception("ArchiveManager is not initialized");
|
||||||
|
|
||||||
|
archName = archiveFolder + archName;
|
||||||
|
|
||||||
|
if (!File.Exists(archName))
|
||||||
|
throw new Exception("Failed to load file !");
|
||||||
|
|
||||||
|
byte[]? data = null;
|
||||||
|
|
||||||
|
using (var zip = ZipFile.OpenRead(archName))
|
||||||
{
|
{
|
||||||
if (isInitialized) throw new Exception("ArchiveManager is already initialized");
|
var entry = zip.Entries.FirstOrDefault(entry => entry.FullName == fileName || entry.Name == fileName);
|
||||||
|
if (entry is null) throw new Exception("File not found in archive");
|
||||||
|
|
||||||
if (!Config.Data.ContainsKey("ArchiveFolder"))
|
var MemoryStream = new MemoryStream();
|
||||||
Config.Data["ArchiveFolder"] = "./Data/PAKS/";
|
|
||||||
|
|
||||||
archiveFolder = Config.Data["ArchiveFolder"];
|
var stream = entry.Open();
|
||||||
|
await stream.CopyToAsync(MemoryStream);
|
||||||
|
data = MemoryStream.ToArray();
|
||||||
|
|
||||||
isInitialized = true;
|
stream.Close();
|
||||||
|
MemoryStream.Close();
|
||||||
}
|
|
||||||
/// <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))
|
|
||||||
{
|
|
||||||
foreach (var entry in zip.Entries)
|
|
||||||
if (entry.Name == FileName || entry.FullName == FileName)
|
|
||||||
using (var s = entry.Open())
|
|
||||||
using (var reader = new StreamReader(s))
|
|
||||||
{
|
|
||||||
textValue = await reader.ReadToEndAsync();
|
|
||||||
reader.Close();
|
|
||||||
s.Close();
|
|
||||||
fs.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
return data;
|
||||||
/// Extract zip to location
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="zip">The zip location</param>
|
/// <summary>
|
||||||
/// <param name="folder">The target location</param>
|
/// Read data from a file that is inside an archive (ZIP format)
|
||||||
/// <param name="progress">The progress that is updated as a file is processed</param>
|
/// </summary>
|
||||||
/// <param name="type">The type of progress</param>
|
/// <param name="FileName">The file name that is inside the archive or its full path</param>
|
||||||
/// <returns></returns>
|
/// <param name="archFile">The archive location from the PAKs folder</param>
|
||||||
public static async Task ExtractArchive(string zip, string folder, IProgress<float> progress,
|
/// <returns>A string that represents the content of the file or null if the file does not exists or it has no content</returns>
|
||||||
UnzipProgressType type)
|
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 not initialized");
|
string? textValue = null;
|
||||||
Directory.CreateDirectory(folder);
|
using (var fs = new FileStream(archFile, FileMode.Open))
|
||||||
using (var archive = ZipFile.OpenRead(zip))
|
using (var zip = new ZipArchive(fs, ZipArchiveMode.Read))
|
||||||
{
|
{
|
||||||
if (type == UnzipProgressType.PERCENTAGE_FROM_NUMBER_OF_FILES)
|
foreach (var entry in zip.Entries)
|
||||||
{
|
if (entry.Name == FileName || entry.FullName == FileName)
|
||||||
var totalZIPFiles = archive.Entries.Count();
|
using (var s = entry.Open())
|
||||||
var currentZIPFile = 0;
|
using (var reader = new StreamReader(s))
|
||||||
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));
|
textValue = await reader.ReadToEndAsync();
|
||||||
continue;
|
reader.Close();
|
||||||
|
s.Close();
|
||||||
|
fs.Close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
var totalZIPFiles = archive.Entries.Count();
|
||||||
|
var currentZIPFile = 0;
|
||||||
|
foreach (var entry in archive.Entries)
|
||||||
|
{
|
||||||
|
if (entry.FullName.EndsWith("/")) // it is a folder
|
||||||
|
Directory.CreateDirectory(Path.Combine(folder, entry.FullName));
|
||||||
|
|
||||||
|
else
|
||||||
try
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ public enum OperatingSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public enum LogLevel
|
public enum LogLevel
|
||||||
{
|
{
|
||||||
NONE,
|
|
||||||
INFO,
|
INFO,
|
||||||
WARNING,
|
WARNING,
|
||||||
ERROR,
|
ERROR,
|
||||||
@@ -35,3 +34,14 @@ public enum SaveType
|
|||||||
BACKUP
|
BACKUP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum InternalActionRunType
|
||||||
|
{
|
||||||
|
ON_STARTUP,
|
||||||
|
ON_CALL
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum ExceptionExitCode : int
|
||||||
|
{
|
||||||
|
CONFIG_FAILED_TO_LOAD = 1,
|
||||||
|
CONFIG_KEY_NOT_FOUND = 2,
|
||||||
|
}
|
||||||
|
|||||||
91
PluginManager/Others/Exceptions/ConfigFailedToLoad.cs
Normal file
91
PluginManager/Others/Exceptions/ConfigFailedToLoad.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using PluginManager.Interfaces.Exceptions;
|
||||||
|
|
||||||
|
namespace PluginManager.Others.Exceptions;
|
||||||
|
|
||||||
|
public class ConfigFailedToLoad : IException
|
||||||
|
{
|
||||||
|
public List<string>? Messages { get; set; }
|
||||||
|
public bool isFatal { get; private set; }
|
||||||
|
public string? File { get; }
|
||||||
|
|
||||||
|
|
||||||
|
public ConfigFailedToLoad(string message, bool isFatal, string file)
|
||||||
|
{
|
||||||
|
this.isFatal = isFatal;
|
||||||
|
Messages = new List<string>() {message};
|
||||||
|
this.File = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigFailedToLoad(string message, bool isFatal)
|
||||||
|
{
|
||||||
|
this.isFatal = isFatal;
|
||||||
|
Messages = new List<string>() {message};
|
||||||
|
this.File = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigFailedToLoad(string message)
|
||||||
|
{
|
||||||
|
this.isFatal = false;
|
||||||
|
Messages = new List<string>() {message};
|
||||||
|
this.File = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GenerateFullMessage()
|
||||||
|
{
|
||||||
|
string messages = "";
|
||||||
|
foreach (var message in Messages)
|
||||||
|
{
|
||||||
|
messages += message + "\n";
|
||||||
|
}
|
||||||
|
return $"\nMessage: {messages}\nIsFatal: {isFatal}\nFile: {File ?? "null"}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleException()
|
||||||
|
{
|
||||||
|
if (isFatal)
|
||||||
|
{
|
||||||
|
Config.Logger.Log(GenerateFullMessage(), LogLevel.CRITICAL, true);
|
||||||
|
Environment.Exit((int)ExceptionExitCode.CONFIG_FAILED_TO_LOAD);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.Logger.Log(GenerateFullMessage(), LogLevel.WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IException AppendError(string message)
|
||||||
|
{
|
||||||
|
Messages.Add(message);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IException AppendError(List<string> messages)
|
||||||
|
{
|
||||||
|
Messages.AddRange(messages);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IException IsFatal(bool isFatal = true)
|
||||||
|
{
|
||||||
|
this.isFatal = isFatal;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static ConfigFailedToLoad CreateError(string message, bool isFatal, string? file = null)
|
||||||
|
{
|
||||||
|
if (file is not null)
|
||||||
|
return new ConfigFailedToLoad(message, isFatal, file);
|
||||||
|
return new ConfigFailedToLoad(message, isFatal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfigFailedToLoad CreateError(string message)
|
||||||
|
{
|
||||||
|
return new ConfigFailedToLoad(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
75
PluginManager/Others/Exceptions/ConfigNoKeyWasPresent.cs
Normal file
75
PluginManager/Others/Exceptions/ConfigNoKeyWasPresent.cs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using PluginManager.Interfaces.Exceptions;
|
||||||
|
|
||||||
|
namespace PluginManager.Others.Exceptions;
|
||||||
|
|
||||||
|
public class ConfigNoKeyWasPresent: IException
|
||||||
|
{
|
||||||
|
public List<string> Messages { get; set; }
|
||||||
|
public bool isFatal { get; private set; }
|
||||||
|
|
||||||
|
public ConfigNoKeyWasPresent(string message, bool isFatal)
|
||||||
|
{
|
||||||
|
this.Messages = new List<string>() { message };
|
||||||
|
this.isFatal = isFatal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigNoKeyWasPresent(string message)
|
||||||
|
{
|
||||||
|
this.Messages = new List<string>() { message };
|
||||||
|
this.isFatal = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GenerateFullMessage()
|
||||||
|
{
|
||||||
|
string messages = "";
|
||||||
|
foreach (var message in Messages)
|
||||||
|
{
|
||||||
|
messages += message + "\n";
|
||||||
|
}
|
||||||
|
return $"\nMessage: {messages}\nIsFatal: {isFatal}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleException()
|
||||||
|
{
|
||||||
|
if (isFatal)
|
||||||
|
{
|
||||||
|
|
||||||
|
Config.Logger.Log(GenerateFullMessage(), LogLevel.CRITICAL, true);
|
||||||
|
Environment.Exit((int)ExceptionExitCode.CONFIG_KEY_NOT_FOUND);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.Logger.Log(GenerateFullMessage(), LogLevel.WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IException AppendError(string message)
|
||||||
|
{
|
||||||
|
Messages.Add(message);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IException AppendError(List<string> messages)
|
||||||
|
{
|
||||||
|
Messages.AddRange(messages);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IException IsFatal(bool isFatal = true)
|
||||||
|
{
|
||||||
|
this.isFatal = isFatal;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfigNoKeyWasPresent CreateError(string message)
|
||||||
|
{
|
||||||
|
return new ConfigNoKeyWasPresent(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfigNoKeyWasPresent CreateError(string message, bool isFatal)
|
||||||
|
{
|
||||||
|
return new ConfigNoKeyWasPresent(message, isFatal);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ using System.Text;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Discord;
|
||||||
|
|
||||||
namespace PluginManager.Others;
|
namespace PluginManager.Others;
|
||||||
|
|
||||||
@@ -15,9 +16,19 @@ public static class Functions
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The location for the Resources folder
|
/// The location for the Resources folder
|
||||||
|
/// String: ./Data/Resources/
|
||||||
/// </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>
|
||||||
@@ -42,9 +53,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));
|
||||||
@@ -53,10 +65,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;
|
||||||
@@ -64,40 +77,22 @@ public static class Functions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Save to JSON file
|
public static T SelectRandomValueOf<T>()
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The class type</typeparam>
|
|
||||||
/// <param name="file">The file path</param>
|
|
||||||
/// <param name="Data">The values</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task SaveToJsonFile<T>(string file, T Data)
|
|
||||||
{
|
{
|
||||||
var str = new MemoryStream();
|
var enums = Enum.GetValues(typeof(T));
|
||||||
await JsonSerializer.SerializeAsync(str, Data, typeof(T), new JsonSerializerOptions { WriteIndented = true });
|
var random = new Random();
|
||||||
await File.WriteAllBytesAsync(file, str.ToArray());
|
return (T)enums.GetValue(random.Next(enums.Length));
|
||||||
await str.FlushAsync();
|
|
||||||
str.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public static T RandomValue<T>(this T[] values)
|
||||||
/// Convert json text or file to some kind of data
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The data type</typeparam>
|
|
||||||
/// <param name="input">The file or json text</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<T> ConvertFromJson<T>(string input)
|
|
||||||
{
|
{
|
||||||
Console.WriteLine(input);
|
Random random = new();
|
||||||
Stream text;
|
return values[random.Next(values.Length)];
|
||||||
if (File.Exists(input))
|
}
|
||||||
text = new MemoryStream(await File.ReadAllBytesAsync(input));
|
|
||||||
else
|
public static string ToResourcesPath(this string path)
|
||||||
text = new MemoryStream(Encoding.ASCII.GetBytes(input));
|
{
|
||||||
text.Position = 0;
|
return Path.Combine(dataFolder, path);
|
||||||
var obj = await JsonSerializer.DeserializeAsync<T>(text);
|
|
||||||
await text.FlushAsync();
|
|
||||||
text.Close();
|
|
||||||
return (obj ?? default)!;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
47
PluginManager/Others/JsonManager.cs
Normal file
47
PluginManager/Others/JsonManager.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PluginManager;
|
||||||
|
|
||||||
|
public class JsonManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Save to JSON file
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The class type</typeparam>
|
||||||
|
/// <param name="file">The file path</param>
|
||||||
|
/// <param name="Data">The values</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task SaveToJsonFile<T>(string file, T Data)
|
||||||
|
{
|
||||||
|
var str = new MemoryStream();
|
||||||
|
await JsonSerializer.SerializeAsync(str, Data, typeof(T), new JsonSerializerOptions { WriteIndented = true });
|
||||||
|
await File.WriteAllBytesAsync(file, str.ToArray());
|
||||||
|
await str.FlushAsync();
|
||||||
|
str.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert json text or file to some kind of data
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The data type</typeparam>
|
||||||
|
/// <param name="input">The file or json text</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<T> ConvertFromJson<T>(string input)
|
||||||
|
{
|
||||||
|
Stream text;
|
||||||
|
if (File.Exists(input))
|
||||||
|
text = new MemoryStream(await File.ReadAllBytesAsync(input));
|
||||||
|
else
|
||||||
|
text = new MemoryStream(Encoding.ASCII.GetBytes(input));
|
||||||
|
text.Position = 0;
|
||||||
|
|
||||||
|
var obj = await JsonSerializer.DeserializeAsync<T>(text);
|
||||||
|
await text.FlushAsync();
|
||||||
|
text.Close();
|
||||||
|
return (obj ?? default)!;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,52 +1,76 @@
|
|||||||
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;
|
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, bool isInternal = false);
|
||||||
|
|
||||||
|
private readonly string _errFolder;
|
||||||
|
|
||||||
|
private readonly string _logFolder;
|
||||||
|
private readonly List<LogMessage> ErrorHistory = new();
|
||||||
|
private readonly List<LogMessage> LogHistory = new();
|
||||||
|
|
||||||
|
public DBLogger()
|
||||||
{
|
{
|
||||||
|
_logFolder = Config.AppSettings["LogFolder"];
|
||||||
|
_errFolder = Config.AppSettings["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, LogLevel type = LogLevel.INFO)
|
||||||
public event LogHandler LogEvent;
|
{
|
||||||
|
Log(new LogMessage(message, type));
|
||||||
|
}
|
||||||
|
|
||||||
private string _logFolder;
|
public void Log(string message, LogLevel type= LogLevel.INFO, bool isInternal = false)
|
||||||
private string _errFolder;
|
{
|
||||||
|
Log(new LogMessage(message, type,"unknown", isInternal));
|
||||||
|
}
|
||||||
|
|
||||||
public DBLogger()
|
public void Log(string message, string sender = "unknown", LogLevel type = LogLevel.INFO, bool isInternal = false)
|
||||||
{
|
{
|
||||||
_logFolder = Config.Data["LogFolder"];
|
Log(new LogMessage(message, type,sender,isInternal));
|
||||||
_errFolder = Config.Data["ErrorFolder"];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void Log(string message, string sender = "unknown", LogLevel type = LogLevel.INFO) => Log(new LogMessage(message, type, sender));
|
public void Log(string message, string sender = "unknown", LogLevel type = LogLevel.INFO)
|
||||||
|
{
|
||||||
|
Log(new LogMessage(message, type, sender));
|
||||||
|
}
|
||||||
|
|
||||||
public void Log(LogMessage message)
|
public void Error(Exception? e)
|
||||||
{
|
{
|
||||||
if(LogEvent is not null)
|
Log(e.Message, e.Source, LogLevel.ERROR);
|
||||||
LogEvent?.Invoke(message.Message, message.Type);
|
}
|
||||||
|
|
||||||
if (message.Type != LogLevel.NONE)
|
public void Log(LogMessage message)
|
||||||
LogHistory.Add(message);
|
{
|
||||||
else
|
LogEvent?.Invoke(message.Message, message.Type);
|
||||||
ErrorHistory.Add(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Log(string message, object sender, LogLevel type = LogLevel.NONE) => Log(message, sender.GetType().Name, type);
|
if (message.Type != LogLevel.ERROR && message.Type != LogLevel.CRITICAL)
|
||||||
|
LogHistory.Add(message);
|
||||||
|
else
|
||||||
|
ErrorHistory.Add(message);
|
||||||
|
}
|
||||||
|
|
||||||
public async void SaveToFile()
|
public void Log(string message, object sender, LogLevel type = LogLevel.INFO)
|
||||||
{
|
{
|
||||||
await Functions.SaveToJsonFile(_logFolder + "/" + DateTime.Now.ToString("yyyy-MM-dd") + ".json", LogHistory);
|
Log(message, sender.GetType().Name, type);
|
||||||
await Functions.SaveToJsonFile(_errFolder + "/" + DateTime.Now.ToString("yyyy-MM-dd") + ".json", ErrorHistory);
|
}
|
||||||
}
|
|
||||||
|
public async Task SaveToFile(bool ErrorsOnly = true)
|
||||||
|
{
|
||||||
|
if(!ErrorsOnly)
|
||||||
|
await JsonManager.SaveToJsonFile(_logFolder + "/" + DateTime.Now.ToString("yyyy-MM-dd") + ".json",
|
||||||
|
LogHistory);
|
||||||
|
await JsonManager.SaveToJsonFile(_errFolder + "/" + DateTime.Now.ToString("yyyy-MM-dd") + ".json",
|
||||||
|
ErrorHistory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,51 @@
|
|||||||
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; }
|
isInternal = false;
|
||||||
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, bool isInternal) : this(message, type)
|
||||||
{
|
{
|
||||||
Sender = sender;
|
Sender = sender;
|
||||||
}
|
this.isInternal = isInternal;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public LogMessage(string message, LogLevel type, string sender) : this (message, type, sender, false)
|
||||||
{
|
{
|
||||||
return $"[{Time}] {Message}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static explicit operator LogMessage(string message)
|
}
|
||||||
{
|
|
||||||
return new LogMessage(message, LogLevel.INFO);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static explicit operator LogMessage((string message, LogLevel type) tuple)
|
public string Message { get; set; }
|
||||||
{
|
public LogLevel Type { get; set; }
|
||||||
return new LogMessage(tuple.message, tuple.type);
|
public string Time { get; set; }
|
||||||
}
|
public string Sender { get; set; }
|
||||||
|
public bool isInternal { get; set; }
|
||||||
|
|
||||||
public static explicit operator LogMessage((string message, LogLevel type, string sender) tuple)
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return new LogMessage(tuple.message, tuple.type, tuple.sender);
|
return $"[{Time}] {Message}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static explicit operator LogMessage(string message)
|
||||||
|
{
|
||||||
|
return new LogMessage(message, LogLevel.INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator LogMessage((string message, LogLevel type) tuple)
|
||||||
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using Discord;
|
using Discord;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
|
|
||||||
|
|||||||
141
PluginManager/Others/SettingsDictionary.cs
Normal file
141
PluginManager/Others/SettingsDictionary.cs
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using PluginManager.Others.Exceptions;
|
||||||
|
|
||||||
|
namespace PluginManager.Others;
|
||||||
|
|
||||||
|
public class SettingsDictionary<TKey, TValue> : IDictionary<TKey, TValue>
|
||||||
|
{
|
||||||
|
public string? _file { get; }
|
||||||
|
private IDictionary<TKey, TValue>? _dictionary;
|
||||||
|
|
||||||
|
public SettingsDictionary(string? file)
|
||||||
|
{
|
||||||
|
_file = file;
|
||||||
|
if (!LoadFromFile())
|
||||||
|
{
|
||||||
|
ConfigFailedToLoad.CreateError("Failed to load config")
|
||||||
|
.AppendError("The file is empty or does not exist")
|
||||||
|
.IsFatal()
|
||||||
|
.HandleException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveToFile()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(_file))
|
||||||
|
await JsonManager.SaveToJsonFile(_file, _dictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool LoadFromFile()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(_file))
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (File.Exists(_file))
|
||||||
|
{
|
||||||
|
string FileContent = File.ReadAllText(_file);
|
||||||
|
if (string.IsNullOrEmpty(FileContent))
|
||||||
|
File.WriteAllText(_file, "{}");
|
||||||
|
|
||||||
|
if(!FileContent.Contains("{") || !FileContent.Contains("}"))
|
||||||
|
File.WriteAllText(_file, "{}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
File.WriteAllText(_file, "{}");
|
||||||
|
_dictionary = JsonManager.ConvertFromJson<IDictionary<TKey, TValue>>(_file).Result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
ConfigFailedToLoad
|
||||||
|
.CreateError("Failed to load config")
|
||||||
|
.IsFatal()
|
||||||
|
.HandleException();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _dictionary!.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return ((IEnumerable) _dictionary!).GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
this._dictionary!.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
this._dictionary!.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
return this._dictionary!.Contains(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
this._dictionary!.CopyTo(array, arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
return this._dictionary!.Remove(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count => _dictionary!.Count;
|
||||||
|
public bool IsReadOnly => _dictionary!.IsReadOnly;
|
||||||
|
public void Add(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
this._dictionary!.Add(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsKey(TKey key)
|
||||||
|
{
|
||||||
|
return this._dictionary!.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(TKey key)
|
||||||
|
{
|
||||||
|
return this._dictionary!.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(TKey key, out TValue value)
|
||||||
|
{
|
||||||
|
return this._dictionary!.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue this[TKey key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._dictionary!.ContainsKey(key))
|
||||||
|
if(this._dictionary[key] is string s && !string.IsNullOrEmpty(s) && !string.IsNullOrWhiteSpace(s))
|
||||||
|
return this._dictionary[key];
|
||||||
|
|
||||||
|
ConfigNoKeyWasPresent.CreateError($"Key {(key is string ? key : typeof(TKey).Name)} was not present in {_file ?? "config"}")
|
||||||
|
.AppendError("Deleting the file may fix this issue")
|
||||||
|
.IsFatal()
|
||||||
|
.HandleException();
|
||||||
|
|
||||||
|
return default!;
|
||||||
|
}
|
||||||
|
set => this._dictionary![key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<TKey> Keys => _dictionary!.Keys;
|
||||||
|
public ICollection<TValue> Values => _dictionary!.Values;
|
||||||
|
}
|
||||||
@@ -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.8.1" />
|
<PackageReference Include="Discord.Net" Version="3.11.0" />
|
||||||
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.117" />
|
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.118" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
10
README.md
10
README.md
@@ -6,6 +6,8 @@ This project is based on:
|
|||||||
- [.NET 6 (C#)](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
|
- [.NET 6 (C#)](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
|
||||||
- [Discord.Net](https://github.com/discord-net/Discord.Net)
|
- [Discord.Net](https://github.com/discord-net/Discord.Net)
|
||||||
|
|
||||||
|
- Some plugins can be found [here](https://github.com/andreitdr/SethPlugins).
|
||||||
|
|
||||||
|
|
||||||
## Plugins
|
## Plugins
|
||||||
#### Requirements:
|
#### Requirements:
|
||||||
@@ -35,7 +37,7 @@ using PluginManager.Interfaces;
|
|||||||
|
|
||||||
namespace LevelingSystem;
|
namespace LevelingSystem;
|
||||||
|
|
||||||
internal class LevelCommand : DBCommand
|
public class LevelCommand : DBCommand
|
||||||
{
|
{
|
||||||
public string Command => "level";
|
public string Command => "level";
|
||||||
|
|
||||||
@@ -47,7 +49,7 @@ internal class LevelCommand : DBCommand
|
|||||||
|
|
||||||
public bool requireAdmin => false;
|
public bool requireAdmin => false;
|
||||||
|
|
||||||
public async void ExecuteServer(CmdArgs context)
|
public async void ExecuteServer(DBCommandExecutingArguments context)
|
||||||
{
|
{
|
||||||
//Variables.database is a sql connection that is defined in an auxiliary file in the same napespace as this class
|
//Variables.database is a sql connection that is defined in an auxiliary file in the same napespace as this class
|
||||||
object[] user = await Variables.database.ReadDataArrayAsync($"SELECT * FROM Levels WHERE UserID='{context.Message.Author.Id}'");
|
object[] user = await Variables.database.ReadDataArrayAsync($"SELECT * FROM Levels WHERE UserID='{context.Message.Author.Id}'");
|
||||||
@@ -72,7 +74,7 @@ internal class LevelCommand : DBCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Optional method (tell the bot what should it do if the command is executed from a DM channel)
|
//Optional method (tell the bot what should it do if the command is executed from a DM channel)
|
||||||
//public async void ExecuteDM(CmdArgs context) {
|
//public async void ExecuteDM(DBCommandExecutingArguments context) {
|
||||||
//
|
//
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
@@ -190,4 +192,4 @@ namespace SlashCommands
|
|||||||
You can create multiple commands, events and slash commands into one single plugin (class library). The PluginManager will detect the classes and load them individualy. If there are more commands (normal commands, events or slash commands) into a single project (class library) they can use the same resources (a class for example) that is contained within the plugin.
|
You can create multiple commands, events and slash commands into one single plugin (class library). The PluginManager will detect the classes and load them individualy. If there are more commands (normal commands, events or slash commands) into a single project (class library) they can use the same resources (a class for example) that is contained within the plugin.
|
||||||
|
|
||||||
|
|
||||||
> Updated: 7.04.2023
|
> Updated: 5.08.2023
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscordBot", "DiscordBot\Di
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PluginManager", "PluginManager\PluginManager.csproj", "{EDD4D9B3-98DD-4367-A09F-D1C5ACB61132}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PluginManager", "PluginManager\PluginManager.csproj", "{EDD4D9B3-98DD-4367-A09F-D1C5ACB61132}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SethPlugins", "SethPlugins", "{78B6D390-F61A-453F-B38D-E4C054321615}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MusicPlayer", "..\SethPlugins\MusicPlayer\MusicPlayer.csproj", "{1690CBBC-BDC0-4DD8-B701-F8817189D9D5}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LevelingSystem", "..\SethPlugins\LevelingSystem\LevelingSystem.csproj", "{BFE3491C-AC01-4252-B242-6451270FC548}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -21,11 +27,21 @@ Global
|
|||||||
{EDD4D9B3-98DD-4367-A09F-D1C5ACB61132}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{EDD4D9B3-98DD-4367-A09F-D1C5ACB61132}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{EDD4D9B3-98DD-4367-A09F-D1C5ACB61132}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{EDD4D9B3-98DD-4367-A09F-D1C5ACB61132}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{EDD4D9B3-98DD-4367-A09F-D1C5ACB61132}.Release|Any CPU.Build.0 = Release|Any CPU
|
{EDD4D9B3-98DD-4367-A09F-D1C5ACB61132}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1690CBBC-BDC0-4DD8-B701-F8817189D9D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1690CBBC-BDC0-4DD8-B701-F8817189D9D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1690CBBC-BDC0-4DD8-B701-F8817189D9D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1690CBBC-BDC0-4DD8-B701-F8817189D9D5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BFE3491C-AC01-4252-B242-6451270FC548}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BFE3491C-AC01-4252-B242-6451270FC548}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BFE3491C-AC01-4252-B242-6451270FC548}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BFE3491C-AC01-4252-B242-6451270FC548}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{1690CBBC-BDC0-4DD8-B701-F8817189D9D5} = {78B6D390-F61A-453F-B38D-E4C054321615}
|
||||||
|
{BFE3491C-AC01-4252-B242-6451270FC548} = {78B6D390-F61A-453F-B38D-E4C054321615}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {3FB3C5DE-ED21-4D2E-ABDD-3A00EE4A2FFF}
|
SolutionGuid = {3FB3C5DE-ED21-4D2E-ABDD-3A00EE4A2FFF}
|
||||||
|
|||||||
Reference in New Issue
Block a user