// Copyright Epic Games, Inc. All Rights Reserved. #include "zenhttp/diagsvcs.h" #include #include #include #include #include #include #include #include #include namespace zen { using namespace std::literals; static bool ReadLogFile(const std::string& Path, StringBuilderBase& Out) { try { constexpr auto ReadSize = std::size_t{4096}; auto FileStream = std::ifstream{Path}; std::string Buf(ReadSize, '\0'); while (FileStream.read(&Buf[0], ReadSize)) { Out.Append(std::string_view(&Buf[0], FileStream.gcount())); } Out.Append(std::string_view(&Buf[0], FileStream.gcount())); return true; } catch (std::exception&) { Out.Reset(); return false; } } HttpHealthService::HttpHealthService() { m_Router.RegisterRoute( "", [](HttpRouterRequest& RoutedReq) { HttpServerRequest& HttpReq = RoutedReq.ServerRequest(); HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, u8"OK!"sv); }, HttpVerb::kGet); m_Router.RegisterRoute( "info", [this](HttpRouterRequest& RoutedReq) { HttpServerRequest& HttpReq = RoutedReq.ServerRequest(); CbObjectWriter Writer; { RwLock::SharedLockScope _(m_InfoLock); Writer << "DataRoot"sv << m_HealthInfo.DataRoot.string(); Writer << "AbsLogPath"sv << m_HealthInfo.AbsLogPath.string(); Writer << "BuildVersion"sv << m_HealthInfo.BuildVersion; Writer << "HttpServerClass"sv << m_HealthInfo.HttpServerClass; } HttpReq.WriteResponse(HttpResponseCode::OK, Writer.Save()); }, HttpVerb::kGet); m_Router.RegisterRoute( "log", [this](HttpRouterRequest& RoutedReq) { HttpServerRequest& HttpReq = RoutedReq.ServerRequest(); zen::Log().flush(); std::filesystem::path Path = [&] { RwLock::SharedLockScope _(m_InfoLock); return m_HealthInfo.AbsLogPath.empty() ? m_HealthInfo.DataRoot / "logs/zenserver.log" : m_HealthInfo.AbsLogPath; }(); ExtendableStringBuilder<4096> Sb; if (ReadLogFile(Path.string(), Sb) && Sb.Size() > 0) { HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Sb.ToView()); } else { HttpReq.WriteResponse(HttpResponseCode::NotFound); } }, HttpVerb::kGet); m_Router.RegisterRoute( "version", [this](HttpRouterRequest& RoutedReq) { HttpServerRequest& HttpReq = RoutedReq.ServerRequest(); if (HttpReq.GetQueryParams().GetValue("detailed") == "true") { HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, ZEN_CFG_VERSION_BUILD_STRING_FULL); } else { HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, ZEN_CFG_VERSION); } }, HttpVerb::kGet); } void HttpHealthService::SetHealthInfo(HealthServiceInfo&& Info) { RwLock::ExclusiveLockScope _(m_InfoLock); m_HealthInfo = std::move(Info); } const char* HttpHealthService::BaseUri() const { return "/health/"; } void HttpHealthService::HandleRequest(HttpServerRequest& Request) { if (!m_Router.HandleRequest(Request)) { Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, u8"OK!"sv); } } } // namespace zen