Finished compile time plugin loading. Refactored plugin loading. Extended build helper script
This commit is contained in:
@@ -1,13 +1,10 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Hangfire;
|
||||
using Hangfire.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using MoonCore.Configuration;
|
||||
using MoonCore.EnvConfiguration;
|
||||
using MoonCore.Extended.Abstractions;
|
||||
using MoonCore.Extended.Extensions;
|
||||
@@ -15,15 +12,14 @@ using MoonCore.Extended.Helpers;
|
||||
using MoonCore.Extended.JwtInvalidation;
|
||||
using MoonCore.Extensions;
|
||||
using MoonCore.Helpers;
|
||||
using MoonCore.Services;
|
||||
using Moonlight.ApiServer.Configuration;
|
||||
using Moonlight.ApiServer.Database;
|
||||
using Moonlight.ApiServer.Database.Entities;
|
||||
using Moonlight.ApiServer.Helpers;
|
||||
using Moonlight.ApiServer.Implementations;
|
||||
using Moonlight.ApiServer.Implementations.Startup;
|
||||
using Moonlight.ApiServer.Interfaces;
|
||||
using Moonlight.ApiServer.Interfaces.Startup;
|
||||
using Moonlight.ApiServer.Models;
|
||||
using Moonlight.ApiServer.Plugins;
|
||||
using Moonlight.ApiServer.Services;
|
||||
|
||||
namespace Moonlight.ApiServer;
|
||||
@@ -34,8 +30,6 @@ namespace Moonlight.ApiServer;
|
||||
public class Startup
|
||||
{
|
||||
private string[] Args;
|
||||
private Assembly[] AdditionalAssemblies;
|
||||
private PluginManifest[] AdditionalPluginManifests;
|
||||
|
||||
// Logging
|
||||
private ILoggerProvider[] LoggerProviders;
|
||||
@@ -51,24 +45,20 @@ public class Startup
|
||||
private WebApplicationBuilder WebApplicationBuilder;
|
||||
|
||||
// Plugin Loading
|
||||
private PluginService PluginService;
|
||||
private AssemblyLoadContext PluginLoadContext;
|
||||
|
||||
private IPluginStartup[] PluginStartups;
|
||||
private IPluginStartup[] AdditionalPlugins;
|
||||
private IServiceProvider PluginLoadServiceProvider;
|
||||
|
||||
public async Task Run(string[] args, Assembly[]? additionalAssemblies = null,
|
||||
PluginManifest[]? additionalManifests = null)
|
||||
public async Task Run(string[] args, IPluginStartup[]? additionalPlugins = null)
|
||||
{
|
||||
Args = args;
|
||||
AdditionalAssemblies = additionalAssemblies ?? [];
|
||||
AdditionalPluginManifests = additionalManifests ?? [];
|
||||
AdditionalPlugins = additionalPlugins ?? [];
|
||||
|
||||
await PrintVersion();
|
||||
|
||||
await CreateStorage();
|
||||
await SetupAppConfiguration();
|
||||
await SetupLogging();
|
||||
await LoadPlugins();
|
||||
await InitializePlugins();
|
||||
|
||||
await CreateWebApplicationBuilder();
|
||||
@@ -139,17 +129,13 @@ public class Startup
|
||||
|
||||
// Add pre-existing services
|
||||
WebApplicationBuilder.Services.AddSingleton(Configuration);
|
||||
WebApplicationBuilder.Services.AddSingleton(PluginService);
|
||||
|
||||
// Configure controllers
|
||||
var mvcBuilder = WebApplicationBuilder.Services.AddControllers();
|
||||
|
||||
// Add plugin and additional assemblies as application parts
|
||||
foreach (var pluginAssembly in PluginLoadContext.Assemblies)
|
||||
mvcBuilder.AddApplicationPart(pluginAssembly);
|
||||
|
||||
foreach (var additionalAssembly in AdditionalAssemblies)
|
||||
mvcBuilder.AddApplicationPart(additionalAssembly);
|
||||
// Add plugin assemblies as application parts
|
||||
foreach (var pluginStartup in PluginStartups.Select(x => x.GetType().Assembly).Distinct())
|
||||
mvcBuilder.AddApplicationPart(pluginStartup.GetType().Assembly);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@@ -199,90 +185,34 @@ public class Startup
|
||||
|
||||
#region Plugin Loading
|
||||
|
||||
private async Task LoadPlugins()
|
||||
{
|
||||
// Load plugins
|
||||
PluginService = new PluginService(
|
||||
LoggerFactory.CreateLogger<PluginService>()
|
||||
);
|
||||
|
||||
// Add plugins manually if specified in the startup
|
||||
foreach (var manifest in AdditionalPluginManifests)
|
||||
PluginService.LoadedPlugins.Add(manifest, Directory.GetCurrentDirectory());
|
||||
|
||||
// Search and load all plugins
|
||||
await PluginService.Load();
|
||||
|
||||
// Search up assemblies for the apiServer
|
||||
var assemblyFiles = PluginService.GetAssemblies("apiServer")
|
||||
.Values
|
||||
.ToArray();
|
||||
|
||||
// Create the load context and add assemblies
|
||||
PluginLoadContext = new AssemblyLoadContext(null);
|
||||
|
||||
foreach (var assemblyFile in assemblyFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
PluginLoadContext.LoadFromAssemblyPath(
|
||||
Path.Combine(Directory.GetCurrentDirectory(), assemblyFile)
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError("Unable to load plugin assembly '{assemblyFile}': {e}", assemblyFile, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Task InitializePlugins()
|
||||
{
|
||||
// Define minimal service collection
|
||||
var startupSc = new ServiceCollection();
|
||||
// Create service provider for starting up
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
||||
// Configure base services for initialisation
|
||||
startupSc.AddSingleton(Configuration);
|
||||
|
||||
startupSc.AddLogging(builder =>
|
||||
serviceCollection.AddSingleton(Configuration);
|
||||
|
||||
serviceCollection.AddLogging(builder =>
|
||||
{
|
||||
builder.ClearProviders();
|
||||
builder.AddProviders(LoggerProviders);
|
||||
});
|
||||
|
||||
//
|
||||
var startupSp = startupSc.BuildServiceProvider();
|
||||
PluginLoadServiceProvider = serviceCollection.BuildServiceProvider();
|
||||
|
||||
// Collect startups
|
||||
var pluginStartups = new List<IPluginStartup>();
|
||||
|
||||
pluginStartups.Add(new CoreStartup());
|
||||
|
||||
pluginStartups.AddRange(AdditionalPlugins); // Used by the development server
|
||||
|
||||
// Do NOT remove the following comment, as its used to place the plugin startup register calls
|
||||
// MLBUILD_PLUGIN_STARTUP_HERE
|
||||
|
||||
// Initialize plugin startups
|
||||
var startups = new List<IPluginStartup>();
|
||||
var startupType = typeof(IPluginStartup);
|
||||
|
||||
var assembliesToScan = new List<Assembly>();
|
||||
|
||||
assembliesToScan.Add(typeof(Startup).Assembly);
|
||||
assembliesToScan.AddRange(PluginLoadContext.Assemblies);
|
||||
assembliesToScan.AddRange(AdditionalAssemblies);
|
||||
|
||||
foreach (var pluginAssembly in assembliesToScan)
|
||||
{
|
||||
var startupTypes = pluginAssembly
|
||||
.ExportedTypes
|
||||
.Where(x => !x.IsAbstract && !x.IsInterface && x.IsAssignableTo(startupType))
|
||||
.ToArray();
|
||||
|
||||
foreach (var type in startupTypes)
|
||||
{
|
||||
var startup = ActivatorUtilities.CreateInstance(startupSp, type) as IPluginStartup;
|
||||
|
||||
if (startup == null)
|
||||
continue;
|
||||
|
||||
startups.Add(startup);
|
||||
}
|
||||
}
|
||||
|
||||
PluginStartups = startups.ToArray();
|
||||
|
||||
PluginStartups = pluginStartups.ToArray();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -298,11 +228,6 @@ public class Startup
|
||||
FileProvider = new BundleAssetFileProvider()
|
||||
});
|
||||
|
||||
WebApplication.UseStaticFiles(new StaticFileOptions()
|
||||
{
|
||||
FileProvider = PluginService.WwwRootFileProvider
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -314,7 +239,7 @@ public class Startup
|
||||
{
|
||||
try
|
||||
{
|
||||
await pluginAppStartup.BuildApplication(WebApplicationBuilder);
|
||||
await pluginAppStartup.BuildApplication(PluginLoadServiceProvider, WebApplicationBuilder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -333,7 +258,7 @@ public class Startup
|
||||
{
|
||||
try
|
||||
{
|
||||
await pluginAppStartup.ConfigureApplication(WebApplication);
|
||||
await pluginAppStartup.ConfigureApplication(PluginLoadServiceProvider, WebApplication);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -352,7 +277,7 @@ public class Startup
|
||||
{
|
||||
try
|
||||
{
|
||||
await pluginEndpointStartup.ConfigureEndpoints(WebApplication);
|
||||
await pluginEndpointStartup.ConfigureEndpoints(PluginLoadServiceProvider, WebApplication);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user