From 660319afec9bd1a4ffb4ce043ced341fe9f00aa7 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Thu, 29 Jan 2026 13:59:24 +0100 Subject: [PATCH] Renamed SharedSerializationContext to SerializationContext. Added error handling and no build cache functionality --- .../Admin/ContainerHelperController.cs | 5 +- .../Requests/RequestRebuildDto.cs | 3 ++ .../ContainerHelper/SerializationContext.cs | 1 + .../Services/ContainerHelperService.cs | 33 +++++++++---- Moonlight.Api/Startup/Startup.Base.cs | 2 +- Moonlight.Frontend/Constants.cs | 2 +- .../UI/Admin/Modals/UpdateInstanceModal.razor | 49 ++++++++++++++----- .../UI/Admin/Views/Sys/Instance.razor | 31 ++++++++---- .../ContainerHelper/RequestRebuildDto.cs | 15 ++++++ ...tionContext.cs => SerializationContext.cs} | 5 +- 10 files changed, 109 insertions(+), 37 deletions(-) create mode 100644 Moonlight.Api/Http/Services/ContainerHelper/Requests/RequestRebuildDto.cs create mode 100644 Moonlight.Shared/Http/Requests/Admin/ContainerHelper/RequestRebuildDto.cs rename Moonlight.Shared/Http/{SharedSerializationContext.cs => SerializationContext.cs} (91%) diff --git a/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs b/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs index 599351a5..7fed23c7 100644 --- a/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs +++ b/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Options; using Moonlight.Api.Configuration; using Moonlight.Api.Mappers; using Moonlight.Api.Services; +using Moonlight.Shared.Http.Events; using Moonlight.Shared.Http.Requests.Admin.ContainerHelper; using Moonlight.Shared.Http.Responses.Admin; @@ -34,9 +35,9 @@ public class ContainerHelperController : Controller } [HttpPost("rebuild")] - public Task RebuildAsync() + public Task RebuildAsync([FromBody] RequestRebuildDto request) { - var result = ContainerHelperService.RebuildAsync(); + var result = ContainerHelperService.RebuildAsync(request.NoBuildCache); var mappedResult = result.Select(ContainerHelperMapper.ToDto); return Task.FromResult( diff --git a/Moonlight.Api/Http/Services/ContainerHelper/Requests/RequestRebuildDto.cs b/Moonlight.Api/Http/Services/ContainerHelper/Requests/RequestRebuildDto.cs new file mode 100644 index 00000000..c7dda283 --- /dev/null +++ b/Moonlight.Api/Http/Services/ContainerHelper/Requests/RequestRebuildDto.cs @@ -0,0 +1,3 @@ +namespace Moonlight.Api.Http.Services.ContainerHelper.Requests; + +public record RequestRebuildDto(bool NoBuildCache); \ No newline at end of file diff --git a/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs b/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs index 182f44d1..371fb761 100644 --- a/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs +++ b/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs @@ -8,6 +8,7 @@ namespace Moonlight.Api.Http.Services.ContainerHelper; [JsonSerializable(typeof(SetVersionDto))] [JsonSerializable(typeof(ProblemDetails))] [JsonSerializable(typeof(RebuildEventDto))] +[JsonSerializable(typeof(RequestRebuildDto))] public partial class SerializationContext : JsonSerializerContext { private static JsonSerializerOptions? InternalTunedOptions; diff --git a/Moonlight.Api/Services/ContainerHelperService.cs b/Moonlight.Api/Services/ContainerHelperService.cs index 5467fe94..434857bd 100644 --- a/Moonlight.Api/Services/ContainerHelperService.cs +++ b/Moonlight.Api/Services/ContainerHelperService.cs @@ -1,4 +1,5 @@ -using System.Net.Http.Json; +using System.Net.Http.Headers; +using System.Net.Http.Json; using System.Text.Json; using Moonlight.Api.Http.Services.ContainerHelper; using Moonlight.Api.Http.Services.ContainerHelper.Requests; @@ -32,11 +33,22 @@ public class ContainerHelperService } } - public async IAsyncEnumerable RebuildAsync() + public async IAsyncEnumerable RebuildAsync(bool noBuildCache) { var client = HttpClientFactory.CreateClient("ContainerHelper"); - var response = await client.GetAsync("api/rebuild", HttpCompletionOption.ResponseHeadersRead); + var request = new HttpRequestMessage(HttpMethod.Post, "api/rebuild"); + + request.Content = JsonContent.Create( + new RequestRebuildDto(noBuildCache), + null, + SerializationContext.TunedOptions + ); + + var response = await client.SendAsync( + request, + HttpCompletionOption.ResponseHeadersRead + ); if (!response.IsSuccessStatusCode) { @@ -90,15 +102,16 @@ public class ContainerHelperService new SetVersionDto(version), SerializationContext.TunedOptions ); - - if(response.IsSuccessStatusCode) + + if (response.IsSuccessStatusCode) return; - - var problemDetails = await response.Content.ReadFromJsonAsync(SerializationContext.TunedOptions); - - if(problemDetails == null) + + var problemDetails = + await response.Content.ReadFromJsonAsync(SerializationContext.TunedOptions); + + if (problemDetails == null) throw new HttpRequestException($"Failed to set version: {response.ReasonPhrase}"); - + throw new HttpRequestException($"Failed to set version: {problemDetails.Detail ?? problemDetails.Title}"); } } \ No newline at end of file diff --git a/Moonlight.Api/Startup/Startup.Base.cs b/Moonlight.Api/Startup/Startup.Base.cs index a40e42b3..25c97ea6 100644 --- a/Moonlight.Api/Startup/Startup.Base.cs +++ b/Moonlight.Api/Startup/Startup.Base.cs @@ -19,7 +19,7 @@ public partial class Startup { builder.Services.AddControllers().AddJsonOptions(options => { - options.JsonSerializerOptions.TypeInfoResolverChain.Add(SharedSerializationContext.Default); + options.JsonSerializerOptions.TypeInfoResolverChain.Add(SerializationContext.Default); }); builder.Logging.ClearProviders(); diff --git a/Moonlight.Frontend/Constants.cs b/Moonlight.Frontend/Constants.cs index 685cc859..5c42627f 100644 --- a/Moonlight.Frontend/Constants.cs +++ b/Moonlight.Frontend/Constants.cs @@ -18,7 +18,7 @@ public static class Constants }; // Add source generated options from shared project - InternalOptions.TypeInfoResolverChain.Add(SharedSerializationContext.Default); + InternalOptions.TypeInfoResolverChain.Add(SerializationContext.Default); return InternalOptions; } diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor index 7bbc6ffc..96668c25 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor @@ -2,6 +2,7 @@ @using System.Text.Json @using LucideBlazor +@using Moonlight.Shared.Http @using Moonlight.Shared.Http.Events @using Moonlight.Shared.Http.Requests.Admin.ContainerHelper @using ShadcnBlazor.Buttons @@ -18,13 +19,20 @@
-
+
@for (var i = 0; i < Steps.Length; i++) { if (CurrentStep == i) { -
- +
+ @if (IsFailed) + { + + } + else + { + + } @Steps[i] @@ -34,8 +42,8 @@ { if (i < CurrentStep) { -
- +
+ @Steps[i] @@ -43,8 +51,8 @@ } else { -
- +
+ @Steps[i]
} @@ -61,7 +69,7 @@
-@if (CurrentStep == Steps.Length) +@if (CurrentStep == Steps.Length || IsFailed) { @@ -77,7 +85,9 @@ else @code { [Parameter] public string Version { get; set; } - + [Parameter] public bool NoBuildCache { get; set; } + + private bool IsFailed; private int Progress; private int CurrentStep; @@ -114,15 +124,23 @@ else await HttpClient.PostAsJsonAsync("api/admin/ch/version", new SetVersionDto() { Version = Version - }); + }, SerializationContext.TunedOptions); // Starting rebuild task CurrentStep = 2; Progress = 30; await InvokeAsync(StateHasChanged); + var request = new HttpRequestMessage(HttpMethod.Post, "api/admin/ch/rebuild"); + + request.Content = JsonContent.Create( + new RequestRebuildDto(NoBuildCache), + null, + SerializationContext.TunedOptions + ); + var response = await HttpClient.SendAsync( - new HttpRequestMessage(HttpMethod.Post, "api/admin/ch/rebuild"), + request, HttpCompletionOption.ResponseHeadersRead ); @@ -176,6 +194,13 @@ else } break; + + case RebuildEventType.Failed: + + IsFailed = true; + await InvokeAsync(StateHasChanged); + + return; } await InvokeAsync(StateHasChanged); @@ -187,7 +212,7 @@ else } while (true); // Waiting for container instance to start up - + CurrentStep = 5; Progress = 90; await InvokeAsync(StateHasChanged); diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor index 13fc0438..6f0bd3cc 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor @@ -10,6 +10,7 @@ @using ShadcnBlazor.Extras.Dialogs @using ShadcnBlazor.Fields @using ShadcnBlazor.Selects +@using ShadcnBlazor.Switches @inject HttpClient HttpClient @inject DialogService DialogService @@ -30,9 +31,7 @@
- - Version - + Version / Branch + + Bypass Build Cache + + + +
@@ -110,6 +116,7 @@ { private ContainerHelperStatusDto StatusDto; private string SelectedVersion = "v2.1"; + private bool NoBuildCache; private async Task LoadAsync(LazyLoader _) { @@ -119,7 +126,11 @@ private async Task ApplyAsync() { await DialogService.LaunchAsync( - parameters => { parameters[nameof(UpdateInstanceModal.Version)] = SelectedVersion; }, + parameters => + { + parameters[nameof(UpdateInstanceModal.Version)] = SelectedVersion; + parameters[nameof(UpdateInstanceModal.NoBuildCache)] = NoBuildCache; + }, onConfigure: model => { model.ShowCloseButton = false; @@ -130,17 +141,17 @@ private async Task AskApplyAsync() { - if(string.IsNullOrWhiteSpace(SelectedVersion)) + if (string.IsNullOrWhiteSpace(SelectedVersion)) return; - + var shouldContinue = await ConfirmRiskyVersionAsync( "Moonlight Rebuild", "If you continue the moonlight instance will become unavailable during the rebuild process. This will impact users on this instance" ); - - if(!shouldContinue) + + if (!shouldContinue) return; - + if (!Regex.IsMatch(SelectedVersion, @"^v\d+(\.\d+)*b?$")) { shouldContinue = await ConfirmRiskyVersionAsync( @@ -163,7 +174,7 @@ if (!shouldContinue) return; - + await ApplyAsync(); } diff --git a/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/RequestRebuildDto.cs b/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/RequestRebuildDto.cs new file mode 100644 index 00000000..335f7be5 --- /dev/null +++ b/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/RequestRebuildDto.cs @@ -0,0 +1,15 @@ +namespace Moonlight.Shared.Http.Requests.Admin.ContainerHelper; + +public class RequestRebuildDto +{ + public bool NoBuildCache { get; set; } + + public RequestRebuildDto() + { + } + + public RequestRebuildDto(bool noBuildCache) + { + NoBuildCache = noBuildCache; + } +} \ No newline at end of file diff --git a/Moonlight.Shared/Http/SharedSerializationContext.cs b/Moonlight.Shared/Http/SerializationContext.cs similarity index 91% rename from Moonlight.Shared/Http/SharedSerializationContext.cs rename to Moonlight.Shared/Http/SerializationContext.cs index 8bb4e776..0d5a3a22 100644 --- a/Moonlight.Shared/Http/SharedSerializationContext.cs +++ b/Moonlight.Shared/Http/SerializationContext.cs @@ -2,6 +2,7 @@ using System.Text.Json.Serialization; using Moonlight.Shared.Http.Events; using Moonlight.Shared.Http.Requests.Admin.ApiKeys; +using Moonlight.Shared.Http.Requests.Admin.ContainerHelper; using Moonlight.Shared.Http.Requests.Admin.Roles; using Moonlight.Shared.Http.Requests.Admin.Themes; using Moonlight.Shared.Http.Requests.Admin.Users; @@ -51,10 +52,12 @@ namespace Moonlight.Shared.Http; // Container Helper [JsonSerializable(typeof(ContainerHelperStatusDto))] +[JsonSerializable(typeof(RequestRebuildDto))] +[JsonSerializable(typeof(SetVersionDto))] // Misc [JsonSerializable(typeof(ProblemDetails))] -public partial class SharedSerializationContext : JsonSerializerContext +public partial class SerializationContext : JsonSerializerContext { private static JsonSerializerOptions? InternalTunedOptions;