From f5f182754027782f9404ab226d510c3b81a43385 Mon Sep 17 00:00:00 2001 From: Wizzy69 Date: Tue, 3 May 2022 21:58:44 +0300 Subject: [PATCH] Updated documentation --- BUILDS/net6.0/PluginManager.dll | Bin 45056 -> 43520 bytes DiscordBot/Discord/Commands/Help.cs | 29 +++++++ DiscordBot/Discord/Commands/Restart.cs | 46 ++++++++--- DiscordBot/Discord/Commands/Settings.cs | 28 +++++++ DiscordBot/Discord/Core/Boot.cs | 39 +++++++++- DiscordBot/Discord/Core/CommandHandler.cs | 17 +++++ DiscordBot/Program.cs | 13 +++- PluginManager/Interfaces/DBEvent.cs | 11 +++ PluginManager/Items/Command.cs | 25 ++++++ PluginManager/Items/CustomProgressBar.cs | 27 ------- PluginManager/Items/Spinner.cs | 14 ++++ PluginManager/Language System/Language.cs | 41 ++++++++-- PluginManager/Loaders/CommandsLoader.cs | 30 ++++++-- PluginManager/Loaders/EventsLoader.cs | 30 ++++++-- PluginManager/Loaders/PluginLoader.cs | 25 +++++- .../Online/Helpers/OnlineFunctions.cs | 19 ++++- PluginManager/Online/LanguageManager.cs | 14 ++++ PluginManager/Online/PluginsManager.cs | 16 ++++ PluginManager/Online/ServerCom.cs | 72 ++++-------------- PluginManager/Others/Channels.cs | 27 +++++++ PluginManager/Others/Console Utilities.cs | 27 ------- PluginManager/Others/Cryptography.cs | 49 +++++++++++- PluginManager/Others/Enums.cs | 6 ++ .../Others/Exceptions/APIException.cs | 39 +++++++++- PluginManager/Others/Functions.cs | 24 ------ .../Others/Permissions/DiscordPermissions.cs | 32 ++++++++ 26 files changed, 520 insertions(+), 180 deletions(-) delete mode 100644 PluginManager/Items/CustomProgressBar.cs diff --git a/BUILDS/net6.0/PluginManager.dll b/BUILDS/net6.0/PluginManager.dll index 2241ba39cd5aa456dce8dcf51fdf7a18e068f309..9a440c283f3f6cc25ec2f5488be089588ccb8a47 100644 GIT binary patch literal 43520 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 Qx^XKOnE&_rzs~~y8{_Wl2VpMPNP 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 E08 + /// The help command + /// internal class Help : DBCommand { + /// + /// Command name + /// public string Command => "help"; + /// + /// Command Description + /// public string Description => "This command allows you to check all loadded commands"; + /// + /// Command usage + /// public string Usage => "help"; + /// + /// Check if the command can be used /> + /// public bool canUseDM => true; + + /// + /// Check if the command can be used in a server + /// public bool canUseServer => true; + /// + /// Check if the command require administrator to be executed + /// public bool requireAdmin => false; + /// + /// The main body of the command + /// + /// The command context + /// The command message + /// The discord bot client + /// True if the message was sent from a DM channel, false otherwise public void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM) { List args = Functions.GetArguments(message); diff --git a/DiscordBot/Discord/Commands/Restart.cs b/DiscordBot/Discord/Commands/Restart.cs index 8132550..0d3a6b4 100644 --- a/DiscordBot/Discord/Commands/Restart.cs +++ b/DiscordBot/Discord/Commands/Restart.cs @@ -14,26 +14,49 @@ using ds = Discord; using PluginManager.Interfaces; using PluginManager.Others.Permissions; -using PluginManager.Online; using PluginManager.Others; namespace DiscordBot.Discord.Commands { - class Restart : DBCommand + internal class Restart : DBCommand { - string DBCommand.Command => "restart"; + /// + /// Command name + /// + public string Command => "restart"; - string DBCommand.Description => "Restart the bot"; + /// + /// Command Description + /// + public string Description => "Restart the bot"; - string DBCommand.Usage => "restart [-option]"; + /// + /// Command usage + /// + public string Usage => "restart [-p | -c | -args | -cmd] "; - bool DBCommand.canUseDM => false; + /// + /// Check if the command can be used /> + /// + public bool canUseDM => false; - bool DBCommand.canUseServer => true; + /// + /// Check if the command can be used in a server + /// + public bool canUseServer => true; - bool DBCommand.requireAdmin => true; - - void DBCommand.Execute(dsc.SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM) + /// + /// Check if the command require administrator to be executed + /// + public bool requireAdmin => false; + /// + /// The main body of the command + /// + /// The command context + /// The command message + /// The discord bot client + /// True if the message was sent from a DM channel, false otherwise + public async void Execute(dsc.SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM) { if (!DiscordPermissions.hasPermission(message.Author as SocketGuildUser, ds.GuildPermission.Administrator)) return; var args = Functions.GetArguments(message); @@ -79,6 +102,9 @@ namespace DiscordBot.Discord.Commands } Environment.Exit(0); break; + default: + await context.Channel.SendMessageAsync("Invalid argument. Use `help restart` to see the usage."); + break; } diff --git a/DiscordBot/Discord/Commands/Settings.cs b/DiscordBot/Discord/Commands/Settings.cs index 04ed19c..4b867f3 100644 --- a/DiscordBot/Discord/Commands/Settings.cs +++ b/DiscordBot/Discord/Commands/Settings.cs @@ -17,16 +17,44 @@ namespace DiscordBot.Discord.Commands { class Settings : DBCommand { + + /// + /// Command name + /// public string Command => "set"; + /// + /// Command Description + /// public string Description => "This command allows you change all settings. Use \"set help\" to show details"; + /// + /// Command usage + /// public string Usage => "set [keyword] [new Value]"; + /// + /// Check if the command can be used /> + /// public bool canUseDM => true; + + /// + /// Check if the command can be used in a server + /// public bool canUseServer => true; + + /// + /// Check if the command require administrator to be executed + /// public bool requireAdmin => true; + /// + /// The main body of the command + /// + /// The command context + /// The command message + /// The discord bot client + /// True if the message was sent from a DM channel, false otherwise public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM) { var channel = message.Channel; diff --git a/DiscordBot/Discord/Core/Boot.cs b/DiscordBot/Discord/Core/Boot.cs index 043e930..cc5194d 100644 --- a/DiscordBot/Discord/Core/Boot.cs +++ b/DiscordBot/Discord/Core/Boot.cs @@ -11,21 +11,53 @@ namespace PluginManager.Core { internal class Boot { + /// + /// The bot prefix + /// public readonly string botPrefix; + + /// + /// The bot token + /// public readonly string botToken; - private bool isReady = false; + /// + /// Checks if the bot is ready + /// + /// true if the bot is ready, othwerwise false + public bool isReady { get; private set; } = false; + + /// + /// The bot client + /// public DiscordSocketClient client; + + /// + /// The bot command handler + /// private CommandHandler commandServiceHandler; + + /// + /// The command service + /// private CommandService service; + /// + /// The main Boot constructor + /// + /// The bot token + /// The bot prefix public Boot(string botToken, string botPrefix) { this.botPrefix = botPrefix; this.botToken = botToken; } + /// + /// The start method for the bot. This method is used to load the bot + /// + /// Task public async Task Awake() { client = new DiscordSocketClient(); @@ -39,10 +71,15 @@ namespace PluginManager.Core commandServiceHandler = new CommandHandler(client, service, botPrefix); await commandServiceHandler.InstallCommandsAsync(); + //wait for isReady to become true while (!isReady) ; } + /// + /// The method that stops the bot from running + /// + /// public async Task ShutDown() { if (client == null) return; diff --git a/DiscordBot/Discord/Core/CommandHandler.cs b/DiscordBot/Discord/Core/CommandHandler.cs index 088a049..5ed266b 100644 --- a/DiscordBot/Discord/Core/CommandHandler.cs +++ b/DiscordBot/Discord/Core/CommandHandler.cs @@ -21,6 +21,12 @@ namespace PluginManager.Core private readonly CommandService commandService; private readonly string botPrefix; + /// + /// Command handler constructor + /// + /// The discord bot client + /// The discord bot command service + /// The prefix to watch for public CommandHandler(DiscordSocketClient client, CommandService commandService, string botPrefix) { this.client = client; @@ -28,12 +34,21 @@ namespace PluginManager.Core this.botPrefix = botPrefix; } + /// + /// The method to initialize all commands + /// + /// public async Task InstallCommandsAsync() { client.MessageReceived += MessageHandler; await commandService.AddModulesAsync(assembly: Assembly.GetEntryAssembly(), services: null); } + /// + /// The message handler for the bot + /// + /// The message got from the user in discord chat + /// private async Task MessageHandler(SocketMessage Message) { try @@ -45,6 +60,8 @@ namespace PluginManager.Core if (message == null) return; + if (!message.Content.StartsWith(botPrefix)) return; + int argPos = 0; if (message.HasMentionPrefix(client.CurrentUser, ref argPos)) diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 7962b1e..b276b1f 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -83,6 +83,10 @@ namespace DiscordBot await manager.ListAvailablePlugins(); if (listLanguagAtStartup) await languageManager.ListAllLanguages(); + + IProgress progress = null; + + while (true) { Console.ForegroundColor = ConsoleColor.White; @@ -131,7 +135,7 @@ namespace DiscordBot } string path = "./Data/Plugins/" + info[0] + "s/" + name + ".dll"; - IProgress progress = new Progress(percent => + progress = new Progress(percent => { Console.Title = $"Downloading {info[0]}: {name} ({MathF.Round(percent, 2)}%)"; }); @@ -145,11 +149,16 @@ namespace DiscordBot // List lines = await ServerCom.ReadTextFromFile(info[2]); int i = 1; + foreach (var line in lines) { string[] split = line.Split(','); Console.WriteLine($"Downloading item: {split[1]}"); - await ServerCom.DownloadFileAsync(split[0], "./" + split[1], i, lines.Count); + progress = new Progress(bytes => + { + Console.Title = $"Downloading {MathF.Round(bytes, 2)}% ({i}/{lines.Count})"; + }); + await ServerCom.DownloadFileAsync(split[0], "./" + split[1], progress); Console_Utilities.WriteColorText($"Downloaded item {split[1]}"); i++; } diff --git a/PluginManager/Interfaces/DBEvent.cs b/PluginManager/Interfaces/DBEvent.cs index 8741e81..77288fb 100644 --- a/PluginManager/Interfaces/DBEvent.cs +++ b/PluginManager/Interfaces/DBEvent.cs @@ -4,9 +4,20 @@ namespace PluginManager.Interfaces { public interface DBEvent { + /// + /// The name of the event + /// string name { get; } + + /// + /// The description of the event + /// string description { get; } + /// + /// The method that is invoked when the event is loaded into memory + /// + /// The discord bot client void Start(DiscordSocketClient client); } } diff --git a/PluginManager/Items/Command.cs b/PluginManager/Items/Command.cs index 1ac0ab1..0842f8a 100644 --- a/PluginManager/Items/Command.cs +++ b/PluginManager/Items/Command.cs @@ -13,10 +13,30 @@ namespace PluginManager.Items { internal class Command { + /// + /// The author of the command + /// public SocketUser Author; + + /// + /// The list of arguments + /// public List Arguments { get; private set; } + + /// + /// The command that is executed + /// public string CommandName { get; private set; } + + /// + /// The prefix that is used for the command + /// public char PrefixUsed { get; private set; } + + /// + /// The Command class contructor + /// + /// The message that was sent public Command(SocketMessage message) { this.Author = message.Author; @@ -28,6 +48,11 @@ namespace PluginManager.Items this.PrefixUsed = data[0][0]; } + /// + /// The Command class contructor + /// + /// The message string itself + /// True if the message has a prefix, false if not public Command(string message, bool hasPrefix) { string[] data = message.Split(' '); diff --git a/PluginManager/Items/CustomProgressBar.cs b/PluginManager/Items/CustomProgressBar.cs deleted file mode 100644 index 0efdccc..0000000 --- a/PluginManager/Items/CustomProgressBar.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -namespace PluginManager.Items -{ - public class CustomProgressBar - { - private const char _block = '#'; - private const char _emptyBlock = ' '; - private const char _leftMargin = '['; - private const char _rightMargin = ']'; - - const string _back = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; - public static void WriteProgressBar(int percent) - { - Console.Write(_back); - Console.Write(_leftMargin); - var p = (int)((percent / 10f) + .5f); - for (var i = 0; i < 10; ++i) - { - if (i >= p) - Console.Write(_emptyBlock); - else - Console.Write(_block); - } - Console.Write($"{_rightMargin} " + percent + " %"); - } - } -} diff --git a/PluginManager/Items/Spinner.cs b/PluginManager/Items/Spinner.cs index 5888eae..ceee3c0 100644 --- a/PluginManager/Items/Spinner.cs +++ b/PluginManager/Items/Spinner.cs @@ -5,13 +5,22 @@ namespace PluginManager.Items { public class Spinner { + /// + /// True if active, false otherwise + /// public bool isSpinning; + /// + /// The Spinner constructor + /// public Spinner() { isSpinning = false; } + /// + /// The method that is called to start spinning the spinner + /// public async void Start() { isSpinning = true; @@ -32,8 +41,13 @@ namespace PluginManager.Items } } + /// + /// The method that is called to stop the spinner from spinning + /// public void Stop() { + if (!isSpinning) + throw new Others.Exceptions.APIException("The spinner was not running", "Stop()"); isSpinning = false; } } diff --git a/PluginManager/Language System/Language.cs b/PluginManager/Language System/Language.cs index d9fe518..f3c5d08 100644 --- a/PluginManager/Language System/Language.cs +++ b/PluginManager/Language System/Language.cs @@ -8,10 +8,34 @@ namespace PluginManager.LanguageSystem { public class Language { + /// + /// The active language + /// public static Language? ActiveLanguage = null; private static readonly string LanguageFileExtension = ".lng"; + /// + /// The name of the language + /// + public string LanguageName { get; } + + /// + /// The file where the language is imported from + /// + public string fileName { get; } + + /// + /// The dictionary of the language + /// + public Dictionary LanguageWords { get; } + + /// + /// The Language constructor + /// + /// The file to import the language from + /// The dictionary of the language + /// The name of the language private Language(string fileName, Dictionary words, string LanguageName) { this.fileName = fileName; @@ -19,12 +43,11 @@ namespace PluginManager.LanguageSystem LanguageWords = words; } - public string LanguageName { get; } - - public string fileName { get; } - - public Dictionary LanguageWords { get; } - + /// + /// Load language from file + /// + /// The file path + /// public static Language? CreateLanguageFromFile(string LanguageFileLocation) { if (!LanguageFileLocation.EndsWith(LanguageFileExtension)) @@ -58,6 +81,12 @@ namespace PluginManager.LanguageSystem return new Language(LanguageFileLocation, words, languageName); } + /// + /// Format text by inserting parameters + /// + /// The raw text + /// The arguments + /// public string FormatText(string text, params string[] args) { if (ActiveLanguage == null) return text; diff --git a/PluginManager/Loaders/CommandsLoader.cs b/PluginManager/Loaders/CommandsLoader.cs index b1cea89..caec835 100644 --- a/PluginManager/Loaders/CommandsLoader.cs +++ b/PluginManager/Loaders/CommandsLoader.cs @@ -8,25 +8,41 @@ using PluginManager.Interfaces; namespace PluginManager.Loaders { - public class CommandsLoader + internal class CommandsLoader { private readonly string CMDPath; private readonly string CMDExtension; - public delegate void onCommandLoaded(string name, bool success, DBCommand? command = null, Exception? exception = null); - public delegate void onCommandFileLoaded(string path); + internal delegate void onCommandLoaded(string name, bool success, DBCommand? command = null, Exception? exception = null); + internal delegate void onCommandFileLoaded(string path); - public onCommandLoaded? OnCommandLoaded; - public onCommandFileLoaded? OnCommandFileLoaded; + /// + /// Event fired when a command is loaded + /// + internal onCommandLoaded? OnCommandLoaded; - public CommandsLoader(string CommandPath, string CommandExtension) + /// + /// Event fired when the file is loaded + /// + internal onCommandFileLoaded? OnCommandFileLoaded; + + /// + /// Command Loader contructor + /// + /// The path to the commands + /// The extension to search for in the + internal CommandsLoader(string CommandPath, string CommandExtension) { CMDPath = CommandPath; CMDExtension = CommandExtension; } - public List? LoadCommands() + /// + /// The method that loads all commands + /// + /// + internal List? LoadCommands() { if (!Directory.Exists(CMDPath)) { diff --git a/PluginManager/Loaders/EventsLoader.cs b/PluginManager/Loaders/EventsLoader.cs index bc1e1eb..28c1766 100644 --- a/PluginManager/Loaders/EventsLoader.cs +++ b/PluginManager/Loaders/EventsLoader.cs @@ -8,25 +8,41 @@ using PluginManager.Interfaces; namespace PluginManager.Loaders { - public class EventsLoader + internal class EventsLoader { private readonly string EVPath; private readonly string EVExtension; - public delegate void onEventLoad(string name, bool success, DBEvent? ev = null, Exception? e = null); - public delegate void onEventFileLoaded(string path); + internal delegate void onEventLoad(string name, bool success, DBEvent? ev = null, Exception? e = null); + internal delegate void onEventFileLoaded(string path); - public onEventLoad? EventLoad; - public onEventFileLoaded? EventFileLoaded; + /// + /// An event that is fired whenever a event is loaded in memory + /// + internal onEventLoad? EventLoad; - public EventsLoader(string path, string ext) + /// + /// An event that is fired whenever a event file is loaded + /// + internal onEventFileLoaded? EventFileLoaded; + + /// + /// The Event Loader constructor + /// + /// The path to all events + /// The extension for events + internal EventsLoader(string path, string ext) { EVPath = path; EVExtension = ext; } - public List? LoadEvents() + /// + /// The method that loads all events + /// + /// + internal List? LoadEvents() { if (!Directory.Exists(EVPath)) diff --git a/PluginManager/Loaders/PluginLoader.cs b/PluginManager/Loaders/PluginLoader.cs index ccff7aa..3f6ed97 100644 --- a/PluginManager/Loaders/PluginLoader.cs +++ b/PluginManager/Loaders/PluginLoader.cs @@ -10,6 +10,11 @@ namespace PluginManager.Loaders public class PluginLoader { private DiscordSocketClient client; + + /// + /// The Plugin Loader constructor + /// + /// The discord bot client where the plugins will pe attached to public PluginLoader(DiscordSocketClient discordSocketClient) { this.client = discordSocketClient; @@ -21,17 +26,33 @@ namespace PluginManager.Loaders private const string pluginCMDExtension = ".dll"; private const string pluginEVEExtension = ".dll"; - + /// + /// A list of commands + /// public static List? Plugins { get; set; } + + /// + /// A list of commands + /// public static List? Events { get; set; } - public delegate void CMDLoaded(string name, string typeName, bool success, Exception? e = null); + public delegate void CMDLoaded(string name, string typeName, bool success, Exception? e = null); public delegate void EVELoaded(string name, string typeName, bool success, Exception? e = null); + /// + /// Event that is fired when a is successfully loaded into commands list + /// public CMDLoaded? onCMDLoad; + + /// + /// Event that is fired when a is successfully loaded into events list + /// public EVELoaded? onEVELoad; + /// + /// The main mathod that is called to load all events + /// public void LoadPlugins() { diff --git a/PluginManager/Online/Helpers/OnlineFunctions.cs b/PluginManager/Online/Helpers/OnlineFunctions.cs index ba2bcbf..8754f15 100644 --- a/PluginManager/Online/Helpers/OnlineFunctions.cs +++ b/PluginManager/Online/Helpers/OnlineFunctions.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; using System.Net.Http; using System.Threading.Tasks; using System.IO; @@ -13,6 +9,15 @@ namespace PluginManager.Online.Helpers { internal static class OnlineFunctions { + /// + /// Downloads a and saves it to another . + /// + /// The that is used to download the file + /// The url to the file + /// The to save the downloaded data + /// The that is used to track the download progress + /// The cancellation token + /// internal static async Task DownloadFileAsync(this HttpClient client, string url, Stream destination, IProgress progress = null, CancellationToken cancellation = default) { using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead)) @@ -39,6 +44,12 @@ namespace PluginManager.Online.Helpers } } + /// + /// Read contents of a file as string from specified URL + /// + /// The URL to read from + /// The cancellation token + /// internal static async Task DownloadStringAsync(string url, CancellationToken cancellation = default) { using (var client = new HttpClient()) diff --git a/PluginManager/Online/LanguageManager.cs b/PluginManager/Online/LanguageManager.cs index 0389922..71eacdd 100644 --- a/PluginManager/Online/LanguageManager.cs +++ b/PluginManager/Online/LanguageManager.cs @@ -11,8 +11,17 @@ namespace PluginManager.Online public class LanguageManager { private string link; + + /// + /// The Language Manager constructor + /// + /// The link to where all the languages for the bot are stored public LanguageManager(string link) => this.link = link; + /// + /// The method to list all languages + /// + /// public async Task ListAllLanguages() { @@ -49,6 +58,11 @@ namespace PluginManager.Online } + /// + /// A function that gets the download link for specified language + /// + /// The name of the language + /// public async Task GetDownloadLink(string langName) { try diff --git a/PluginManager/Online/PluginsManager.cs b/PluginManager/Online/PluginsManager.cs index 581f6ca..1de837e 100644 --- a/PluginManager/Online/PluginsManager.cs +++ b/PluginManager/Online/PluginsManager.cs @@ -10,13 +10,24 @@ namespace PluginManager.Online { public class PluginsManager { + /// + /// The URL of the server + /// public string PluginsLink { get; private set; } + /// + /// The Plugin Manager constructor + /// + /// The link to the file where all plugins are stored public PluginsManager(string link) { PluginsLink = link; } + /// + /// The method to load all plugins + /// + /// public async Task ListAvailablePlugins() { try @@ -77,6 +88,11 @@ namespace PluginManager.Online } + /// + /// The method to get plugin information by its name + /// + /// The plugin name + /// public async Task GetPluginLinkByName(string name) { try diff --git a/PluginManager/Online/ServerCom.cs b/PluginManager/Online/ServerCom.cs index 264ee45..2dbc85e 100644 --- a/PluginManager/Online/ServerCom.cs +++ b/PluginManager/Online/ServerCom.cs @@ -13,27 +13,26 @@ namespace PluginManager.Online { public class ServerCom { + + /// + /// Read all lines from a file async + /// + /// The link of the file + /// public static async Task> ReadTextFromFile(string link) { string response = await OnlineFunctions.DownloadStringAsync(link); string[] lines = response.Split('\n'); return lines.ToList(); - - - //[Obsolete] - #region old code for reading text from link - /* - List s = new List(); - WebClient webClient = new WebClient(); - var data = await webClient.OpenReadTaskAsync(link); - var response = await new StreamReader(data).ReadToEndAsync(); - s.AddRange(from a in response.Split('\n') - where !a.StartsWith("$") - select a); - return s;*/ - #endregion } + /// + /// Download file from url + /// + /// The url to the file + /// The location where to store the downloaded data + /// The to track the download + /// public static async Task DownloadFileAsync(string URL, string location, IProgress progress) { using (var client = new System.Net.Http.HttpClient()) @@ -46,50 +45,5 @@ namespace PluginManager.Online } } } - - public static async Task DownloadFileAsync(string url, string location, int downloadNumber, int totalToDownload) - { - - IProgress progress = new Progress(bytes => - { - Console.Title = $"Downloading {MathF.Round(bytes, 2)}% ({downloadNumber}/{totalToDownload})"; - }); - - await DownloadFileAsync(url, location, progress); - Console.Title = "ONLINE"; - return; - - //[Obsolete] - #region old download code - /* - WebClient client = new WebClient(); - Spinner spinner = new Spinner(); - Console.Write("Downloading "); - spinner.Start(); - string oldTitle = Console.Title ?? ""; - client.DownloadProgressChanged += (sender, e) => - { - Console.Title = e.BytesReceived + "/" + e.TotalBytesToReceive + " (" + e.ProgressPercentage + "%) (" + downloadNumber + " / " + totalToDownload + ")"; - }; - client.DownloadFileCompleted += (sender, e) => - { - spinner.Stop(); Console.WriteLine(); - - }; - try - { - await client.DownloadFileTaskAsync(new Uri(url), location); - } - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); - } - finally - { - Console.Title = oldTitle; - }*/ - - #endregion - } } } diff --git a/PluginManager/Others/Channels.cs b/PluginManager/Others/Channels.cs index 84682a7..89ea068 100644 --- a/PluginManager/Others/Channels.cs +++ b/PluginManager/Others/Channels.cs @@ -4,11 +4,38 @@ using System.Threading.Tasks; namespace PluginManager.Others { + /// + /// A class that handles the sending of messages to the user. + /// public static class ChannelManagement { + /// + /// Get the text channel by name from server + /// + /// The server + /// The channel name + /// public static IGuildChannel GetTextChannel(this IGuild server, string name) => server.GetTextChannel(name); + /// + /// Get the voice channel by name from server + /// + /// The server + /// The channel name + /// public static IGuildChannel GetVoiceChannel(this IGuild server, string name) => server.GetVoiceChannel(name); + + /// + /// Get the DM channel between and + /// + /// + /// public static async Task GetDMChannel(IGuildUser user) => await user.CreateDMChannelAsync(); + + /// + /// Get the channel where the message was sent + /// + /// The message + /// public static IChannel GetChannel(IMessage message) => message.Channel; } diff --git a/PluginManager/Others/Console Utilities.cs b/PluginManager/Others/Console Utilities.cs index a21d6b7..a57cbc4 100644 --- a/PluginManager/Others/Console Utilities.cs +++ b/PluginManager/Others/Console Utilities.cs @@ -8,33 +8,6 @@ namespace PluginManager.Others { public class Console_Utilities { - const char _block = '■'; - const string _back = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; - const string _twirl = "-\\|/"; - public static void WriteProgressBar(int percent, bool update = false) - { - if (update) - Console.Write(_back); - Console.Write("["); - var p = (int)((percent / 10f) + .5f); - for (var i = 0; i < 10; ++i) - { - if (i >= p) - Console.Write(' '); - else - Console.Write(_block); - } - Console.Write("] {0,3:##0}%", percent); - - if (percent == 100) - Console.WriteLine(); - } - public static void WriteProgress(int progress, bool update = false) - { - if (update) - Console.Write("\b"); - Console.Write(_twirl[progress % _twirl.Length]); - } /// /// A way to create a table based on input data diff --git a/PluginManager/Others/Cryptography.cs b/PluginManager/Others/Cryptography.cs index d9e53e4..e2c13de 100644 --- a/PluginManager/Others/Cryptography.cs +++ b/PluginManager/Others/Cryptography.cs @@ -1,7 +1,49 @@ +using System; + namespace PluginManager.Others { public class Cryptography { + + /// + /// Translate hex to string + /// + /// The encrypted string + /// + public static string FromHexToString(string hexString) + { + var bytes = new byte[hexString.Length / 2]; + for (var i = 0; i < bytes.Length; i++) + { + bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); + } + + return System.Text.Encoding.Unicode.GetString(bytes); + } + + /// + /// Translate string to hex + /// + /// The string to encrypt + /// + public static string ToHexString(string str) + { + var sb = new System.Text.StringBuilder(); + + var bytes = System.Text.Encoding.Unicode.GetBytes(str); + foreach (var t in bytes) + { + sb.Append(t.ToString("X2")); + } + + return sb.ToString(); + } + + /// + /// Create MD5 hash + /// + /// The text to encrypt + /// public static async System.Threading.Tasks.Task CreateMD5(string text) { string output = ""; @@ -17,6 +59,11 @@ namespace PluginManager.Others return output; } + /// + /// Create SHA256 hash + /// + /// The text to encrypt + /// public static async System.Threading.Tasks.Task CreateSHA256(string text) { string output = ""; @@ -31,7 +78,7 @@ namespace PluginManager.Others return output; } - public static System.IO.Stream GenerateStreamFromString(string s) + private static System.IO.Stream GenerateStreamFromString(string s) { var stream = new System.IO.MemoryStream(); var writer = new System.IO.StreamWriter(stream); diff --git a/PluginManager/Others/Enums.cs b/PluginManager/Others/Enums.cs index 43cb702..5413955 100644 --- a/PluginManager/Others/Enums.cs +++ b/PluginManager/Others/Enums.cs @@ -7,8 +7,14 @@ public enum OperatingSystem { WINDOWS, LINUX, MAC_OS, UNKNOWN } + /// + /// A list with all errors + /// public enum Error { UNKNOWN_ERROR, GUILD_NOT_FOUND, STREAM_NOT_FOUND } + /// + /// The output log type + /// public enum OutputLogLevel { NONE, INFO, WARNING, ERROR, CRITICAL } } \ No newline at end of file diff --git a/PluginManager/Others/Exceptions/APIException.cs b/PluginManager/Others/Exceptions/APIException.cs index ac9c895..881de94 100644 --- a/PluginManager/Others/Exceptions/APIException.cs +++ b/PluginManager/Others/Exceptions/APIException.cs @@ -5,10 +5,28 @@ namespace PluginManager.Others.Exceptions [Serializable] public class APIException : Exception { + /// + /// The function where the error occurred + /// public string? Function { get; } = "not specified"; + + /// + /// The error code + /// public Error? ErrorCode { get; } = Error.UNKNOWN_ERROR; + + /// + /// The possible cause that determined the error + /// public string? PossibleCause { get; } = "not specified"; + /// + /// The APIException contructor + /// + /// The error message + /// The function where the message was triggered + /// The possible cause of the error + /// The error code public APIException(string message, string? function, string possible_cause, Error error) : base(message) { ErrorCode = error; @@ -16,22 +34,37 @@ namespace PluginManager.Others.Exceptions PossibleCause = possible_cause; } + /// + /// The APIException contructor + /// + /// The error message + /// The function where the message was triggered + /// The error code public APIException(string message, string? function, Error? errorCode) : base(message) { ErrorCode = errorCode; Function = function; } - + /// + /// The APIException contructor + /// + /// The error message + /// The function where the message was triggered public APIException(string message, string? function) : base(message) { Function = function; } - + /// + /// The APIException contructor + /// + /// The error message public APIException(string message) : base(message) { } - + /// + /// Method to print the error to + /// public void Print() { Console.WriteLine("Message Content: " + Message); diff --git a/PluginManager/Others/Functions.cs b/PluginManager/Others/Functions.cs index fb23cd5..02afbf5 100644 --- a/PluginManager/Others/Functions.cs +++ b/PluginManager/Others/Functions.cs @@ -199,30 +199,6 @@ namespace PluginManager.Others } - public static string FromHexToString(string hexString) - { - var bytes = new byte[hexString.Length / 2]; - for (var i = 0; i < bytes.Length; i++) - { - bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); - } - - return System.Text.Encoding.Unicode.GetString(bytes); - } - - public static string ToHexString(string str) - { - var sb = new System.Text.StringBuilder(); - - var bytes = System.Text.Encoding.Unicode.GetBytes(str); - foreach (var t in bytes) - { - sb.Append(t.ToString("X2")); - } - - return sb.ToString(); - } - /// /// Copy one Stream to another /// diff --git a/PluginManager/Others/Permissions/DiscordPermissions.cs b/PluginManager/Others/Permissions/DiscordPermissions.cs index 5343cf5..be55780 100644 --- a/PluginManager/Others/Permissions/DiscordPermissions.cs +++ b/PluginManager/Others/Permissions/DiscordPermissions.cs @@ -5,15 +5,47 @@ using System.Linq; namespace PluginManager.Others.Permissions { + /// + /// A class whith all discord permissions + /// public static class DiscordPermissions { + /// + /// Checks if the role has the specified permission + /// + /// The role + /// The permission + /// public static bool hasPermission(this IRole role, GuildPermission permission) => role.Permissions.Has(permission); + /// + /// Check if user has the specified role + /// + /// The user + /// The role + /// public static bool hasRole(this SocketGuildUser user, IRole role) => user.Roles.Contains(role); + /// + /// Check if user has the specified permission + /// + /// The user + /// The permission + /// public static bool hasPermission(this SocketGuildUser user, GuildPermission permission) => user.Roles.Where(role => role.hasPermission(permission)).Any() || user.Guild.Owner == user; + /// + /// Check if user is administrator of server + /// + /// The user + /// public static bool isAdmin(this SocketGuildUser user) => user.hasPermission(GuildPermission.Administrator); + + /// + /// Check if user is administrator of server + /// + /// The user + /// public static bool isAdmin(this SocketUser user) => isAdmin((SocketGuildUser)user); }