Removed unused calls and classes from the old plugin system

This commit is contained in:
2025-05-14 09:15:18 +02:00
parent 6922242b4f
commit 0e5402c347
6 changed files with 31 additions and 206 deletions

View File

@@ -55,5 +55,6 @@ public class AppConfiguration
public class KestrelConfig public class KestrelConfig
{ {
public int UploadLimit { get; set; } = 100; public int UploadLimit { get; set; } = 100;
public string AllowedOrigins { get; set; } = "*";
} }
} }

View File

@@ -1,28 +0,0 @@
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.FileProviders.Physical;
using Microsoft.Extensions.Primitives;
using MoonCore.Helpers;
namespace Moonlight.ApiServer.Helpers;
public class BundleAssetFileProvider : IFileProvider
{
public IDirectoryContents GetDirectoryContents(string subpath)
=> NotFoundDirectoryContents.Singleton;
public IFileInfo GetFileInfo(string subpath)
{
if(subpath != "/css/bundle.css")
return new NotFoundFileInfo(subpath);
var physicalPath = PathBuilder.File("storage", "tmp", "bundle.css");
if(!File.Exists(physicalPath))
return new NotFoundFileInfo(subpath);
return new PhysicalFileInfo(new FileInfo(physicalPath));
}
public IChangeToken Watch(string filter)
=> NullChangeToken.Singleton;
}

View File

@@ -25,7 +25,7 @@
<form class="space-y-6" method="POST"> <form class="space-y-6" method="POST">
<div> <div>
<label for="email" class="block text-sm font-medium leading-6 text-gray-100">Username</label> <label for="username" class="block text-sm font-medium leading-6 text-gray-100">Username</label>
<div class="mt-2"> <div class="mt-2">
<input id="username" name="username" type="text" required class="block bg-white/5 w-full rounded-md border-0 py-1.5 text-gray-100 shadow-sm ring-1 ring-inset ring-gray-700 placeholder:text-gray-600 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"> <input id="username" name="username" type="text" required class="block bg-white/5 w-full rounded-md border-0 py-1.5 text-gray-100 shadow-sm ring-1 ring-inset ring-gray-700 placeholder:text-gray-600 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
</div> </div>

View File

@@ -1,14 +0,0 @@
namespace Moonlight.ApiServer.Models;
public class PluginManifest
{
public string Id { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public string[] Dependencies { get; set; } = [];
public string[] Scripts { get; set; } = [];
public string[] Styles { get; set; } = [];
public Dictionary<string, string[]> Assemblies { get; set; } = new();
}

View File

@@ -1,139 +0,0 @@
using System.Text.Json;
using Microsoft.Extensions.FileProviders;
using MoonCore.Helpers;
using Moonlight.ApiServer.Models;
namespace Moonlight.ApiServer.Services;
public class PluginService
{
private readonly ILogger<PluginService> Logger;
private readonly string PluginRoot;
public readonly Dictionary<PluginManifest, string> LoadedPlugins = new();
public IFileProvider WwwRootFileProvider;
public PluginService(ILogger<PluginService> logger)
{
Logger = logger;
PluginRoot = PathBuilder.Dir("storage", "plugins");
}
public async Task Load()
{
var jsonOptions = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
};
var pluginDirs = Directory.GetDirectories(PluginRoot);
var pluginMap = new Dictionary<PluginManifest, string>();
#region Scan plugins/ directory for plugin.json files
foreach (var dir in pluginDirs)
{
var metaPath = PathBuilder.File(dir, "plugin.json");
if (!File.Exists(metaPath))
{
Logger.LogWarning("Skipped '{dir}' as it is missing a plugin.json", dir);
continue;
}
var json = await File.ReadAllTextAsync(metaPath);
try
{
var meta = JsonSerializer.Deserialize<PluginManifest>(json, jsonOptions);
if (meta == null)
throw new JsonException("Unable to parse. Return value was null");
pluginMap.Add(meta, dir);
}
catch (JsonException e)
{
Logger.LogError("Unable to load plugin.json at '{path}': {e}", metaPath, e);
}
}
#endregion
#region Depdenency check
foreach (var plugin in pluginMap.Keys)
{
var hasMissingDep = false;
foreach (var dependency in plugin.Dependencies)
{
if (pluginMap.Keys.All(x => x.Id != dependency))
{
hasMissingDep = true;
Logger.LogWarning("Plugin '{name}' has missing dependency: {dep}", plugin.Name, dependency);
}
}
if (hasMissingDep)
Logger.LogWarning("Unable to load '{name}' due to missing dependencies", plugin.Name);
else
LoadedPlugins.Add(plugin, pluginMap[plugin]);
}
#endregion
#region Create wwwroot file provider
Logger.LogInformation("Creating wwwroot file provider");
WwwRootFileProvider = CreateWwwRootProvider();
#endregion
Logger.LogInformation("Loaded {count} plugins", LoadedPlugins.Count);
}
public Dictionary<string, string> GetAssemblies(string section)
{
var assemblyMap = new Dictionary<string, string>();
foreach (var loadedPlugin in LoadedPlugins.Keys)
{
// Skip all plugins which haven't defined any assemblies in that section
if (!loadedPlugin.Assemblies.ContainsKey(section))
continue;
var pluginPath = LoadedPlugins[loadedPlugin];
foreach (var assembly in loadedPlugin.Assemblies[section])
{
var assemblyFile = Path.GetFileName(assembly);
assemblyMap[assemblyFile] = PathBuilder.File(pluginPath, assembly);
}
}
return assemblyMap;
}
private IFileProvider CreateWwwRootProvider()
{
List<IFileProvider> wwwRootProviders = new();
foreach (var pluginFolder in LoadedPlugins.Values)
{
var wwwRootPath = Path.GetFullPath(
PathBuilder.Dir(pluginFolder, "wwwroot")
);
if(!Directory.Exists(wwwRootPath))
continue;
wwwRootProviders.Add(
new PhysicalFileProvider(wwwRootPath)
);
}
return new CompositeFileProvider(wwwRootProviders);
}
}

View File

@@ -1,8 +1,8 @@
using System.Runtime.Loader;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using Hangfire; using Hangfire;
using Hangfire.EntityFrameworkCore; using Hangfire.EntityFrameworkCore;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using MoonCore.EnvConfiguration; using MoonCore.EnvConfiguration;
@@ -15,12 +15,10 @@ using MoonCore.Helpers;
using Moonlight.ApiServer.Configuration; using Moonlight.ApiServer.Configuration;
using Moonlight.ApiServer.Database; using Moonlight.ApiServer.Database;
using Moonlight.ApiServer.Database.Entities; using Moonlight.ApiServer.Database.Entities;
using Moonlight.ApiServer.Helpers;
using Moonlight.ApiServer.Implementations; using Moonlight.ApiServer.Implementations;
using Moonlight.ApiServer.Implementations.Startup; using Moonlight.ApiServer.Implementations.Startup;
using Moonlight.ApiServer.Interfaces; using Moonlight.ApiServer.Interfaces;
using Moonlight.ApiServer.Plugins; using Moonlight.ApiServer.Plugins;
using Moonlight.ApiServer.Services;
namespace Moonlight.ApiServer; namespace Moonlight.ApiServer;
@@ -79,7 +77,6 @@ public class Startup
await PrepareDatabase(); await PrepareDatabase();
await UseCors(); await UseCors();
await UsePluginAssets(); // We need to move the plugin assets to the top to allow plugins to override content
await UseBase(); await UseBase();
await UseAuth(); await UseAuth();
await UseHangfire(); await UseHangfire();
@@ -191,7 +188,7 @@ public class Startup
var serviceCollection = new ServiceCollection(); var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(Configuration); serviceCollection.AddSingleton(Configuration);
serviceCollection.AddLogging(builder => serviceCollection.AddLogging(builder =>
{ {
builder.ClearProviders(); builder.ClearProviders();
@@ -199,20 +196,20 @@ public class Startup
}); });
PluginLoadServiceProvider = serviceCollection.BuildServiceProvider(); PluginLoadServiceProvider = serviceCollection.BuildServiceProvider();
// Collect startups // Collect startups
var pluginStartups = new List<IPluginStartup>(); var pluginStartups = new List<IPluginStartup>();
pluginStartups.Add(new CoreStartup()); pluginStartups.Add(new CoreStartup());
pluginStartups.AddRange(AdditionalPlugins); // Used by the development server pluginStartups.AddRange(AdditionalPlugins); // Used by the development server
// Do NOT remove the following comment, as its used to place the plugin startup register calls // Do NOT remove the following comment, as its used to place the plugin startup register calls
// MLBUILD_PLUGIN_STARTUP_HERE // MLBUILD_PLUGIN_STARTUP_HERE
PluginStartups = pluginStartups.ToArray(); PluginStartups = pluginStartups.ToArray();
return Task.CompletedTask; return Task.CompletedTask;
} }
@@ -221,16 +218,6 @@ public class Startup
return Task.CompletedTask; return Task.CompletedTask;
} }
private Task UsePluginAssets()
{
WebApplication.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new BundleAssetFileProvider()
});
return Task.CompletedTask;
}
#region Hooks #region Hooks
private async Task HookPluginBuild() private async Task HookPluginBuild()
@@ -489,7 +476,7 @@ public class Startup
}); });
WebApplicationBuilder.Services.AddAuthorization(); WebApplicationBuilder.Services.AddAuthorization();
// Add local oauth2 provider if enabled // Add local oauth2 provider if enabled
if (Configuration.Authentication.EnableLocalOAuth2) if (Configuration.Authentication.EnableLocalOAuth2)
WebApplicationBuilder.Services.AddScoped<IOAuth2Provider, LocalOAuth2Provider>(); WebApplicationBuilder.Services.AddScoped<IOAuth2Provider, LocalOAuth2Provider>();
@@ -514,12 +501,30 @@ public class Startup
private Task RegisterCors() private Task RegisterCors()
{ {
var allowedOrigins = Configuration.Kestrel.AllowedOrigins.Split(";", StringSplitOptions.RemoveEmptyEntries);
WebApplicationBuilder.Services.AddCors(options => WebApplicationBuilder.Services.AddCors(options =>
{ {
options.AddDefaultPolicy(builder => var cors = new CorsPolicyBuilder();
if (allowedOrigins.Contains("*"))
{ {
builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().Build(); cors.SetIsOriginAllowed(_ => true)
}); .AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}
else
{
cors.WithOrigins(allowedOrigins)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
}
options.AddDefaultPolicy(
cors.Build()
);
}); });
return Task.CompletedTask; return Task.CompletedTask;