diff options
| author | Stefan Boberg <[email protected]> | 2026-01-19 13:14:42 +0100 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2026-01-19 13:14:42 +0100 |
| commit | 5081a33dcd19c5d6f9d9cdae9f8745ba786374d4 (patch) | |
| tree | 6733e6f69137afc690a8c6dcdf618e69ce8029c5 /src/zenutil/consul/consul.cpp | |
| parent | Merge pull request #701 from ue-foundation/lm/mac-daemon-mode (diff) | |
| download | zen-5081a33dcd19c5d6f9d9cdae9f8745ba786374d4.tar.xz zen-5081a33dcd19c5d6f9d9cdae9f8745ba786374d4.zip | |
consul package and basic client added (#716)
* this adds a consul package which can be used to fetch a consul binary
* it also adds a `ConsulProcess` helper which can be used to spawn and manage a consul service instance
* zencore dependencies brought across:
- `except_fmt.h` for easer generation of formatted exception messages
- `process.h/cpp` changes (adds `Kill` operation and process group support on Windows)
- `string.h` changes to allow generic use of `WideToUtf8()`
Diffstat (limited to 'src/zenutil/consul/consul.cpp')
| -rw-r--r-- | src/zenutil/consul/consul.cpp | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/src/zenutil/consul/consul.cpp b/src/zenutil/consul/consul.cpp new file mode 100644 index 000000000..6ddebf97a --- /dev/null +++ b/src/zenutil/consul/consul.cpp @@ -0,0 +1,140 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include <zenutil/consul.h> + +#include <zencore/except_fmt.h> +#include <zencore/fmtutils.h> +#include <zencore/logging.h> +#include <zencore/process.h> +#include <zencore/string.h> +#include <zencore/timer.h> + +#include <fmt/format.h> + +namespace zen::consul { + +////////////////////////////////////////////////////////////////////////// + +struct ConsulProcess::Impl +{ + Impl(std::string_view BaseUri) : m_HttpClient(BaseUri) {} + ~Impl() = default; + + void SpawnConsulAgent() + { + if (m_ProcessHandle.IsValid()) + { + return; + } + + CreateProcOptions Options; + Options.Flags |= CreateProcOptions::Flag_Windows_NewProcessGroup; + + CreateProcResult Result = CreateProc("consul" ZEN_EXE_SUFFIX_LITERAL, "consul" ZEN_EXE_SUFFIX_LITERAL " agent -dev", Options); + + if (Result) + { + m_ProcessHandle.Initialize(Result); + + Stopwatch Timer; + + // Poll to check when the agent is ready + + do + { + Sleep(100); + HttpClient::Response Resp = m_HttpClient.Get("v1/status/leader"); + if (Resp) + { + ZEN_INFO("Consul agent started successfully (waited {})", NiceTimeSpanMs(Timer.GetElapsedTimeMs())); + + return; + } + } while (Timer.GetElapsedTimeMs() < 10000); + } + + // Report failure! + + ZEN_WARN("Consul agent failed to start within timeout period"); + } + + void StopConsulAgent() + { + if (!m_ProcessHandle.IsValid()) + { + return; + } + + // This waits for the process to exit and also resets the handle + m_ProcessHandle.Kill(); + } + +private: + ProcessHandle m_ProcessHandle; + HttpClient m_HttpClient; +}; + +ConsulProcess::ConsulProcess() : m_Impl(std::make_unique<Impl>("http://localhost:8500/")) +{ +} + +ConsulProcess::~ConsulProcess() +{ +} + +void +ConsulProcess::SpawnConsulAgent() +{ + m_Impl->SpawnConsulAgent(); +} + +void +ConsulProcess::StopConsulAgent() +{ + m_Impl->StopConsulAgent(); +} + +////////////////////////////////////////////////////////////////////////// + +ConsulClient::ConsulClient(std::string_view BaseUri) : m_HttpClient(BaseUri) +{ +} + +ConsulClient::~ConsulClient() +{ +} + +void +ConsulClient::SetKeyValue(std::string_view Key, std::string_view Value) +{ + IoBuffer ValueBuffer = IoBufferBuilder::MakeFromMemory(MakeMemoryView(Value)); + HttpClient::Response Result = + m_HttpClient.Put(fmt::format("v1/kv/{}", Key), ValueBuffer, {{"Content-Type", "text/plain"}, {"Accept", "application/json"}}); + if (!Result) + { + throw runtime_error("ConsulClient::SetKeyValue() failed to set key '{}' ({})", Key, Result.ErrorMessage("")); + } +} + +std::string +ConsulClient::GetKeyValue(std::string_view Key) +{ + HttpClient::Response Result = m_HttpClient.Get(fmt::format("v1/kv/{}?raw", Key)); + if (!Result) + { + throw runtime_error("ConsulClient::GetKeyValue() failed to get key '{}' ({})", Key, Result.ErrorMessage("")); + } + return Result.ToText(); +} + +void +ConsulClient::DeleteKey(std::string_view Key) +{ + HttpClient::Response Result = m_HttpClient.Delete(fmt::format("v1/kv/{}", Key)); + if (!Result) + { + throw runtime_error("ConsulClient::DeleteKey() failed to delete key '{}' ({})", Key, Result.ErrorMessage("")); + } +} + +} // namespace zen::consul |