diff --git a/ArchiSteamFarm/Core/ASF.cs b/ArchiSteamFarm/Core/ASF.cs index 7f6e3957a..158c9f04c 100644 --- a/ArchiSteamFarm/Core/ASF.cs +++ b/ArchiSteamFarm/Core/ASF.cs @@ -355,8 +355,8 @@ public static class ASF { } ArchiLogger.LogGenericInfo(Strings.IPCConfigChanged); - await ArchiKestrel.Stop().ConfigureAwait(false); - await ArchiKestrel.Start().ConfigureAwait(false); + + await ArchiKestrel.Restart().ConfigureAwait(false); } private static async Task OnChangedFile(string name, string fullPath) { diff --git a/ArchiSteamFarm/IPC/ArchiKestrel.cs b/ArchiSteamFarm/IPC/ArchiKestrel.cs index 619501416..e379751e2 100644 --- a/ArchiSteamFarm/IPC/ArchiKestrel.cs +++ b/ArchiSteamFarm/IPC/ArchiKestrel.cs @@ -30,6 +30,7 @@ using System.Net; using System.Reflection; using System.Text.Json; using System.Text.Json.Nodes; +using System.Threading; using System.Threading.Tasks; using ArchiSteamFarm.Core; using ArchiSteamFarm.Helpers.Json; @@ -64,6 +65,8 @@ internal static class ArchiKestrel { internal static HistoryTarget? HistoryTarget { get; private set; } + private static readonly SemaphoreSlim StateSemaphore = new(1, 1); + private static WebApplication? WebApplication; internal static void OnNewHistoryTarget(HistoryTarget? historyTarget = null) { @@ -78,43 +81,43 @@ internal static class ArchiKestrel { } } - internal static async Task Start() { - if (WebApplication != null) { - return; - } - - ASF.ArchiLogger.LogGenericInfo(Strings.IPCStarting); - - // Init history logger for /Api/Log usage - Logging.InitHistoryLogger(); - - WebApplication webApplication = await CreateWebApplication().ConfigureAwait(false); + internal static async Task Restart() { + await StateSemaphore.WaitAsync().ConfigureAwait(false); try { - // Start the server - await webApplication.StartAsync().ConfigureAwait(false); - } catch (Exception e) { - ASF.ArchiLogger.LogGenericException(e); - - await webApplication.DisposeAsync().ConfigureAwait(false); + await StopInternally().ConfigureAwait(false); + await StartInternally().ConfigureAwait(false); + } finally { + StateSemaphore.Release(); + } + } + internal static async Task Start() { + if (IsRunning) { return; } - WebApplication = webApplication; + await StateSemaphore.WaitAsync().ConfigureAwait(false); - ASF.ArchiLogger.LogGenericInfo(Strings.IPCReady); + try { + await StartInternally().ConfigureAwait(false); + } finally { + StateSemaphore.Release(); + } } internal static async Task Stop() { - if (WebApplication == null) { + if (!IsRunning) { return; } - await WebApplication.StopAsync().ConfigureAwait(false); - await WebApplication.DisposeAsync().ConfigureAwait(false); + await StateSemaphore.WaitAsync().ConfigureAwait(false); - WebApplication = null; + try { + await StopInternally().ConfigureAwait(false); + } finally { + StateSemaphore.Release(); + } } [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "PathString is a primitive, it's unlikely to be trimmed to the best of our knowledge")] @@ -519,4 +522,43 @@ internal static class ArchiKestrel { headers.CacheControl = cacheControl; } + + private static async Task StartInternally() { + if (WebApplication != null) { + return; + } + + ASF.ArchiLogger.LogGenericInfo(Strings.IPCStarting); + + // Init history logger for /Api/Log usage + Logging.InitHistoryLogger(); + + WebApplication webApplication = await CreateWebApplication().ConfigureAwait(false); + + try { + // Start the server + await webApplication.StartAsync().ConfigureAwait(false); + } catch (Exception e) { + ASF.ArchiLogger.LogGenericException(e); + + await webApplication.DisposeAsync().ConfigureAwait(false); + + return; + } + + WebApplication = webApplication; + + ASF.ArchiLogger.LogGenericInfo(Strings.IPCReady); + } + + private static async Task StopInternally() { + if (WebApplication == null) { + return; + } + + await WebApplication.StopAsync().ConfigureAwait(false); + await WebApplication.DisposeAsync().ConfigureAwait(false); + + WebApplication = null; + } }