Removed unused calls and classes from the old plugin system
This commit is contained in:
@@ -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; } = "*";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user