245 lines
6.6 KiB
Plaintext
245 lines
6.6 KiB
Plaintext
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
|
|
|
|
@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
|
|
@using ShadcnBlazor.Dialogs
|
|
@using ShadcnBlazor.Progresses
|
|
@using ShadcnBlazor.Spinners
|
|
|
|
@inject HttpClient HttpClient
|
|
|
|
<DialogHeader>
|
|
<DialogTitle>
|
|
Updating instance to @Version...
|
|
</DialogTitle>
|
|
</DialogHeader>
|
|
|
|
<div class="grid grid-cols-1 xl:grid-cols-2 w-full gap-5">
|
|
<div class="text-base flex flex-col p-2 gap-y-1">
|
|
@for (var i = 0; i < Steps.Length; i++)
|
|
{
|
|
if (CurrentStep == i)
|
|
{
|
|
<div class="flex flex-row items-center gap-x-1">
|
|
@if (IsFailed)
|
|
{
|
|
<CircleXIcon ClassName="text-red-500 size-5"/>
|
|
}
|
|
else
|
|
{
|
|
<Spinner ClassName="size-5"/>
|
|
}
|
|
<span>
|
|
@Steps[i]
|
|
</span>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
if (i < CurrentStep)
|
|
{
|
|
<div class="flex flex-row items-center gap-x-1">
|
|
<CircleCheckIcon ClassName="text-green-500 size-5"/>
|
|
<span>
|
|
@Steps[i]
|
|
</span>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<div class="text-muted-foreground flex flex-row items-center gap-x-1">
|
|
<span class="size-5"></span>
|
|
@Steps[i]
|
|
</div>
|
|
}
|
|
}
|
|
}
|
|
</div>
|
|
<div class="bg-black text-white rounded-lg font-mono h-96 flex flex-col-reverse overflow-auto p-3 scrollbar-thin">
|
|
@for (var i = LogLines.Count - 1; i >= 0; i--)
|
|
{
|
|
<div>
|
|
@LogLines[i]
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
@if (CurrentStep == Steps.Length || IsFailed)
|
|
{
|
|
<DialogFooter ClassName="justify-end">
|
|
<Button Variant="ButtonVariant.Outline" @onclick="CloseAsync">Close</Button>
|
|
</DialogFooter>
|
|
}
|
|
else
|
|
{
|
|
<DialogFooter>
|
|
<Progress ClassName="my-1" Value="@Progress"></Progress>
|
|
</DialogFooter>
|
|
}
|
|
|
|
@code
|
|
{
|
|
[Parameter] public string Version { get; set; }
|
|
[Parameter] public bool NoBuildCache { get; set; }
|
|
|
|
private bool IsFailed;
|
|
private int Progress;
|
|
private int CurrentStep;
|
|
|
|
private readonly string[] Steps =
|
|
[
|
|
"Checking", // 0
|
|
"Updating configuration files", // 1
|
|
"Starting rebuild task", // 2
|
|
"Building docker image", // 3
|
|
"Redeploying container instance", // 4
|
|
"Waiting for container instance to start up", // 5
|
|
"Update complete" // 6
|
|
];
|
|
|
|
private readonly List<string?> LogLines = new();
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
if (!firstRender)
|
|
return;
|
|
|
|
// Checking
|
|
CurrentStep = 0;
|
|
Progress = 0;
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
await Task.Delay(2000);
|
|
|
|
// Update configuration
|
|
CurrentStep = 1;
|
|
Progress = 20;
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
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(
|
|
request,
|
|
HttpCompletionOption.ResponseHeadersRead
|
|
);
|
|
|
|
await using var responseStream = await response.Content.ReadAsStreamAsync();
|
|
using var streamReader = new StreamReader(responseStream);
|
|
|
|
do
|
|
{
|
|
try
|
|
{
|
|
var line = await streamReader.ReadLineAsync();
|
|
|
|
if (line == null)
|
|
break;
|
|
|
|
if (string.IsNullOrWhiteSpace(line))
|
|
continue;
|
|
|
|
var data = line.Trim("data: ");
|
|
var deserializedData = JsonSerializer.Deserialize<RebuildEventDto>(data, Constants.SerializerOptions);
|
|
|
|
switch (deserializedData.Type)
|
|
{
|
|
case RebuildEventType.Log:
|
|
LogLines.Add(deserializedData.Data);
|
|
break;
|
|
|
|
case RebuildEventType.Step:
|
|
|
|
switch (deserializedData.Data)
|
|
{
|
|
case "BuildImage":
|
|
|
|
// Building docker image
|
|
|
|
CurrentStep = 3;
|
|
Progress = 40;
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
break;
|
|
|
|
case "ServiceDown":
|
|
|
|
// Redeploying container instance
|
|
|
|
CurrentStep = 4;
|
|
Progress = 60;
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case RebuildEventType.Failed:
|
|
|
|
IsFailed = true;
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
return;
|
|
}
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
break;
|
|
}
|
|
} while (true);
|
|
|
|
// Waiting for container instance to start up
|
|
|
|
CurrentStep = 5;
|
|
Progress = 90;
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
// Wait some time for instance to shut down
|
|
await Task.Delay(TimeSpan.FromSeconds(5));
|
|
|
|
// Ping instance until its reachable again
|
|
while (true)
|
|
{
|
|
try
|
|
{
|
|
await HttpClient.GetStringAsync("api/ping");
|
|
break;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Ignored
|
|
}
|
|
|
|
await Task.Delay(3000);
|
|
}
|
|
|
|
// Update complete
|
|
CurrentStep = 7;
|
|
Progress = 100;
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
}
|