Upgraded packages. Improved startup. Removed unused components
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moonlight.ApiServer.Configuration;
|
||||||
using Moonlight.ApiServer.Database.Entities;
|
using Moonlight.ApiServer.Database.Entities;
|
||||||
using Moonlight.ApiServer.Helpers;
|
using Moonlight.ApiServer.Helpers;
|
||||||
|
|
||||||
@@ -10,4 +11,8 @@ public class CoreDataContext : DatabaseContext
|
|||||||
|
|
||||||
public DbSet<User> Users { get; set; }
|
public DbSet<User> Users { get; set; }
|
||||||
public DbSet<ApiKey> ApiKeys { get; set; }
|
public DbSet<ApiKey> ApiKeys { get; set; }
|
||||||
|
|
||||||
|
public CoreDataContext(AppConfiguration configuration) : base(configuration)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer;
|
|
||||||
|
|
||||||
public static class DevServer
|
|
||||||
{
|
|
||||||
public async static Task Run(string[] args, Assembly[] pluginAssemblies)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Preparing development server");
|
|
||||||
await Startup.Run(args, pluginAssemblies);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using MoonCore.Services;
|
|
||||||
using Moonlight.ApiServer.Configuration;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Helpers;
|
|
||||||
|
|
||||||
public class ApplicationStateHelper
|
|
||||||
{
|
|
||||||
public static AppConfiguration Configuration { get; private set; }
|
|
||||||
|
|
||||||
public static void SetConfiguration(AppConfiguration configuration) => Configuration = configuration;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using MoonCore.Helpers;
|
|
||||||
using MoonCore.Services;
|
|
||||||
using Moonlight.ApiServer.Configuration;
|
using Moonlight.ApiServer.Configuration;
|
||||||
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
|
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
|
||||||
|
|
||||||
@@ -8,12 +6,13 @@ namespace Moonlight.ApiServer.Helpers;
|
|||||||
|
|
||||||
public abstract class DatabaseContext : DbContext
|
public abstract class DatabaseContext : DbContext
|
||||||
{
|
{
|
||||||
private AppConfiguration? Configuration;
|
|
||||||
public abstract string Prefix { get; }
|
public abstract string Prefix { get; }
|
||||||
|
|
||||||
public DatabaseContext()
|
private readonly AppConfiguration Configuration;
|
||||||
|
|
||||||
|
public DatabaseContext(AppConfiguration configuration)
|
||||||
{
|
{
|
||||||
Configuration = ApplicationStateHelper.Configuration;
|
Configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
@@ -21,15 +20,6 @@ public abstract class DatabaseContext : DbContext
|
|||||||
if (optionsBuilder.IsConfigured)
|
if (optionsBuilder.IsConfigured)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If no config service has been configured, we are probably
|
|
||||||
// in a EF Core migration, so we need to construct the config manually
|
|
||||||
if (Configuration == null)
|
|
||||||
{
|
|
||||||
Configuration = new ConfigService<AppConfiguration>(
|
|
||||||
PathBuilder.File("storage", "app.json")
|
|
||||||
).Get();
|
|
||||||
}
|
|
||||||
|
|
||||||
var config = Configuration.Database;
|
var config = Configuration.Database;
|
||||||
|
|
||||||
var connectionString = $"host={config.Host};" +
|
var connectionString = $"host={config.Host};" +
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MoonCore" Version="1.7.8" />
|
<PackageReference Include="MoonCore" Version="1.7.8" />
|
||||||
<PackageReference Include="MoonCore.Extended" Version="1.1.7" />
|
<PackageReference Include="MoonCore.Extended" Version="1.2.1" />
|
||||||
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.4" />
|
<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="Swashbuckle.AspNetCore" Version="6.4.0"/>
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
|
||||||
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
||||||
|
|||||||
5
Moonlight.ApiServer/Program.cs
Normal file
5
Moonlight.ApiServer/Program.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
using Moonlight.ApiServer;
|
||||||
|
|
||||||
|
var startup = new Startup();
|
||||||
|
|
||||||
|
await startup.Run(args);
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.Loader;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using MoonCore.Authentication;
|
using MoonCore.Configuration;
|
||||||
using MoonCore.Exceptions;
|
|
||||||
using MoonCore.Extended.Abstractions;
|
using MoonCore.Extended.Abstractions;
|
||||||
using MoonCore.Extended.Extensions;
|
using MoonCore.Extended.Extensions;
|
||||||
using MoonCore.Extended.Helpers;
|
using MoonCore.Extended.Helpers;
|
||||||
@@ -15,6 +13,7 @@ using MoonCore.Extensions;
|
|||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCore.PluginFramework.Extensions;
|
using MoonCore.PluginFramework.Extensions;
|
||||||
using MoonCore.Plugins;
|
using MoonCore.Plugins;
|
||||||
|
using MoonCore.Services;
|
||||||
using Moonlight.ApiServer.Configuration;
|
using Moonlight.ApiServer.Configuration;
|
||||||
using Moonlight.ApiServer.Database.Entities;
|
using Moonlight.ApiServer.Database.Entities;
|
||||||
using Moonlight.ApiServer.Helpers;
|
using Moonlight.ApiServer.Helpers;
|
||||||
@@ -24,20 +23,80 @@ using Moonlight.ApiServer.Interfaces.Auth;
|
|||||||
using Moonlight.ApiServer.Interfaces.OAuth2;
|
using Moonlight.ApiServer.Interfaces.OAuth2;
|
||||||
using Moonlight.ApiServer.Interfaces.Startup;
|
using Moonlight.ApiServer.Interfaces.Startup;
|
||||||
using Moonlight.ApiServer.Services;
|
using Moonlight.ApiServer.Services;
|
||||||
using Moonlight.Shared.Http.Responses.OAuth2;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer;
|
namespace Moonlight.ApiServer;
|
||||||
|
|
||||||
public static class Startup
|
// Cry about it
|
||||||
{
|
|
||||||
public static async Task Main(string[] args)
|
|
||||||
=> await Run(args, []);
|
|
||||||
|
|
||||||
public static async Task Run(string[] args, Assembly[]? additionalAssemblies = null)
|
|
||||||
{
|
|
||||||
// Cry about it
|
|
||||||
#pragma warning disable ASP0000
|
#pragma warning disable ASP0000
|
||||||
|
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
private string[] Args;
|
||||||
|
private Assembly[] AdditionalAssemblies;
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
private ILoggerProvider[] LoggerProviders;
|
||||||
|
private ILoggerFactory LoggerFactory;
|
||||||
|
private ILogger<Startup> Logger;
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
private AppConfiguration Configuration;
|
||||||
|
private ConfigurationService ConfigurationService;
|
||||||
|
private ConfigurationOptions ConfigurationOptions;
|
||||||
|
|
||||||
|
// WebApplication Stuff
|
||||||
|
private WebApplication WebApplication;
|
||||||
|
private WebApplicationBuilder WebApplicationBuilder;
|
||||||
|
|
||||||
|
// Plugin Loading
|
||||||
|
private PluginService PluginService;
|
||||||
|
private PluginLoaderService PluginLoaderService;
|
||||||
|
|
||||||
|
private IAppStartup[] PluginAppStartups;
|
||||||
|
private IDatabaseStartup[] PluginDatabaseStartups;
|
||||||
|
private IEndpointStartup[] PluginEndpointStartups;
|
||||||
|
|
||||||
|
public async Task Run(string[] args, Assembly[]? additionalAssemblies = null)
|
||||||
|
{
|
||||||
|
Args = args;
|
||||||
|
AdditionalAssemblies = additionalAssemblies ?? [];
|
||||||
|
|
||||||
|
await PrintVersion();
|
||||||
|
|
||||||
|
await CreateStorage();
|
||||||
|
await SetupAppConfiguration();
|
||||||
|
await SetupLogging();
|
||||||
|
await LoadPlugins();
|
||||||
|
await InitializePlugins();
|
||||||
|
|
||||||
|
await CreateWebApplicationBuilder();
|
||||||
|
|
||||||
|
await RegisterAppConfiguration();
|
||||||
|
await RegisterLogging();
|
||||||
|
await RegisterBase();
|
||||||
|
await RegisterDatabase();
|
||||||
|
await RegisterOAuth2();
|
||||||
|
await RegisterCaching();
|
||||||
|
await HookPluginBuild();
|
||||||
|
|
||||||
|
await BuildWebApplication();
|
||||||
|
|
||||||
|
await PrepareDatabase();
|
||||||
|
|
||||||
|
await UseBase();
|
||||||
|
await UseOAuth2();
|
||||||
|
await UseBaseMiddleware();
|
||||||
|
await HookPluginConfigure();
|
||||||
|
|
||||||
|
await MapBase();
|
||||||
|
await MapOAuth2();
|
||||||
|
await HookPluginEndpoints();
|
||||||
|
|
||||||
|
await WebApplication.RunAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task PrintVersion()
|
||||||
|
{
|
||||||
// Fancy start console output... yes very fancy :>
|
// Fancy start console output... yes very fancy :>
|
||||||
var rainbow = new Crayon.Rainbow(0.5);
|
var rainbow = new Crayon.Rainbow(0.5);
|
||||||
foreach (var c in "Moonlight")
|
foreach (var c in "Moonlight")
|
||||||
@@ -52,214 +111,313 @@ public static class Startup
|
|||||||
|
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
|
|
||||||
// Storage i guess
|
return Task.CompletedTask;
|
||||||
Directory.CreateDirectory(PathBuilder.Dir("storage"));
|
}
|
||||||
|
|
||||||
// Configure startup logger
|
private Task CreateStorage()
|
||||||
var startupLoggerFactory = new LoggerFactory();
|
{
|
||||||
|
Directory.CreateDirectory("storage");
|
||||||
|
Directory.CreateDirectory(PathBuilder.Dir("storage", "logs"));
|
||||||
|
Directory.CreateDirectory(PathBuilder.Dir("storage", "plugins"));
|
||||||
|
|
||||||
// TODO: Add direct extension method
|
return Task.CompletedTask;
|
||||||
var providers = LoggerBuildHelper.BuildFromConfiguration(configuration =>
|
}
|
||||||
|
|
||||||
|
#region Base
|
||||||
|
|
||||||
|
private Task RegisterBase()
|
||||||
|
{
|
||||||
|
WebApplicationBuilder.Services.AutoAddServices<Startup>();
|
||||||
|
WebApplicationBuilder.Services.AddHttpClient();
|
||||||
|
WebApplicationBuilder.Services.AddApiExceptionHandler();
|
||||||
|
|
||||||
|
// 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 PluginLoaderService.PluginAssemblies)
|
||||||
|
mvcBuilder.AddApplicationPart(pluginAssembly);
|
||||||
|
|
||||||
|
foreach (var additionalAssembly in AdditionalAssemblies)
|
||||||
|
mvcBuilder.AddApplicationPart(additionalAssembly);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task UseBase()
|
||||||
|
{
|
||||||
|
WebApplication.UseRouting();
|
||||||
|
WebApplication.UseExceptionHandler("/");
|
||||||
|
|
||||||
|
if (Configuration.Client.Enable)
|
||||||
|
{
|
||||||
|
if (WebApplication.Environment.IsDevelopment())
|
||||||
|
WebApplication.UseWebAssemblyDebugging();
|
||||||
|
|
||||||
|
WebApplication.UseBlazorFrameworkFiles();
|
||||||
|
WebApplication.UseStaticFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task UseBaseMiddleware()
|
||||||
|
{
|
||||||
|
WebApplication.UseMiddleware<AuthorizationMiddleware>();
|
||||||
|
WebApplication.UseMiddleware<ApiAuthenticationMiddleware>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task MapBase()
|
||||||
|
{
|
||||||
|
WebApplication.MapControllers();
|
||||||
|
|
||||||
|
if (Configuration.Client.Enable)
|
||||||
|
{
|
||||||
|
WebApplication.MapFallbackToFile("index.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Interfaces
|
||||||
|
|
||||||
|
private Task RegisterInterfaces()
|
||||||
|
{
|
||||||
|
WebApplicationBuilder.Services.AddInterfaces(configuration =>
|
||||||
|
{
|
||||||
|
// We use moonlight itself as a plugin assembly
|
||||||
|
configuration.AddAssembly(typeof(Startup).Assembly);
|
||||||
|
|
||||||
|
configuration.AddAssemblies(AdditionalAssemblies);
|
||||||
|
configuration.AddAssemblies(PluginLoaderService.PluginAssemblies);
|
||||||
|
|
||||||
|
configuration.AddInterface<IOAuth2Provider>();
|
||||||
|
configuration.AddInterface<IAuthInterceptor>();
|
||||||
|
});
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Plugin Loading
|
||||||
|
|
||||||
|
private async Task LoadPlugins()
|
||||||
|
{
|
||||||
|
// Load plugins
|
||||||
|
PluginService = new PluginService(
|
||||||
|
LoggerFactory.CreateLogger<PluginService>()
|
||||||
|
);
|
||||||
|
|
||||||
|
await PluginService.Load();
|
||||||
|
|
||||||
|
// Initialize api server plugin loader
|
||||||
|
PluginLoaderService = new PluginLoaderService(
|
||||||
|
LoggerFactory.CreateLogger<PluginLoaderService>()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Search up entrypoints and assemblies for the apiServer
|
||||||
|
var assemblyFiles = PluginService.GetAssemblies("apiServer")
|
||||||
|
.Values
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var entrypoints = PluginService.GetEntrypoints("apiServer");
|
||||||
|
|
||||||
|
// Build source from the retrieved data
|
||||||
|
PluginLoaderService.AddFilesSource(assemblyFiles, entrypoints);
|
||||||
|
|
||||||
|
// Perform assembly loading
|
||||||
|
await PluginLoaderService.Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task InitializePlugins()
|
||||||
|
{
|
||||||
|
var initialisationServiceCollection = new ServiceCollection();
|
||||||
|
|
||||||
|
// Configure base services for initialisation
|
||||||
|
initialisationServiceCollection.AddSingleton(Configuration);
|
||||||
|
|
||||||
|
initialisationServiceCollection.AddLogging(builder => { builder.AddProviders(LoggerProviders); });
|
||||||
|
|
||||||
|
// Configure plugin loading by using the interface service
|
||||||
|
initialisationServiceCollection.AddInterfaces(configuration =>
|
||||||
|
{
|
||||||
|
// We use moonlight itself as a plugin assembly
|
||||||
|
configuration.AddAssembly(typeof(Startup).Assembly);
|
||||||
|
|
||||||
|
configuration.AddAssemblies(PluginLoaderService.PluginAssemblies);
|
||||||
|
configuration.AddAssemblies(AdditionalAssemblies);
|
||||||
|
|
||||||
|
configuration.AddInterface<IAppStartup>();
|
||||||
|
configuration.AddInterface<IDatabaseStartup>();
|
||||||
|
configuration.AddInterface<IEndpointStartup>();
|
||||||
|
});
|
||||||
|
|
||||||
|
var initialisationServiceProvider = initialisationServiceCollection.BuildServiceProvider();
|
||||||
|
|
||||||
|
PluginAppStartups = initialisationServiceProvider.GetRequiredService<IAppStartup[]>();
|
||||||
|
PluginDatabaseStartups = initialisationServiceProvider.GetRequiredService<IDatabaseStartup[]>();
|
||||||
|
PluginEndpointStartups = initialisationServiceProvider.GetRequiredService<IEndpointStartup[]>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Hooks
|
||||||
|
|
||||||
|
private async Task HookPluginBuild()
|
||||||
|
{
|
||||||
|
foreach (var pluginAppStartup in PluginAppStartups)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await pluginAppStartup.BuildApp(WebApplicationBuilder);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(
|
||||||
|
"An error occured while processing 'BuildApp' for '{name}': {e}",
|
||||||
|
pluginAppStartup.GetType().FullName,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HookPluginConfigure()
|
||||||
|
{
|
||||||
|
foreach (var pluginAppStartup in PluginAppStartups)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await pluginAppStartup.ConfigureApp(WebApplication);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(
|
||||||
|
"An error occured while processing 'ConfigureApp' for '{name}': {e}",
|
||||||
|
pluginAppStartup.GetType().FullName,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HookPluginEndpoints()
|
||||||
|
{
|
||||||
|
foreach (var pluginEndpointStartup in PluginEndpointStartups)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await pluginEndpointStartup.ConfigureEndpoints(WebApplication);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(
|
||||||
|
"An error occured while processing 'ConfigureEndpoints' for '{name}': {e}",
|
||||||
|
pluginEndpointStartup.GetType().FullName,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Configurations
|
||||||
|
|
||||||
|
private Task SetupAppConfiguration()
|
||||||
|
{
|
||||||
|
ConfigurationService = new ConfigurationService();
|
||||||
|
|
||||||
|
// Setup options
|
||||||
|
ConfigurationOptions = new ConfigurationOptions();
|
||||||
|
|
||||||
|
ConfigurationOptions.AddConfiguration<AppConfiguration>("app");
|
||||||
|
ConfigurationOptions.Path = PathBuilder.Dir("storage");
|
||||||
|
ConfigurationOptions.EnvironmentPrefix = "MOONLIGHT";
|
||||||
|
|
||||||
|
// Create minimal logger
|
||||||
|
var loggerFactory = new LoggerFactory();
|
||||||
|
|
||||||
|
loggerFactory.AddMoonCore(configuration =>
|
||||||
{
|
{
|
||||||
configuration.Console.Enable = true;
|
configuration.Console.Enable = true;
|
||||||
configuration.Console.EnableAnsiMode = true;
|
configuration.Console.EnableAnsiMode = true;
|
||||||
configuration.FileLogging.Enable = false;
|
configuration.FileLogging.Enable = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
startupLoggerFactory.AddProviders(providers);
|
var logger = loggerFactory.CreateLogger<ConfigurationService>();
|
||||||
|
|
||||||
var startupLogger = startupLoggerFactory.CreateLogger("Startup");
|
// Retrieve configuration
|
||||||
|
Configuration = ConfigurationService.GetConfiguration<AppConfiguration>(
|
||||||
// Load plugins
|
ConfigurationOptions,
|
||||||
var pluginService = new PluginService(
|
logger
|
||||||
startupLoggerFactory.CreateLogger<PluginService>()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await pluginService.Load();
|
return Task.CompletedTask;
|
||||||
|
|
||||||
var pluginAssemblies = await LoadPlugins(pluginService, startupLoggerFactory);
|
|
||||||
|
|
||||||
// Configure startup interfaces
|
|
||||||
var startupServiceCollection = new ServiceCollection();
|
|
||||||
|
|
||||||
startupServiceCollection.AddConfiguration(options =>
|
|
||||||
{
|
|
||||||
options.UsePath(PathBuilder.Dir("storage"));
|
|
||||||
options.UseEnvironmentPrefix("MOONLIGHT");
|
|
||||||
|
|
||||||
options.AddConfiguration<AppConfiguration>("app");
|
|
||||||
});
|
|
||||||
|
|
||||||
startupServiceCollection.AddLogging(loggingBuilder => { loggingBuilder.AddProviders(providers); });
|
|
||||||
|
|
||||||
startupServiceCollection.AddPlugins(configuration =>
|
|
||||||
{
|
|
||||||
// Configure startup interfaces
|
|
||||||
configuration.AddInterface<IAppStartup>();
|
|
||||||
configuration.AddInterface<IDatabaseStartup>();
|
|
||||||
configuration.AddInterface<IEndpointStartup>();
|
|
||||||
|
|
||||||
// Configure assemblies to scan
|
|
||||||
configuration.AddAssembly(typeof(Startup).Assembly);
|
|
||||||
|
|
||||||
if (additionalAssemblies != null)
|
|
||||||
configuration.AddAssemblies(additionalAssemblies);
|
|
||||||
|
|
||||||
configuration.AddAssemblies(pluginAssemblies);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var startupServiceProvider = startupServiceCollection.BuildServiceProvider();
|
|
||||||
var appStartupInterfaces = startupServiceProvider.GetRequiredService<IAppStartup[]>();
|
|
||||||
|
|
||||||
var config = startupServiceProvider.GetRequiredService<AppConfiguration>();
|
|
||||||
ApplicationStateHelper.SetConfiguration(config);
|
|
||||||
|
|
||||||
// Start the actual app
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
|
||||||
|
|
||||||
await ConfigureLogging(builder);
|
|
||||||
|
|
||||||
await ConfigureDatabase(
|
|
||||||
builder,
|
|
||||||
startupLoggerFactory,
|
|
||||||
startupServiceProvider.GetRequiredService<IDatabaseStartup[]>()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Call interfaces
|
|
||||||
foreach (var startupInterface in appStartupInterfaces)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await startupInterface.BuildApp(builder);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
startupLogger.LogCritical(
|
|
||||||
"An unhandled error occured while processing BuildApp call for interface '{interfaceName}': {e}",
|
|
||||||
startupInterface.GetType().FullName,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var controllerBuilder = builder.Services.AddControllers();
|
|
||||||
|
|
||||||
// Add current assemblies to the application part
|
|
||||||
foreach (var moduleAssembly in pluginAssemblies)
|
|
||||||
controllerBuilder.AddApplicationPart(moduleAssembly);
|
|
||||||
|
|
||||||
builder.Services.AddSingleton(config);
|
|
||||||
builder.Services.AddSingleton(pluginService);
|
|
||||||
builder.Services.AutoAddServices(typeof(Startup).Assembly);
|
|
||||||
builder.Services.AddHttpClient();
|
|
||||||
|
|
||||||
await ConfigureCaching(builder, startupLogger, config);
|
|
||||||
|
|
||||||
await ConfigureOAuth2(builder, startupLogger, config);
|
|
||||||
|
|
||||||
// Implementation service
|
|
||||||
builder.Services.AddPlugins(configuration =>
|
|
||||||
{
|
|
||||||
configuration.AddInterface<IOAuth2Provider>();
|
|
||||||
configuration.AddInterface<IAuthInterceptor>();
|
|
||||||
|
|
||||||
configuration.AddAssembly(typeof(Startup).Assembly);
|
|
||||||
|
|
||||||
if (additionalAssemblies != null)
|
|
||||||
configuration.AddAssemblies(additionalAssemblies);
|
|
||||||
|
|
||||||
configuration.AddAssemblies(pluginAssemblies);
|
|
||||||
});
|
|
||||||
|
|
||||||
var app = builder.Build();
|
|
||||||
|
|
||||||
await PrepareDatabase(app);
|
|
||||||
|
|
||||||
if (config.Client.Enable)
|
|
||||||
{
|
|
||||||
if (app.Environment.IsDevelopment())
|
|
||||||
app.UseWebAssemblyDebugging();
|
|
||||||
|
|
||||||
app.UseBlazorFrameworkFiles();
|
|
||||||
app.UseStaticFiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseRouting();
|
|
||||||
|
|
||||||
app.UseApiErrorHandling();
|
|
||||||
|
|
||||||
await UseOAuth2(app);
|
|
||||||
|
|
||||||
// Call interfaces
|
|
||||||
foreach (var startupInterface in appStartupInterfaces)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await startupInterface.ConfigureApp(app);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
startupLogger.LogCritical(
|
|
||||||
"An unhandled error occured while processing ConfigureApp call for interface '{interfaceName}': {e}",
|
|
||||||
startupInterface.GetType().FullName,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseMiddleware<ApiAuthenticationMiddleware>();
|
|
||||||
|
|
||||||
app.UseMiddleware<AuthorizationMiddleware>();
|
|
||||||
|
|
||||||
// Call interfaces
|
|
||||||
var endpointStartupInterfaces = startupServiceProvider.GetRequiredService<IEndpointStartup[]>();
|
|
||||||
|
|
||||||
foreach (var endpointStartup in endpointStartupInterfaces)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await endpointStartup.ConfigureEndpoints(app);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
startupLogger.LogCritical(
|
|
||||||
"An unhandled error occured while processing ConfigureEndpoints call for interface '{interfaceName}': {e}",
|
|
||||||
endpointStartup.GetType().FullName,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app.MapControllers();
|
|
||||||
|
|
||||||
if (config.Client.Enable)
|
|
||||||
app.MapFallbackToFile("index.html");
|
|
||||||
|
|
||||||
await app.RunAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task RegisterAppConfiguration()
|
||||||
|
{
|
||||||
|
ConfigurationService.RegisterInDi(ConfigurationOptions, WebApplicationBuilder.Services);
|
||||||
|
WebApplicationBuilder.Services.AddSingleton(ConfigurationService);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Web Application
|
||||||
|
|
||||||
|
private Task CreateWebApplicationBuilder()
|
||||||
|
{
|
||||||
|
WebApplicationBuilder = WebApplication.CreateBuilder(Args);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task BuildWebApplication()
|
||||||
|
{
|
||||||
|
WebApplication = WebApplicationBuilder.Build();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Logging
|
#region Logging
|
||||||
|
|
||||||
public static async Task ConfigureLogging(IHostApplicationBuilder builder)
|
private Task SetupLogging()
|
||||||
{
|
{
|
||||||
// Create logging path
|
LoggerProviders = LoggerBuildHelper.BuildFromConfiguration(configuration =>
|
||||||
Directory.CreateDirectory(PathBuilder.Dir("storage", "logs"));
|
|
||||||
|
|
||||||
// Configure application logging
|
|
||||||
builder.Logging.ClearProviders();
|
|
||||||
|
|
||||||
builder.Logging.AddMoonCore(configuration =>
|
|
||||||
{
|
{
|
||||||
configuration.Console.Enable = true;
|
configuration.Console.Enable = true;
|
||||||
configuration.Console.EnableAnsiMode = true;
|
configuration.Console.EnableAnsiMode = true;
|
||||||
|
configuration.FileLogging.Enable = false;
|
||||||
configuration.FileLogging.Enable = true;
|
|
||||||
configuration.FileLogging.Path = PathBuilder.File("storage", "logs", "moonlight.log");
|
|
||||||
configuration.FileLogging.EnableLogRotation = true;
|
|
||||||
configuration.FileLogging.RotateLogNameTemplate = PathBuilder.File("storage", "logs", "moonlight.log.{0}");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
LoggerFactory = new LoggerFactory();
|
||||||
|
LoggerFactory.AddProviders(LoggerProviders);
|
||||||
|
|
||||||
|
Logger = LoggerFactory.CreateLogger<Startup>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RegisterLogging()
|
||||||
|
{
|
||||||
|
// Configure application logging
|
||||||
|
WebApplicationBuilder.Logging.ClearProviders();
|
||||||
|
WebApplicationBuilder.Logging.AddProviders(LoggerProviders);
|
||||||
|
|
||||||
// Logging levels
|
// Logging levels
|
||||||
var logConfigPath = PathBuilder.File("storage", "logConfig.json");
|
var logConfigPath = PathBuilder.File("storage", "logConfig.json");
|
||||||
|
|
||||||
@@ -278,40 +436,49 @@ public static class Startup
|
|||||||
await File.WriteAllTextAsync(logConfigPath, logConfig);
|
await File.WriteAllTextAsync(logConfigPath, logConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.Logging.AddConfiguration(await File.ReadAllTextAsync(logConfigPath));
|
// Add logging configuration
|
||||||
|
WebApplicationBuilder.Logging.AddConfiguration(
|
||||||
|
await File.ReadAllTextAsync(logConfigPath)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mute exception handler middleware
|
||||||
|
// https://github.com/dotnet/aspnetcore/issues/19740
|
||||||
|
WebApplicationBuilder.Logging.AddFilter(
|
||||||
|
"Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware",
|
||||||
|
LogLevel.Critical
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Database
|
#region Database
|
||||||
|
|
||||||
public static async Task ConfigureDatabase(IHostApplicationBuilder builder, ILoggerFactory loggerFactory,
|
private async Task RegisterDatabase()
|
||||||
IDatabaseStartup[] databaseStartups)
|
|
||||||
{
|
{
|
||||||
var logger = loggerFactory.CreateLogger<DatabaseHelper>();
|
var logger = LoggerFactory.CreateLogger<DatabaseHelper>();
|
||||||
var databaseHelper = new DatabaseHelper(logger);
|
var databaseHelper = new DatabaseHelper(logger);
|
||||||
|
|
||||||
var databaseCollection = new DatabaseContextCollection();
|
var databaseCollection = new DatabaseContextCollection();
|
||||||
|
|
||||||
foreach (var databaseStartup in databaseStartups)
|
foreach (var databaseStartup in PluginDatabaseStartups)
|
||||||
await databaseStartup.ConfigureDatabase(databaseCollection);
|
await databaseStartup.ConfigureDatabase(databaseCollection);
|
||||||
|
|
||||||
foreach (var database in databaseCollection)
|
foreach (var database in databaseCollection)
|
||||||
{
|
{
|
||||||
databaseHelper.AddDbContext(database);
|
databaseHelper.AddDbContext(database);
|
||||||
builder.Services.AddScoped(database);
|
WebApplicationBuilder.Services.AddScoped(database);
|
||||||
}
|
}
|
||||||
|
|
||||||
databaseHelper.GenerateMappings();
|
databaseHelper.GenerateMappings();
|
||||||
|
|
||||||
builder.Services.AddSingleton(databaseHelper);
|
WebApplicationBuilder.Services.AddSingleton(databaseHelper);
|
||||||
builder.Services.AddScoped(typeof(DatabaseRepository<>));
|
WebApplicationBuilder.Services.AddScoped(typeof(DatabaseRepository<>));
|
||||||
builder.Services.AddScoped(typeof(CrudHelper<,>));
|
WebApplicationBuilder.Services.AddScoped(typeof(CrudHelper<,>));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task PrepareDatabase(IApplicationBuilder builder)
|
private async Task PrepareDatabase()
|
||||||
{
|
{
|
||||||
using var scope = builder.ApplicationServices.CreateScope();
|
using var scope = WebApplication.Services.CreateScope();
|
||||||
var databaseHelper = scope.ServiceProvider.GetRequiredService<DatabaseHelper>();
|
var databaseHelper = scope.ServiceProvider.GetRequiredService<DatabaseHelper>();
|
||||||
|
|
||||||
await databaseHelper.EnsureMigrated(scope.ServiceProvider);
|
await databaseHelper.EnsureMigrated(scope.ServiceProvider);
|
||||||
@@ -321,39 +488,48 @@ public static class Startup
|
|||||||
|
|
||||||
#region OAuth2
|
#region OAuth2
|
||||||
|
|
||||||
public static Task ConfigureOAuth2(WebApplicationBuilder builder, ILogger logger, AppConfiguration config)
|
private Task RegisterOAuth2()
|
||||||
{
|
{
|
||||||
builder.AddOAuth2Authentication<User>(configuration =>
|
WebApplicationBuilder.Services.AddOAuth2Authentication<User>(configuration =>
|
||||||
{
|
{
|
||||||
configuration.AccessSecret = config.Authentication.AccessSecret;
|
configuration.AccessSecret = Configuration.Authentication.AccessSecret;
|
||||||
configuration.RefreshSecret = config.Authentication.RefreshSecret;
|
configuration.RefreshSecret = Configuration.Authentication.RefreshSecret;
|
||||||
configuration.RefreshDuration = TimeSpan.FromSeconds(config.Authentication.RefreshDuration);
|
configuration.RefreshDuration = TimeSpan.FromSeconds(Configuration.Authentication.RefreshDuration);
|
||||||
configuration.RefreshInterval = TimeSpan.FromSeconds(config.Authentication.AccessDuration);
|
configuration.RefreshInterval = TimeSpan.FromSeconds(Configuration.Authentication.AccessDuration);
|
||||||
configuration.ClientId = config.Authentication.OAuth2.ClientId;
|
configuration.ClientId = Configuration.Authentication.OAuth2.ClientId;
|
||||||
configuration.ClientSecret = config.Authentication.OAuth2.ClientSecret;
|
configuration.ClientSecret = Configuration.Authentication.OAuth2.ClientSecret;
|
||||||
configuration.AuthorizeEndpoint = config.PublicUrl + "/api/_auth/oauth2/authorize";
|
configuration.AuthorizeEndpoint = Configuration.PublicUrl + "/api/_auth/oauth2/authorize";
|
||||||
configuration.RedirectUri = config.PublicUrl;
|
configuration.RedirectUri = Configuration.PublicUrl;
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddScoped<IDataProvider<User>, LocalOAuth2Provider>();
|
WebApplicationBuilder.Services.AddScoped<IDataProvider<User>, LocalOAuth2Provider>();
|
||||||
|
|
||||||
if (config.Authentication.UseLocalOAuth2)
|
if (!Configuration.Authentication.UseLocalOAuth2)
|
||||||
{
|
return Task.CompletedTask;
|
||||||
builder.AddLocalOAuth2Provider<User>(config.PublicUrl);
|
|
||||||
builder.Services.AddScoped<ILocalProviderImplementation<User>, LocalOAuth2Provider>();
|
WebApplicationBuilder.Services.AddLocalOAuth2Provider<User>(Configuration.PublicUrl);
|
||||||
builder.Services.AddScoped<IOAuth2Provider<User>, LocalOAuth2Provider<User>>();
|
WebApplicationBuilder.Services.AddScoped<ILocalProviderImplementation<User>, LocalOAuth2Provider>();
|
||||||
}
|
WebApplicationBuilder.Services.AddScoped<IOAuth2Provider<User>, LocalOAuth2Provider<User>>();
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task UseOAuth2(WebApplication application)
|
private Task UseOAuth2()
|
||||||
{
|
{
|
||||||
application.UseOAuth2Authentication<User>();
|
WebApplication.UseOAuth2Authentication<User>();
|
||||||
application.UseLocalOAuth2Provider<User>();
|
WebApplication.UseMiddleware<PermissionLoaderMiddleware>();
|
||||||
|
|
||||||
application.UseMiddleware<PermissionLoaderMiddleware>();
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task MapOAuth2()
|
||||||
|
{
|
||||||
|
WebApplication.MapOAuth2Authentication<User>();
|
||||||
|
|
||||||
|
if (!Configuration.Authentication.UseLocalOAuth2)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
WebApplication.MapLocalOAuth2Provider<User>();
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,31 +537,11 @@ public static class Startup
|
|||||||
|
|
||||||
#region Caching
|
#region Caching
|
||||||
|
|
||||||
public static Task ConfigureCaching(WebApplicationBuilder builder, ILogger logger, AppConfiguration configuration)
|
private Task RegisterCaching()
|
||||||
{
|
{
|
||||||
builder.Services.AddMemoryCache();
|
WebApplicationBuilder.Services.AddMemoryCache();
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Plugin loading
|
|
||||||
|
|
||||||
private static async Task<Assembly[]> LoadPlugins(PluginService pluginService, ILoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
var pluginLoader = new PluginLoaderService(
|
|
||||||
loggerFactory.CreateLogger<PluginLoaderService>()
|
|
||||||
);
|
|
||||||
|
|
||||||
var assemblyFiles = pluginService.GetAssemblies("apiServer").Values.ToArray();
|
|
||||||
var entrypoints = pluginService.GetEntrypoints("apiServer");
|
|
||||||
|
|
||||||
pluginLoader.AddFilesSource(assemblyFiles, entrypoints);
|
|
||||||
|
|
||||||
await pluginLoader.Load();
|
|
||||||
|
|
||||||
return pluginLoader.PluginAssemblies;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Moonlight.Client;
|
|
||||||
|
|
||||||
public class DevClient
|
|
||||||
{
|
|
||||||
public async static Task Run(string[] args, Assembly[] assemblies)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Preparing development client");
|
|
||||||
await Startup.Run(args, assemblies);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
<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.7.8" />
|
<PackageReference Include="MoonCore" Version="1.7.8" />
|
||||||
<PackageReference Include="MoonCore.Blazor" Version="1.2.7" />
|
<PackageReference Include="MoonCore.Blazor" Version="1.2.7" />
|
||||||
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.4" />
|
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.5" />
|
||||||
<PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.1.2" />
|
<PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
13
Moonlight.Client/Program.cs
Normal file
13
Moonlight.Client/Program.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Moonlight.Client;
|
||||||
|
|
||||||
|
var startup = new Startup();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await startup.Run(args);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
@@ -19,22 +19,46 @@ namespace Moonlight.Client;
|
|||||||
|
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
public static async Task Main(string[] args)
|
private string[] Args;
|
||||||
=> await Run(args, []);
|
private Assembly[] AdditionalAssemblies;
|
||||||
|
|
||||||
public static async Task Run(string[] args, Assembly[] assemblies)
|
// Logging
|
||||||
|
private ILoggerProvider[] LoggerProviders;
|
||||||
|
private ILoggerFactory LoggerFactory;
|
||||||
|
private ILogger<Startup> Logger;
|
||||||
|
|
||||||
|
// WebAssemblyHost
|
||||||
|
private WebAssemblyHostBuilder WebAssemblyHostBuilder;
|
||||||
|
private WebAssemblyHost WebAssemblyHost;
|
||||||
|
|
||||||
|
// Plugin Loading
|
||||||
|
private PluginLoaderService PluginLoaderService;
|
||||||
|
|
||||||
|
public async Task Run(string[] args, Assembly[]? assemblies = null)
|
||||||
{
|
{
|
||||||
// Build pre run logger
|
Args = args;
|
||||||
var providers = LoggerBuildHelper.BuildFromConfiguration(configuration =>
|
AdditionalAssemblies = assemblies ?? [];
|
||||||
{
|
|
||||||
configuration.Console.Enable = true;
|
|
||||||
configuration.Console.EnableAnsiMode = true;
|
|
||||||
configuration.FileLogging.Enable = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
using var loggerFactory = new LoggerFactory(providers);
|
await PrintVersion();
|
||||||
var logger = loggerFactory.CreateLogger("Startup");
|
await SetupLogging();
|
||||||
|
|
||||||
|
await CreateWebAssemblyHostBuilder();
|
||||||
|
|
||||||
|
await LoadPlugins();
|
||||||
|
|
||||||
|
await RegisterLogging();
|
||||||
|
await RegisterBase();
|
||||||
|
await RegisterOAuth2();
|
||||||
|
await RegisterFormComponents();
|
||||||
|
await RegisterInterfaces();
|
||||||
|
|
||||||
|
await BuildWebAssemblyHost();
|
||||||
|
|
||||||
|
await WebAssemblyHost.RunAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task PrintVersion()
|
||||||
|
{
|
||||||
// Fancy start console output... yes very fancy :>
|
// Fancy start console output... yes very fancy :>
|
||||||
Console.Write("Running ");
|
Console.Write("Running ");
|
||||||
|
|
||||||
@@ -51,58 +75,132 @@ public class Startup
|
|||||||
|
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
|
|
||||||
// Building app
|
return Task.CompletedTask;
|
||||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
}
|
||||||
|
|
||||||
// Load plugins
|
private Task RegisterBase()
|
||||||
var pluginLoader = new PluginLoaderService(
|
{
|
||||||
loggerFactory.CreateLogger<PluginLoaderService>()
|
WebAssemblyHostBuilder.RootComponents.Add<App>("#app");
|
||||||
|
WebAssemblyHostBuilder.RootComponents.Add<HeadOutlet>("head::after");
|
||||||
|
|
||||||
|
WebAssemblyHostBuilder.Services.AddScoped(_ =>
|
||||||
|
new HttpClient
|
||||||
|
{
|
||||||
|
BaseAddress = new Uri(WebAssemblyHostBuilder.HostEnvironment.BaseAddress)
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
pluginLoader.AddHttpHostedSource($"{builder.HostEnvironment.BaseAddress}api/pluginsStream");
|
WebAssemblyHostBuilder.Services.AddScoped<WindowService>();
|
||||||
await pluginLoader.Load();
|
WebAssemblyHostBuilder.Services.AddMoonCoreBlazorTailwind();
|
||||||
|
WebAssemblyHostBuilder.Services.AddScoped<LocalStorageService>();
|
||||||
|
|
||||||
builder.Services.AddSingleton(pluginLoader);
|
WebAssemblyHostBuilder.Services.AutoAddServices<Program>();
|
||||||
|
|
||||||
// Configure application logging
|
return Task.CompletedTask;
|
||||||
builder.Logging.ClearProviders();
|
}
|
||||||
builder.Logging.AddProviders(providers);
|
|
||||||
|
|
||||||
builder.RootComponents.Add<App>("#app");
|
private Task RegisterOAuth2()
|
||||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
{
|
||||||
|
WebAssemblyHostBuilder.AddTokenAuthentication();
|
||||||
|
WebAssemblyHostBuilder.AddOAuth2();
|
||||||
|
|
||||||
builder.Services.AddScoped(_ => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
builder.AddTokenAuthentication();
|
|
||||||
builder.AddOAuth2();
|
|
||||||
|
|
||||||
builder.Services.AddMoonCoreBlazorTailwind();
|
|
||||||
builder.Services.AddScoped<WindowService>();
|
|
||||||
builder.Services.AddScoped<LocalStorageService>();
|
|
||||||
|
|
||||||
builder.Services.AutoAddServices<Startup>();
|
|
||||||
|
|
||||||
|
private Task RegisterFormComponents()
|
||||||
|
{
|
||||||
FormComponentRepository.Set<string, StringComponent>();
|
FormComponentRepository.Set<string, StringComponent>();
|
||||||
FormComponentRepository.Set<int, IntComponent>();
|
FormComponentRepository.Set<int, IntComponent>();
|
||||||
FormComponentRepository.Set<DateTime, DateComponent>();
|
|
||||||
|
|
||||||
// Interface service
|
return Task.CompletedTask;
|
||||||
builder.Services.AddPlugins(configuration =>
|
}
|
||||||
|
|
||||||
|
#region Interfaces
|
||||||
|
|
||||||
|
private Task RegisterInterfaces()
|
||||||
|
{
|
||||||
|
WebAssemblyHostBuilder.Services.AddInterfaces(configuration =>
|
||||||
{
|
{
|
||||||
|
// We use moonlight itself as a plugin assembly
|
||||||
configuration.AddAssembly(typeof(Startup).Assembly);
|
configuration.AddAssembly(typeof(Startup).Assembly);
|
||||||
|
|
||||||
configuration.AddAssemblies(assemblies);
|
configuration.AddAssemblies(AdditionalAssemblies);
|
||||||
|
configuration.AddAssemblies(PluginLoaderService.PluginAssemblies);
|
||||||
configuration.AddAssemblies(pluginLoader.PluginAssemblies);
|
|
||||||
|
|
||||||
configuration.AddInterface<IAppLoader>();
|
configuration.AddInterface<IAppLoader>();
|
||||||
configuration.AddInterface<IAppScreen>();
|
configuration.AddInterface<IAppScreen>();
|
||||||
|
|
||||||
configuration.AddInterface<ISidebarItemProvider>();
|
configuration.AddInterface<ISidebarItemProvider>();
|
||||||
});
|
});
|
||||||
|
|
||||||
var app = builder.Build();
|
return Task.CompletedTask;
|
||||||
|
|
||||||
await app.RunAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Plugins
|
||||||
|
|
||||||
|
private async Task LoadPlugins()
|
||||||
|
{
|
||||||
|
// Initialize api server plugin loader
|
||||||
|
PluginLoaderService = new PluginLoaderService(
|
||||||
|
LoggerFactory.CreateLogger<PluginLoaderService>()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Build source from the retrieved data
|
||||||
|
var pluginsStreamUrl = $"{WebAssemblyHostBuilder.HostEnvironment.BaseAddress}api/pluginsStream";
|
||||||
|
PluginLoaderService.AddHttpHostedSource(pluginsStreamUrl);
|
||||||
|
|
||||||
|
// Perform assembly loading
|
||||||
|
await PluginLoaderService.Load();
|
||||||
|
|
||||||
|
// Add plugin loader service to di for the Router/App.razor
|
||||||
|
WebAssemblyHostBuilder.Services.AddSingleton(PluginLoaderService);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Logging
|
||||||
|
|
||||||
|
private Task SetupLogging()
|
||||||
|
{
|
||||||
|
LoggerProviders = LoggerBuildHelper.BuildFromConfiguration(configuration =>
|
||||||
|
{
|
||||||
|
configuration.Console.Enable = true;
|
||||||
|
configuration.Console.EnableAnsiMode = true;
|
||||||
|
configuration.FileLogging.Enable = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
LoggerFactory = new LoggerFactory();
|
||||||
|
LoggerFactory.AddProviders(LoggerProviders);
|
||||||
|
|
||||||
|
Logger = LoggerFactory.CreateLogger<Startup>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task RegisterLogging()
|
||||||
|
{
|
||||||
|
WebAssemblyHostBuilder.Logging.ClearProviders();
|
||||||
|
WebAssemblyHostBuilder.Logging.AddProviders(LoggerProviders);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Web Application
|
||||||
|
|
||||||
|
private Task CreateWebAssemblyHostBuilder()
|
||||||
|
{
|
||||||
|
WebAssemblyHostBuilder = WebAssemblyHostBuilder.CreateDefault(Args);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task BuildWebAssemblyHost()
|
||||||
|
{
|
||||||
|
WebAssemblyHost = WebAssemblyHostBuilder.Build();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -399,5 +399,14 @@
|
|||||||
"whitespace-nowrap",
|
"whitespace-nowrap",
|
||||||
"z-10",
|
"z-10",
|
||||||
"z-40",
|
"z-40",
|
||||||
"z-50"
|
"z-50",
|
||||||
|
"sm:max-w-md",
|
||||||
|
"sm:max-w-lg",
|
||||||
|
"sm:max-w-xl",
|
||||||
|
"sm:max-w-2xl",
|
||||||
|
"sm:max-w-3xl",
|
||||||
|
"sm:max-w-4xl",
|
||||||
|
"sm:max-w-5xl",
|
||||||
|
"sm:max-w-6xl",
|
||||||
|
"sm:max-w-7xl"
|
||||||
]
|
]
|
||||||
Reference in New Issue
Block a user