// Copyright Epic Games, Inc. All Rights Reserved. #include "up_cmd.h" #include #include #include #include #include namespace zen { UpCommand::UpCommand() { m_Options.add_option("lifetime", "", "owner-pid", "Specify owning process id", cxxopts::value(m_OwnerPid)->default_value("0"), ""); m_Options.add_options()("config", "Path to Lua config file", cxxopts::value(m_ConfigFile)); } UpCommand::~UpCommand() = default; int UpCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) { ZEN_UNUSED(GlobalOptions, argc, argv); if (!ParseOptions(argc, argv)) { return 0; } { ZenServerState State; if (State.InitializeReadOnly()) { struct EntryInfo { uint32_t Pid = 0; uint16_t DesiredPort = 0; uint16_t EffectivePort = 0; }; std::vector RunningEntries; State.Snapshot([&RunningEntries](const zen::ZenServerState::ZenServerEntry& Entry) { RunningEntries.push_back(EntryInfo{.Pid = Entry.Pid.load(), .DesiredPort = Entry.DesiredListenPort.load(), .EffectivePort = Entry.EffectiveListenPort.load()}); }); if (RunningEntries.size() > 0) { ZEN_CONSOLE("Zen server already running. First instance at port {}, pid {}", RunningEntries[0].EffectivePort, RunningEntries[0].Pid); return 0; } } } std::filesystem::path ExePath = zen::GetRunningExecutablePath(); ZenServerEnvironment ServerEnvironment; ServerEnvironment.Initialize(ExePath.parent_path()); ZenServerInstance Server(ServerEnvironment); if (m_OwnerPid != 0) { Server.SetOwnerPid(m_OwnerPid); } std::string AdditionalArguments; if (!m_ConfigFile.empty()) { AdditionalArguments = fmt::format("--config {}", m_ConfigFile); } Server.SpawnServer(0, AdditionalArguments); int Timeout = 10000; if (!Server.WaitUntilReady(Timeout)) { ZEN_ERROR("zen server launch failed (timed out)"); } else { ZEN_CONSOLE("zen server up"); } return 0; } ////////////////////////////////////////////////////////////////////////// AttachCommand::AttachCommand() { m_Options.add_option("", "p", "port", "Host port", cxxopts::value(m_Port)->default_value("8558"), ""); m_Options.add_option("lifetime", "", "owner-pid", "Specify owning process id", cxxopts::value(m_OwnerPid), ""); } AttachCommand::~AttachCommand() = default; int AttachCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) { ZEN_UNUSED(GlobalOptions, argc, argv); if (!ParseOptions(argc, argv)) { return 0; } ZenServerState Instance; Instance.Initialize(); ZenServerState::ZenServerEntry* Entry = Instance.Lookup(m_Port); if (!Entry) { ZEN_WARN("no zen server instance to add sponsor process to"); return 1; } if (!Entry->AddSponsorProcess(m_OwnerPid)) { ZEN_WARN("unable to add sponsor process to running zen server instance"); return 1; } ZEN_CONSOLE("added sponsor process {} to running instance {} on port {}", m_OwnerPid, Entry->Pid.load(), m_Port); return 0; } ////////////////////////////////////////////////////////////////////////// DownCommand::DownCommand() { m_Options.add_option("", "p", "port", "Host port", cxxopts::value(m_Port)->default_value("8558"), ""); } DownCommand::~DownCommand() = default; int DownCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) { ZEN_UNUSED(GlobalOptions); if (!ParseOptions(argc, argv)) { return 0; } // Discover executing instances ZenServerState Instance; Instance.Initialize(); ZenServerState::ZenServerEntry* Entry = Instance.Lookup(m_Port); if (!Entry) { ZEN_WARN("no zen server to bring down"); return 0; } try { std::filesystem::path ExePath = zen::GetRunningExecutablePath(); ZenServerEnvironment ServerEnvironment; ServerEnvironment.Initialize(ExePath.parent_path()); ZenServerInstance Server(ServerEnvironment); Server.AttachToRunningServer(m_Port); ZEN_CONSOLE("attached to server on port {}, requesting shutdown", m_Port); Server.Shutdown(); ZEN_CONSOLE("shutdown complete"); return 0; } catch (const std::exception& Ex) { ZEN_DEBUG("Exception caught when requesting shutdown: {}", Ex.what()); } // Since we cannot obtain a handle to the process we are unable to block on the process // handle to determine when the server has shut down. Thus we signal that we would like // a shutdown via the shutdown flag and then exit. ZEN_CONSOLE("requesting shutdown of server on port {}", m_Port); Entry->SignalShutdownRequest(); return 0; } } // namespace zen