diff --git a/Utilities/SilKitRegistry/Registry.cpp b/Utilities/SilKitRegistry/Registry.cpp index 01c5bde9a..db7ef9fb5 100644 --- a/Utilities/SilKitRegistry/Registry.cpp +++ b/Utilities/SilKitRegistry/Registry.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "silkit/config/IParticipantConfiguration.hpp" #include "silkit/services/logging/string_utils.hpp" @@ -307,6 +308,69 @@ auto StartRegistry(std::shared_ptr co return result; } +class StatusFile +{ + std::optional path; + +public: + StatusFile() = default; + + explicit StatusFile(const std::filesystem::path& path) : path{Resolve(path)} + { + Write("starting"); + } + + ~StatusFile() + { + Write("stopped"); + + if (path.has_value()) + { + try + { + std::filesystem::remove(path.value()); + } + catch (const std::exception& exception) + { + std::cerr << "Error: Failed to remove status file " << path.value() << ": " << exception.what() << std::endl; + } + } + } + + void Write(const std::string_view content) + { + if (!path.has_value()) + { + return; + } + + try + { + std::ofstream file{path.value(), std::ios::out | std::ios::trunc | std::ios::binary}; + file << content; + file.flush(); + file.close(); + } + catch (const std::exception & exception) + { + std::cerr << "Error: Failed to write status file " << path.value() << ": " << exception.what() << std::endl; + } + } + + static auto Resolve(const std::filesystem::path& path) -> std::optional + { + try + { + return std::filesystem::absolute(path); + } + catch (const std::exception& exception) + { + std::cerr << "Error: Failed to resolve status file path " << path << ": " << exception.what() << std::endl; + return std::nullopt; + } + } +}; + } // namespace int main(int argc, char** argv) @@ -345,6 +409,13 @@ int main(int argc, char** argv) "not set, the process runs infinitely.", CliParser::Hidden); + commandlineParser.Add( + "x-status-file", "", "", "[--x-status-file ]", + "--x-status-file : The registry process will write the current status ('starting', 'running', or " + "'stopped') as the entire content of the file. This option is ignored if the registry is run as a Windows " + "service.", + CliParser::Hidden); + if (SilKitRegistry::HasWindowsServiceSupport()) { commandlineParser.Add("windows-service", "W", "[--windows-service]", @@ -413,6 +484,7 @@ int main(int argc, char** argv) auto dashboardUri{commandlineParser.Get("dashboard-uri").Value()}; const auto useSignalHandler{commandlineParser.Get("use-signal-handler").Value()}; auto enableDashboard{commandlineParser.Get("dashboard-uri").HasValue()}; + const auto argStatusFile{commandlineParser.Get("x-status-file").Value()}; if (commandlineParser.Get("enable-dashboard").Value()) { @@ -431,6 +503,9 @@ int main(int argc, char** argv) bool windowsService{SilKitRegistry::HasWindowsServiceSupport() && commandlineParser.Get("windows-service").Value()}; + // Use the status file only if the path isn't empty and the registry is not running as a Windows service. + auto statusFile = argStatusFile.empty() || windowsService ? StatusFile{} : StatusFile{argStatusFile}; + if (!isValidLogLevel(logLevel)) { std::cerr << "Error: Argument '' must be one of " @@ -490,6 +565,8 @@ int main(int argc, char** argv) { const auto registry = callStartRegistry(); + statusFile.Write("running"); + std::cout << "Press Ctrl-C to terminate..." << std::endl; std::promise signalPromise;