// Copyright Epic Games, Inc. All Rights Reserved. #include #include #include #include #include #include #include #include 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("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