From fc53dd4bd6737f4e1c406f24cd66b4255f383e60 Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Tue, 2 May 2023 13:23:42 +0200 Subject: move testing and observability code to zenhttp (#266) --- src/zenhttp/diagsvcs.cpp | 127 ++++++++++++++++++ src/zenhttp/include/zenhttp/diagsvcs.h | 111 ++++++++++++++++ src/zenhttp/include/zenhttp/formatters.h | 71 ++++++++++ src/zenhttp/include/zenhttp/httpstats.h | 38 ++++++ src/zenhttp/include/zenhttp/httpstatus.h | 38 ++++++ src/zenhttp/include/zenhttp/httptest.h | 55 ++++++++ src/zenhttp/monitoring/httpstats.cpp | 62 +++++++++ src/zenhttp/monitoring/httpstatus.cpp | 62 +++++++++ src/zenhttp/testing/httptest.cpp | 207 ++++++++++++++++++++++++++++++ src/zenserver/cache/structuredcache.cpp | 2 +- src/zenserver/cache/structuredcache.h | 5 +- src/zenserver/cidstore.cpp | 124 ------------------ src/zenserver/cidstore.h | 35 ----- src/zenserver/config.cpp | 12 +- src/zenserver/diag/diagsvcs.cpp | 127 ------------------ src/zenserver/diag/diagsvcs.h | 111 ---------------- src/zenserver/diag/formatters.h | 71 ---------- src/zenserver/httpcidstore.cpp | 124 ++++++++++++++++++ src/zenserver/httpcidstore.h | 35 +++++ src/zenserver/monitoring/httpstats.cpp | 62 --------- src/zenserver/monitoring/httpstats.h | 38 ------ src/zenserver/monitoring/httpstatus.cpp | 62 --------- src/zenserver/monitoring/httpstatus.h | 38 ------ src/zenserver/projectstore/projectstore.h | 3 +- src/zenserver/testing/httptest.cpp | 207 ------------------------------ src/zenserver/testing/httptest.h | 55 -------- src/zenserver/upstream/jupiter.cpp | 2 +- src/zenserver/upstream/zen.cpp | 2 +- src/zenserver/zenserver.cpp | 16 +-- 29 files changed, 950 insertions(+), 952 deletions(-) create mode 100644 src/zenhttp/diagsvcs.cpp create mode 100644 src/zenhttp/include/zenhttp/diagsvcs.h create mode 100644 src/zenhttp/include/zenhttp/formatters.h create mode 100644 src/zenhttp/include/zenhttp/httpstats.h create mode 100644 src/zenhttp/include/zenhttp/httpstatus.h create mode 100644 src/zenhttp/include/zenhttp/httptest.h create mode 100644 src/zenhttp/monitoring/httpstats.cpp create mode 100644 src/zenhttp/monitoring/httpstatus.cpp create mode 100644 src/zenhttp/testing/httptest.cpp delete mode 100644 src/zenserver/cidstore.cpp delete mode 100644 src/zenserver/cidstore.h delete mode 100644 src/zenserver/diag/diagsvcs.cpp delete mode 100644 src/zenserver/diag/diagsvcs.h delete mode 100644 src/zenserver/diag/formatters.h create mode 100644 src/zenserver/httpcidstore.cpp create mode 100644 src/zenserver/httpcidstore.h delete mode 100644 src/zenserver/monitoring/httpstats.cpp delete mode 100644 src/zenserver/monitoring/httpstats.h delete mode 100644 src/zenserver/monitoring/httpstatus.cpp delete mode 100644 src/zenserver/monitoring/httpstatus.h delete mode 100644 src/zenserver/testing/httptest.cpp delete mode 100644 src/zenserver/testing/httptest.h (limited to 'src') diff --git a/src/zenhttp/diagsvcs.cpp b/src/zenhttp/diagsvcs.cpp new file mode 100644 index 000000000..8fa71b375 --- /dev/null +++ b/src/zenhttp/diagsvcs.cpp @@ -0,0 +1,127 @@ +// 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; + +bool +ReadFile(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; + 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 = + m_HealthInfo.AbsLogPath.empty() ? m_HealthInfo.DataRoot / "logs/zenserver.log" : m_HealthInfo.AbsLogPath; + + ExtendableStringBuilder<4096> Sb; + if (ReadFile(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) +{ + 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 diff --git a/src/zenhttp/include/zenhttp/diagsvcs.h b/src/zenhttp/include/zenhttp/diagsvcs.h new file mode 100644 index 000000000..bd03f8023 --- /dev/null +++ b/src/zenhttp/include/zenhttp/diagsvcs.h @@ -0,0 +1,111 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include +#include + +#include + +////////////////////////////////////////////////////////////////////////// + +namespace zen { + +class HttpTestService : public HttpService +{ + uint32_t LogPoint = 0; + +public: + HttpTestService() {} + ~HttpTestService() = default; + + virtual const char* BaseUri() const override { return "/test/"; } + + virtual void HandleRequest(HttpServerRequest& Request) override + { + using namespace std::literals; + + auto Uri = Request.RelativeUri(); + + if (Uri == "hello"sv) + { + Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, u8"hello world!"sv); + + // OutputLogMessageInternal(&LogPoint, 0, 0); + } + else if (Uri == "1K"sv) + { + Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, m_1k); + } + else if (Uri == "1M"sv) + { + Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, m_1m); + } + else if (Uri == "1M_1k"sv) + { + std::vector Buffers; + Buffers.reserve(1024); + + for (int i = 0; i < 1024; ++i) + { + Buffers.push_back(m_1k); + } + + Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Buffers); + } + else if (Uri == "1G"sv) + { + std::vector Buffers; + Buffers.reserve(1024); + + for (int i = 0; i < 1024; ++i) + { + Buffers.push_back(m_1m); + } + + Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Buffers); + } + else if (Uri == "1G_1k"sv) + { + std::vector Buffers; + Buffers.reserve(1024 * 1024); + + for (int i = 0; i < 1024 * 1024; ++i) + { + Buffers.push_back(m_1k); + } + + Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Buffers); + } + } + +private: + IoBuffer m_1m{1024 * 1024}; + IoBuffer m_1k{m_1m, 0u, 1024}; +}; + +struct HealthServiceInfo +{ + std::filesystem::path DataRoot; + std::filesystem::path AbsLogPath; + std::string HttpServerClass; + std::string BuildVersion; +}; + +class HttpHealthService : public HttpService +{ +public: + HttpHealthService(); + ~HttpHealthService() = default; + + void SetHealthInfo(HealthServiceInfo&& Info); + + virtual const char* BaseUri() const override; + virtual void HandleRequest(HttpServerRequest& Request) override final; + +private: + HttpRequestRouter m_Router; + HealthServiceInfo m_HealthInfo; +}; + +} // namespace zen diff --git a/src/zenhttp/include/zenhttp/formatters.h b/src/zenhttp/include/zenhttp/formatters.h new file mode 100644 index 000000000..759df58d3 --- /dev/null +++ b/src/zenhttp/include/zenhttp/formatters.h @@ -0,0 +1,71 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include + +ZEN_THIRD_PARTY_INCLUDES_START +#include +#include +ZEN_THIRD_PARTY_INCLUDES_END + +template<> +struct fmt::formatter +{ + constexpr auto parse(format_parse_context& Ctx) -> decltype(Ctx.begin()) { return Ctx.end(); } + + template + auto format(const cpr::Response& Response, FormatContext& Ctx) -> decltype(Ctx.out()) + { + using namespace std::literals; + + if (Response.status_code == 200 || Response.status_code == 201) + { + return fmt::format_to(Ctx.out(), + "Url: {}, Status: {}, Bytes: {}/{} (Up/Down), Elapsed: {}s", + Response.url.str(), + Response.status_code, + Response.uploaded_bytes, + Response.downloaded_bytes, + Response.elapsed); + } + else + { + const auto It = Response.header.find("Content-Type"); + const std::string_view ContentType = It != Response.header.end() ? It->second : ""sv; + + if (ContentType == "application/x-ue-cb"sv) + { + zen::IoBuffer Body(zen::IoBuffer::Wrap, Response.text.data(), Response.text.size()); + zen::CbObjectView Obj(Body.Data()); + zen::ExtendableStringBuilder<256> Sb; + std::string_view Json = Obj.ToJson(Sb).ToView(); + + return fmt::format_to(Ctx.out(), + "Url: {}, Status: {}, Bytes: {}/{} (Up/Down), Elapsed: {}s, Response: '{}', Reason: '{}'", + Response.url.str(), + Response.status_code, + Response.uploaded_bytes, + Response.downloaded_bytes, + Response.elapsed, + Json, + Response.reason); + } + else + { + return fmt::format_to(Ctx.out(), + "Url: {}, Status: {}, Bytes: {}/{} (Up/Down), Elapsed: {}s, Reponse: '{}', Reason: '{}'", + Response.url.str(), + Response.status_code, + Response.uploaded_bytes, + Response.downloaded_bytes, + Response.elapsed, + Response.text, + Response.reason); + } + } + } +}; diff --git a/src/zenhttp/include/zenhttp/httpstats.h b/src/zenhttp/include/zenhttp/httpstats.h new file mode 100644 index 000000000..732815a9a --- /dev/null +++ b/src/zenhttp/include/zenhttp/httpstats.h @@ -0,0 +1,38 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include +#include + +#include + +namespace zen { + +struct IHttpStatsProvider +{ + virtual void HandleStatsRequest(HttpServerRequest& Request) = 0; +}; + +class HttpStatsService : public HttpService +{ +public: + HttpStatsService(); + ~HttpStatsService(); + + virtual const char* BaseUri() const override; + virtual void HandleRequest(HttpServerRequest& Request) override; + void RegisterHandler(std::string_view Id, IHttpStatsProvider& Provider); + void UnregisterHandler(std::string_view Id, IHttpStatsProvider& Provider); + +private: + spdlog::logger& m_Log; + HttpRequestRouter m_Router; + + inline spdlog::logger& Log() { return m_Log; } + + RwLock m_Lock; + std::map m_Providers; +}; + +} // namespace zen \ No newline at end of file diff --git a/src/zenhttp/include/zenhttp/httpstatus.h b/src/zenhttp/include/zenhttp/httpstatus.h new file mode 100644 index 000000000..b04e45324 --- /dev/null +++ b/src/zenhttp/include/zenhttp/httpstatus.h @@ -0,0 +1,38 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include +#include + +#include + +namespace zen { + +struct IHttpStatusProvider +{ + virtual void HandleStatusRequest(HttpServerRequest& Request) = 0; +}; + +class HttpStatusService : public HttpService +{ +public: + HttpStatusService(); + ~HttpStatusService(); + + virtual const char* BaseUri() const override; + virtual void HandleRequest(HttpServerRequest& Request) override; + void RegisterHandler(std::string_view Id, IHttpStatusProvider& Provider); + void UnregisterHandler(std::string_view Id, IHttpStatusProvider& Provider); + +private: + spdlog::logger& m_Log; + HttpRequestRouter m_Router; + + RwLock m_Lock; + std::map m_Providers; + + inline spdlog::logger& Log() { return m_Log; } +}; + +} // namespace zen \ No newline at end of file diff --git a/src/zenhttp/include/zenhttp/httptest.h b/src/zenhttp/include/zenhttp/httptest.h new file mode 100644 index 000000000..57d2d63f3 --- /dev/null +++ b/src/zenhttp/include/zenhttp/httptest.h @@ -0,0 +1,55 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include + +#include + +namespace zen { + +/** + * Test service to facilitate testing the HTTP framework and client interactions + */ +class HttpTestingService : public HttpService, public WebSocketService +{ +public: + HttpTestingService(); + ~HttpTestingService(); + + virtual const char* BaseUri() const override; + virtual void HandleRequest(HttpServerRequest& Request) override; + virtual Ref HandlePackageRequest(HttpServerRequest& HttpServiceRequest) override; + + class PackageHandler : public IHttpPackageHandler + { + public: + PackageHandler(HttpTestingService& Svc, uint32_t RequestId); + ~PackageHandler(); + + virtual void FilterOffer(std::vector& OfferCids) override; + virtual void OnRequestBegin() override; + virtual IoBuffer CreateTarget(const IoHash& Cid, uint64_t StorageSize) override; + virtual void OnRequestComplete() override; + + private: + HttpTestingService& m_Svc; + uint32_t m_RequestId; + }; + +private: + virtual void RegisterHandlers(WebSocketServer& Server) override; + virtual bool HandleRequest(const WebSocketMessage& Request) override; + + HttpRequestRouter m_Router; + std::atomic m_Counter{0}; + metrics::OperationTiming m_TimingStats; + + RwLock m_RwLock; + std::unordered_map> m_HandlerMap; +}; + +} // namespace zen diff --git a/src/zenhttp/monitoring/httpstats.cpp b/src/zenhttp/monitoring/httpstats.cpp new file mode 100644 index 000000000..a873b4977 --- /dev/null +++ b/src/zenhttp/monitoring/httpstats.cpp @@ -0,0 +1,62 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "zenhttp/httpstats.h" + +namespace zen { + +HttpStatsService::HttpStatsService() : m_Log(logging::Get("stats")) +{ +} + +HttpStatsService::~HttpStatsService() +{ +} + +const char* +HttpStatsService::BaseUri() const +{ + return "/stats/"; +} + +void +HttpStatsService::RegisterHandler(std::string_view Id, IHttpStatsProvider& Provider) +{ + RwLock::ExclusiveLockScope _(m_Lock); + m_Providers.insert_or_assign(std::string(Id), &Provider); +} + +void +HttpStatsService::UnregisterHandler(std::string_view Id, IHttpStatsProvider& Provider) +{ + ZEN_UNUSED(Provider); + + RwLock::ExclusiveLockScope _(m_Lock); + m_Providers.erase(std::string(Id)); +} + +void +HttpStatsService::HandleRequest(HttpServerRequest& Request) +{ + using namespace std::literals; + + std::string_view Key = Request.RelativeUri(); + + switch (Request.RequestVerb()) + { + case HttpVerb::kHead: + case HttpVerb::kGet: + { + RwLock::SharedLockScope _(m_Lock); + if (auto It = m_Providers.find(std::string{Key}); It != end(m_Providers)) + { + return It->second->HandleStatsRequest(Request); + } + } + + [[fallthrough]]; + default: + return; + } +} + +} // namespace zen diff --git a/src/zenhttp/monitoring/httpstatus.cpp b/src/zenhttp/monitoring/httpstatus.cpp new file mode 100644 index 000000000..9fecedb06 --- /dev/null +++ b/src/zenhttp/monitoring/httpstatus.cpp @@ -0,0 +1,62 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "zenhttp/httpstatus.h" + +namespace zen { + +HttpStatusService::HttpStatusService() : m_Log(logging::Get("status")) +{ +} + +HttpStatusService::~HttpStatusService() +{ +} + +const char* +HttpStatusService::BaseUri() const +{ + return "/status/"; +} + +void +HttpStatusService::RegisterHandler(std::string_view Id, IHttpStatusProvider& Provider) +{ + RwLock::ExclusiveLockScope _(m_Lock); + m_Providers.insert_or_assign(std::string(Id), &Provider); +} + +void +HttpStatusService::UnregisterHandler(std::string_view Id, IHttpStatusProvider& Provider) +{ + ZEN_UNUSED(Provider); + + RwLock::ExclusiveLockScope _(m_Lock); + m_Providers.erase(std::string(Id)); +} + +void +HttpStatusService::HandleRequest(HttpServerRequest& Request) +{ + using namespace std::literals; + + std::string_view Key = Request.RelativeUri(); + + switch (Request.RequestVerb()) + { + case HttpVerb::kHead: + case HttpVerb::kGet: + { + RwLock::SharedLockScope _(m_Lock); + if (auto It = m_Providers.find(std::string{Key}); It != end(m_Providers)) + { + return It->second->HandleStatusRequest(Request); + } + } + + [[fallthrough]]; + default: + return; + } +} + +} // namespace zen diff --git a/src/zenhttp/testing/httptest.cpp b/src/zenhttp/testing/httptest.cpp new file mode 100644 index 000000000..3e77e9c8c --- /dev/null +++ b/src/zenhttp/testing/httptest.cpp @@ -0,0 +1,207 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "zenhttp/httptest.h" + +#include +#include +#include + +namespace zen { + +using namespace std::literals; + +HttpTestingService::HttpTestingService() +{ + m_Router.RegisterRoute( + "hello", + [](HttpRouterRequest& Req) { Req.ServerRequest().WriteResponse(HttpResponseCode::OK); }, + HttpVerb::kGet); + + m_Router.RegisterRoute( + "hello_slow", + [](HttpRouterRequest& Req) { + Req.ServerRequest().WriteResponseAsync([](HttpServerRequest& Request) { + Stopwatch Timer; + Sleep(1000); + Request.WriteResponse(HttpResponseCode::OK, + HttpContentType::kText, + fmt::format("hello, took me {}", NiceTimeSpanMs(Timer.GetElapsedTimeMs()))); + }); + }, + HttpVerb::kGet); + + m_Router.RegisterRoute( + "hello_veryslow", + [](HttpRouterRequest& Req) { + Req.ServerRequest().WriteResponseAsync([](HttpServerRequest& Request) { + Stopwatch Timer; + Sleep(60000); + Request.WriteResponse(HttpResponseCode::OK, + HttpContentType::kText, + fmt::format("hello, took me {}", NiceTimeSpanMs(Timer.GetElapsedTimeMs()))); + }); + }, + HttpVerb::kGet); + + m_Router.RegisterRoute( + "hello_throw", + [](HttpRouterRequest& Req) { + Req.ServerRequest().WriteResponseAsync([](HttpServerRequest&) { throw std::runtime_error("intentional error"); }); + }, + HttpVerb::kGet); + + m_Router.RegisterRoute( + "hello_noresponse", + [](HttpRouterRequest& Req) { Req.ServerRequest().WriteResponseAsync([](HttpServerRequest&) {}); }, + HttpVerb::kGet); + + m_Router.RegisterRoute( + "metrics", + [this](HttpRouterRequest& Req) { + metrics::OperationTiming::Scope _(m_TimingStats); + Req.ServerRequest().WriteResponse(HttpResponseCode::OK); + }, + HttpVerb::kGet); + + m_Router.RegisterRoute( + "get_metrics", + [this](HttpRouterRequest& Req) { + CbObjectWriter Cbo; + EmitSnapshot("requests", m_TimingStats, Cbo); + Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Cbo.Save()); + }, + HttpVerb::kGet); + + m_Router.RegisterRoute( + "json", + [this](HttpRouterRequest& Req) { + CbObjectWriter Obj; + Obj.AddBool("ok", true); + Obj.AddInteger("counter", ++m_Counter); + Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); + }, + HttpVerb::kGet); + + m_Router.RegisterRoute( + "echo", + [](HttpRouterRequest& Req) { + IoBuffer Body = Req.ServerRequest().ReadPayload(); + Req.ServerRequest().WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Body); + }, + HttpVerb::kPost); + + m_Router.RegisterRoute( + "package", + [](HttpRouterRequest& Req) { + CbPackage Pkg = Req.ServerRequest().ReadPayloadPackage(); + Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Pkg); + }, + HttpVerb::kPost); +} + +HttpTestingService::~HttpTestingService() +{ +} + +const char* +HttpTestingService::BaseUri() const +{ + return "/testing/"; +} + +void +HttpTestingService::HandleRequest(HttpServerRequest& Request) +{ + m_Router.HandleRequest(Request); +} + +Ref +HttpTestingService::HandlePackageRequest(HttpServerRequest& HttpServiceRequest) +{ + RwLock::ExclusiveLockScope _(m_RwLock); + + const uint32_t RequestId = HttpServiceRequest.RequestId(); + + if (auto It = m_HandlerMap.find(RequestId); It != m_HandlerMap.end()) + { + Ref Handler = std::move(It->second); + + m_HandlerMap.erase(It); + + return Handler; + } + + auto InsertResult = m_HandlerMap.insert({RequestId, Ref()}); + + _.ReleaseNow(); + + return (InsertResult.first->second = Ref(new PackageHandler(*this, RequestId))); +} + +void +HttpTestingService::RegisterHandlers(WebSocketServer& Server) +{ + Server.RegisterRequestHandler("SayHello"sv, *this); +} + +bool +HttpTestingService::HandleRequest(const WebSocketMessage& RequestMsg) +{ + CbObjectView Request = RequestMsg.Body().GetObject(); + + std::string_view Method = Request["Method"].AsString(); + + if (Method != "SayHello"sv) + { + return false; + } + + CbObjectWriter Response; + Response.AddString("Result"sv, "Hello Friend!!"); + + WebSocketMessage ResponseMsg; + ResponseMsg.SetMessageType(WebSocketMessageType::kResponse); + ResponseMsg.SetCorrelationId(RequestMsg.CorrelationId()); + ResponseMsg.SetSocketId(RequestMsg.SocketId()); + ResponseMsg.SetBody(Response.Save()); + + SocketServer().SendResponse(std::move(ResponseMsg)); + + return true; +} + +////////////////////////////////////////////////////////////////////////// + +HttpTestingService::PackageHandler::PackageHandler(HttpTestingService& Svc, uint32_t RequestId) : m_Svc(Svc), m_RequestId(RequestId) +{ +} + +HttpTestingService::PackageHandler::~PackageHandler() +{ +} + +void +HttpTestingService::PackageHandler::FilterOffer(std::vector& OfferCids) +{ + ZEN_UNUSED(OfferCids); + // No-op + return; +} +void +HttpTestingService::PackageHandler::OnRequestBegin() +{ +} + +void +HttpTestingService::PackageHandler::OnRequestComplete() +{ +} + +IoBuffer +HttpTestingService::PackageHandler::CreateTarget(const IoHash& Cid, uint64_t StorageSize) +{ + ZEN_UNUSED(Cid); + return IoBuffer{StorageSize}; +} + +} // namespace zen diff --git a/src/zenserver/cache/structuredcache.cpp b/src/zenserver/cache/structuredcache.cpp index 90e905bf6..3c829f0e8 100644 --- a/src/zenserver/cache/structuredcache.cpp +++ b/src/zenserver/cache/structuredcache.cpp @@ -17,10 +17,10 @@ #include #include #include +#include #include #include -#include "monitoring/httpstats.h" #include "structuredcachestore.h" #include "upstream/jupiter.h" #include "upstream/upstreamcache.h" diff --git a/src/zenserver/cache/structuredcache.h b/src/zenserver/cache/structuredcache.h index 4e7b98ac9..8309361f4 100644 --- a/src/zenserver/cache/structuredcache.h +++ b/src/zenserver/cache/structuredcache.h @@ -4,9 +4,8 @@ #include #include - -#include "monitoring/httpstats.h" -#include "monitoring/httpstatus.h" +#include +#include #include #include diff --git a/src/zenserver/cidstore.cpp b/src/zenserver/cidstore.cpp deleted file mode 100644 index bce4f1dfb..000000000 --- a/src/zenserver/cidstore.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "cidstore.h" - -#include -#include -#include -#include - -#include - -namespace zen { - -HttpCidService::HttpCidService(CidStore& Store) : m_CidStore(Store) -{ - m_Router.AddPattern("cid", "([0-9A-Fa-f]{40})"); - - m_Router.RegisterRoute( - "{cid}", - [this](HttpRouterRequest& Req) { - IoHash Hash = IoHash::FromHexString(Req.GetCapture(1)); - ZEN_DEBUG("CID request for {}", Hash); - - HttpServerRequest& ServerRequest = Req.ServerRequest(); - - switch (ServerRequest.RequestVerb()) - { - case HttpVerb::kGet: - case HttpVerb::kHead: - { - if (IoBuffer Value = m_CidStore.FindChunkByCid(Hash)) - { - return ServerRequest.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Value); - } - - return ServerRequest.WriteResponse(HttpResponseCode::NotFound); - } - break; - - case HttpVerb::kPut: - { - IoBuffer Payload = ServerRequest.ReadPayload(); - IoHash RawHash; - uint64_t RawSize; - if (!CompressedBuffer::ValidateCompressedHeader(Payload, RawHash, RawSize)) - { - return ServerRequest.WriteResponse(HttpResponseCode::UnsupportedMediaType); - } - - // URI hash must match content hash - if (RawHash != Hash) - { - return ServerRequest.WriteResponse(HttpResponseCode::BadRequest); - } - - m_CidStore.AddChunk(Payload, RawHash); - - return ServerRequest.WriteResponse(HttpResponseCode::OK); - } - break; - - default: - break; - } - }, - HttpVerb::kGet | HttpVerb::kPut | HttpVerb::kHead); -} - -const char* -HttpCidService::BaseUri() const -{ - return "/cid/"; -} - -void -HttpCidService::HandleRequest(zen::HttpServerRequest& Request) -{ - if (Request.RelativeUri().empty()) - { - // Root URI request - - switch (Request.RequestVerb()) - { - case HttpVerb::kPut: - case HttpVerb::kPost: - { - IoBuffer Payload = Request.ReadPayload(); - IoHash RawHash; - uint64_t RawSize; - if (!CompressedBuffer::ValidateCompressedHeader(Payload, RawHash, RawSize)) - { - return Request.WriteResponse(HttpResponseCode::UnsupportedMediaType); - } - - ZEN_DEBUG("CID POST request for {} ({} bytes)", RawHash, Payload.Size()); - - auto InsertResult = m_CidStore.AddChunk(Payload, RawHash); - - if (InsertResult.New) - { - return Request.WriteResponse(HttpResponseCode::Created); - } - else - { - return Request.WriteResponse(HttpResponseCode::OK); - } - } - break; - - case HttpVerb::kGet: - case HttpVerb::kHead: - break; - - default: - break; - } - } - else - { - m_Router.HandleRequest(Request); - } -} - -} // namespace zen diff --git a/src/zenserver/cidstore.h b/src/zenserver/cidstore.h deleted file mode 100644 index 8e7832b35..000000000 --- a/src/zenserver/cidstore.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include - -namespace zen { - -/** - * Simple CID store HTTP endpoint - * - * Note that since this does not end up pinning any of the chunks it's only really useful for a small subset of use cases where you know a - * chunk exists in the underlying CID store. Thus it's mainly useful for internal use when communicating between Zen store instances - * - * Using this interface for adding CID chunks makes little sense except for testing purposes as garbage collection may reap anything you add - * before anything ever gets to access it - */ - -class CidStore; - -class HttpCidService : public HttpService -{ -public: - explicit HttpCidService(CidStore& Store); - ~HttpCidService() = default; - - virtual const char* BaseUri() const override; - virtual void HandleRequest(zen::HttpServerRequest& Request) override; - -private: - CidStore& m_CidStore; - HttpRequestRouter m_Router; -}; - -} // namespace zen diff --git a/src/zenserver/config.cpp b/src/zenserver/config.cpp index cff93d67b..d28262607 100644 --- a/src/zenserver/config.cpp +++ b/src/zenserver/config.cpp @@ -33,16 +33,16 @@ std::filesystem::path PickDefaultStateDirectory() { // Pick sensible default - PWSTR programDataDir = nullptr; - HRESULT hRes = SHGetKnownFolderPath(FOLDERID_ProgramData, 0, NULL, &programDataDir); + PWSTR ProgramDataDir = nullptr; + HRESULT hRes = SHGetKnownFolderPath(FOLDERID_ProgramData, 0, NULL, &ProgramDataDir); if (SUCCEEDED(hRes)) { - std::filesystem::path finalPath(programDataDir); - finalPath /= L"Epic\\Zen\\Data"; - ::CoTaskMemFree(programDataDir); + std::filesystem::path FinalPath(ProgramDataDir); + FinalPath /= L"Epic\\Zen\\Data"; + ::CoTaskMemFree(ProgramDataDir); - return finalPath; + return FinalPath; } return L""; diff --git a/src/zenserver/diag/diagsvcs.cpp b/src/zenserver/diag/diagsvcs.cpp deleted file mode 100644 index 29ad5c3dd..000000000 --- a/src/zenserver/diag/diagsvcs.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "diagsvcs.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace zen { - -using namespace std::literals; - -bool -ReadFile(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; - 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 = - m_HealthInfo.AbsLogPath.empty() ? m_HealthInfo.DataRoot / "logs/zenserver.log" : m_HealthInfo.AbsLogPath; - - ExtendableStringBuilder<4096> Sb; - if (ReadFile(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) -{ - 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 diff --git a/src/zenserver/diag/diagsvcs.h b/src/zenserver/diag/diagsvcs.h deleted file mode 100644 index bd03f8023..000000000 --- a/src/zenserver/diag/diagsvcs.h +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include -#include - -#include - -////////////////////////////////////////////////////////////////////////// - -namespace zen { - -class HttpTestService : public HttpService -{ - uint32_t LogPoint = 0; - -public: - HttpTestService() {} - ~HttpTestService() = default; - - virtual const char* BaseUri() const override { return "/test/"; } - - virtual void HandleRequest(HttpServerRequest& Request) override - { - using namespace std::literals; - - auto Uri = Request.RelativeUri(); - - if (Uri == "hello"sv) - { - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, u8"hello world!"sv); - - // OutputLogMessageInternal(&LogPoint, 0, 0); - } - else if (Uri == "1K"sv) - { - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, m_1k); - } - else if (Uri == "1M"sv) - { - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, m_1m); - } - else if (Uri == "1M_1k"sv) - { - std::vector Buffers; - Buffers.reserve(1024); - - for (int i = 0; i < 1024; ++i) - { - Buffers.push_back(m_1k); - } - - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Buffers); - } - else if (Uri == "1G"sv) - { - std::vector Buffers; - Buffers.reserve(1024); - - for (int i = 0; i < 1024; ++i) - { - Buffers.push_back(m_1m); - } - - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Buffers); - } - else if (Uri == "1G_1k"sv) - { - std::vector Buffers; - Buffers.reserve(1024 * 1024); - - for (int i = 0; i < 1024 * 1024; ++i) - { - Buffers.push_back(m_1k); - } - - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Buffers); - } - } - -private: - IoBuffer m_1m{1024 * 1024}; - IoBuffer m_1k{m_1m, 0u, 1024}; -}; - -struct HealthServiceInfo -{ - std::filesystem::path DataRoot; - std::filesystem::path AbsLogPath; - std::string HttpServerClass; - std::string BuildVersion; -}; - -class HttpHealthService : public HttpService -{ -public: - HttpHealthService(); - ~HttpHealthService() = default; - - void SetHealthInfo(HealthServiceInfo&& Info); - - virtual const char* BaseUri() const override; - virtual void HandleRequest(HttpServerRequest& Request) override final; - -private: - HttpRequestRouter m_Router; - HealthServiceInfo m_HealthInfo; -}; - -} // namespace zen diff --git a/src/zenserver/diag/formatters.h b/src/zenserver/diag/formatters.h deleted file mode 100644 index 759df58d3..000000000 --- a/src/zenserver/diag/formatters.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include -#include -#include -#include - -ZEN_THIRD_PARTY_INCLUDES_START -#include -#include -ZEN_THIRD_PARTY_INCLUDES_END - -template<> -struct fmt::formatter -{ - constexpr auto parse(format_parse_context& Ctx) -> decltype(Ctx.begin()) { return Ctx.end(); } - - template - auto format(const cpr::Response& Response, FormatContext& Ctx) -> decltype(Ctx.out()) - { - using namespace std::literals; - - if (Response.status_code == 200 || Response.status_code == 201) - { - return fmt::format_to(Ctx.out(), - "Url: {}, Status: {}, Bytes: {}/{} (Up/Down), Elapsed: {}s", - Response.url.str(), - Response.status_code, - Response.uploaded_bytes, - Response.downloaded_bytes, - Response.elapsed); - } - else - { - const auto It = Response.header.find("Content-Type"); - const std::string_view ContentType = It != Response.header.end() ? It->second : ""sv; - - if (ContentType == "application/x-ue-cb"sv) - { - zen::IoBuffer Body(zen::IoBuffer::Wrap, Response.text.data(), Response.text.size()); - zen::CbObjectView Obj(Body.Data()); - zen::ExtendableStringBuilder<256> Sb; - std::string_view Json = Obj.ToJson(Sb).ToView(); - - return fmt::format_to(Ctx.out(), - "Url: {}, Status: {}, Bytes: {}/{} (Up/Down), Elapsed: {}s, Response: '{}', Reason: '{}'", - Response.url.str(), - Response.status_code, - Response.uploaded_bytes, - Response.downloaded_bytes, - Response.elapsed, - Json, - Response.reason); - } - else - { - return fmt::format_to(Ctx.out(), - "Url: {}, Status: {}, Bytes: {}/{} (Up/Down), Elapsed: {}s, Reponse: '{}', Reason: '{}'", - Response.url.str(), - Response.status_code, - Response.uploaded_bytes, - Response.downloaded_bytes, - Response.elapsed, - Response.text, - Response.reason); - } - } - } -}; diff --git a/src/zenserver/httpcidstore.cpp b/src/zenserver/httpcidstore.cpp new file mode 100644 index 000000000..233a45edb --- /dev/null +++ b/src/zenserver/httpcidstore.cpp @@ -0,0 +1,124 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "httpcidstore.h" + +#include +#include +#include +#include + +#include + +namespace zen { + +HttpCidService::HttpCidService(CidStore& Store) : m_CidStore(Store) +{ + m_Router.AddPattern("cid", "([0-9A-Fa-f]{40})"); + + m_Router.RegisterRoute( + "{cid}", + [this](HttpRouterRequest& Req) { + IoHash Hash = IoHash::FromHexString(Req.GetCapture(1)); + ZEN_DEBUG("CID request for {}", Hash); + + HttpServerRequest& ServerRequest = Req.ServerRequest(); + + switch (ServerRequest.RequestVerb()) + { + case HttpVerb::kGet: + case HttpVerb::kHead: + { + if (IoBuffer Value = m_CidStore.FindChunkByCid(Hash)) + { + return ServerRequest.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Value); + } + + return ServerRequest.WriteResponse(HttpResponseCode::NotFound); + } + break; + + case HttpVerb::kPut: + { + IoBuffer Payload = ServerRequest.ReadPayload(); + IoHash RawHash; + uint64_t RawSize; + if (!CompressedBuffer::ValidateCompressedHeader(Payload, RawHash, RawSize)) + { + return ServerRequest.WriteResponse(HttpResponseCode::UnsupportedMediaType); + } + + // URI hash must match content hash + if (RawHash != Hash) + { + return ServerRequest.WriteResponse(HttpResponseCode::BadRequest); + } + + m_CidStore.AddChunk(Payload, RawHash); + + return ServerRequest.WriteResponse(HttpResponseCode::OK); + } + break; + + default: + break; + } + }, + HttpVerb::kGet | HttpVerb::kPut | HttpVerb::kHead); +} + +const char* +HttpCidService::BaseUri() const +{ + return "/cid/"; +} + +void +HttpCidService::HandleRequest(zen::HttpServerRequest& Request) +{ + if (Request.RelativeUri().empty()) + { + // Root URI request + + switch (Request.RequestVerb()) + { + case HttpVerb::kPut: + case HttpVerb::kPost: + { + IoBuffer Payload = Request.ReadPayload(); + IoHash RawHash; + uint64_t RawSize; + if (!CompressedBuffer::ValidateCompressedHeader(Payload, RawHash, RawSize)) + { + return Request.WriteResponse(HttpResponseCode::UnsupportedMediaType); + } + + ZEN_DEBUG("CID POST request for {} ({} bytes)", RawHash, Payload.Size()); + + auto InsertResult = m_CidStore.AddChunk(Payload, RawHash); + + if (InsertResult.New) + { + return Request.WriteResponse(HttpResponseCode::Created); + } + else + { + return Request.WriteResponse(HttpResponseCode::OK); + } + } + break; + + case HttpVerb::kGet: + case HttpVerb::kHead: + break; + + default: + break; + } + } + else + { + m_Router.HandleRequest(Request); + } +} + +} // namespace zen diff --git a/src/zenserver/httpcidstore.h b/src/zenserver/httpcidstore.h new file mode 100644 index 000000000..8e7832b35 --- /dev/null +++ b/src/zenserver/httpcidstore.h @@ -0,0 +1,35 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include + +namespace zen { + +/** + * Simple CID store HTTP endpoint + * + * Note that since this does not end up pinning any of the chunks it's only really useful for a small subset of use cases where you know a + * chunk exists in the underlying CID store. Thus it's mainly useful for internal use when communicating between Zen store instances + * + * Using this interface for adding CID chunks makes little sense except for testing purposes as garbage collection may reap anything you add + * before anything ever gets to access it + */ + +class CidStore; + +class HttpCidService : public HttpService +{ +public: + explicit HttpCidService(CidStore& Store); + ~HttpCidService() = default; + + virtual const char* BaseUri() const override; + virtual void HandleRequest(zen::HttpServerRequest& Request) override; + +private: + CidStore& m_CidStore; + HttpRequestRouter m_Router; +}; + +} // namespace zen diff --git a/src/zenserver/monitoring/httpstats.cpp b/src/zenserver/monitoring/httpstats.cpp deleted file mode 100644 index 4d985f8c2..000000000 --- a/src/zenserver/monitoring/httpstats.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "httpstats.h" - -namespace zen { - -HttpStatsService::HttpStatsService() : m_Log(logging::Get("stats")) -{ -} - -HttpStatsService::~HttpStatsService() -{ -} - -const char* -HttpStatsService::BaseUri() const -{ - return "/stats/"; -} - -void -HttpStatsService::RegisterHandler(std::string_view Id, IHttpStatsProvider& Provider) -{ - RwLock::ExclusiveLockScope _(m_Lock); - m_Providers.insert_or_assign(std::string(Id), &Provider); -} - -void -HttpStatsService::UnregisterHandler(std::string_view Id, IHttpStatsProvider& Provider) -{ - ZEN_UNUSED(Provider); - - RwLock::ExclusiveLockScope _(m_Lock); - m_Providers.erase(std::string(Id)); -} - -void -HttpStatsService::HandleRequest(HttpServerRequest& Request) -{ - using namespace std::literals; - - std::string_view Key = Request.RelativeUri(); - - switch (Request.RequestVerb()) - { - case HttpVerb::kHead: - case HttpVerb::kGet: - { - RwLock::SharedLockScope _(m_Lock); - if (auto It = m_Providers.find(std::string{Key}); It != end(m_Providers)) - { - return It->second->HandleStatsRequest(Request); - } - } - - [[fallthrough]]; - default: - return; - } -} - -} // namespace zen diff --git a/src/zenserver/monitoring/httpstats.h b/src/zenserver/monitoring/httpstats.h deleted file mode 100644 index 732815a9a..000000000 --- a/src/zenserver/monitoring/httpstats.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include -#include - -#include - -namespace zen { - -struct IHttpStatsProvider -{ - virtual void HandleStatsRequest(HttpServerRequest& Request) = 0; -}; - -class HttpStatsService : public HttpService -{ -public: - HttpStatsService(); - ~HttpStatsService(); - - virtual const char* BaseUri() const override; - virtual void HandleRequest(HttpServerRequest& Request) override; - void RegisterHandler(std::string_view Id, IHttpStatsProvider& Provider); - void UnregisterHandler(std::string_view Id, IHttpStatsProvider& Provider); - -private: - spdlog::logger& m_Log; - HttpRequestRouter m_Router; - - inline spdlog::logger& Log() { return m_Log; } - - RwLock m_Lock; - std::map m_Providers; -}; - -} // namespace zen \ No newline at end of file diff --git a/src/zenserver/monitoring/httpstatus.cpp b/src/zenserver/monitoring/httpstatus.cpp deleted file mode 100644 index 8b10601dd..000000000 --- a/src/zenserver/monitoring/httpstatus.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "httpstatus.h" - -namespace zen { - -HttpStatusService::HttpStatusService() : m_Log(logging::Get("status")) -{ -} - -HttpStatusService::~HttpStatusService() -{ -} - -const char* -HttpStatusService::BaseUri() const -{ - return "/status/"; -} - -void -HttpStatusService::RegisterHandler(std::string_view Id, IHttpStatusProvider& Provider) -{ - RwLock::ExclusiveLockScope _(m_Lock); - m_Providers.insert_or_assign(std::string(Id), &Provider); -} - -void -HttpStatusService::UnregisterHandler(std::string_view Id, IHttpStatusProvider& Provider) -{ - ZEN_UNUSED(Provider); - - RwLock::ExclusiveLockScope _(m_Lock); - m_Providers.erase(std::string(Id)); -} - -void -HttpStatusService::HandleRequest(HttpServerRequest& Request) -{ - using namespace std::literals; - - std::string_view Key = Request.RelativeUri(); - - switch (Request.RequestVerb()) - { - case HttpVerb::kHead: - case HttpVerb::kGet: - { - RwLock::SharedLockScope _(m_Lock); - if (auto It = m_Providers.find(std::string{Key}); It != end(m_Providers)) - { - return It->second->HandleStatusRequest(Request); - } - } - - [[fallthrough]]; - default: - return; - } -} - -} // namespace zen diff --git a/src/zenserver/monitoring/httpstatus.h b/src/zenserver/monitoring/httpstatus.h deleted file mode 100644 index b04e45324..000000000 --- a/src/zenserver/monitoring/httpstatus.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include -#include - -#include - -namespace zen { - -struct IHttpStatusProvider -{ - virtual void HandleStatusRequest(HttpServerRequest& Request) = 0; -}; - -class HttpStatusService : public HttpService -{ -public: - HttpStatusService(); - ~HttpStatusService(); - - virtual const char* BaseUri() const override; - virtual void HandleRequest(HttpServerRequest& Request) override; - void RegisterHandler(std::string_view Id, IHttpStatusProvider& Provider); - void UnregisterHandler(std::string_view Id, IHttpStatusProvider& Provider); - -private: - spdlog::logger& m_Log; - HttpRequestRouter m_Router; - - RwLock m_Lock; - std::map m_Providers; - - inline spdlog::logger& Log() { return m_Log; } -}; - -} // namespace zen \ No newline at end of file diff --git a/src/zenserver/projectstore/projectstore.h b/src/zenserver/projectstore/projectstore.h index e4f664b85..be3ee7075 100644 --- a/src/zenserver/projectstore/projectstore.h +++ b/src/zenserver/projectstore/projectstore.h @@ -5,10 +5,9 @@ #include #include #include +#include #include -#include "monitoring/httpstats.h" - ZEN_THIRD_PARTY_INCLUDES_START #include ZEN_THIRD_PARTY_INCLUDES_END diff --git a/src/zenserver/testing/httptest.cpp b/src/zenserver/testing/httptest.cpp deleted file mode 100644 index 349a95ab3..000000000 --- a/src/zenserver/testing/httptest.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "httptest.h" - -#include -#include -#include - -namespace zen { - -using namespace std::literals; - -HttpTestingService::HttpTestingService() -{ - m_Router.RegisterRoute( - "hello", - [](HttpRouterRequest& Req) { Req.ServerRequest().WriteResponse(HttpResponseCode::OK); }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "hello_slow", - [](HttpRouterRequest& Req) { - Req.ServerRequest().WriteResponseAsync([](HttpServerRequest& Request) { - Stopwatch Timer; - Sleep(1000); - Request.WriteResponse(HttpResponseCode::OK, - HttpContentType::kText, - fmt::format("hello, took me {}", NiceTimeSpanMs(Timer.GetElapsedTimeMs()))); - }); - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "hello_veryslow", - [](HttpRouterRequest& Req) { - Req.ServerRequest().WriteResponseAsync([](HttpServerRequest& Request) { - Stopwatch Timer; - Sleep(60000); - Request.WriteResponse(HttpResponseCode::OK, - HttpContentType::kText, - fmt::format("hello, took me {}", NiceTimeSpanMs(Timer.GetElapsedTimeMs()))); - }); - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "hello_throw", - [](HttpRouterRequest& Req) { - Req.ServerRequest().WriteResponseAsync([](HttpServerRequest&) { throw std::runtime_error("intentional error"); }); - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "hello_noresponse", - [](HttpRouterRequest& Req) { Req.ServerRequest().WriteResponseAsync([](HttpServerRequest&) {}); }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "metrics", - [this](HttpRouterRequest& Req) { - metrics::OperationTiming::Scope _(m_TimingStats); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK); - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "get_metrics", - [this](HttpRouterRequest& Req) { - CbObjectWriter Cbo; - EmitSnapshot("requests", m_TimingStats, Cbo); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Cbo.Save()); - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "json", - [this](HttpRouterRequest& Req) { - CbObjectWriter Obj; - Obj.AddBool("ok", true); - Obj.AddInteger("counter", ++m_Counter); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); - }, - HttpVerb::kGet); - - m_Router.RegisterRoute( - "echo", - [](HttpRouterRequest& Req) { - IoBuffer Body = Req.ServerRequest().ReadPayload(); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Body); - }, - HttpVerb::kPost); - - m_Router.RegisterRoute( - "package", - [](HttpRouterRequest& Req) { - CbPackage Pkg = Req.ServerRequest().ReadPayloadPackage(); - Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Pkg); - }, - HttpVerb::kPost); -} - -HttpTestingService::~HttpTestingService() -{ -} - -const char* -HttpTestingService::BaseUri() const -{ - return "/testing/"; -} - -void -HttpTestingService::HandleRequest(HttpServerRequest& Request) -{ - m_Router.HandleRequest(Request); -} - -Ref -HttpTestingService::HandlePackageRequest(HttpServerRequest& HttpServiceRequest) -{ - RwLock::ExclusiveLockScope _(m_RwLock); - - const uint32_t RequestId = HttpServiceRequest.RequestId(); - - if (auto It = m_HandlerMap.find(RequestId); It != m_HandlerMap.end()) - { - Ref Handler = std::move(It->second); - - m_HandlerMap.erase(It); - - return Handler; - } - - auto InsertResult = m_HandlerMap.insert({RequestId, Ref()}); - - _.ReleaseNow(); - - return (InsertResult.first->second = Ref(new PackageHandler(*this, RequestId))); -} - -void -HttpTestingService::RegisterHandlers(WebSocketServer& Server) -{ - Server.RegisterRequestHandler("SayHello"sv, *this); -} - -bool -HttpTestingService::HandleRequest(const WebSocketMessage& RequestMsg) -{ - CbObjectView Request = RequestMsg.Body().GetObject(); - - std::string_view Method = Request["Method"].AsString(); - - if (Method != "SayHello"sv) - { - return false; - } - - CbObjectWriter Response; - Response.AddString("Result"sv, "Hello Friend!!"); - - WebSocketMessage ResponseMsg; - ResponseMsg.SetMessageType(WebSocketMessageType::kResponse); - ResponseMsg.SetCorrelationId(RequestMsg.CorrelationId()); - ResponseMsg.SetSocketId(RequestMsg.SocketId()); - ResponseMsg.SetBody(Response.Save()); - - SocketServer().SendResponse(std::move(ResponseMsg)); - - return true; -} - -////////////////////////////////////////////////////////////////////////// - -HttpTestingService::PackageHandler::PackageHandler(HttpTestingService& Svc, uint32_t RequestId) : m_Svc(Svc), m_RequestId(RequestId) -{ -} - -HttpTestingService::PackageHandler::~PackageHandler() -{ -} - -void -HttpTestingService::PackageHandler::FilterOffer(std::vector& OfferCids) -{ - ZEN_UNUSED(OfferCids); - // No-op - return; -} -void -HttpTestingService::PackageHandler::OnRequestBegin() -{ -} - -void -HttpTestingService::PackageHandler::OnRequestComplete() -{ -} - -IoBuffer -HttpTestingService::PackageHandler::CreateTarget(const IoHash& Cid, uint64_t StorageSize) -{ - ZEN_UNUSED(Cid); - return IoBuffer{StorageSize}; -} - -} // namespace zen diff --git a/src/zenserver/testing/httptest.h b/src/zenserver/testing/httptest.h deleted file mode 100644 index 57d2d63f3..000000000 --- a/src/zenserver/testing/httptest.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include -#include -#include -#include - -#include - -namespace zen { - -/** - * Test service to facilitate testing the HTTP framework and client interactions - */ -class HttpTestingService : public HttpService, public WebSocketService -{ -public: - HttpTestingService(); - ~HttpTestingService(); - - virtual const char* BaseUri() const override; - virtual void HandleRequest(HttpServerRequest& Request) override; - virtual Ref HandlePackageRequest(HttpServerRequest& HttpServiceRequest) override; - - class PackageHandler : public IHttpPackageHandler - { - public: - PackageHandler(HttpTestingService& Svc, uint32_t RequestId); - ~PackageHandler(); - - virtual void FilterOffer(std::vector& OfferCids) override; - virtual void OnRequestBegin() override; - virtual IoBuffer CreateTarget(const IoHash& Cid, uint64_t StorageSize) override; - virtual void OnRequestComplete() override; - - private: - HttpTestingService& m_Svc; - uint32_t m_RequestId; - }; - -private: - virtual void RegisterHandlers(WebSocketServer& Server) override; - virtual bool HandleRequest(const WebSocketMessage& Request) override; - - HttpRequestRouter m_Router; - std::atomic m_Counter{0}; - metrics::OperationTiming m_TimingStats; - - RwLock m_RwLock; - std::unordered_map> m_HandlerMap; -}; - -} // namespace zen diff --git a/src/zenserver/upstream/jupiter.cpp b/src/zenserver/upstream/jupiter.cpp index dbb185bec..bd075a436 100644 --- a/src/zenserver/upstream/jupiter.cpp +++ b/src/zenserver/upstream/jupiter.cpp @@ -2,7 +2,6 @@ #include "jupiter.h" -#include "diag/formatters.h" #include "diag/logging.h" #include @@ -12,6 +11,7 @@ #include #include #include +#include ZEN_THIRD_PARTY_INCLUDES_START #include diff --git a/src/zenserver/upstream/zen.cpp b/src/zenserver/upstream/zen.cpp index 9e1212834..8ae33597a 100644 --- a/src/zenserver/upstream/zen.cpp +++ b/src/zenserver/upstream/zen.cpp @@ -8,11 +8,11 @@ #include #include #include +#include #include #include #include "cache/structuredcachestore.h" -#include "diag/formatters.h" #include "diag/logging.h" ZEN_THIRD_PARTY_INCLUDES_START diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp index 3b81a3ada..9c79f9997 100644 --- a/src/zenserver/zenserver.cpp +++ b/src/zenserver/zenserver.cpp @@ -98,22 +98,22 @@ ZEN_THIRD_PARTY_INCLUDES_END // Services // +#include +#include +#include +#include +#include +#include +#include #include "admin/admin.h" #include "cache/structuredcache.h" #include "cache/structuredcachestore.h" -#include "cidstore.h" #include "compute/function.h" -#include "diag/diagsvcs.h" #include "frontend/frontend.h" -#include "monitoring/httpstats.h" -#include "monitoring/httpstatus.h" +#include "httpcidstore.h" #include "objectstore/objectstore.h" #include "projectstore/projectstore.h" -#include "testing/httptest.h" #include "upstream/upstream.h" -#include "zenhttp/auth/authmgr.h" -#include "zenhttp/auth/authservice.h" -#include "zenstore/gc.h" #define ZEN_APP_NAME "Zen store" -- cgit v1.2.3