aboutsummaryrefslogtreecommitdiff
path: root/zenserver/upstream/upstreamservice.cpp
diff options
context:
space:
mode:
authorPer Larsson <[email protected]>2022-01-24 11:11:10 +0100
committerPer Larsson <[email protected]>2022-01-24 11:11:10 +0100
commitdc6becffb513280170958f94e18c1b2966ade4d1 (patch)
treec7f9cccafcc21e241abdecde6f5219ab1009aff6 /zenserver/upstream/upstreamservice.cpp
parentFormat fix. (diff)
downloadzen-dc6becffb513280170958f94e18c1b2966ade4d1.tar.xz
zen-dc6becffb513280170958f94e18c1b2966ade4d1.zip
Refactored upstream cache to better handle different states in prep for dynamic auth tokens.
Diffstat (limited to 'zenserver/upstream/upstreamservice.cpp')
-rw-r--r--zenserver/upstream/upstreamservice.cpp208
1 files changed, 208 insertions, 0 deletions
diff --git a/zenserver/upstream/upstreamservice.cpp b/zenserver/upstream/upstreamservice.cpp
new file mode 100644
index 000000000..1cfd1df85
--- /dev/null
+++ b/zenserver/upstream/upstreamservice.cpp
@@ -0,0 +1,208 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include <upstream/jupiter.h>
+#include <upstream/upstreamcache.h>
+#include <upstream/upstreamservice.h>
+#include <upstream/zen.h>
+#include <zencore/compactbinarybuilder.h>
+#include <zencore/string.h>
+
+#include <json11.hpp>
+
+namespace zen {
+
+using namespace std::literals;
+
+namespace {
+ json11::Json TryGetJson(IoBuffer Body, HttpContentType ContentType, std::string& OutError)
+ {
+ if (!Body)
+ {
+ OutError = "No data"sv;
+ return json11::Json();
+ }
+
+ if ((ContentType == HttpContentType::kJSON || ContentType == HttpContentType::kCbObject) == false)
+ {
+ OutError = "Invalid content type"sv;
+ return json11::Json();
+ }
+
+ if (ContentType == ZenContentType::kJSON)
+ {
+ std::string JsonText(reinterpret_cast<const char*>(Body.GetData()), Body.GetSize());
+ return json11::Json::parse(JsonText, OutError);
+ }
+
+ if (CbObject Obj = LoadCompactBinaryObject(Body))
+ {
+ ExtendableStringBuilder<512> Sb;
+ return json11::Json::parse(Obj.ToJson(Sb).ToString(), OutError);
+ }
+
+ OutError = "Invalid compact binary"sv;
+ return json11::Json();
+ }
+
+ void WriteErrorResponse(HttpServerRequest& Request, std::string_view Property, std::string_view Reason)
+ {
+ CbObjectWriter Response;
+ Response << "Result"sv << false;
+ Response.BeginObject("Error"sv);
+ Response << "Property"sv << Property << "Reason"sv << Reason;
+ Response.EndObject();
+
+ Request.WriteResponse(HttpResponseCode::BadRequest, Response.Save());
+ }
+
+ void WriteSuccessResponse(HttpServerRequest& Request)
+ {
+ CbObjectWriter Response;
+ Response << "Result"sv << true;
+
+ Request.WriteResponse(HttpResponseCode::OK, Response.Save());
+ }
+} // namespace
+
+HttpUpstreamService::HttpUpstreamService(UpstreamCache& Upstream) : m_Upstream(Upstream)
+{
+ m_Router.RegisterRoute(
+ "endpoints",
+ [this](HttpRouterRequest& Req) {
+ CbObjectWriter Writer;
+ Writer.BeginArray("Endpoints"sv);
+ m_Upstream.IterateEndpoints([&Writer](UpstreamEndpoint& Ep) {
+ UpstreamEndpointInfo Info = Ep.GetEndpointInfo();
+ UpstreamEndpointStatus Status = Ep.GetStatus();
+
+ Writer.BeginObject();
+ Writer << "Name"sv << Info.Name;
+ Writer << "Url"sv << Info.Url;
+ Writer << "State"sv << ToString(Status.State);
+ Writer << "Reason"sv << Status.Reason;
+ Writer.EndObject();
+
+ return true;
+ });
+ Writer.EndArray();
+ Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Writer.Save());
+ },
+ HttpVerb::kGet);
+
+ m_Router.RegisterRoute(
+ "endpoints",
+ [this](HttpRouterRequest& RouterRequest) {
+ HttpServerRequest& ServerRequest = RouterRequest.ServerRequest();
+ std::string JsonError;
+
+ json11::Json Json = TryGetJson(ServerRequest.ReadPayload(), ServerRequest.RequestContentType(), JsonError);
+
+ if (!JsonError.empty())
+ {
+ return ServerRequest.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, JsonError);
+ }
+
+ const auto Type = Json["Type"].string_value();
+ const auto Name = Json["Name"].string_value();
+ const auto Url = Json["Url"].string_value();
+ const auto Namespace = Json["Namespace"].string_value();
+ const auto OAuthProvider = Json["OAuthProvider"].string_value();
+ const auto OAuthClientId = Json["OAuthClientId"].string_value();
+ const auto OAuthSecret = Json["OAuthSecret"].string_value();
+ const auto OAuthToken = Json["OAuthToken"].string_value();
+
+ if ((Type == "Horde"sv || Type == "Zen"sv) == false)
+ {
+ return WriteErrorResponse(ServerRequest, "Type"sv, "Invalid endpoint type, must be Zen or Horde"sv);
+ }
+
+ if (Name.empty())
+ {
+ return WriteErrorResponse(ServerRequest, "Name"sv, "Invalid endpoint name"sv);
+ }
+
+ if (Url.empty())
+ {
+ return WriteErrorResponse(ServerRequest, "Url"sv, "Invalid endpoint URL"sv);
+ }
+
+ bool IsNameUnique = true;
+ m_Upstream.IterateEndpoints([&Name, &IsNameUnique](UpstreamEndpoint& Ep) {
+ IsNameUnique = IsNameUnique && Ep.GetEndpointInfo().Name != Name;
+ return IsNameUnique;
+ });
+
+ if (IsNameUnique == false)
+ {
+ return WriteErrorResponse(ServerRequest, "Url"sv, "Endpoint name is not unique"sv);
+ }
+
+ std::unique_ptr<zen::UpstreamEndpoint> Endpoint;
+
+ if (Type == "Zen"sv)
+ {
+ std::vector<std::string> Urls;
+ Urls.push_back(Json["Url"].string_value());
+ Endpoint = zen::MakeZenUpstreamEndpoint({.Name = Name, .Urls = Urls});
+ }
+ else
+ {
+ if (Namespace.empty())
+ {
+ return WriteErrorResponse(ServerRequest, "Namespace"sv, "Invalid Horde namespace"sv);
+ }
+
+ if (OAuthProvider.empty())
+ {
+ return WriteErrorResponse(ServerRequest, "OAuthProvider"sv, "Invalid Horde OAuth provider URL"sv);
+ }
+
+ if (OAuthToken.empty())
+ {
+ if (OAuthClientId.empty())
+ {
+ return WriteErrorResponse(ServerRequest, "OAuthClientId"sv, "Invalid Horde OAuth client ID"sv);
+ }
+
+ if (OAuthSecret.empty())
+ {
+ return WriteErrorResponse(ServerRequest, "OAuthSecret"sv, "Invalid Horde OAuth secret"sv);
+ }
+ }
+
+ const zen::CloudCacheClientOptions Options = {.Name = Name,
+ .ServiceUrl = Url,
+ .DdcNamespace = Namespace,
+ .BlobStoreNamespace = Namespace,
+ .OAuthProvider = OAuthProvider,
+ .OAuthClientId = OAuthClientId,
+ .OAuthSecret = OAuthSecret,
+ .AccessToken = OAuthToken};
+
+ Endpoint = zen::MakeJupiterUpstreamEndpoint(Options);
+ }
+
+ m_Upstream.RegisterEndpoint(std::move(Endpoint));
+
+ WriteSuccessResponse(ServerRequest);
+ },
+ HttpVerb::kPost);
+}
+
+HttpUpstreamService::~HttpUpstreamService()
+{
+}
+
+const char*
+HttpUpstreamService::BaseUri() const
+{
+ return "/upstream/";
+}
+
+void
+HttpUpstreamService::HandleRequest(zen::HttpServerRequest& Request)
+{
+ m_Router.HandleRequest(Request);
+}
+
+} // namespace zen