Started implementing modular payment gateways. Implemented a basic plugin system
TODO: Add capability for plugins to modify the kestrel pipeline
This commit is contained in:
120
Moonlight/App/Services/PluginService.cs
Normal file
120
Moonlight/App/Services/PluginService.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using System.Reflection;
|
||||
using Moonlight.App.Helpers;
|
||||
using Moonlight.App.Plugins;
|
||||
using Moonlight.App.Plugins.Contexts;
|
||||
|
||||
namespace Moonlight.App.Services;
|
||||
|
||||
public class PluginService
|
||||
{
|
||||
private readonly List<MoonlightPlugin> Plugins = new();
|
||||
|
||||
public async Task Load(IServiceCollection services)
|
||||
{
|
||||
var path = PathBuilder.Dir("storage", "plugins");
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
var files = FindFiles(path)
|
||||
.Where(x => x.EndsWith(".dll"))
|
||||
.ToArray();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assembly = Assembly.LoadFile(PathBuilder.File(Directory.GetCurrentDirectory(), file));
|
||||
|
||||
int plugins = 0;
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (type.IsSubclassOf(typeof(MoonlightPlugin)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var plugin = (Activator.CreateInstance(type) as MoonlightPlugin)!;
|
||||
|
||||
// Create environment
|
||||
plugin.Context = new PluginContext()
|
||||
{
|
||||
Services = services
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await plugin.Enable();
|
||||
|
||||
// After here we can treat the plugin as successfully loaded
|
||||
plugins++;
|
||||
Plugins.Add(plugin);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Fatal($"Unhandled exception while enabling plugin '{type.Name}'");
|
||||
Logger.Fatal(e);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Fatal($"Failed to create plugin environment for '{type.Name}'");
|
||||
Logger.Fatal(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(plugins == 0) // If 0, we can assume that it was a library dll
|
||||
Logger.Info($"Loaded {file} as a library");
|
||||
else
|
||||
Logger.Info($"Loaded {plugins} plugin(s) from {file}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Fatal($"Unable to load assembly from file '{file}'");
|
||||
Logger.Fatal(e);
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Info($"Loaded {Plugins.Count} plugin(s)");
|
||||
}
|
||||
|
||||
public async Task RunPreInit()
|
||||
{
|
||||
foreach (var plugin in Plugins)
|
||||
{
|
||||
Logger.Info($"Running pre init tasks for {plugin.GetType().Name}");
|
||||
|
||||
foreach (var preInitTask in plugin.Context.PreInitTasks)
|
||||
await Task.Run(preInitTask);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RunPrePost(IServiceProvider provider)
|
||||
{
|
||||
foreach (var plugin in Plugins)
|
||||
{
|
||||
// Pass through the dependency injection
|
||||
var scope = provider.CreateScope();
|
||||
plugin.Context.Provider = scope.ServiceProvider;
|
||||
plugin.Context.Scope = scope;
|
||||
|
||||
Logger.Info($"Running post init tasks for {plugin.GetType().Name}");
|
||||
|
||||
foreach (var postInitTask in plugin.Context.PostInitTasks)
|
||||
await Task.Run(postInitTask);
|
||||
}
|
||||
}
|
||||
|
||||
private string[] FindFiles(string dir)
|
||||
{
|
||||
var result = new List<string>();
|
||||
|
||||
foreach (var file in Directory.GetFiles(dir))
|
||||
result.Add(file);
|
||||
|
||||
foreach (var directory in Directory.GetDirectories(dir))
|
||||
{
|
||||
result.AddRange(FindFiles(directory));
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user