Implemented plugin loading via di on the api server. Fixed plugin loading in the client
This commit is contained in:
@@ -1,67 +0,0 @@
|
|||||||
using System.Text.Json;
|
|
||||||
using MoonCore.Authentication;
|
|
||||||
using MoonCore.Extended.Abstractions;
|
|
||||||
using Moonlight.ApiServer.Database.Entities;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Http.Middleware;
|
|
||||||
|
|
||||||
public class ApiAuthenticationMiddleware
|
|
||||||
{
|
|
||||||
private readonly RequestDelegate Next;
|
|
||||||
private readonly ILogger<ApiAuthenticationMiddleware> Logger;
|
|
||||||
|
|
||||||
public ApiAuthenticationMiddleware(RequestDelegate next, ILogger<ApiAuthenticationMiddleware> logger)
|
|
||||||
{
|
|
||||||
Next = next;
|
|
||||||
Logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InvokeAsync(HttpContext context)
|
|
||||||
{
|
|
||||||
await Authenticate(context);
|
|
||||||
await Next(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task Authenticate(HttpContext context)
|
|
||||||
{
|
|
||||||
var request = context.Request;
|
|
||||||
|
|
||||||
if(!request.Headers.ContainsKey("Authorization"))
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
if(request.Headers["Authorization"].Count == 0)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var authHeader = request.Headers["Authorization"].First();
|
|
||||||
|
|
||||||
if(string.IsNullOrEmpty(authHeader))
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var parts = authHeader.Split(" ");
|
|
||||||
|
|
||||||
if(parts.Length != 2)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var bearerValue = parts[1];
|
|
||||||
|
|
||||||
if(!bearerValue.StartsWith("api_"))
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
if(bearerValue.Length != "api_".Length + 32)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var apiKeyRepo = context.RequestServices.GetRequiredService<DatabaseRepository<ApiKey>>();
|
|
||||||
var apiKey = apiKeyRepo.Get().FirstOrDefault(x => x.Secret == bearerValue);
|
|
||||||
|
|
||||||
if(apiKey == null)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var permissions = JsonSerializer.Deserialize<string[]>(apiKey.PermissionsJson) ?? [];
|
|
||||||
context.User = new PermClaimsPrinciple()
|
|
||||||
{
|
|
||||||
Permissions = permissions
|
|
||||||
};
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
|
||||||
using MoonCore.Attributes;
|
|
||||||
using MoonCore.Authentication;
|
|
||||||
using MoonCore.Extensions;
|
|
||||||
using Moonlight.ApiServer.Exceptions;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Http.Middleware;
|
|
||||||
|
|
||||||
public class AuthorizationMiddleware
|
|
||||||
{
|
|
||||||
private readonly RequestDelegate Next;
|
|
||||||
private readonly ILogger<AuthorizationMiddleware> Logger;
|
|
||||||
|
|
||||||
public AuthorizationMiddleware(RequestDelegate next, ILogger<AuthorizationMiddleware> logger)
|
|
||||||
{
|
|
||||||
Next = next;
|
|
||||||
Logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InvokeAsync(HttpContext context)
|
|
||||||
{
|
|
||||||
if (await Authorize(context))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await Next(context);
|
|
||||||
}
|
|
||||||
catch (MissingPermissionException e)
|
|
||||||
{
|
|
||||||
if (e.Permission == "meta.authenticated")
|
|
||||||
{
|
|
||||||
await Results.Problem(
|
|
||||||
title: "This endpoint requires a user authenticated token",
|
|
||||||
statusCode: 401
|
|
||||||
).ExecuteAsync(context);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Results.Problem(
|
|
||||||
title: "You dont have the required permission",
|
|
||||||
detail: e.Permission,
|
|
||||||
statusCode: 403
|
|
||||||
).ExecuteAsync(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> Authorize(HttpContext context)
|
|
||||||
{
|
|
||||||
var requiredPermissions = ResolveRequiredPermissions(context);
|
|
||||||
|
|
||||||
if (requiredPermissions.Length == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Check if no context => permissions have been loaded
|
|
||||||
if (context.User is not PermClaimsPrinciple permClaimsPrinciple)
|
|
||||||
{
|
|
||||||
await Results.Problem(
|
|
||||||
title: "An unauthenticated request is not allowed to use this endpoint",
|
|
||||||
statusCode: 401
|
|
||||||
).ExecuteAsync(context);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if one of the required permissions is to be logged in
|
|
||||||
if (requiredPermissions.Any(x => x == "meta.authenticated") && permClaimsPrinciple.IdentityModel == null)
|
|
||||||
{
|
|
||||||
await Results.Problem(
|
|
||||||
title: "This endpoint requires a user authenticated token",
|
|
||||||
statusCode: 401
|
|
||||||
).ExecuteAsync(context);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var permission in requiredPermissions)
|
|
||||||
{
|
|
||||||
if(permission == "meta.authenticated") // We already verified that
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!permClaimsPrinciple.HasPermission(permission))
|
|
||||||
{
|
|
||||||
await Results.Problem(
|
|
||||||
title: "You dont have the required permission",
|
|
||||||
detail: permission,
|
|
||||||
statusCode: 403
|
|
||||||
).ExecuteAsync(context);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string[] ResolveRequiredPermissions(HttpContext context)
|
|
||||||
{
|
|
||||||
// Basic handling
|
|
||||||
var endpoint = context.GetEndpoint();
|
|
||||||
|
|
||||||
if (endpoint == null)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
var metadata = endpoint
|
|
||||||
.Metadata
|
|
||||||
.GetMetadata<ControllerActionDescriptor>();
|
|
||||||
|
|
||||||
if (metadata == null)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
// Retrieve attribute infos
|
|
||||||
var controllerAttrInfo = metadata
|
|
||||||
.ControllerTypeInfo
|
|
||||||
.CustomAttributes
|
|
||||||
.FirstOrDefault(x => x.AttributeType == typeof(RequirePermissionAttribute));
|
|
||||||
|
|
||||||
var methodAttrInfo = metadata
|
|
||||||
.MethodInfo
|
|
||||||
.CustomAttributes
|
|
||||||
.FirstOrDefault(x => x.AttributeType == typeof(RequirePermissionAttribute));
|
|
||||||
|
|
||||||
// Retrieve permissions from attribute infos
|
|
||||||
var controllerPermission = controllerAttrInfo != null
|
|
||||||
? controllerAttrInfo.ConstructorArguments.First().Value as string
|
|
||||||
: null;
|
|
||||||
|
|
||||||
var methodPermission = methodAttrInfo != null
|
|
||||||
? methodAttrInfo.ConstructorArguments.First().Value as string
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// If both have a permission flag, return both
|
|
||||||
if (controllerPermission != null && methodPermission != null)
|
|
||||||
return [controllerPermission, methodPermission];
|
|
||||||
|
|
||||||
// If either of them have a permission set, return it
|
|
||||||
if (controllerPermission != null)
|
|
||||||
return [controllerPermission];
|
|
||||||
|
|
||||||
if (methodPermission != null)
|
|
||||||
return [methodPermission];
|
|
||||||
|
|
||||||
// If both have no permission set, allow everyone to access it
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using System.Text.Json;
|
|
||||||
using MoonCore.Authentication;
|
|
||||||
using Moonlight.ApiServer.Database.Entities;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Http.Middleware;
|
|
||||||
|
|
||||||
public class PermissionLoaderMiddleware
|
|
||||||
{
|
|
||||||
private readonly RequestDelegate Next;
|
|
||||||
|
|
||||||
public PermissionLoaderMiddleware(RequestDelegate next)
|
|
||||||
{
|
|
||||||
Next = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
|
||||||
{
|
|
||||||
await Load(context);
|
|
||||||
await Next(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task Load(HttpContext context)
|
|
||||||
{
|
|
||||||
if(context.User is not PermClaimsPrinciple permClaimsPrinciple)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
if(permClaimsPrinciple.IdentityModel is not User user)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
permClaimsPrinciple.Permissions = JsonSerializer.Deserialize<string[]>(user.PermissionsJson) ?? [];
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using MoonCore.Services;
|
|
||||||
using Moonlight.ApiServer.Configuration;
|
|
||||||
using Moonlight.ApiServer.Interfaces.Startup;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Implementations.Startup;
|
|
||||||
|
|
||||||
public class ApiDocsStartup : IAppStartup, IEndpointStartup
|
|
||||||
{
|
|
||||||
private readonly ILogger<ApiDocsStartup> Logger;
|
|
||||||
private readonly AppConfiguration AppConfiguration;
|
|
||||||
|
|
||||||
public ApiDocsStartup(ILogger<ApiDocsStartup> logger, AppConfiguration appConfiguration)
|
|
||||||
{
|
|
||||||
Logger = logger;
|
|
||||||
AppConfiguration = appConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task BuildApp(IHostApplicationBuilder builder)
|
|
||||||
{
|
|
||||||
if(!AppConfiguration.Development.EnableApiDocs)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
|
||||||
|
|
||||||
// Configure swagger api specification generator and set the document title for the api docs to use
|
|
||||||
builder.Services.AddSwaggerGen(options => options.SwaggerDoc("main", new OpenApiInfo()
|
|
||||||
{
|
|
||||||
Title = "Moonlight API"
|
|
||||||
}));
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task ConfigureApp(IApplicationBuilder app) => Task.CompletedTask;
|
|
||||||
|
|
||||||
public Task ConfigureEndpoints(IEndpointRouteBuilder routeBuilder)
|
|
||||||
{
|
|
||||||
if(!AppConfiguration.Development.EnableApiDocs)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
routeBuilder.MapSwagger("/api/swagger/{documentName}");
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using Moonlight.ApiServer.Interfaces.Startup;
|
|
||||||
using Moonlight.ApiServer.Services;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Implementations.Startup;
|
|
||||||
|
|
||||||
public class CoreAssetStartup : IAppStartup
|
|
||||||
{
|
|
||||||
private readonly BundleService BundleService;
|
|
||||||
|
|
||||||
public CoreAssetStartup(BundleService bundleService)
|
|
||||||
{
|
|
||||||
BundleService = bundleService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task BuildApp(IHostApplicationBuilder builder)
|
|
||||||
{
|
|
||||||
BundleService.BundleCss("css/core.min.css");
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task ConfigureApp(IApplicationBuilder app)
|
|
||||||
=> Task.CompletedTask;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using Moonlight.ApiServer.Database;
|
|
||||||
using Moonlight.ApiServer.Helpers;
|
|
||||||
using Moonlight.ApiServer.Interfaces.Startup;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Implementations.Startup;
|
|
||||||
|
|
||||||
public class CoreDatabaseStartup : IDatabaseStartup
|
|
||||||
{
|
|
||||||
public Task ConfigureDatabase(DatabaseContextCollection collection)
|
|
||||||
{
|
|
||||||
collection.Add<CoreDataContext>();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
66
Moonlight.ApiServer/Implementations/Startup/CoreStartup.cs
Normal file
66
Moonlight.ApiServer/Implementations/Startup/CoreStartup.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Moonlight.ApiServer.Configuration;
|
||||||
|
using Moonlight.ApiServer.Database;
|
||||||
|
using Moonlight.ApiServer.Helpers;
|
||||||
|
using Moonlight.ApiServer.Interfaces.Startup;
|
||||||
|
using Moonlight.ApiServer.Services;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Implementations.Startup;
|
||||||
|
|
||||||
|
public class CoreStartup : IPluginStartup
|
||||||
|
{
|
||||||
|
private readonly AppConfiguration Configuration;
|
||||||
|
private readonly BundleService BundleService;
|
||||||
|
|
||||||
|
public CoreStartup(AppConfiguration configuration, BundleService bundleService)
|
||||||
|
{
|
||||||
|
Configuration = configuration;
|
||||||
|
BundleService = bundleService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task BuildApplication(IHostApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
#region Api Docs
|
||||||
|
|
||||||
|
if (Configuration.Development.EnableApiDocs)
|
||||||
|
{
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
|
||||||
|
// Configure swagger api specification generator and set the document title for the api docs to use
|
||||||
|
builder.Services.AddSwaggerGen(options => options.SwaggerDoc("main", new OpenApiInfo()
|
||||||
|
{
|
||||||
|
Title = "Moonlight API"
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Assets
|
||||||
|
|
||||||
|
BundleService.BundleCss("css/core.min.css");
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ConfigureApplication(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ConfigureDatabase(DatabaseContextCollection collection)
|
||||||
|
{
|
||||||
|
collection.Add<CoreDataContext>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ConfigureEndpoints(IEndpointRouteBuilder routeBuilder)
|
||||||
|
{
|
||||||
|
if(Configuration.Development.EnableApiDocs)
|
||||||
|
routeBuilder.MapSwagger("/api/swagger/{documentName}");
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Moonlight.ApiServer.Interfaces.Startup;
|
|
||||||
|
|
||||||
public interface IAppStartup
|
|
||||||
{
|
|
||||||
public Task BuildApp(IHostApplicationBuilder builder);
|
|
||||||
public Task ConfigureApp(IApplicationBuilder app);
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using Moonlight.ApiServer.Helpers;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Interfaces.Startup;
|
|
||||||
|
|
||||||
public interface IDatabaseStartup
|
|
||||||
{
|
|
||||||
public Task ConfigureDatabase(DatabaseContextCollection collection);
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Moonlight.ApiServer.Interfaces.Startup;
|
|
||||||
|
|
||||||
public interface IEndpointStartup
|
|
||||||
{
|
|
||||||
public Task ConfigureEndpoints(IEndpointRouteBuilder routeBuilder);
|
|
||||||
}
|
|
||||||
11
Moonlight.ApiServer/Interfaces/Startup/IPluginStartup.cs
Normal file
11
Moonlight.ApiServer/Interfaces/Startup/IPluginStartup.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using Moonlight.ApiServer.Helpers;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Interfaces.Startup;
|
||||||
|
|
||||||
|
public interface IPluginStartup
|
||||||
|
{
|
||||||
|
public Task BuildApplication(IHostApplicationBuilder builder);
|
||||||
|
public Task ConfigureApplication(IApplicationBuilder app);
|
||||||
|
public Task ConfigureDatabase(DatabaseContextCollection collection);
|
||||||
|
public Task ConfigureEndpoints(IEndpointRouteBuilder routeBuilder);
|
||||||
|
}
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MoonCore" Version="1.8.2" />
|
<PackageReference Include="MoonCore" Version="1.8.3" />
|
||||||
<PackageReference Include="MoonCore.Extended" Version="1.2.7" />
|
<PackageReference Include="MoonCore.Extended" Version="1.2.8" />
|
||||||
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.5" />
|
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.5" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||||
|
|||||||
@@ -53,9 +53,7 @@ public class Startup
|
|||||||
// Asset bundling
|
// Asset bundling
|
||||||
private BundleService BundleService;
|
private BundleService BundleService;
|
||||||
|
|
||||||
private IAppStartup[] PluginAppStartups;
|
private IPluginStartup[] PluginStartups;
|
||||||
private IDatabaseStartup[] PluginDatabaseStartups;
|
|
||||||
private IEndpointStartup[] PluginEndpointStartups;
|
|
||||||
|
|
||||||
public async Task Run(string[] args, Assembly[]? additionalAssemblies = null)
|
public async Task Run(string[] args, Assembly[]? additionalAssemblies = null)
|
||||||
{
|
{
|
||||||
@@ -303,35 +301,53 @@ public class Startup
|
|||||||
|
|
||||||
private Task InitializePlugins()
|
private Task InitializePlugins()
|
||||||
{
|
{
|
||||||
var initialisationServiceCollection = new ServiceCollection();
|
// Define minimal service collection
|
||||||
|
var startupSc = new ServiceCollection();
|
||||||
|
|
||||||
// Configure base services for initialisation
|
// Configure base services for initialisation
|
||||||
initialisationServiceCollection.AddSingleton(Configuration);
|
startupSc.AddSingleton(Configuration);
|
||||||
|
|
||||||
BundleService = new BundleService();
|
BundleService = new BundleService();
|
||||||
initialisationServiceCollection.AddSingleton(BundleService);
|
startupSc.AddSingleton(BundleService);
|
||||||
|
|
||||||
initialisationServiceCollection.AddLogging(builder => { builder.AddProviders(LoggerProviders); });
|
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(PluginLoaderService.PluginAssemblies);
|
|
||||||
configuration.AddAssemblies(AdditionalAssemblies);
|
|
||||||
|
|
||||||
configuration.AddInterface<IAppStartup>();
|
|
||||||
configuration.AddInterface<IDatabaseStartup>();
|
|
||||||
configuration.AddInterface<IEndpointStartup>();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var initialisationServiceProvider = initialisationServiceCollection.BuildServiceProvider();
|
//
|
||||||
|
var startupSp = startupSc.BuildServiceProvider();
|
||||||
|
|
||||||
PluginAppStartups = initialisationServiceProvider.GetRequiredService<IAppStartup[]>();
|
// Initialize plugin startups
|
||||||
PluginDatabaseStartups = initialisationServiceProvider.GetRequiredService<IDatabaseStartup[]>();
|
var startups = new List<IPluginStartup>();
|
||||||
PluginEndpointStartups = initialisationServiceProvider.GetRequiredService<IEndpointStartup[]>();
|
var startupType = typeof(IPluginStartup);
|
||||||
|
|
||||||
|
var assembliesToScan = new List<Assembly>();
|
||||||
|
|
||||||
|
assembliesToScan.Add(typeof(Startup).Assembly);
|
||||||
|
assembliesToScan.AddRange(PluginLoaderService.PluginAssemblies);
|
||||||
|
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();
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -364,11 +380,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(WebApplicationBuilder);
|
await pluginAppStartup.BuildApplication(WebApplicationBuilder);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -383,11 +399,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(WebApplication);
|
await pluginAppStartup.ConfigureApplication(WebApplication);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -402,7 +418,7 @@ public class Startup
|
|||||||
|
|
||||||
private async Task HookPluginEndpoints()
|
private async Task HookPluginEndpoints()
|
||||||
{
|
{
|
||||||
foreach (var pluginEndpointStartup in PluginEndpointStartups)
|
foreach (var pluginEndpointStartup in PluginStartups)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -555,7 +571,7 @@ public class Startup
|
|||||||
|
|
||||||
var databaseCollection = new DatabaseContextCollection();
|
var databaseCollection = new DatabaseContextCollection();
|
||||||
|
|
||||||
foreach (var databaseStartup in PluginDatabaseStartups)
|
foreach (var databaseStartup in PluginStartups)
|
||||||
await databaseStartup.ConfigureDatabase(databaseCollection);
|
await databaseStartup.ConfigureDatabase(databaseCollection);
|
||||||
|
|
||||||
foreach (var database in databaseCollection)
|
foreach (var database in databaseCollection)
|
||||||
|
|||||||
17
Moonlight.Client/Implementations/CoreStartup.cs
Normal file
17
Moonlight.Client/Implementations/CoreStartup.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
|
using Moonlight.Client.Interfaces;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Implementations;
|
||||||
|
|
||||||
|
public class CoreStartup : IPluginStartup
|
||||||
|
{
|
||||||
|
public Task BuildApplication(WebAssemblyHostBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Services.AddSingleton<ISidebarItemProvider, DefaultSidebarItemProvider>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ConfigureApplication(WebAssemblyHost app)
|
||||||
|
=> Task.CompletedTask;
|
||||||
|
}
|
||||||
@@ -24,10 +24,10 @@
|
|||||||
<PackageReference Include="Blazor-ApexCharts" Version="4.0.1" />
|
<PackageReference Include="Blazor-ApexCharts" Version="4.0.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.10"/>
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.10"/>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.10" PrivateAssets="all"/>
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.10" PrivateAssets="all"/>
|
||||||
<PackageReference Include="MoonCore" Version="1.8.2" />
|
<PackageReference Include="MoonCore" Version="1.8.3" />
|
||||||
<PackageReference Include="MoonCore.Blazor" Version="1.2.8" />
|
<PackageReference Include="MoonCore.Blazor" Version="1.2.9" />
|
||||||
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.5"/>
|
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.5"/>
|
||||||
<PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.3.0" />
|
<PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.3.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|||||||
@@ -8,13 +8,12 @@ using MoonCore.Blazor.Tailwind.Extensions;
|
|||||||
using MoonCore.Blazor.Tailwind.Auth;
|
using MoonCore.Blazor.Tailwind.Auth;
|
||||||
using MoonCore.Extensions;
|
using MoonCore.Extensions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCore.PluginFramework.Extensions;
|
|
||||||
using MoonCore.Plugins;
|
using MoonCore.Plugins;
|
||||||
using Moonlight.Client.Implementations;
|
using Moonlight.Client.Implementations;
|
||||||
using Moonlight.Client.Interfaces;
|
using Moonlight.Client.Interfaces;
|
||||||
using Moonlight.Client.Services;
|
using Moonlight.Client.Services;
|
||||||
using Moonlight.Client.UI;
|
|
||||||
using Moonlight.Shared.Misc;
|
using Moonlight.Shared.Misc;
|
||||||
|
using Moonlight.Client.UI;
|
||||||
|
|
||||||
namespace Moonlight.Client;
|
namespace Moonlight.Client;
|
||||||
|
|
||||||
@@ -62,7 +61,6 @@ public class Startup
|
|||||||
await RegisterLogging();
|
await RegisterLogging();
|
||||||
await RegisterBase();
|
await RegisterBase();
|
||||||
await RegisterAuthentication();
|
await RegisterAuthentication();
|
||||||
await RegisterInterfaces();
|
|
||||||
await HookPluginBuild();
|
await HookPluginBuild();
|
||||||
|
|
||||||
await BuildWebAssemblyHost();
|
await BuildWebAssemblyHost();
|
||||||
@@ -153,7 +151,9 @@ public class Startup
|
|||||||
WebAssemblyHostBuilder.Services.AddMoonCoreBlazorTailwind();
|
WebAssemblyHostBuilder.Services.AddMoonCoreBlazorTailwind();
|
||||||
WebAssemblyHostBuilder.Services.AddScoped<LocalStorageService>();
|
WebAssemblyHostBuilder.Services.AddScoped<LocalStorageService>();
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AutoAddServices<Program>();
|
WebAssemblyHostBuilder.Services.AddScoped<ThemeService>();
|
||||||
|
|
||||||
|
//WebAssemblyHostBuilder.Services.AutoAddServices<Program>();
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -170,26 +170,6 @@ public class Startup
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Interfaces
|
|
||||||
|
|
||||||
private Task RegisterInterfaces()
|
|
||||||
{
|
|
||||||
WebAssemblyHostBuilder.Services.AddInterfaces(configuration =>
|
|
||||||
{
|
|
||||||
// We use moonlight itself as a plugin assembly
|
|
||||||
configuration.AddAssembly(typeof(Startup).Assembly);
|
|
||||||
|
|
||||||
configuration.AddAssemblies(ApplicationAssemblyService.AdditionalAssemblies);
|
|
||||||
configuration.AddAssemblies(ApplicationAssemblyService.PluginAssemblies);
|
|
||||||
|
|
||||||
configuration.AddInterface<ISidebarItemProvider>();
|
|
||||||
});
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Plugins
|
#region Plugins
|
||||||
|
|
||||||
private async Task LoadPlugins()
|
private async Task LoadPlugins()
|
||||||
@@ -241,11 +221,17 @@ public class Startup
|
|||||||
var startups = new List<IPluginStartup>();
|
var startups = new List<IPluginStartup>();
|
||||||
var startupType = typeof(IPluginStartup);
|
var startupType = typeof(IPluginStartup);
|
||||||
|
|
||||||
foreach (var pluginAssembly in ApplicationAssemblyService.PluginAssemblies)
|
var assembliesToScan = new List<Assembly>();
|
||||||
|
|
||||||
|
assembliesToScan.Add(typeof(Startup).Assembly);
|
||||||
|
assembliesToScan.AddRange(PluginLoaderService.PluginAssemblies);
|
||||||
|
assembliesToScan.AddRange(ApplicationAssemblyService.AdditionalAssemblies);
|
||||||
|
|
||||||
|
foreach (var pluginAssembly in assembliesToScan)
|
||||||
{
|
{
|
||||||
var startupTypes = pluginAssembly
|
var startupTypes = pluginAssembly
|
||||||
.ExportedTypes
|
.ExportedTypes
|
||||||
.Where(x => x.IsAbstract && x.IsInterface && x.IsAssignableTo(startupType))
|
.Where(x => !x.IsAbstract && !x.IsInterface && x.IsAssignableTo(startupType))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
foreach (var type in startupTypes)
|
foreach (var type in startupTypes)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
@using Moonlight.Client.UI.Layouts
|
@using Moonlight.Client.UI.Layouts
|
||||||
@using MoonCore.Blazor.Components
|
|
||||||
@using Moonlight.Client.Services
|
@using Moonlight.Client.Services
|
||||||
|
|
||||||
@inject ApplicationAssemblyService ApplicationAssemblyService
|
@inject ApplicationAssemblyService ApplicationAssemblyService
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
@using Moonlight.Client.UI.Layouts
|
@using Moonlight.Client.UI.Layouts
|
||||||
|
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
@inject ISidebarItemProvider[] SidebarItemProviders
|
@inject IEnumerable<ISidebarItemProvider> SidebarItemProviders
|
||||||
|
|
||||||
@{
|
@{
|
||||||
var url = new Uri(Navigation.Uri);
|
var url = new Uri(Navigation.Uri);
|
||||||
|
|||||||
Reference in New Issue
Block a user