using System.Reflection; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Microsoft.JSInterop; using MoonCore.Blazor.Extensions; using MoonCore.Blazor.Services; using MoonCore.Blazor.Tailwind.Extensions; using MoonCore.Blazor.Tailwind.Forms; using MoonCore.Blazor.Tailwind.Forms.Components; using MoonCore.Extensions; using MoonCore.Helpers; using MoonCore.PluginFramework.Extensions; using MoonCore.Plugins; using Moonlight.Client.Interfaces; using Moonlight.Client.Services; using Moonlight.Client.UI; using Moonlight.Client.UI.Forms; using Moonlight.Shared.Http.Responses.Assets; using Moonlight.Shared.Http.Responses.PluginsStream; namespace Moonlight.Client; public class Startup { private string[] Args; // Logging private ILoggerProvider[] LoggerProviders; private ILoggerFactory LoggerFactory; private ILogger Logger; // WebAssemblyHost private WebAssemblyHostBuilder WebAssemblyHostBuilder; private WebAssemblyHost WebAssemblyHost; // Plugin Loading private PluginLoaderService PluginLoaderService; private ApplicationAssemblyService ApplicationAssemblyService; public async Task Run(string[] args, Assembly[]? assemblies = null) { Args = args; // Setup assembly storage ApplicationAssemblyService = new() { AdditionalAssemblies = assemblies ?? [] }; await PrintVersion(); await SetupLogging(); await CreateWebAssemblyHostBuilder(); await LoadPlugins(); await RegisterLogging(); await RegisterBase(); await RegisterOAuth2(); await RegisterFormComponents(); await RegisterInterfaces(); await BuildWebAssemblyHost(); await LoadAssets(); await WebAssemblyHost.RunAsync(); } private Task PrintVersion() { // Fancy start console output... yes very fancy :> Console.Write("Running "); var rainbow = new Crayon.Rainbow(0.5); foreach (var c in "Moonlight") { Console.Write( rainbow .Next() .Bold() .Text(c.ToString()) ); } Console.WriteLine(); return Task.CompletedTask; } private Task RegisterBase() { WebAssemblyHostBuilder.RootComponents.Add("#app"); WebAssemblyHostBuilder.RootComponents.Add("head::after"); WebAssemblyHostBuilder.Services.AddScoped(_ => new HttpClient { BaseAddress = new Uri(WebAssemblyHostBuilder.HostEnvironment.BaseAddress) } ); WebAssemblyHostBuilder.Services.AddScoped(); WebAssemblyHostBuilder.Services.AddMoonCoreBlazorTailwind(); WebAssemblyHostBuilder.Services.AddScoped(); WebAssemblyHostBuilder.Services.AutoAddServices(); return Task.CompletedTask; } private Task RegisterOAuth2() { WebAssemblyHostBuilder.AddTokenAuthentication(); WebAssemblyHostBuilder.AddOAuth2(); return Task.CompletedTask; } private Task RegisterFormComponents() { FormComponentRepository.Set(); FormComponentRepository.Set(); return Task.CompletedTask; } #region Asset Loading private async Task LoadAssets() { var apiClient = WebAssemblyHost.Services.GetRequiredService(); var assetManifest = await apiClient.GetJson("api/assets"); var jsRuntime = WebAssemblyHost.Services.GetRequiredService(); foreach (var cssFile in assetManifest.CssFiles) await jsRuntime.InvokeVoidAsync("moonlight.assets.loadCss", cssFile); foreach (var javascriptFile in assetManifest.JavascriptFiles) await jsRuntime.InvokeVoidAsync("moonlight.assets.loadJavascript", javascriptFile); } #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(); configuration.AddInterface(); configuration.AddInterface(); }); return Task.CompletedTask; } #endregion #region Plugins private async Task LoadPlugins() { // Initialize api server plugin loader PluginLoaderService = new PluginLoaderService( LoggerFactory.CreateLogger() ); // Build source from the retrieved data var pluginsStreamUrl = $"{WebAssemblyHostBuilder.HostEnvironment.BaseAddress}api/assets/plugins"; PluginLoaderService.AddHttpHostedSource(pluginsStreamUrl); // Perform assembly loading await PluginLoaderService.Load(); // Add plugin loader service to di for the Router/App.razor ApplicationAssemblyService.PluginAssemblies = PluginLoaderService.PluginAssemblies; WebAssemblyHostBuilder.Services.AddSingleton(ApplicationAssemblyService); } #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(); 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 }