Added Core module support. Things are unstable
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
using DiscordBotCore.Online;
|
||||
using DiscordBotCore.Others;
|
||||
using DiscordBotCore.Others.Actions;
|
||||
using DiscordBotCore.Others.Logger;
|
||||
using DiscordBotCore.Plugin;
|
||||
|
||||
using System;
|
||||
@@ -10,6 +9,12 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using DiscordBotCore.Others.Exceptions;
|
||||
using DiscordBotCore.Loaders;
|
||||
using DiscordBotCore.Interfaces.Modules;
|
||||
using DiscordBotCore.Interfaces.Logger;
|
||||
using DiscordBotCore.Modules;
|
||||
using System.Linq;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
|
||||
namespace DiscordBotCore
|
||||
@@ -21,9 +26,9 @@ namespace DiscordBotCore
|
||||
{
|
||||
public static Application CurrentApplication { get; private set; } = null!;
|
||||
|
||||
private static readonly string _DefaultLogMessageFormat = "{ThrowTime} {SenderName} {Message}";
|
||||
private static readonly string _ConfigFile = "./Data/Resources/config.json";
|
||||
private static readonly string _PluginsDatabaseFile = "./Data/Resources/plugins.json";
|
||||
private static readonly string _ModuleFolder = "./Data/Modules";
|
||||
|
||||
private static readonly string _ResourcesFolder = "./Data/Resources";
|
||||
private static readonly string _PluginsFolder = "./Data/Plugins";
|
||||
@@ -36,10 +41,13 @@ namespace DiscordBotCore
|
||||
public string PluginDatabase => ApplicationEnvironmentVariables["PluginDatabase"] ?? _PluginsDatabaseFile;
|
||||
public string LogFile => $"{ApplicationEnvironmentVariables["LogFolder"]}/{DateTime.Now.ToLongDateString().Replace(" / ", "")}.log";
|
||||
|
||||
private ModuleManager _ModuleManager;
|
||||
|
||||
public SettingsDictionary<string, string> ApplicationEnvironmentVariables { get; private set; }
|
||||
public InternalActionManager InternalActionManager { get; private set; }
|
||||
|
||||
public ILogger Logger => _ModuleManager.GetModule<ILogger>();
|
||||
public IPluginManager PluginManager { get; private set; }
|
||||
public Logger Logger { get; private set; }
|
||||
public Bot.App DiscordBotClient { get; internal set; }
|
||||
|
||||
public static async Task CreateApplication()
|
||||
@@ -63,9 +71,10 @@ namespace DiscordBotCore
|
||||
await CurrentApplication.ApplicationEnvironmentVariables.SaveToFile();
|
||||
}
|
||||
|
||||
CurrentApplication.Logger = CurrentApplication.ApplicationEnvironmentVariables.ContainsKey("LogMessageFormat") ?
|
||||
new Logger(CurrentApplication.ApplicationEnvironmentVariables["LogMessageFormat"]) :
|
||||
new Logger(_DefaultLogMessageFormat);
|
||||
CurrentApplication.ApplicationEnvironmentVariables.Add("ModuleFolder", _ModuleFolder);
|
||||
|
||||
CurrentApplication._ModuleManager = new(_ModuleFolder);
|
||||
await CurrentApplication._ModuleManager.LoadModules();
|
||||
|
||||
if (!File.Exists(_PluginsDatabaseFile))
|
||||
{
|
||||
@@ -88,6 +97,7 @@ namespace DiscordBotCore
|
||||
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<Type, List<object>> GetLoadedCoreModules() => _ModuleManager.LoadedModules.AsReadOnly();
|
||||
|
||||
private static void PopulateEnvWithDefault()
|
||||
{
|
||||
@@ -102,7 +112,6 @@ namespace DiscordBotCore
|
||||
CurrentApplication.ApplicationEnvironmentVariables["PluginFolder"] = _PluginsFolder;
|
||||
CurrentApplication.ApplicationEnvironmentVariables["ArchiveFolder"] = _ArchivesFolder;
|
||||
CurrentApplication.ApplicationEnvironmentVariables["PluginDatabase"] = _PluginsDatabaseFile;
|
||||
CurrentApplication.ApplicationEnvironmentVariables["LogMessageFormat"] = _DefaultLogMessageFormat;
|
||||
CurrentApplication.ApplicationEnvironmentVariables["MaxParallelDownloads"] = _MaxParallelDownloads;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,29 @@
|
||||
using DiscordBotCore.Others;
|
||||
using DiscordBotCore.Interfaces.Modules;
|
||||
using DiscordBotCore.Others;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DiscordBotCore.Interfaces.Logger
|
||||
{
|
||||
public interface ILogger
|
||||
public interface ILogger : IBaseModule
|
||||
{
|
||||
public struct FormattedMessage { public string Message; public LogType Type; }
|
||||
public string LogMessageFormat { get; set; }
|
||||
public struct FormattedMessage {
|
||||
public string Message;
|
||||
public LogType Type;
|
||||
}
|
||||
|
||||
public void Log(ILogMessage message);
|
||||
public void LogException(Exception exception, object Sender, bool logFullStack = false);
|
||||
string LogMessageFormat { get; set; }
|
||||
|
||||
public event EventHandler<FormattedMessage> OnFormattedLog;
|
||||
public event EventHandler<ILogMessage> OnRawLog;
|
||||
event EventHandler<FormattedMessage> OnFormattedLog;
|
||||
event EventHandler<ILogMessage> OnRawLog;
|
||||
|
||||
void Log(ILogMessage message);
|
||||
void Log(ILogMessage message, string format);
|
||||
void Log(string message);
|
||||
void Log(string message, LogType logType);
|
||||
void Log(string message, LogType logType, string format);
|
||||
void Log(string message, object Sender);
|
||||
void Log(string message, object Sender, LogType type);
|
||||
void LogException(Exception exception, object Sender, bool logFullStack = false);
|
||||
}
|
||||
}
|
||||
|
||||
8
DiscordBotCore/Interfaces/Modules/IBaseModule.cs
Normal file
8
DiscordBotCore/Interfaces/Modules/IBaseModule.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace DiscordBotCore.Interfaces.Modules
|
||||
{
|
||||
public interface IBaseModule
|
||||
{
|
||||
}
|
||||
}
|
||||
11
DiscordBotCore/Interfaces/Modules/IModule.cs
Normal file
11
DiscordBotCore/Interfaces/Modules/IModule.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DiscordBotCore.Interfaces.Modules
|
||||
{
|
||||
public interface IModule<T> where T : IBaseModule
|
||||
{
|
||||
public string Name { get; }
|
||||
public T Module { get; }
|
||||
public Task Initialize();
|
||||
}
|
||||
}
|
||||
70
DiscordBotCore/Loaders/ModuleLoader.cs
Normal file
70
DiscordBotCore/Loaders/ModuleLoader.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DiscordBotCore.Interfaces.Modules;
|
||||
using System.Reflection;
|
||||
using Discord.Commands;
|
||||
|
||||
namespace DiscordBotCore.Loaders
|
||||
{
|
||||
internal class ModuleLoader
|
||||
{
|
||||
private string _moduleFolder;
|
||||
|
||||
public ModuleLoader(string moduleFolder)
|
||||
{
|
||||
_moduleFolder = moduleFolder;
|
||||
}
|
||||
|
||||
public Task LoadFileModules()
|
||||
{
|
||||
var files = Directory.GetFiles(_moduleFolder, "*.dll");
|
||||
foreach (var file in files)
|
||||
{
|
||||
try
|
||||
{
|
||||
Assembly.LoadFrom(file);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Error loading module {file}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<List<IModule<T>>> LoadModules<T>() where T : IBaseModule
|
||||
{
|
||||
var moduleType = typeof(IModule<T>);
|
||||
var moduleTypes = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(s => s.GetTypes())
|
||||
.Where(p => moduleType.IsAssignableFrom(p) && !p.IsInterface);
|
||||
|
||||
var modules = new List<IModule<T>>();
|
||||
foreach (var module in moduleTypes)
|
||||
{
|
||||
try
|
||||
{
|
||||
var instance = (IModule<T>?)Activator.CreateInstance(module);
|
||||
if (instance == null)
|
||||
{
|
||||
Console.WriteLine($"Error loading module {module.Name}: Could not create instance");
|
||||
continue;
|
||||
}
|
||||
|
||||
modules.Add(instance);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Error loading module {module.Name}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(modules);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
DiscordBotCore/Modules/ModuleManager.cs
Normal file
52
DiscordBotCore/Modules/ModuleManager.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DiscordBotCore.Interfaces.Logger;
|
||||
using DiscordBotCore.Interfaces.Modules;
|
||||
using DiscordBotCore.Loaders;
|
||||
|
||||
namespace DiscordBotCore.Modules
|
||||
{
|
||||
internal class ModuleManager
|
||||
{
|
||||
private string _moduleFolder;
|
||||
internal Dictionary<Type, List<object>> LoadedModules { get; private set; }
|
||||
|
||||
public ModuleManager(string moduleFolder)
|
||||
{
|
||||
_moduleFolder = moduleFolder;
|
||||
LoadedModules = new Dictionary<Type, List<object>>();
|
||||
}
|
||||
|
||||
public T GetModule<T>() where T : IBaseModule
|
||||
{
|
||||
if(!LoadedModules.ContainsKey(typeof(T)))
|
||||
throw new Exception($"No module loaded with this signature: {nameof(T)}");
|
||||
|
||||
IModule<T> module = (IModule<T>)LoadedModules[typeof(T)][0];
|
||||
return module.Module;
|
||||
}
|
||||
|
||||
public async Task LoadModules()
|
||||
{
|
||||
ModuleLoader loader = new ModuleLoader(_moduleFolder);
|
||||
await loader.LoadFileModules();
|
||||
|
||||
|
||||
// Load All Loggers
|
||||
var loggers = await loader.LoadModules<ILogger>();
|
||||
foreach (var logger in loggers)
|
||||
{
|
||||
await logger.Initialize();
|
||||
Console.WriteLine("Module Loaded: " + logger.Name);
|
||||
}
|
||||
|
||||
LoadedModules.Add(typeof(ILogger), loggers.Cast<object>().ToList());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
using DiscordBotCore.Interfaces.Logger;
|
||||
|
||||
using System;
|
||||
|
||||
namespace DiscordBotCore.Others.Logger
|
||||
{
|
||||
internal sealed class LogMessage : ILogMessage
|
||||
{
|
||||
private static readonly string _DefaultLogMessageSender = "\b";
|
||||
public string Message { get; set; }
|
||||
public DateTime ThrowTime { get; set; }
|
||||
public string SenderName { get; set; }
|
||||
public LogType LogMessageType { get; set; }
|
||||
|
||||
public LogMessage(string message, LogType logMessageType)
|
||||
{
|
||||
Message = message;
|
||||
LogMessageType = logMessageType;
|
||||
ThrowTime = DateTime.Now;
|
||||
SenderName = string.Empty;
|
||||
}
|
||||
|
||||
public LogMessage(string message, object sender)
|
||||
{
|
||||
Message = message;
|
||||
SenderName = sender is string && sender as string == string.Empty ? _DefaultLogMessageSender : sender.GetType().FullName ?? sender.GetType().Name;
|
||||
ThrowTime = DateTime.Now;
|
||||
LogMessageType = LogType.INFO;
|
||||
}
|
||||
|
||||
public LogMessage(string message, object sender, DateTime throwTime)
|
||||
{
|
||||
Message = message;
|
||||
SenderName = sender is string && sender as string == string.Empty ? _DefaultLogMessageSender : sender.GetType().FullName ?? sender.GetType().Name;
|
||||
ThrowTime = throwTime;
|
||||
LogMessageType = LogType.INFO;
|
||||
}
|
||||
|
||||
public LogMessage(string message, object sender, LogType logMessageType)
|
||||
{
|
||||
Message = message;
|
||||
SenderName = sender is string && sender as string == string.Empty ? _DefaultLogMessageSender : 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 is string && sender as string == string.Empty ? _DefaultLogMessageSender : 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, bool logFullStack)
|
||||
{
|
||||
LogMessage message = new LogMessage(logFullStack? exception.ToString() : exception.Message, Sender, LogType.ERROR);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using DiscordBotCore.Interfaces.Logger;
|
||||
|
||||
namespace DiscordBotCore.Others.Logger;
|
||||
|
||||
public sealed class Logger : ILogger
|
||||
{
|
||||
private readonly FileStream _LogFileStream;
|
||||
|
||||
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;
|
||||
_LogFileStream = File.Open(Application.CurrentApplication.LogFile, FileMode.Append, FileAccess.Write, FileShare.Read);
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
|
||||
private async void LogToFile(string message)
|
||||
{
|
||||
byte[] messageAsBytes = System.Text.Encoding.ASCII.GetBytes(message);
|
||||
await _LogFileStream.WriteAsync(messageAsBytes, 0, messageAsBytes.Length);
|
||||
|
||||
byte[] newLine = System.Text.Encoding.ASCII.GetBytes(Environment.NewLine);
|
||||
await _LogFileStream.WriteAsync(newLine, 0, newLine.Length);
|
||||
|
||||
await _LogFileStream.FlushAsync();
|
||||
}
|
||||
|
||||
private string GenerateLogMessage(ILogMessage message, string customFormat)
|
||||
{
|
||||
string messageAsString = customFormat;
|
||||
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, string format)
|
||||
{
|
||||
OnRawLog?.Invoke(this, message);
|
||||
string messageAsString = GenerateLogMessage(message, format);
|
||||
OnFormattedLog?.Invoke(this, new ILogger.FormattedMessage() { Message = messageAsString, Type = message.LogMessageType });
|
||||
LogToFile(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 }) ;
|
||||
LogToFile(messageAsString);
|
||||
|
||||
}
|
||||
|
||||
public void Log(string message) => Log(new LogMessage(message, string.Empty, LogType.INFO));
|
||||
public void Log(string message, LogType logType, string format) => Log(new LogMessage(message, logType), format);
|
||||
public void Log(string message, LogType logType) => Log(new LogMessage(message, logType));
|
||||
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, bool logFullStack = false) => Log(LogMessage.CreateFromException(exception, Sender, logFullStack));
|
||||
}
|
||||
@@ -58,6 +58,9 @@ public class SettingsDictionary<TKey, TValue>
|
||||
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
if (_Dictionary.ContainsKey(key))
|
||||
return;
|
||||
|
||||
_Dictionary.Add(key, value);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user