From a423905c6f22cbcc9e5841337ef38b718344b860 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:40:17 -0700 Subject: [PATCH] feat(console): add Core.Headless flag and guard the exit-pause prompt --- .../Console/HeadlessConsoleInputException.cs | 18 ++++++++++++++++++ Projects/Server/Main.cs | 10 +++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 Projects/Server/Console/HeadlessConsoleInputException.cs diff --git a/Projects/Server/Console/HeadlessConsoleInputException.cs b/Projects/Server/Console/HeadlessConsoleInputException.cs new file mode 100644 index 000000000..ff02fcc94 --- /dev/null +++ b/Projects/Server/Console/HeadlessConsoleInputException.cs @@ -0,0 +1,18 @@ +using System; + +namespace Server; + +/// +/// Thrown when interactive console input is required but the server is running +/// headless (stdin is not a TTY). Rides the fatal-shutdown path. +/// +public sealed class HeadlessConsoleInputException : Exception +{ + public HeadlessConsoleInputException(string context) + : base( + $"Interactive console input required but the server is headless (stdin is not a TTY). " + + $"Pre-supply the required configuration/save data. Prompt: {context}." + ) + { + } +} diff --git a/Projects/Server/Main.cs b/Projects/Server/Main.cs index 9f6553904..f89fd3084 100644 --- a/Projects/Server/Main.cs +++ b/Projects/Server/Main.cs @@ -147,6 +147,8 @@ public static class Core public static bool Closing => ClosingTokenSource.IsCancellationRequested; + public static bool Headless { get; private set; } + public static int GlobalUpdateRange { get; set; } = 18; public static int GlobalMaxUpdateRange { get; set; } = 24; @@ -258,7 +260,7 @@ public static class Core // ignored } - if (!close) + if (!close && !Core.Headless) { Console.WriteLine("This exception is fatal, press return to exit"); ConsoleInputHandler.ReadLine(); @@ -407,6 +409,12 @@ public static class Core Console.CancelKeyPress += Console_CancelKeyPressed; + Headless = Console.IsInputRedirected; + if (Headless) + { + logger.Information("Headless mode detected (stdin is not a TTY); interactive console input is disabled."); + } + // LibDeflate is not thread safe, so we need to create a new instance for each thread var standard = Deflate.Standard; AppDomain.CurrentDomain.ProcessExit += (_, _) => standard.Dispose();