First steps to Web UI
This commit is contained in:
@@ -32,6 +32,7 @@ namespace DiscordBotCore
|
||||
/// <summary>
|
||||
/// Defines the current application. This is a singleton class
|
||||
/// </summary>
|
||||
|
||||
public static Application CurrentApplication { get; private set; } = null!;
|
||||
|
||||
private static readonly string _ConfigFile = "./Data/Resources/config.json";
|
||||
@@ -41,7 +42,7 @@ namespace DiscordBotCore
|
||||
private static readonly string _PluginsFolder = "./Data/Plugins";
|
||||
private static readonly string _LogsFolder = "./Data/Logs";
|
||||
|
||||
private ModuleManager _ModuleManager = null!;
|
||||
public ModuleManager ModuleManager = null!;
|
||||
public DiscordBotApplication DiscordBotClient { get; set; } = null!;
|
||||
|
||||
public List<ulong> ServerIDs => ApplicationEnvironmentVariables.GetList("ServerID", new List<ulong>());
|
||||
@@ -53,7 +54,8 @@ namespace DiscordBotCore
|
||||
/// <summary>
|
||||
/// Create the application. This method is used to initialize the application. Can not initialize multiple times.
|
||||
/// </summary>
|
||||
public static async Task CreateApplication()
|
||||
/// <param name="moduleRequirementsSolver">A function that will be called when a module is required to be installed. If set to default, will use the built in method(console)</param>
|
||||
public static async Task CreateApplication(Func<ModuleRequirement, Task>? moduleRequirementsSolver)
|
||||
{
|
||||
if (!await OnlineFunctions.IsInternetConnected())
|
||||
{
|
||||
@@ -78,10 +80,15 @@ namespace DiscordBotCore
|
||||
CurrentApplication.ApplicationEnvironmentVariables.Add("ResourceFolder", _ResourcesFolder);
|
||||
CurrentApplication.ApplicationEnvironmentVariables.Add("LogsFolder", _LogsFolder);
|
||||
|
||||
CurrentApplication._ModuleManager = new ModuleManager();
|
||||
await CurrentApplication._ModuleManager.LoadModules();
|
||||
var requirements = await CurrentApplication._ModuleManager.CheckRequiredModules();
|
||||
await CurrentApplication._ModuleManager.SolveRequirementIssues(requirements);
|
||||
CurrentApplication.ModuleManager = new ModuleManager();
|
||||
await CurrentApplication.ModuleManager.LoadModules();
|
||||
var requirements = await CurrentApplication.ModuleManager.CheckRequiredModules();
|
||||
if(requirements.RequireAny)
|
||||
{
|
||||
moduleRequirementsSolver ??= requirement => CurrentApplication.ModuleManager.SolveRequirementIssues(requirement);
|
||||
await moduleRequirementsSolver(requirements);
|
||||
}
|
||||
|
||||
|
||||
if (!File.Exists(_PluginsDatabaseFile))
|
||||
{
|
||||
@@ -100,6 +107,24 @@ namespace DiscordBotCore
|
||||
CurrentApplication.InternalActionManager = new InternalActionManager();
|
||||
await CurrentApplication.InternalActionManager.Initialize();
|
||||
}
|
||||
|
||||
public static async Task InvokeMethod(string moduleName, string methodFriendlyName, params object[] parameters)
|
||||
{
|
||||
var module = CurrentApplication.ModuleManager.GetModule(moduleName);
|
||||
var methodName = module.Value.MethodMapping[methodFriendlyName];
|
||||
|
||||
await CurrentApplication.ModuleManager.InvokeMethod(module.Value, methodName, parameters);
|
||||
}
|
||||
|
||||
public static async Task<object?> InvokeMethodWithReturnValue(string moduleName, string methodFriendlyName, params object[] parameters)
|
||||
{
|
||||
var module = CurrentApplication.ModuleManager.GetModule(moduleName).Value;
|
||||
var methodName = module.MethodMapping[methodFriendlyName];
|
||||
|
||||
var response = await CurrentApplication.ModuleManager.InvokeMethodWithReturnValue(module, methodName, parameters);
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A special class that is designed to log messages. It is a wrapper around the Logger module
|
||||
/// The logger module is required to have this specific methods:
|
||||
@@ -117,54 +142,52 @@ namespace DiscordBotCore
|
||||
/// </summary>
|
||||
public static class Logger
|
||||
{
|
||||
private static readonly KeyValuePair<ModuleData, IModule> _LoggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger);
|
||||
private static readonly LoadedModule _LoggerModule = CurrentApplication.ModuleManager.GetLoadedModuleWithTag(ModuleType.Logger);
|
||||
public static async void LogException(Exception ex, object sender, bool fullStackTrace = false)
|
||||
{
|
||||
await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["BaseLogException"], [ex, sender, fullStackTrace]);
|
||||
await CurrentApplication.ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["BaseLogException"], [ex, sender, fullStackTrace]);
|
||||
}
|
||||
|
||||
public static async void Log(string message)
|
||||
{
|
||||
await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["BaseLog"], [message]);
|
||||
await CurrentApplication.ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["BaseLog"], [message]);
|
||||
}
|
||||
|
||||
public static async void Log(string message, LogType logType, string format)
|
||||
{
|
||||
await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithTypeAndFormat"], [message, logType, format]);
|
||||
await CurrentApplication.ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithTypeAndFormat"], [message, logType, format]);
|
||||
}
|
||||
|
||||
public static async void Log(string message, LogType logType)
|
||||
{
|
||||
await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithType"], [message, logType]);
|
||||
await CurrentApplication.ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithType"], [message, logType]);
|
||||
}
|
||||
|
||||
public static async void Log(string message, object sender)
|
||||
{
|
||||
await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithSender"], [message, sender]);
|
||||
await CurrentApplication.ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithSender"], [message, sender]);
|
||||
}
|
||||
|
||||
public static async void Log(string message, object sender, LogType type)
|
||||
{
|
||||
await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithTypeAndSender"], [message, sender, type]);
|
||||
await CurrentApplication.ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithTypeAndSender"], [message, sender, type]);
|
||||
}
|
||||
|
||||
public static async void SetOutFunction(Action<string> outFunction)
|
||||
{
|
||||
await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["SetPrintFunction"], [outFunction]);
|
||||
await CurrentApplication.ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["SetPrintFunction"], [outFunction]);
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyDictionary<ModuleData, IModule> GetLoadedCoreModules() => _ModuleManager.Modules.AsReadOnly();
|
||||
|
||||
public static string GetResourceFullPath(string path)
|
||||
{
|
||||
string result = Path.Combine(_ResourcesFolder, path);
|
||||
var result = Path.Combine(_ResourcesFolder, path);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string GetPluginFullPath(string path)
|
||||
{
|
||||
string result = Path.Combine(_PluginsFolder, path);
|
||||
var result = Path.Combine(_PluginsFolder, path);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,10 +100,6 @@ public class DiscordBotApplication
|
||||
Application.CurrentApplication.ApplicationEnvironmentVariables.Remove("token");
|
||||
Application.Logger.Log("The token is invalid.", this, LogType.Critical);
|
||||
await Application.CurrentApplication.ApplicationEnvironmentVariables.SaveToFile();
|
||||
await Task.Delay(3000);
|
||||
|
||||
Process.Start(Environment.ProcessPath);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,22 +13,39 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace DiscordBotCore.Modules
|
||||
{
|
||||
internal class ModuleManager
|
||||
|
||||
public class LoadedModule
|
||||
{
|
||||
public IModule Value { get; init; }
|
||||
public ModuleData ModuleData { get; init; }
|
||||
public LoadedModule(IModule module, ModuleData moduleData)
|
||||
{
|
||||
Value = module;
|
||||
ModuleData = moduleData;
|
||||
}
|
||||
}
|
||||
|
||||
public class ModuleManager
|
||||
{
|
||||
private static readonly string _BaseModuleFolder = "./Data/Modules";
|
||||
private static readonly string _BaseModuleConfig = "./Data/Resources/modules.json";
|
||||
|
||||
private const string _ModuleDatabase = "https://raw.githubusercontent.com/andreitdr/SethPlugins/tests/modules.json";
|
||||
|
||||
internal Dictionary<ModuleData, IModule> Modules { get; set; }
|
||||
|
||||
public ModuleManager()
|
||||
private List<LoadedModule> Modules { get; }
|
||||
|
||||
public IEnumerable<ModuleData> GetLocalModules()
|
||||
{
|
||||
Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("ModuleFolder", _BaseModuleFolder);
|
||||
Modules = new Dictionary<ModuleData, IModule>();
|
||||
return Modules.Select(module => module.ModuleData);
|
||||
}
|
||||
|
||||
public async Task<List<ModuleOnlineData>> GetAllModules(ModuleType? moduleTypeFilter = null)
|
||||
internal ModuleManager()
|
||||
{
|
||||
Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("ModuleFolder", _BaseModuleFolder);
|
||||
Modules = new();
|
||||
}
|
||||
|
||||
public async Task<List<ModuleOnlineData>> ServerGetAllModules(ModuleType? moduleTypeFilter = null)
|
||||
{
|
||||
string jsonDatabaseRemote = await ServerCom.GetAllTextFromUrl(_ModuleDatabase);
|
||||
|
||||
@@ -49,7 +66,7 @@ namespace DiscordBotCore.Modules
|
||||
|
||||
Directory.CreateDirectory(moduleFolder);
|
||||
|
||||
List<ModuleOnlineData> modules = await GetAllModules();
|
||||
List<ModuleOnlineData> modules = await ServerGetAllModules();
|
||||
|
||||
string url = modules.Find(m => m.ModuleName == moduleName)?.ModuleDownloadUrl ?? string.Empty;
|
||||
|
||||
@@ -64,11 +81,11 @@ namespace DiscordBotCore.Modules
|
||||
await AddModuleToDatabase(localModuleData);
|
||||
}
|
||||
|
||||
public KeyValuePair<ModuleData, IModule> GetModule(string moduleName)
|
||||
public LoadedModule GetModule(string moduleName)
|
||||
{
|
||||
var result = Modules.FirstOrDefault(module => module.Key.ModuleName == moduleName);
|
||||
var result = Modules.FirstOrDefault(module => module.ModuleData.ModuleName == moduleName);
|
||||
|
||||
if (result.Value is null || result.Key is null)
|
||||
if(result is null)
|
||||
{
|
||||
throw new ModuleNotFound(moduleName);
|
||||
}
|
||||
@@ -76,11 +93,11 @@ namespace DiscordBotCore.Modules
|
||||
return result;
|
||||
}
|
||||
|
||||
public KeyValuePair<ModuleData, IModule> GetModule(ModuleType moduleType)
|
||||
public LoadedModule GetLoadedModuleWithTag(ModuleType moduleType)
|
||||
{
|
||||
var result = Modules.FirstOrDefault(module => module.Value.ModuleType == moduleType);
|
||||
|
||||
if (result.Value is null || result.Key is null)
|
||||
if(result is null)
|
||||
{
|
||||
throw new ModuleNotFound(moduleType);
|
||||
}
|
||||
@@ -112,27 +129,27 @@ namespace DiscordBotCore.Modules
|
||||
await File.WriteAllTextAsync(moduleConfigPath, json);
|
||||
}
|
||||
|
||||
public Task<RequireInstallModule> CheckRequiredModules()
|
||||
internal Task<ModuleRequirement> CheckRequiredModules()
|
||||
{
|
||||
RequireInstallModule requireInstallModule = new RequireInstallModule();
|
||||
if (!Modules.Any(module => module.Value.ModuleType == ModuleType.Logger))
|
||||
ModuleRequirement moduleRequirement = new ModuleRequirement();
|
||||
if (Modules.All(module => module.Value.ModuleType != ModuleType.Logger))
|
||||
{
|
||||
requireInstallModule.AddType(ModuleType.Logger);
|
||||
moduleRequirement.AddType(ModuleType.Logger);
|
||||
}
|
||||
|
||||
return Task.FromResult(requireInstallModule);
|
||||
return Task.FromResult(moduleRequirement);
|
||||
}
|
||||
|
||||
public async Task SolveRequirementIssues(RequireInstallModule requirements)
|
||||
internal async Task SolveRequirementIssues(ModuleRequirement requirements)
|
||||
{
|
||||
if (!requirements.RequireAny)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var module in requirements.RequiredModules)
|
||||
foreach (var module in requirements.RequiredModulesWithTypes)
|
||||
{
|
||||
var availableModules = await GetAllModules(module);
|
||||
var availableModules = await ServerGetAllModules(module);
|
||||
|
||||
Console.WriteLine("Please select a module of type " + module);
|
||||
for (var i = 0; i < availableModules.Count; i++)
|
||||
@@ -162,7 +179,7 @@ namespace DiscordBotCore.Modules
|
||||
System.Diagnostics.Process.Start(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName);
|
||||
}
|
||||
|
||||
public async Task LoadModules()
|
||||
internal async Task LoadModules()
|
||||
{
|
||||
string moduleConfigPath = Application.CurrentApplication.ApplicationEnvironmentVariables
|
||||
.Get<string>("ModuleConfig", _BaseModuleConfig);
|
||||
@@ -199,7 +216,7 @@ namespace DiscordBotCore.Modules
|
||||
{
|
||||
try{
|
||||
await module.Initialize();
|
||||
Modules.Add(moduleData, module);
|
||||
Modules.Add(new LoadedModule(module, moduleData));
|
||||
}catch(Exception e){
|
||||
Console.WriteLine($"Error loading module {moduleData.ModuleName}: {e.Message}");
|
||||
}
|
||||
@@ -207,7 +224,7 @@ namespace DiscordBotCore.Modules
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<object?> InvokeMethodWithReturnValue(string moduleName, string methodName, object[] parameters)
|
||||
internal async Task<object?> InvokeMethodWithReturnValue(string moduleName, string methodName, object[] parameters)
|
||||
{
|
||||
IModule module = GetModule(moduleName).Value;
|
||||
var method = module.GetType().GetMethod(methodName);
|
||||
@@ -222,7 +239,7 @@ namespace DiscordBotCore.Modules
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<object?> InvokeMethodWithReturnValue(IModule module, string methodName, object[] parameters)
|
||||
internal async Task<object?> InvokeMethodWithReturnValue(IModule module, string methodName, object[] parameters)
|
||||
{
|
||||
var method = module.GetType().GetMethod(methodName);
|
||||
|
||||
@@ -237,7 +254,7 @@ namespace DiscordBotCore.Modules
|
||||
}
|
||||
|
||||
|
||||
public async Task InvokeMethod(string moduleName, string methodName, object[] parameters)
|
||||
internal async Task InvokeMethod(string moduleName, string methodName, object[] parameters)
|
||||
{
|
||||
IModule module = GetModule(moduleName).Value;
|
||||
var method = module.GetType().GetMethod(methodName);
|
||||
@@ -250,7 +267,7 @@ namespace DiscordBotCore.Modules
|
||||
await Task.Run(() => method.Invoke(module, parameters));
|
||||
}
|
||||
|
||||
public async Task InvokeMethod(IModule module, string methodName, object[] parameters)
|
||||
internal async Task InvokeMethod(IModule module, string methodName, object[] parameters)
|
||||
{
|
||||
var method = module.GetType().GetMethod(methodName);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DiscordBotCore.Others;
|
||||
@@ -34,7 +35,6 @@ public static class ArchiveManager
|
||||
/// <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[]?> ReadAllBytes(string fileName, string archName)
|
||||
{
|
||||
|
||||
string? archiveFolderBasePath = Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("ArchiveFolder", _ArchivesFolder);
|
||||
if(archiveFolderBasePath is null)
|
||||
throw new Exception("Archive folder not found");
|
||||
|
||||
31
DiscordBotCore/Others/Exceptions/ModuleRequirement.cs
Normal file
31
DiscordBotCore/Others/Exceptions/ModuleRequirement.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using DiscordBotCore.Interfaces.Modules;
|
||||
using DiscordBotCore.Modules;
|
||||
|
||||
namespace DiscordBotCore.Others.Exceptions;
|
||||
|
||||
public class ModuleRequirement
|
||||
{
|
||||
private List<ModuleType> RequiredModulesWithType { get; }
|
||||
private List<string> RequiredModulesWithName { get; }
|
||||
|
||||
public ModuleRequirement()
|
||||
{
|
||||
RequiredModulesWithType = new List<ModuleType>();
|
||||
RequiredModulesWithName = new List<string>();
|
||||
}
|
||||
|
||||
public void AddType (ModuleType moduleType)
|
||||
{
|
||||
RequiredModulesWithType.Add(moduleType);
|
||||
}
|
||||
|
||||
public void AddName (string moduleName)
|
||||
{
|
||||
RequiredModulesWithName.Add(moduleName);
|
||||
}
|
||||
|
||||
public bool RequireAny => RequiredModulesWithType.Count > 0 || RequiredModulesWithName.Count > 0;
|
||||
public IList<ModuleType> RequiredModulesWithTypes => RequiredModulesWithType ;
|
||||
public IList<string> RequiredModulesWithNames => RequiredModulesWithName;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using DiscordBotCore.Interfaces.Modules;
|
||||
using DiscordBotCore.Modules;
|
||||
|
||||
namespace DiscordBotCore.Others.Exceptions;
|
||||
|
||||
public class RequireInstallModule
|
||||
{
|
||||
private List<ModuleType> RequiredModulesWithType { get; }
|
||||
|
||||
public RequireInstallModule()
|
||||
{
|
||||
RequiredModulesWithType = new List<ModuleType>();
|
||||
}
|
||||
|
||||
public void AddType (ModuleType moduleType)
|
||||
{
|
||||
RequiredModulesWithType.Add(moduleType);
|
||||
}
|
||||
|
||||
public bool RequireAny => RequiredModulesWithType.Count > 0;
|
||||
public IList<ModuleType> RequiredModules => RequiredModulesWithType;
|
||||
}
|
||||
Reference in New Issue
Block a user