Renamed PluginManager to DiscordBotCore.
Revamped the Logger
This commit is contained in:
14
DiscordBotCore/Others/Actions/InternalActionOption.cs
Normal file
14
DiscordBotCore/Others/Actions/InternalActionOption.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace DiscordBotCore.Others.Actions
|
||||
{
|
||||
public class InternalActionOption
|
||||
{
|
||||
public string OptionName { get; set; }
|
||||
public string OptionDescription { get; set; }
|
||||
|
||||
public InternalActionOption(string optionName, string optionDescription)
|
||||
{
|
||||
OptionName = optionName;
|
||||
OptionDescription = optionDescription;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
DiscordBotCore/Others/Actions/InternalActionsManager.cs
Normal file
54
DiscordBotCore/Others/Actions/InternalActionsManager.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Loaders;
|
||||
|
||||
namespace DiscordBotCore.Others.Actions;
|
||||
|
||||
public class InternalActionManager
|
||||
{
|
||||
public Dictionary<string, ICommandAction> Actions = new();
|
||||
private readonly ActionsLoader _loader;
|
||||
|
||||
public InternalActionManager(string path, string extension)
|
||||
{
|
||||
_loader = new ActionsLoader(path, extension);
|
||||
}
|
||||
|
||||
public async Task Initialize()
|
||||
{
|
||||
var loadedActions = await _loader.Load();
|
||||
if (loadedActions == null)
|
||||
return;
|
||||
foreach (var action in loadedActions)
|
||||
Actions.TryAdd(action.ActionName, action);
|
||||
|
||||
}
|
||||
|
||||
public async Task Refresh()
|
||||
{
|
||||
Actions.Clear();
|
||||
await Initialize();
|
||||
}
|
||||
|
||||
public async Task<bool> Execute(string actionName, params string[]? args)
|
||||
{
|
||||
if (!Actions.ContainsKey(actionName))
|
||||
{
|
||||
Application.CurrentApplication.Logger.Log($"Action {actionName} not found", this, LogType.ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Actions[actionName].Execute(args);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Application.CurrentApplication.Logger.Log(e.Message, type: LogType.ERROR, Sender: this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
167
DiscordBotCore/Others/ArchiveManager.cs
Normal file
167
DiscordBotCore/Others/ArchiveManager.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DiscordBotCore.Others;
|
||||
|
||||
public static class ArchiveManager
|
||||
{
|
||||
|
||||
public static void CreateFromFile(string file, string folder)
|
||||
{
|
||||
if (!Directory.Exists(folder))
|
||||
Directory.CreateDirectory(folder);
|
||||
|
||||
var archiveName = folder + Path.GetFileNameWithoutExtension(file) + ".zip";
|
||||
if (File.Exists(archiveName))
|
||||
File.Delete(archiveName);
|
||||
|
||||
using(ZipArchive archive = ZipFile.Open(archiveName, ZipArchiveMode.Create))
|
||||
{
|
||||
archive.CreateEntryFromFile(file, Path.GetFileName(file));
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 static async Task<byte[]?> ReadStreamFromPakAsync(string fileName, string archName)
|
||||
{
|
||||
|
||||
archName = Application.CurrentApplication.ApplicationEnvironmentVariables["ArchiveFolder"] + archName;
|
||||
|
||||
if (!File.Exists(archName))
|
||||
throw new Exception("Failed to load file !");
|
||||
|
||||
using var zip = ZipFile.OpenRead(archName);
|
||||
var entry = zip.Entries.FirstOrDefault(entry => entry.FullName == fileName || entry.Name == fileName);
|
||||
if (entry is null) throw new Exception("File not found in archive");
|
||||
|
||||
await using var memoryStream = new MemoryStream();
|
||||
var stream = entry.Open();
|
||||
await stream.CopyToAsync(memoryStream);
|
||||
var data = memoryStream.ToArray();
|
||||
|
||||
stream.Close();
|
||||
memoryStream.Close();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
archFile = Application.CurrentApplication.ApplicationEnvironmentVariables["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)
|
||||
{
|
||||
Application.CurrentApplication.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.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)
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
using var archive = ZipFile.OpenRead(zip);
|
||||
var totalZipFiles = archive.Entries.Count();
|
||||
if (type == UnzipProgressType.PERCENTAGE_FROM_NUMBER_OF_FILES)
|
||||
{
|
||||
var currentZipFile = 0;
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
if (entry.FullName.EndsWith("/")) // it is a folder
|
||||
Directory.CreateDirectory(Path.Combine(folder, entry.FullName));
|
||||
|
||||
else
|
||||
try
|
||||
{
|
||||
entry.ExtractToFile(Path.Combine(folder, entry.FullName), true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Application.CurrentApplication.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.ERROR);
|
||||
}
|
||||
|
||||
currentZipFile++;
|
||||
await Task.Delay(10);
|
||||
if (progress != null)
|
||||
progress.Report((float)currentZipFile / totalZipFiles * 100);
|
||||
}
|
||||
}
|
||||
else if (type == UnzipProgressType.PERCENTAGE_FROM_TOTAL_SIZE)
|
||||
{
|
||||
ulong zipSize = 0;
|
||||
|
||||
foreach (var entry in archive.Entries)
|
||||
zipSize += (ulong)entry.CompressedLength;
|
||||
|
||||
ulong currentSize = 0;
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
if (entry.FullName.EndsWith("/"))
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(folder, entry.FullName));
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
entry.ExtractToFile(Path.Combine(folder, entry.FullName), true);
|
||||
currentSize += (ulong)entry.CompressedLength;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Application.CurrentApplication.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.ERROR);
|
||||
}
|
||||
|
||||
await Task.Delay(10);
|
||||
if (progress != null)
|
||||
progress.Report((float)currentSize / zipSize * 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
DiscordBotCore/Others/DBCommandExecutingArguments.cs
Normal file
48
DiscordBotCore/Others/DBCommandExecutingArguments.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
|
||||
|
||||
namespace DiscordBotCore.Others;
|
||||
|
||||
public class DbCommandExecutingArguments
|
||||
{
|
||||
|
||||
public SocketCommandContext context { get; init; }
|
||||
public string cleanContent { get; init; }
|
||||
public string commandUsed { get; init; }
|
||||
public string[]? arguments { get; init; }
|
||||
public ISocketMessageChannel Channel => context.Channel;
|
||||
|
||||
public DbCommandExecutingArguments(
|
||||
SocketCommandContext context, string cleanContent, string commandUsed, string[]? arguments)
|
||||
{
|
||||
this.context = context;
|
||||
this.cleanContent = cleanContent;
|
||||
this.commandUsed = commandUsed;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
public DbCommandExecutingArguments(SocketUserMessage? message, DiscordSocketClient client)
|
||||
{
|
||||
context = new SocketCommandContext(client, message);
|
||||
var pos = 0;
|
||||
if (message.HasMentionPrefix(client.CurrentUser, ref pos))
|
||||
{
|
||||
var mentionPrefix = "<@" + client.CurrentUser.Id + ">";
|
||||
cleanContent = message.Content.Substring(mentionPrefix.Length + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
cleanContent = message.Content.Substring(Application.CurrentApplication.DiscordBotClient.BotPrefix.Length);
|
||||
}
|
||||
|
||||
var split = cleanContent.Split(' ');
|
||||
|
||||
string[]? argsClean = null;
|
||||
if (split.Length > 1)
|
||||
argsClean = string.Join(' ', split, 1, split.Length - 1).Split(' ');
|
||||
|
||||
commandUsed = split[0];
|
||||
arguments = argsClean;
|
||||
}
|
||||
}
|
||||
43
DiscordBotCore/Others/Enums.cs
Normal file
43
DiscordBotCore/Others/Enums.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
|
||||
namespace DiscordBotCore.Others;
|
||||
|
||||
/// <summary>
|
||||
/// The output log type
|
||||
/// </summary>
|
||||
public enum LogType
|
||||
{
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR,
|
||||
CRITICAL
|
||||
}
|
||||
|
||||
public enum UnzipProgressType
|
||||
{
|
||||
PERCENTAGE_FROM_NUMBER_OF_FILES,
|
||||
PERCENTAGE_FROM_TOTAL_SIZE
|
||||
}
|
||||
|
||||
public enum InternalActionRunType
|
||||
{
|
||||
ON_STARTUP,
|
||||
ON_CALL
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum OSType: byte
|
||||
{
|
||||
NONE = 0,
|
||||
WINDOWS = 1 << 0,
|
||||
LINUX = 2 << 1,
|
||||
MACOSX = 3 << 2
|
||||
}
|
||||
|
||||
public enum PluginType
|
||||
{
|
||||
UNKNOWN,
|
||||
COMMAND,
|
||||
EVENT,
|
||||
SLASH_COMMAND
|
||||
}
|
||||
83
DiscordBotCore/Others/Functions.cs
Normal file
83
DiscordBotCore/Others/Functions.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
|
||||
namespace DiscordBotCore.Others;
|
||||
|
||||
/// <summary>
|
||||
/// A special class with functions
|
||||
/// </summary>
|
||||
public static class Functions
|
||||
{
|
||||
/// <summary>
|
||||
/// The location for the Resources folder
|
||||
/// String: ./Data/Resources/
|
||||
/// </summary>
|
||||
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>
|
||||
/// Copy one Stream to another <see langword="async" />
|
||||
/// </summary>
|
||||
/// <param name="stream">The base stream</param>
|
||||
/// <param name="destination">The destination stream</param>
|
||||
/// <param name="bufferSize">The buffer to read</param>
|
||||
/// <param name="progress">The progress</param>
|
||||
/// <param name="cancellationToken">The cancellation token</param>
|
||||
/// <exception cref="ArgumentNullException">Triggered if any <see cref="Stream" /> is empty</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="ArgumentException">Triggered in <paramref name="destination" /> is not writable</exception>
|
||||
public static async Task CopyToOtherStreamAsync(
|
||||
this Stream stream, Stream destination, int bufferSize,
|
||||
IProgress<long>? progress = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (stream == null) throw new ArgumentNullException(nameof(stream));
|
||||
if (destination == null) throw new ArgumentNullException(nameof(destination));
|
||||
if (bufferSize <= 0) throw new ArgumentOutOfRangeException(nameof(bufferSize));
|
||||
if (!stream.CanRead) throw new InvalidOperationException("The stream is not readable.");
|
||||
if (!destination.CanWrite)
|
||||
throw new ArgumentException("Destination stream is not writable", nameof(destination));
|
||||
|
||||
var buffer = new byte[bufferSize];
|
||||
long totalBytesRead = 0;
|
||||
int bytesRead;
|
||||
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)
|
||||
.ConfigureAwait(false)) != 0)
|
||||
{
|
||||
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
|
||||
totalBytesRead += bytesRead;
|
||||
progress?.Report(totalBytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static T SelectRandomValueOf<T>()
|
||||
{
|
||||
var enums = Enum.GetValues(typeof(T));
|
||||
var random = new Random();
|
||||
return (T)enums.GetValue(random.Next(enums.Length));
|
||||
}
|
||||
|
||||
public static T RandomValue<T>(this T[] values)
|
||||
{
|
||||
Random random = new();
|
||||
return values[random.Next(values.Length)];
|
||||
}
|
||||
|
||||
public static string ToResourcesPath(this string path)
|
||||
{
|
||||
return Path.Combine(dataFolder, path);
|
||||
}
|
||||
}
|
||||
53
DiscordBotCore/Others/JsonManager.cs
Normal file
53
DiscordBotCore/Others/JsonManager.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DiscordBotCore.Others;
|
||||
|
||||
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)!;
|
||||
}
|
||||
}
|
||||
71
DiscordBotCore/Others/Logger/LogMessage.cs
Normal file
71
DiscordBotCore/Others/Logger/LogMessage.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using DiscordBotCore.Interfaces.Logger;
|
||||
|
||||
using System;
|
||||
|
||||
namespace DiscordBotCore.Others.Logger
|
||||
{
|
||||
internal sealed class LogMessage : ILogMessage
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public DateTime ThrowTime { get; set; }
|
||||
public string SenderName { get; set; }
|
||||
public LogType LogMessageType { get; set; }
|
||||
|
||||
public LogMessage(string message, object sender)
|
||||
{
|
||||
Message = message;
|
||||
SenderName = sender.GetType().FullName ?? sender.GetType().Name;
|
||||
ThrowTime = DateTime.Now;
|
||||
LogMessageType = LogType.INFO;
|
||||
}
|
||||
|
||||
public LogMessage(string message, object sender, DateTime throwTime)
|
||||
{
|
||||
Message = message;
|
||||
SenderName = sender.GetType().FullName ?? sender.GetType().Name;
|
||||
ThrowTime = throwTime;
|
||||
LogMessageType = LogType.INFO;
|
||||
}
|
||||
|
||||
public LogMessage(string message, object sender, LogType logMessageType)
|
||||
{
|
||||
Message = message;
|
||||
SenderName = sender.GetType().FullName ?? sender.GetType().Name;
|
||||
ThrowTime = DateTime.Now;
|
||||
LogMessageType = logMessageType;
|
||||
|
||||
}
|
||||
|
||||
public LogMessage(string message, DateTime throwTime, object sender, LogType logMessageType)
|
||||
{
|
||||
Message = message;
|
||||
ThrowTime = throwTime;
|
||||
SenderName = sender.GetType().FullName ?? sender.GetType().Name;
|
||||
LogMessageType = logMessageType;
|
||||
}
|
||||
|
||||
public LogMessage WithMessage(string message)
|
||||
{
|
||||
this.Message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LogMessage WithCurrentThrowTime()
|
||||
{
|
||||
this.ThrowTime = DateTime.Now;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LogMessage WithMessageType(LogType logType)
|
||||
{
|
||||
this.LogMessageType = logType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static LogMessage CreateFromException(Exception exception, object Sender)
|
||||
{
|
||||
LogMessage message = new LogMessage(exception.Message, Sender, LogType.ERROR);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
51
DiscordBotCore/Others/Logger/Logger.cs
Normal file
51
DiscordBotCore/Others/Logger/Logger.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using DiscordBotCore.Interfaces.Logger;
|
||||
|
||||
namespace DiscordBotCore.Others.Logger;
|
||||
|
||||
public sealed class Logger : ILogger
|
||||
{
|
||||
|
||||
public List<string> LogMessageProperties = typeof(ILogMessage).GetProperties().Select(p => p.Name).ToList();
|
||||
public string LogMessageFormat { get ; set; }
|
||||
|
||||
public event EventHandler<ILogger.FormattedMessage> OnFormattedLog;
|
||||
public event EventHandler<ILogMessage> OnRawLog;
|
||||
|
||||
public Logger(string logMessageFormat)
|
||||
{
|
||||
this.LogMessageFormat = logMessageFormat;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a formatted string based on the default parameters of the ILogMessage and a string defined as model
|
||||
/// </summary>
|
||||
/// <param name="message">The message</param>
|
||||
/// <returns>A formatted string with the message values</returns>
|
||||
private string GenerateLogMessage(ILogMessage message)
|
||||
{
|
||||
string messageAsString = new string(LogMessageFormat);
|
||||
foreach (var prop in LogMessageProperties)
|
||||
{
|
||||
Type messageType = typeof(ILogMessage);
|
||||
messageAsString = messageAsString.Replace("{" + prop + "}", messageType?.GetProperty(prop)?.GetValue(message)?.ToString());
|
||||
}
|
||||
|
||||
return messageAsString;
|
||||
}
|
||||
|
||||
public void Log(ILogMessage message)
|
||||
{
|
||||
OnRawLog?.Invoke(this, message);
|
||||
string messageAsString = GenerateLogMessage(message);
|
||||
OnFormattedLog?.Invoke(this, new ILogger.FormattedMessage() { Message = messageAsString, Type = message.LogMessageType }) ;
|
||||
}
|
||||
|
||||
public void Log(string message, object Sender) => Log(new LogMessage(message, Sender));
|
||||
public void Log(string message, object Sender, LogType type) => Log(new LogMessage(message, Sender, type));
|
||||
public void LogException(Exception exception, object Sender) => Log(LogMessage.CreateFromException(exception, Sender));
|
||||
|
||||
}
|
||||
135
DiscordBotCore/Others/OneOf.cs
Normal file
135
DiscordBotCore/Others/OneOf.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
|
||||
namespace DiscordBotCore.Others
|
||||
{
|
||||
public class OneOf<T0, T1>
|
||||
{
|
||||
public T0 Item0 { get; }
|
||||
public T1 Item1 { get; }
|
||||
|
||||
public object? Value => Item0 != null ? Item0 : Item1;
|
||||
|
||||
public OneOf(T0 item0)
|
||||
{
|
||||
Item0 = item0;
|
||||
}
|
||||
|
||||
public OneOf(T1 item1)
|
||||
{
|
||||
Item1 = item1;
|
||||
}
|
||||
|
||||
public static implicit operator OneOf<T0, T1>(T0 item0) => new OneOf<T0, T1>(item0);
|
||||
public static implicit operator OneOf<T0, T1>(T1 item1) => new OneOf<T0, T1>(item1);
|
||||
|
||||
public void Match(Action<T0> item0, Action<T1> item1)
|
||||
{
|
||||
if (Item0 != null)
|
||||
item0(Item0);
|
||||
else
|
||||
item1(Item1);
|
||||
}
|
||||
|
||||
public TResult Match<TResult>(Func<T0, TResult> item0, Func<T1, TResult> item1)
|
||||
{
|
||||
return Item0 != null ? item0(Item0) : item1(Item1);
|
||||
}
|
||||
|
||||
public Type GetActualType()
|
||||
{
|
||||
return Item0 != null ? Item0.GetType() : Item1.GetType();
|
||||
}
|
||||
}
|
||||
|
||||
public class OneOf<T0, T1, T2>
|
||||
{
|
||||
public T0 Item0 { get; }
|
||||
public T1 Item1 { get; }
|
||||
public T2 Item2 { get; }
|
||||
|
||||
public OneOf(T0 item0)
|
||||
{
|
||||
Item0 = item0;
|
||||
}
|
||||
|
||||
public OneOf(T1 item1)
|
||||
{
|
||||
Item1 = item1;
|
||||
}
|
||||
|
||||
public OneOf(T2 item2)
|
||||
{
|
||||
Item2 = item2;
|
||||
}
|
||||
|
||||
public static implicit operator OneOf<T0, T1, T2>(T0 item0) => new OneOf<T0, T1, T2>(item0);
|
||||
public static implicit operator OneOf<T0, T1, T2>(T1 item1) => new OneOf<T0, T1, T2>(item1);
|
||||
public static implicit operator OneOf<T0, T1, T2>(T2 item2) => new OneOf<T0, T1, T2>(item2);
|
||||
|
||||
public void Match(Action<T0> item0, Action<T1> item1, Action<T2> item2)
|
||||
{
|
||||
if (Item0 != null)
|
||||
item0(Item0);
|
||||
else if (Item1 != null)
|
||||
item1(Item1);
|
||||
else
|
||||
item2(Item2);
|
||||
}
|
||||
|
||||
public TResult Match<TResult>(Func<T0, TResult> item0, Func<T1, TResult> item1, Func<T2, TResult> item2)
|
||||
{
|
||||
return Item0 != null ? item0(Item0) : Item1 != null ? item1(Item1) : item2(Item2);
|
||||
}
|
||||
}
|
||||
|
||||
public class OneOf<T0, T1, T2, T3>
|
||||
{
|
||||
public T0 Item0 { get; }
|
||||
public T1 Item1 { get; }
|
||||
public T2 Item2 { get; }
|
||||
public T3 Item3 { get; }
|
||||
|
||||
public OneOf(T0 item0)
|
||||
{
|
||||
Item0 = item0;
|
||||
}
|
||||
|
||||
public OneOf(T1 item1)
|
||||
{
|
||||
Item1 = item1;
|
||||
}
|
||||
|
||||
public OneOf(T2 item2)
|
||||
{
|
||||
Item2 = item2;
|
||||
}
|
||||
|
||||
public OneOf(T3 item3)
|
||||
{
|
||||
Item3 = item3;
|
||||
}
|
||||
|
||||
public static implicit operator OneOf<T0, T1, T2, T3>(T0 item0) => new OneOf<T0, T1, T2, T3>(item0);
|
||||
public static implicit operator OneOf<T0, T1, T2, T3>(T1 item1) => new OneOf<T0, T1, T2, T3>(item1);
|
||||
public static implicit operator OneOf<T0, T1, T2, T3>(T2 item2) => new OneOf<T0, T1, T2, T3>(item2);
|
||||
public static implicit operator OneOf<T0, T1, T2, T3>(T3 item3) => new OneOf<T0, T1, T2, T3>(item3);
|
||||
|
||||
public void Match(Action<T0> item0, Action<T1> item1, Action<T2> item2, Action<T3> item3)
|
||||
{
|
||||
if (Item0 != null)
|
||||
item0(Item0);
|
||||
else if (Item1 != null)
|
||||
item1(Item1);
|
||||
else if (Item2 != null)
|
||||
item2(Item2);
|
||||
else
|
||||
item3(Item3);
|
||||
}
|
||||
|
||||
public TResult Match<TResult>(Func<T0, TResult> item0, Func<T1, TResult> item1, Func<T2, TResult> item2, Func<T3, TResult> item3)
|
||||
{
|
||||
return Item0 != null ? item0(Item0) : Item1 != null ? item1(Item1) : Item2 != null ? item2(Item2) : item3(Item3);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
64
DiscordBotCore/Others/Permissions/DiscordPermissions.cs
Normal file
64
DiscordBotCore/Others/Permissions/DiscordPermissions.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System.Linq;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
|
||||
namespace DiscordBotCore.Others.Permissions;
|
||||
|
||||
/// <summary>
|
||||
/// A class whith all discord permissions
|
||||
/// </summary>
|
||||
public static class DiscordPermissions
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if the role has the specified permission
|
||||
/// </summary>
|
||||
/// <param name="role">The role</param>
|
||||
/// <param name="permission">The permission</param>
|
||||
/// <returns></returns>
|
||||
public static bool hasPermission(this IRole role, GuildPermission permission)
|
||||
{
|
||||
return role.Permissions.Has(permission);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if user has the specified role
|
||||
/// </summary>
|
||||
/// <param name="user">The user</param>
|
||||
/// <param name="role">The role</param>
|
||||
/// <returns></returns>
|
||||
public static bool HasRole(this SocketGuildUser user, IRole role)
|
||||
{
|
||||
return user.Roles.Contains(role);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if user has the specified permission
|
||||
/// </summary>
|
||||
/// <param name="user">The user</param>
|
||||
/// <param name="permission">The permission</param>
|
||||
/// <returns></returns>
|
||||
public static bool HasPermission(this SocketGuildUser user, GuildPermission permission)
|
||||
{
|
||||
return user.Roles.Where(role => role.hasPermission(permission)).Any() || user.Guild.Owner == user;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if user is administrator of server
|
||||
/// </summary>
|
||||
/// <param name="user">The user</param>
|
||||
/// <returns></returns>
|
||||
public static bool IsAdmin(this SocketGuildUser user)
|
||||
{
|
||||
return user.HasPermission(GuildPermission.Administrator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if user is administrator of server
|
||||
/// </summary>
|
||||
/// <param name="user">The user</param>
|
||||
/// <returns></returns>
|
||||
public static bool IsAdmin(this SocketUser user)
|
||||
{
|
||||
return IsAdmin((SocketGuildUser)user);
|
||||
}
|
||||
}
|
||||
87
DiscordBotCore/Others/SettingsDictionary.cs
Normal file
87
DiscordBotCore/Others/SettingsDictionary.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DiscordBotCore.Others;
|
||||
|
||||
public class SettingsDictionary<TKey, TValue>
|
||||
{
|
||||
private string _File { get; }
|
||||
private IDictionary<TKey, TValue> _Dictionary;
|
||||
|
||||
public SettingsDictionary(string file)
|
||||
{
|
||||
this._File = file;
|
||||
_Dictionary = null!;
|
||||
}
|
||||
|
||||
public async Task SaveToFile()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_File))
|
||||
await JsonManager.SaveToJsonFile(_File, _Dictionary);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
return _Dictionary.GetEnumerator();
|
||||
}
|
||||
|
||||
public async Task<bool> LoadFromFile()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_File))
|
||||
return false;
|
||||
|
||||
if(!File.Exists(_File))
|
||||
{
|
||||
_Dictionary = new Dictionary<TKey, TValue>();
|
||||
return false;
|
||||
}
|
||||
|
||||
string fileAsText = await File.ReadAllTextAsync(_File);
|
||||
if(string.IsNullOrEmpty(fileAsText) || string.IsNullOrWhiteSpace(fileAsText))
|
||||
{
|
||||
_Dictionary = new Dictionary<TKey, TValue>();
|
||||
return false;
|
||||
}
|
||||
|
||||
_Dictionary = await JsonManager.ConvertFromJson<IDictionary<TKey,TValue>>(fileAsText);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
_Dictionary.Add(key, value);
|
||||
}
|
||||
|
||||
public bool ContainsAllKeys(params TKey[] keys)
|
||||
{
|
||||
return keys.All(key => _Dictionary.ContainsKey(key));
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
return _Dictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
return _Dictionary.Remove(key);
|
||||
}
|
||||
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if(!_Dictionary.ContainsKey(key))
|
||||
throw new System.Exception($"The key {key} ({typeof(TKey)}) (file: {this._File}) was not present in the dictionary");
|
||||
|
||||
if(_Dictionary[key] is not TValue)
|
||||
throw new System.Exception("The dictionary is corrupted. This error is critical !");
|
||||
|
||||
return _Dictionary[key];
|
||||
}
|
||||
set => _Dictionary[key] = value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user