Redesigned the DiscordBotCore by splitting it into multiple projects. Created a WebUI and preparing to remove the DiscordBot application
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\DiscordBotCore\DiscordBotCore.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,112 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscordBotCore;
|
||||
|
||||
namespace CppWrapper.LibraryManagement
|
||||
{
|
||||
public sealed class ExternLibrary
|
||||
{
|
||||
public string LibraryPath { get; init; }
|
||||
public IntPtr LibraryHandle { get; private set; }
|
||||
|
||||
public ExternLibrary(string libraryPath)
|
||||
{
|
||||
LibraryPath = libraryPath;
|
||||
LibraryHandle = IntPtr.Zero;
|
||||
}
|
||||
|
||||
public void InitializeLibrary()
|
||||
{
|
||||
if(LibraryHandle != IntPtr.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Application.CurrentApplication.Logger.Log($"Loading library {LibraryPath}");
|
||||
|
||||
|
||||
if(!NativeLibrary.TryLoad(LibraryPath, out IntPtr hModule))
|
||||
{
|
||||
throw new DllNotFoundException($"Unable to load library {LibraryPath}");
|
||||
}
|
||||
|
||||
Application.CurrentApplication.Logger.Log($"Library {LibraryPath} loaded successfully [{hModule}]");
|
||||
|
||||
LibraryHandle = hModule;
|
||||
}
|
||||
|
||||
public void FreeLibrary()
|
||||
{
|
||||
if(LibraryHandle == IntPtr.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NativeLibrary.Free(LibraryHandle);
|
||||
LibraryHandle = IntPtr.Zero;
|
||||
|
||||
Application.CurrentApplication.Logger.Log($"Library {LibraryPath} freed successfully");
|
||||
}
|
||||
|
||||
private IntPtr GetFunctionPointer(string functionName)
|
||||
{
|
||||
if(LibraryHandle == IntPtr.Zero)
|
||||
{
|
||||
throw new InvalidOperationException("Library is not loaded");
|
||||
}
|
||||
|
||||
if(!NativeLibrary.TryGetExport(LibraryHandle, functionName, out IntPtr functionPointer))
|
||||
{
|
||||
throw new EntryPointNotFoundException($"Unable to find function {functionName}");
|
||||
}
|
||||
|
||||
return functionPointer;
|
||||
}
|
||||
|
||||
public T GetDelegateForFunctionPointer<T>(string methodName) where T : Delegate
|
||||
{
|
||||
IntPtr functionPointer = GetFunctionPointer(methodName);
|
||||
|
||||
Application.CurrentApplication.Logger.Log($"Function pointer for {methodName} obtained successfully [address: {functionPointer}]");
|
||||
|
||||
T result = (T)Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(T));
|
||||
|
||||
Application.CurrentApplication.Logger.Log($"Delegate for {methodName} created successfully");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private IntPtr GetFunctionPointerForDelegate<T>(T functionDelegate) where T : Delegate
|
||||
{
|
||||
IntPtr functionPointer = Marshal.GetFunctionPointerForDelegate(functionDelegate);
|
||||
|
||||
Application.CurrentApplication.Logger.Log($"Function pointer for delegate {functionDelegate.Method.Name} obtained successfully [address: {functionPointer}]");
|
||||
|
||||
return functionPointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells the extern setter function to point its function to this C# function instead.
|
||||
/// This function takes the name of the extern setter function and the C# function to be executed.
|
||||
/// <para><b>How it works:</b></para>
|
||||
/// Find the external setter method by its name. It should take one parameter, which is the pointer to the function to be executed.
|
||||
/// Take the delegate function that should be executed and get its function pointer.
|
||||
/// Call the external setter with the new function memory address. This should replace the old C++ function with the new C# function.
|
||||
/// </summary>
|
||||
/// <param name="setterExternFunctionName">The setter function name</param>
|
||||
/// <param name="executableFunction">The function that the C++ setter will make its internal function to point to</param>
|
||||
/// <typeparam name="ExecuteDelegate">A delegate that reflects the executable function structure</typeparam>
|
||||
/// <typeparam name="SetDelegate">The Setter delegate </typeparam>
|
||||
/// <returns>A response if it exists as an object</returns>
|
||||
public object? SetExternFunctionSetterPointerToCustomDelegate<SetDelegate, ExecuteDelegate>(string setterExternFunctionName, ExecuteDelegate executableFunction) where ExecuteDelegate : Delegate where SetDelegate : Delegate
|
||||
{
|
||||
SetDelegate setterDelegate = GetDelegateForFunctionPointer<SetDelegate>(setterExternFunctionName);
|
||||
IntPtr executableFunctionPtr = GetFunctionPointerForDelegate(executableFunction);
|
||||
|
||||
var result = setterDelegate.DynamicInvoke(executableFunctionPtr);
|
||||
|
||||
Application.CurrentApplication.Logger.Log($"Function {setterExternFunctionName} bound to local action successfully");
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CppWrapper.Objects
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
public struct ApplicationStruct
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
|
||||
public ulong[] ServerIds;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
|
||||
public string Prefix;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 71)]
|
||||
public string Token;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
public struct ComplexObject
|
||||
{
|
||||
public int Integer;
|
||||
public double DoubleValue;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
||||
public string strValue;
|
||||
|
||||
public ComplexObject(int integer, double doubleValue, string strValue)
|
||||
{
|
||||
Integer = integer;
|
||||
DoubleValue = doubleValue;
|
||||
this.strValue = strValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using DiscordBotCore;
|
||||
|
||||
namespace CppWrapper.Objects
|
||||
{
|
||||
public static class ObjectConvertor
|
||||
{
|
||||
public static ApplicationStruct ToApplicationStruct(this Application application)
|
||||
{
|
||||
return new ApplicationStruct
|
||||
{
|
||||
Token = application.ApplicationEnvironmentVariables.Get<string>("token") ?? throw new Exception("Token not found"),
|
||||
Prefix = application.ApplicationEnvironmentVariables.Get<string>("prefix") ?? throw new Exception("Prefix not found"),
|
||||
ServerIds = application.ServerIDs.ToArray()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using CppWrapper.Objects;
|
||||
|
||||
namespace DiscordBotUI
|
||||
{
|
||||
public abstract class Delegates
|
||||
{
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void ProcessApplicationData(ref ApplicationStruct appData);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void ProcessComplexObject(ref ComplexObject complexObject);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void CsharpFunctionDelegate();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void SetCsharpFunctionPointerDelegate(IntPtr funcPtr);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\DiscordBotCore\DiscordBotCore.csproj" />
|
||||
<ProjectReference Include="..\CppWrapper\CppWrapper.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,55 +0,0 @@
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Others;
|
||||
using DiscordBotCore.Others.Actions;
|
||||
|
||||
using CppWrapper.Objects;
|
||||
using CppWrapper.LibraryManagement;
|
||||
using DiscordBotCore;
|
||||
using CppWrapper;
|
||||
|
||||
namespace DiscordBotUI;
|
||||
|
||||
public class Entry : ICommandAction
|
||||
{
|
||||
public string ActionName => "cppui";
|
||||
|
||||
public string? Description => "A C++ linker to the C++ UI for the bot";
|
||||
|
||||
public string? Usage => "cppui";
|
||||
|
||||
public IEnumerable<InternalActionOption> ListOfOptions => [];
|
||||
|
||||
public InternalActionRunType RunType => InternalActionRunType.OnStartupAndCall;
|
||||
|
||||
public bool RequireOtherThread => false;
|
||||
|
||||
public Task Execute(string[]? args)
|
||||
{
|
||||
try{
|
||||
string appUiComponent = "./Data/Test/libtestlib.dll";
|
||||
|
||||
ExternLibrary externalLibrary = new ExternLibrary(appUiComponent);
|
||||
externalLibrary.InitializeLibrary();
|
||||
|
||||
externalLibrary.SetExternFunctionSetterPointerToCustomDelegate<Delegates.SetCsharpFunctionPointerDelegate, Delegates.CsharpFunctionDelegate>("setCSharpFunctionPointer", () =>
|
||||
{
|
||||
Console.WriteLine("Hello from C#. This code is called from the C# function");
|
||||
});
|
||||
|
||||
Delegates.ProcessComplexObject processObj = externalLibrary.GetDelegateForFunctionPointer<Delegates.ProcessComplexObject>("ProcessComplexObject");
|
||||
|
||||
ComplexObject complexObject = new ComplexObject(10, 10.5, "Hello from C#");
|
||||
processObj(ref complexObject);
|
||||
|
||||
Console.WriteLine($"Integer: {complexObject.Integer}");
|
||||
Console.WriteLine($"Double: {complexObject.DoubleValue}");
|
||||
Console.WriteLine($"String: {complexObject.strValue}");
|
||||
|
||||
externalLibrary.FreeLibrary();
|
||||
} catch (Exception dllException) {
|
||||
Application.CurrentApplication.Logger.LogException(dllException, this);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
using Discord;
|
||||
using DiscordBotCore;
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Others;
|
||||
using DiscordBotCore.Logging;
|
||||
using DiscordBotCore.PluginCore.Helpers;
|
||||
using DiscordBotCore.PluginCore.Helpers.Execution.DbCommand;
|
||||
using DiscordBotCore.PluginCore.Interfaces;
|
||||
|
||||
namespace LevelingSystem;
|
||||
|
||||
@@ -17,11 +18,11 @@ internal class LevelCommand: IDbCommand
|
||||
|
||||
public bool RequireAdmin => false;
|
||||
|
||||
public async void ExecuteServer(DbCommandExecutingArguments args)
|
||||
public async Task ExecuteServer(IDbCommandExecutingArgument args)
|
||||
{
|
||||
if(Variables.Database is null)
|
||||
{
|
||||
Application.CurrentApplication.Logger.Log("Database is not initialized", this, LogType.Warning);
|
||||
args.Logger.Log("Database is not initialized", this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using Discord.WebSocket;
|
||||
|
||||
using DiscordBotCore;
|
||||
using DiscordBotCore.Database;
|
||||
using DiscordBotCore.Interfaces;
|
||||
using System.Net.Mime;
|
||||
using Discord.WebSocket;
|
||||
using DiscordBotCore.Database.Sqlite;
|
||||
using DiscordBotCore.Logging;
|
||||
using DiscordBotCore.PluginCore;
|
||||
using DiscordBotCore.PluginCore.Helpers;
|
||||
using DiscordBotCore.PluginCore.Helpers.Execution.DbEvent;
|
||||
using DiscordBotCore.PluginCore.Interfaces;
|
||||
using static LevelingSystem.Variables;
|
||||
|
||||
namespace LevelingSystem;
|
||||
@@ -12,7 +15,7 @@ internal class LevelEvent : IDbEvent
|
||||
public string Name => "Leveling System Event Handler";
|
||||
public string Description => "The Leveling System Event Handler";
|
||||
|
||||
public async void Start(DiscordSocketClient client)
|
||||
public async Task Start(IDbEventExecutingArgument args)
|
||||
{
|
||||
|
||||
Directory.CreateDirectory(DataFolder);
|
||||
@@ -29,10 +32,11 @@ internal class LevelEvent : IDbEvent
|
||||
MaxExp = 7,
|
||||
MinExp = 1
|
||||
};
|
||||
await DiscordBotCore.Others.JsonManager.SaveToJsonFile(DataFolder + "Settings.txt", GlobalSettings);
|
||||
|
||||
await DiscordBotCore.Utilities.JsonManager.SaveToJsonFile(DataFolder + "Settings.txt", GlobalSettings);
|
||||
}
|
||||
else
|
||||
GlobalSettings = await DiscordBotCore.Others.JsonManager.ConvertFromJson<Settings>(DataFolder + "Settings.txt");
|
||||
GlobalSettings = await DiscordBotCore.Utilities.JsonManager.ConvertFromJson<Settings>(DataFolder + "Settings.txt");
|
||||
|
||||
if (!await Database.TableExistsAsync("Levels"))
|
||||
await Database.CreateTableAsync("Levels", "UserID VARCHAR(128)", "Level INT", "EXP INT");
|
||||
@@ -40,14 +44,12 @@ internal class LevelEvent : IDbEvent
|
||||
if (!await Database.TableExistsAsync("Users"))
|
||||
await Database.CreateTableAsync("Users", "UserID VARCHAR(128)", "UserMention VARCHAR(128)", "Username VARCHAR(128)", "Discriminator VARCHAR(128)");
|
||||
|
||||
|
||||
|
||||
client.MessageReceived += ClientOnMessageReceived;
|
||||
args.Client.MessageReceived += (message) => ClientOnMessageReceived(message, args.BotPrefix);
|
||||
}
|
||||
|
||||
private async Task ClientOnMessageReceived(SocketMessage arg)
|
||||
private async Task ClientOnMessageReceived(SocketMessage arg, string botPrefix)
|
||||
{
|
||||
if (arg.Author.IsBot || arg.IsTTS || arg.Content.StartsWith(Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("prefix")))
|
||||
if (arg.Author.IsBot || arg.IsTTS || arg.Content.StartsWith(botPrefix))
|
||||
return;
|
||||
|
||||
if (WaitingList.ContainsKey(arg.Author.Id) && WaitingList[arg.Author.Id] > DateTime.Now.AddSeconds(-GlobalSettings.SecondsToWaitBetweenMessages))
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\DiscordBotCore\DiscordBotCore.csproj" />
|
||||
<ProjectReference Include="..\..\DiscordBotCore.Database.Sqlite\DiscordBotCore.Database.Sqlite.csproj" />
|
||||
<ProjectReference Include="..\..\DiscordBotCore.Logging\DiscordBotCore.Logging.csproj" />
|
||||
<ProjectReference Include="..\..\DiscordBotCore.PluginCore\DiscordBotCore.PluginCore.csproj" />
|
||||
<ProjectReference Include="..\..\DiscordBotCore.Utilities\DiscordBotCore.Utilities.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Others;
|
||||
using DiscordBotCore.Others.Actions;
|
||||
|
||||
namespace LevelingSystem;
|
||||
|
||||
public class ReloadAction: ICommandAction
|
||||
{
|
||||
public string ActionName => "LevelingSystemReload";
|
||||
public string? Description => "Reloads the Leveling System config file";
|
||||
public string? Usage => "LevelingSystemReload";
|
||||
public InternalActionRunType RunType => InternalActionRunType.OnCall;
|
||||
public bool RequireOtherThread => false;
|
||||
public IEnumerable<InternalActionOption> ListOfOptions => [];
|
||||
|
||||
public async Task Execute(string[]? args)
|
||||
{
|
||||
Variables.GlobalSettings = await JsonManager.ConvertFromJson<Settings>(Variables.DataFolder + "Settings.txt");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using DiscordBotCore;
|
||||
using DiscordBotCore.Database;
|
||||
using DiscordBotCore.Database.Sqlite;
|
||||
|
||||
namespace LevelingSystem;
|
||||
|
||||
@@ -12,8 +11,8 @@ public class Settings
|
||||
|
||||
internal static class Variables
|
||||
{
|
||||
internal static readonly string DataFolder = Application.GetResourceFullPath("LevelingSystem/");
|
||||
internal static SqlDatabase? Database;
|
||||
internal static readonly Dictionary<ulong, DateTime> WaitingList = new();
|
||||
internal static Settings GlobalSettings = new();
|
||||
}
|
||||
internal static readonly string DataFolder = "./Data/Resources/LevelingSystem/";
|
||||
internal static SqlDatabase? Database;
|
||||
internal static readonly Dictionary<ulong, DateTime> WaitingList = new();
|
||||
internal static Settings GlobalSettings = new();
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
using Discord;
|
||||
|
||||
using DiscordBotCore;
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Online;
|
||||
using DiscordBotCore.Others;
|
||||
using Discord;
|
||||
using DiscordBotCore.Networking;
|
||||
using DiscordBotCore.PluginCore.Helpers.Execution.DbCommand;
|
||||
using DiscordBotCore.PluginCore.Interfaces;
|
||||
|
||||
namespace MusicPlayer.Commands;
|
||||
|
||||
@@ -20,7 +19,7 @@ public class AddMelody: IDbCommand
|
||||
public string Usage => "add_melody [title],[description?],[aliases],[byteSize]";
|
||||
public bool RequireAdmin => false;
|
||||
|
||||
public async void ExecuteServer(DbCommandExecutingArguments args)
|
||||
public async void ExecuteServer(IDbCommandExecutingArgument args)
|
||||
{
|
||||
var arguments = string.Join(" ", args.Arguments);
|
||||
string[] split = arguments.Split(',');
|
||||
@@ -68,19 +67,19 @@ public class AddMelody: IDbCommand
|
||||
|
||||
IProgress<float> downloadProgress = new Progress<float>();
|
||||
|
||||
var melodiesDirectory = Path.Combine(args.PluginBaseDirectory.FullName, "Music/Melodies");
|
||||
var fileLocation = Path.Combine(melodiesDirectory, $"{title}.mp3");
|
||||
Directory.CreateDirectory(melodiesDirectory);
|
||||
FileDownloader downloader = new FileDownloader(file.Url, fileLocation);
|
||||
await downloader.DownloadFile(downloadProgress.Report);
|
||||
|
||||
var location = Application.GetResourceFullPath($"Music/Melodies/{title}.mp3");
|
||||
Directory.CreateDirectory(Application.GetResourceFullPath("Music/Melodies"));
|
||||
await ServerCom.DownloadFileAsync(file.Url, location, downloadProgress);
|
||||
|
||||
Console.WriteLine($"Done. Saved at {location}");
|
||||
|
||||
args.Logger.Log($"Melody downloaded. Saved at {fileLocation}", this);
|
||||
await msg.ModifyAsync(a => a.Content = "Done");
|
||||
|
||||
|
||||
var info = MusicInfoExtensions.CreateMusicInfo(title, location, description ?? "Unknown", aliases.ToList(), bsize);
|
||||
var info = MusicInfoExtensions.CreateMusicInfo(title, fileLocation, description ?? "Unknown", aliases.ToList(), bsize);
|
||||
|
||||
Variables._MusicDatabase?.Add(title, info);
|
||||
Variables._MusicDatabase.Add(title, info);
|
||||
|
||||
var builder = new EmbedBuilder();
|
||||
builder.Title = "A new music was successfully added !";
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\DiscordBotCore.PluginCore\DiscordBotCore.PluginCore.csproj" />
|
||||
<ProjectReference Include="..\..\DiscordBotCore\DiscordBotCore.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -25,11 +25,8 @@ public class Play: IDbSlashCommand
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
public async void ExecuteServer(SocketSlashCommand context)
|
||||
{
|
||||
|
||||
if(Variables._MusicDatabase is null)
|
||||
{
|
||||
await context.RespondAsync("Music Database is not loaded !");
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace MusicPlayer;
|
||||
|
||||
public class Variables
|
||||
{
|
||||
public static MusicDatabase? _MusicDatabase;
|
||||
public static MusicPlayer? _MusicPlayer;
|
||||
public static Dictionary<string, MusicInfo> _MusicDatabase;
|
||||
public static MusicPlayer _MusicPlayer;
|
||||
|
||||
public static IAudioClient? audioClient;
|
||||
public static IAudioClient audioClient;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user