From f33b218b17cad3eadbddf7fcf643a16da267038b Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 23 May 2023 01:32:49 +0200 Subject: [PATCH 1/2] Added base bundle service --- ...seCheckup.cs => DatabaseCheckupService.cs} | 36 ++++--- .../Api/Moonlight/ResourcesController.cs | 38 ++++++- .../App/Services/Sessions/BundleService.cs | 101 ++++++++++++++++++ Moonlight/Pages/_Layout.cshtml | 84 +++++++++------ Moonlight/Program.cs | 35 +++--- 5 files changed, 229 insertions(+), 65 deletions(-) rename Moonlight/App/Helpers/{DatabaseCheckup.cs => DatabaseCheckupService.cs} (76%) create mode 100644 Moonlight/App/Services/Sessions/BundleService.cs diff --git a/Moonlight/App/Helpers/DatabaseCheckup.cs b/Moonlight/App/Helpers/DatabaseCheckupService.cs similarity index 76% rename from Moonlight/App/Helpers/DatabaseCheckup.cs rename to Moonlight/App/Helpers/DatabaseCheckupService.cs index 63d637c6..0bccd8cc 100644 --- a/Moonlight/App/Helpers/DatabaseCheckup.cs +++ b/Moonlight/App/Helpers/DatabaseCheckupService.cs @@ -8,16 +8,22 @@ using MySql.Data.MySqlClient; namespace Moonlight.App.Helpers; -public class DatabaseCheckup +public class DatabaseCheckupService { - public static void Perform() + private readonly ConfigService ConfigService; + + public DatabaseCheckupService(ConfigService configService) { - // This will also copy all default config files - var context = new DataContext(new ConfigService(new StorageService())); + ConfigService = configService; + } + + public async Task Perform() + { + var context = new DataContext(ConfigService); Logger.Info("Checking database"); - if (!context.Database.CanConnect()) + if (!await context.Database.CanConnectAsync()) { Logger.Fatal("-----------------------------------------------"); Logger.Fatal("Unable to connect to mysql database"); @@ -32,19 +38,19 @@ public class DatabaseCheckup Logger.Info("Checking for pending migrations"); - var migrations = context.Database - .GetPendingMigrations() + var migrations = (await context.Database + .GetPendingMigrationsAsync()) .ToArray(); - + if (migrations.Any()) { Logger.Info($"{migrations.Length} migrations pending. Updating now"); - BackupDatabase(); + await BackupDatabase(); Logger.Info("Applying migrations"); - context.Database.Migrate(); + await context.Database.MigrateAsync(); Logger.Info("Successfully applied migrations"); } @@ -54,7 +60,7 @@ public class DatabaseCheckup } } - public static void BackupDatabase() + public async Task BackupDatabase() { Logger.Info("Creating backup from database"); @@ -79,14 +85,14 @@ public class DatabaseCheckup var sw = new Stopwatch(); sw.Start(); - using MySqlConnection conn = new MySqlConnection(connectionString); - using MySqlCommand cmd = new MySqlCommand(); + await using MySqlConnection conn = new MySqlConnection(connectionString); + await using MySqlCommand cmd = new MySqlCommand(); using MySqlBackup mb = new MySqlBackup(cmd); cmd.Connection = conn; - conn.Open(); + await conn.OpenAsync(); mb.ExportToFile(file); - conn.Close(); + await conn.CloseAsync(); sw.Stop(); Logger.Info($"Done. {sw.Elapsed.TotalSeconds}s"); diff --git a/Moonlight/App/Http/Controllers/Api/Moonlight/ResourcesController.cs b/Moonlight/App/Http/Controllers/Api/Moonlight/ResourcesController.cs index 329fa63a..6632386c 100644 --- a/Moonlight/App/Http/Controllers/Api/Moonlight/ResourcesController.cs +++ b/Moonlight/App/Http/Controllers/Api/Moonlight/ResourcesController.cs @@ -1,10 +1,12 @@ -using Logging.Net; +using System.Text; +using Logging.Net; using Microsoft.AspNetCore.Mvc; using Moonlight.App.Helpers; using Moonlight.App.Models.Misc; using Moonlight.App.Services; using Moonlight.App.Services.Files; using Moonlight.App.Services.LogServices; +using Moonlight.App.Services.Sessions; namespace Moonlight.App.Http.Controllers.Api.Moonlight; @@ -14,12 +16,14 @@ public class ResourcesController : Controller { private readonly SecurityLogService SecurityLogService; private readonly BucketService BucketService; + private readonly BundleService BundleService; public ResourcesController(SecurityLogService securityLogService, - BucketService bucketService) + BucketService bucketService, BundleService bundleService) { SecurityLogService = securityLogService; BucketService = bucketService; + BundleService = bundleService; } [HttpGet("images/{name}")] @@ -73,4 +77,34 @@ public class ResourcesController : Controller return Problem(); } } + + [HttpGet("bundle/js")] + public Task GetJs() + { + if (BundleService.BundledFinished) + { + return Task.FromResult( + File(Encoding.ASCII.GetBytes(BundleService.BundledJs), "text/javascript") + ); + } + + return Task.FromResult( + NotFound() + ); + } + + [HttpGet("bundle/css")] + public Task GetCss() + { + if (BundleService.BundledFinished) + { + return Task.FromResult( + File(Encoding.ASCII.GetBytes(BundleService.BundledCss), "text/css") + ); + } + + return Task.FromResult( + NotFound() + ); + } } \ No newline at end of file diff --git a/Moonlight/App/Services/Sessions/BundleService.cs b/Moonlight/App/Services/Sessions/BundleService.cs new file mode 100644 index 00000000..70a70ece --- /dev/null +++ b/Moonlight/App/Services/Sessions/BundleService.cs @@ -0,0 +1,101 @@ +using Logging.Net; + +namespace Moonlight.App.Services.Sessions; + +public class BundleService +{ + private readonly ConfigService ConfigService; + + public BundleService(ConfigService configService) + { + ConfigService = configService; + + CacheId = Guid.NewGuid().ToString(); + + Task.Run(Bundle); + } + + public string BundledJs { get; private set; } + public string BundledCss { get; private set; } + public string CacheId { get; private set; } + public bool BundledFinished { get; set; } = false; + private bool IsBundling { get; set; } = false; + + public async Task Bundle() + { + if (!IsBundling) + IsBundling = true; + + Logger.Info("Bundling js and css files"); + + BundledJs = ""; + BundledCss = ""; + + var url = ConfigService + .GetSection("Moonlight") + .GetValue("AppUrl"); + + BundledJs = await BundleFiles( + new[] + { + url + "/_framework/blazor.server.js", + url + "/assets/plugins/global/plugins.bundle.js", + url + "/_content/XtermBlazor/XtermBlazor.min.js", + url + "/_content/BlazorTable/BlazorTable.min.js", + url + "/_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js", + url + "/_content/Blazor.ContextMenu/blazorContextMenu.min.js", + "https://www.google.com/recaptcha/api.js", + "https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.5.0/lib/xterm-addon-fit.min.js", + "https://cdn.jsdelivr.net/npm/xterm-addon-search@0.8.2/lib/xterm-addon-search.min.js", + "https://cdn.jsdelivr.net/npm/xterm-addon-web-links@0.5.0/lib/xterm-addon-web-links.min.js", + url + "/_content/BlazorMonaco/lib/monaco-editor/min/vs/loader.js", + "require.config({ paths: { 'vs': '/_content/BlazorMonaco/lib/monaco-editor/min/vs' } });", + url + "/_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.js", + url + "/_content/BlazorMonaco/jsInterop.js", + url + "/assets/js/scripts.bundle.js", + url + "/assets/js/moonlight.js", + "moonlight.loading.registerXterm();", + url + "/_content/Blazor-ApexCharts/js/apex-charts.min.js", + url + "/_content/Blazor-ApexCharts/js/blazor-apex-charts.js" + } + ); + + BundledCss = await BundleFiles( + new[] + { + "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700", + url + "/assets/css/style.bundle.css", + url + "/assets/css/flashbang.css", + url + "/assets/css/snow.css", + url + "/assets/css/utils.css", + url + "/assets/css/blazor.css", + url + "/_content/XtermBlazor/XtermBlazor.css", + url + "/_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.css", + url + "/_content/Blazor.ContextMenu/blazorContextMenu.min.css", + url + "/assets/plugins/global/plugins.bundle.css", + } + ); + + Logger.Info("Successfully bundled"); + BundledFinished = true; + } + + private async Task BundleFiles(string[] jsUrls) + { + var bundledJs = ""; + + using HttpClient client = new HttpClient(); + foreach (string url in jsUrls) + { + if (url.StartsWith("http")) + { + var jsCode = await client.GetStringAsync(url); + bundledJs += jsCode + "\n"; + } + else + bundledJs += url + "\n"; + } + + return bundledJs; + } +} \ No newline at end of file diff --git a/Moonlight/Pages/_Layout.cshtml b/Moonlight/Pages/_Layout.cshtml index 8038b0be..fbc5889a 100644 --- a/Moonlight/Pages/_Layout.cshtml +++ b/Moonlight/Pages/_Layout.cshtml @@ -2,10 +2,12 @@ @using Moonlight.App.Extensions @using Moonlight.App.Repositories @using Moonlight.App.Services +@using Moonlight.App.Services.Sessions @namespace Moonlight.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @inject ConfigService ConfigService +@inject BundleService BundleService @inject LoadingMessageRepository LoadingMessageRepository @{ @@ -36,20 +38,29 @@ - - - - - - - + + @if (BundleService.BundledFinished) + { + + } + else + { + - - - + + + + + + - + + + + + + } @@ -78,7 +89,7 @@ @{ string loadingMessage; - + try { loadingMessage = LoadingMessageRepository.Get().Random().Message; @@ -95,33 +106,38 @@ - - - - - - - +@if (BundleService.BundledFinished) +{ + +} +else +{ + + + + + + - + - - - + + + - - - - + + + + - - + + - + - - + + +} \ No newline at end of file diff --git a/Moonlight/Program.cs b/Moonlight/Program.cs index 28a2e9cb..d9a46b8e 100644 --- a/Moonlight/Program.cs +++ b/Moonlight/Program.cs @@ -33,17 +33,23 @@ namespace Moonlight { // App version. Change for release public static readonly string AppVersion = $"InDev {Formatter.FormatDateOnly(DateTime.Now.Date)}"; - - public static void Main(string[] args) + + public static async Task Main(string[] args) { Logger.UsedLogger = new CacheLogger(); - - Logger.Info($"Working dir: {Directory.GetCurrentDirectory()}"); - - DatabaseCheckup.Perform(); - var builder = WebApplication.CreateBuilder(args); + Logger.Info($"Working dir: {Directory.GetCurrentDirectory()}"); + + Logger.Info("Running pre-init tasks"); + // This will also copy all default config files + var configService = new ConfigService(new StorageService()); + var databaseCheckupService = new DatabaseCheckupService(configService); + + await databaseCheckupService.Perform(); + + var builder = WebApplication.CreateBuilder(args); + // Switch to logging.net injection // TODO: Enable in production //builder.Logging.ClearProviders(); @@ -59,10 +65,10 @@ namespace Moonlight options.HandshakeTimeout = TimeSpan.FromSeconds(10); }); builder.Services.AddHttpContextAccessor(); - + // Databases builder.Services.AddDbContext(); - + // Repositories builder.Services.AddSingleton(); builder.Services.AddScoped(); @@ -84,7 +90,7 @@ namespace Moonlight builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(typeof(Repository<>)); - + // Services builder.Services.AddSingleton(); builder.Services.AddSingleton(); @@ -121,6 +127,7 @@ namespace Moonlight builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -148,7 +155,7 @@ namespace Moonlight builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddScoped(); - + // Background services builder.Services.AddSingleton(); builder.Services.AddSingleton(); @@ -176,7 +183,7 @@ namespace Moonlight app.UseWebSockets(); app.MapControllers(); - + app.MapBlazorHub(); app.MapFallbackToPage("/_Host"); @@ -185,11 +192,11 @@ namespace Moonlight _ = app.Services.GetRequiredService(); _ = app.Services.GetRequiredService(); _ = app.Services.GetRequiredService(); - + // Discord bot service //var discordBotService = app.Services.GetRequiredService(); - app.Run(); + await app.RunAsync(); } } } \ No newline at end of file From a308a067d44cff9a700c7659440980f744135b11 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 23 May 2023 03:29:52 +0200 Subject: [PATCH 2/2] Reworked all css and js imports using new bundler --- .../App/Services/Sessions/BundleService.cs | 142 +++++++++++------- Moonlight/Pages/_Layout.cshtml | 64 +++----- 2 files changed, 110 insertions(+), 96 deletions(-) diff --git a/Moonlight/App/Services/Sessions/BundleService.cs b/Moonlight/App/Services/Sessions/BundleService.cs index 70a70ece..2b0cfbfc 100644 --- a/Moonlight/App/Services/Sessions/BundleService.cs +++ b/Moonlight/App/Services/Sessions/BundleService.cs @@ -4,98 +4,126 @@ namespace Moonlight.App.Services.Sessions; public class BundleService { - private readonly ConfigService ConfigService; - public BundleService(ConfigService configService) { - ConfigService = configService; + var url = configService + .GetSection("Moonlight") + .GetValue("AppUrl"); + + #region JS + + JsFiles = new(); + + JsFiles.AddRange(new[] + { + url + "/_framework/blazor.server.js", + url + "/assets/plugins/global/plugins.bundle.js", + url + "/_content/XtermBlazor/XtermBlazor.min.js", + url + "/_content/BlazorTable/BlazorTable.min.js", + url + "/_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js", + url + "/_content/Blazor.ContextMenu/blazorContextMenu.min.js", + "https://www.google.com/recaptcha/api.js", + "https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.5.0/lib/xterm-addon-fit.min.js", + "https://cdn.jsdelivr.net/npm/xterm-addon-search@0.8.2/lib/xterm-addon-search.min.js", + "https://cdn.jsdelivr.net/npm/xterm-addon-web-links@0.5.0/lib/xterm-addon-web-links.min.js", + url + "/_content/BlazorMonaco/lib/monaco-editor/min/vs/loader.js", + "require.config({ paths: { 'vs': '/_content/BlazorMonaco/lib/monaco-editor/min/vs' } });", + url + "/_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.js", + url + "/_content/BlazorMonaco/jsInterop.js", + url + "/assets/js/scripts.bundle.js", + url + "/assets/js/moonlight.js", + "moonlight.loading.registerXterm();", + url + "/_content/Blazor-ApexCharts/js/apex-charts.min.js", + url + "/_content/Blazor-ApexCharts/js/blazor-apex-charts.js" + }); + + #endregion + + #region CSS + + CssFiles = new(); + + CssFiles.AddRange(new[] + { + "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700", + url + "/assets/css/style.bundle.css", + url + "/assets/css/flashbang.css", + url + "/assets/css/snow.css", + url + "/assets/css/utils.css", + url + "/assets/css/blazor.css", + url + "/_content/XtermBlazor/XtermBlazor.css", + url + "/_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.css", + url + "/_content/Blazor.ContextMenu/blazorContextMenu.min.css", + url + "/assets/plugins/global/plugins.bundle.css" + }); + + #endregion CacheId = Guid.NewGuid().ToString(); Task.Run(Bundle); } - + + // Javascript public string BundledJs { get; private set; } + public readonly List JsFiles; + + // CSS public string BundledCss { get; private set; } + public readonly List CssFiles; + + // States public string CacheId { get; private set; } public bool BundledFinished { get; set; } = false; private bool IsBundling { get; set; } = false; - public async Task Bundle() + private async Task Bundle() { if (!IsBundling) IsBundling = true; - + Logger.Info("Bundling js and css files"); - + BundledJs = ""; BundledCss = ""; - var url = ConfigService - .GetSection("Moonlight") - .GetValue("AppUrl"); - BundledJs = await BundleFiles( - new[] - { - url + "/_framework/blazor.server.js", - url + "/assets/plugins/global/plugins.bundle.js", - url + "/_content/XtermBlazor/XtermBlazor.min.js", - url + "/_content/BlazorTable/BlazorTable.min.js", - url + "/_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js", - url + "/_content/Blazor.ContextMenu/blazorContextMenu.min.js", - "https://www.google.com/recaptcha/api.js", - "https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.5.0/lib/xterm-addon-fit.min.js", - "https://cdn.jsdelivr.net/npm/xterm-addon-search@0.8.2/lib/xterm-addon-search.min.js", - "https://cdn.jsdelivr.net/npm/xterm-addon-web-links@0.5.0/lib/xterm-addon-web-links.min.js", - url + "/_content/BlazorMonaco/lib/monaco-editor/min/vs/loader.js", - "require.config({ paths: { 'vs': '/_content/BlazorMonaco/lib/monaco-editor/min/vs' } });", - url + "/_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.js", - url + "/_content/BlazorMonaco/jsInterop.js", - url + "/assets/js/scripts.bundle.js", - url + "/assets/js/moonlight.js", - "moonlight.loading.registerXterm();", - url + "/_content/Blazor-ApexCharts/js/apex-charts.min.js", - url + "/_content/Blazor-ApexCharts/js/blazor-apex-charts.js" - } + JsFiles ); BundledCss = await BundleFiles( - new[] - { - "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700", - url + "/assets/css/style.bundle.css", - url + "/assets/css/flashbang.css", - url + "/assets/css/snow.css", - url + "/assets/css/utils.css", - url + "/assets/css/blazor.css", - url + "/_content/XtermBlazor/XtermBlazor.css", - url + "/_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.css", - url + "/_content/Blazor.ContextMenu/blazorContextMenu.min.css", - url + "/assets/plugins/global/plugins.bundle.css", - } + CssFiles ); - + Logger.Info("Successfully bundled"); BundledFinished = true; } - - private async Task BundleFiles(string[] jsUrls) + + private async Task BundleFiles(IEnumerable items) { - var bundledJs = ""; + var bundled = ""; using HttpClient client = new HttpClient(); - foreach (string url in jsUrls) + foreach (string item in items) { - if (url.StartsWith("http")) + // Item is a url, fetch it + if (item.StartsWith("http")) { - var jsCode = await client.GetStringAsync(url); - bundledJs += jsCode + "\n"; + try + { + var jsCode = await client.GetStringAsync(item); + bundled += jsCode + "\n"; + } + catch (Exception e) + { + Logger.Warn($"Error fetching '{item}' while bundling"); + Logger.Warn(e); + } } - else - bundledJs += url + "\n"; + else // If not, it is probably a manual addition, so add it + bundled += item + "\n"; } - return bundledJs; + return bundled; } } \ No newline at end of file diff --git a/Moonlight/Pages/_Layout.cshtml b/Moonlight/Pages/_Layout.cshtml index fbc5889a..975533a9 100644 --- a/Moonlight/Pages/_Layout.cshtml +++ b/Moonlight/Pages/_Layout.cshtml @@ -38,6 +38,7 @@ + @*This import is not in the bundle because the files it references are linked relative to the current lath*@ @if (BundleService.BundledFinished) @@ -46,20 +47,19 @@ } else { - - - - - - - - - - - - - - + foreach (var cssFile in BundleService.CssFiles) + { + if (cssFile.StartsWith("http")) + { + + } + else + { + + } + } } @@ -113,31 +113,17 @@ } else { - - - - - - - - - - - - - - - - - - - - - - - - - + foreach (var jsFile in BundleService.JsFiles) + { + if (jsFile.StartsWith("http")) + { + + } + else + { + @Html.Raw("") + } + } } \ No newline at end of file