Implemented plugin interface loading via di
1^
This commit is contained in:
@@ -1,7 +0,0 @@
|
|||||||
namespace Moonlight.Client.Interfaces;
|
|
||||||
|
|
||||||
public interface IAppLoader
|
|
||||||
{
|
|
||||||
public int Priority { get; }
|
|
||||||
public Task Load(IServiceProvider serviceProvider);
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
|
||||||
|
|
||||||
namespace Moonlight.Client.Interfaces;
|
|
||||||
|
|
||||||
public interface IAppScreen
|
|
||||||
{
|
|
||||||
public int Priority { get; }
|
|
||||||
public Task<bool> ShouldRender(IServiceProvider serviceProvider);
|
|
||||||
public RenderFragment Render();
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
|
||||||
|
|
||||||
namespace Moonlight.Client.Interfaces;
|
|
||||||
|
|
||||||
public interface IAppStartup
|
|
||||||
{
|
|
||||||
public Task BuildApp(WebAssemblyHostBuilder builder);
|
|
||||||
public Task ConfigureApp(WebAssemblyHost app);
|
|
||||||
}
|
|
||||||
9
Moonlight.Client/Interfaces/IPluginStartup.cs
Normal file
9
Moonlight.Client/Interfaces/IPluginStartup.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Interfaces;
|
||||||
|
|
||||||
|
public interface IPluginStartup
|
||||||
|
{
|
||||||
|
public Task BuildApplication(WebAssemblyHostBuilder builder);
|
||||||
|
public Task ConfigureApplication(WebAssemblyHost app);
|
||||||
|
}
|
||||||
@@ -38,7 +38,7 @@ public class Startup
|
|||||||
private PluginLoaderService PluginLoaderService;
|
private PluginLoaderService PluginLoaderService;
|
||||||
private ApplicationAssemblyService ApplicationAssemblyService;
|
private ApplicationAssemblyService ApplicationAssemblyService;
|
||||||
|
|
||||||
private IAppStartup[] PluginAppStartups;
|
private IPluginStartup[] PluginStartups;
|
||||||
|
|
||||||
public async Task Run(string[] args, Assembly[]? assemblies = null)
|
public async Task Run(string[] args, Assembly[]? assemblies = null)
|
||||||
{
|
{
|
||||||
@@ -182,8 +182,6 @@ public class Startup
|
|||||||
configuration.AddAssemblies(ApplicationAssemblyService.AdditionalAssemblies);
|
configuration.AddAssemblies(ApplicationAssemblyService.AdditionalAssemblies);
|
||||||
configuration.AddAssemblies(ApplicationAssemblyService.PluginAssemblies);
|
configuration.AddAssemblies(ApplicationAssemblyService.PluginAssemblies);
|
||||||
|
|
||||||
configuration.AddInterface<IAppLoader>();
|
|
||||||
configuration.AddInterface<IAppScreen>();
|
|
||||||
configuration.AddInterface<ISidebarItemProvider>();
|
configuration.AddInterface<ISidebarItemProvider>();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -226,25 +224,42 @@ public class Startup
|
|||||||
|
|
||||||
private Task InitializePlugins()
|
private Task InitializePlugins()
|
||||||
{
|
{
|
||||||
var initialisationServiceCollection = new ServiceCollection();
|
// Define minimal service collection
|
||||||
|
var startupSc = new ServiceCollection();
|
||||||
|
|
||||||
initialisationServiceCollection.AddLogging(builder => { builder.AddProviders(LoggerProviders); });
|
// Create logging proxy
|
||||||
|
startupSc.AddLogging(builder =>
|
||||||
// Configure plugin loading by using the interface service
|
|
||||||
initialisationServiceCollection.AddInterfaces(configuration =>
|
|
||||||
{
|
{
|
||||||
// We use moonlight itself as a plugin assembly
|
builder.ClearProviders();
|
||||||
configuration.AddAssembly(typeof(Startup).Assembly);
|
builder.AddProviders(LoggerProviders);
|
||||||
|
|
||||||
configuration.AddAssemblies(ApplicationAssemblyService.AdditionalAssemblies);
|
|
||||||
configuration.AddAssemblies(ApplicationAssemblyService.PluginAssemblies);
|
|
||||||
|
|
||||||
configuration.AddInterface<IAppStartup>();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var initialisationServiceProvider = initialisationServiceCollection.BuildServiceProvider();
|
//
|
||||||
|
var startupSp = startupSc.BuildServiceProvider();
|
||||||
|
|
||||||
PluginAppStartups = initialisationServiceProvider.GetRequiredService<IAppStartup[]>();
|
// Initialize plugin startups
|
||||||
|
var startups = new List<IPluginStartup>();
|
||||||
|
var startupType = typeof(IPluginStartup);
|
||||||
|
|
||||||
|
foreach (var pluginAssembly in ApplicationAssemblyService.PluginAssemblies)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -253,11 +268,11 @@ public class Startup
|
|||||||
|
|
||||||
private async Task HookPluginBuild()
|
private async Task HookPluginBuild()
|
||||||
{
|
{
|
||||||
foreach (var pluginAppStartup in PluginAppStartups)
|
foreach (var pluginAppStartup in PluginStartups)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await pluginAppStartup.BuildApp(WebAssemblyHostBuilder);
|
await pluginAppStartup.BuildApplication(WebAssemblyHostBuilder);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -272,11 +287,11 @@ public class Startup
|
|||||||
|
|
||||||
private async Task HookPluginConfigure()
|
private async Task HookPluginConfigure()
|
||||||
{
|
{
|
||||||
foreach (var pluginAppStartup in PluginAppStartups)
|
foreach (var pluginAppStartup in PluginStartups)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await pluginAppStartup.ConfigureApp(WebAssemblyHost);
|
await pluginAppStartup.ConfigureApplication(WebAssemblyHost);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
|
|
||||||
@inject IServiceProvider ServiceProvider
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject ILogger<MainLayout> Logger
|
@inject ILogger<MainLayout> Logger
|
||||||
@inject IAppLoader[] AppLoaders
|
|
||||||
@inject IAppScreen[] AppScreens
|
|
||||||
@inject FrontendConfiguration Configuration
|
@inject FrontendConfiguration Configuration
|
||||||
|
|
||||||
<PageTitle>@Configuration.Title</PageTitle>
|
<PageTitle>@Configuration.Title</PageTitle>
|
||||||
@@ -83,58 +81,8 @@ else
|
|||||||
IsLoading = true;
|
IsLoading = true;
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
|
|
||||||
//
|
|
||||||
await RunLoaders();
|
|
||||||
|
|
||||||
// Screens
|
|
||||||
await RenderScreens();
|
|
||||||
|
|
||||||
//
|
//
|
||||||
IsLoading = false;
|
IsLoading = false;
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunLoaders()
|
|
||||||
{
|
|
||||||
var appLoaders = AppLoaders
|
|
||||||
.OrderBy(x => x.Priority);
|
|
||||||
|
|
||||||
foreach (var loader in appLoaders) //TODO: Measure performance of every loader?
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Logger.LogDebug("Running application loader '{name}'", loader.GetType().Name);
|
|
||||||
await loader.Load(ServiceProvider);
|
|
||||||
}
|
|
||||||
catch (HttpApiException)
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogCritical("An app loader threw an unhandled exception: {e}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task RenderScreens()
|
|
||||||
{
|
|
||||||
CurrentScreen = null;
|
|
||||||
|
|
||||||
var appScreens = AppScreens
|
|
||||||
.OrderBy(x => x.Priority);
|
|
||||||
|
|
||||||
foreach (var screen in appScreens)
|
|
||||||
{
|
|
||||||
if (!await screen.ShouldRender(ServiceProvider))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
CurrentScreen = screen.Render();
|
|
||||||
|
|
||||||
await InvokeAsync(StateHasChanged);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await InvokeAsync(StateHasChanged);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user