diff options
Diffstat (limited to 'src/zenutil')
| -rw-r--r-- | src/zenutil/consul/consul.cpp | 140 | ||||
| -rw-r--r-- | src/zenutil/include/zenutil/consul.h | 47 |
2 files changed, 187 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 diff --git a/src/zenutil/include/zenutil/consul.h b/src/zenutil/include/zenutil/consul.h new file mode 100644 index 000000000..08871fa66 --- /dev/null +++ b/src/zenutil/include/zenutil/consul.h @@ -0,0 +1,47 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include <zenbase/zenbase.h> +#include <zenhttp/httpclient.h> + +#include <string> +#include <string_view> + +namespace zen::consul { + +class ConsulClient +{ +public: + ConsulClient(std::string_view BaseUri); + ~ConsulClient(); + + ConsulClient(const ConsulClient&) = delete; + ConsulClient& operator=(const ConsulClient&) = delete; + + void SetKeyValue(std::string_view Key, std::string_view Value); + std::string GetKeyValue(std::string_view Key); + void DeleteKey(std::string_view Key); + +private: + HttpClient m_HttpClient; +}; + +class ConsulProcess +{ +public: + ConsulProcess(); + ~ConsulProcess(); + + ConsulProcess(const ConsulProcess&) = delete; + ConsulProcess& operator=(const ConsulProcess&) = delete; + + void SpawnConsulAgent(); + void StopConsulAgent(); + +private: + struct Impl; + std::unique_ptr<Impl> m_Impl; +}; + +} // namespace zen::consul |