diff --git a/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs b/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs
index 6c01e184aade5..bfec118186550 100644
--- a/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs
+++ b/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs
@@ -23,6 +23,7 @@
using System;
using System.Net;
+using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.IPC.Requests;
@@ -31,11 +32,20 @@
using ArchiSteamFarm.Steam;
using ArchiSteamFarm.Storage;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Hosting;
namespace ArchiSteamFarm.IPC.Controllers.Api;
[Route("Api/Command")]
public sealed class CommandController : ArchiController {
+ private readonly IHostApplicationLifetime ApplicationLifetime;
+
+ public CommandController(IHostApplicationLifetime applicationLifetime) {
+ ArgumentNullException.ThrowIfNull(applicationLifetime);
+
+ ApplicationLifetime = applicationLifetime;
+ }
+
///
/// Executes a command.
///
@@ -72,8 +82,28 @@ public async Task> CommandPost([FromBody] CommandR
command = command[commandPrefix.Length..];
}
- string? response = await targetBot.Commands.Response(EAccess.Owner, command).ConfigureAwait(false);
+ // Update process can result in kestrel shutdown request, just before patching the files
+ // In this case, we have very little opportunity to do anything, especially we will not have access to the return value of the command
+ // That's because update command will synchronously stop the kestrel, and wait for it before proceeding with an update, and that'll wait for us finishing the request, never happening
+ // Therefore, we'll allow this command to proceed while listening for application shutdown request, if it happens, we'll do our best by getting alternative signal that update is proceeding
+ TaskCompletionSource applicationStopping = new();
+
+ CancellationTokenRegistration applicationStoppingRegistration = ApplicationLifetime.ApplicationStopping.Register(() => applicationStopping.SetResult(true));
- return Ok(new GenericResponse(response));
+ await using (applicationStoppingRegistration.ConfigureAwait(false)) {
+ Task commandTask = targetBot.Commands.Response(EAccess.Owner, command);
+
+ string? response;
+
+ if (await Task.WhenAny(commandTask, applicationStopping.Task).ConfigureAwait(false) == commandTask) {
+ response = await commandTask.ConfigureAwait(false);
+ } else {
+ // It's almost guaranteed that this is the result of update process requesting kestrel shutdown
+ // However, we're still going to check PendingVersionUpdate, which should be set by the update process as alternative way to inform us about pending update
+ response = ASFController.PendingVersionUpdate != null ? Strings.PatchingFiles : Strings.Exiting;
+ }
+
+ return Ok(new GenericResponse(response));
+ }
}
}