225 lines
7.2 KiB
C++
225 lines
7.2 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
#pragma once
|
|
|
|
#include "Containers/Array.h"
|
|
#include "Containers/Map.h"
|
|
#include "Containers/UnrealString.h"
|
|
#include "CoreTypes.h"
|
|
#include "HttpPath.h"
|
|
#include "HttpRequestHandler.h"
|
|
#include "HttpResultCallback.h"
|
|
#include "HttpRouteHandle.h"
|
|
#include "HttpServerRequest.h"
|
|
#include "IHttpRouter.h"
|
|
#include "Logging/LogMacros.h"
|
|
#include "UObject/NameTypes.h"
|
|
#include "UObject/Object.h"
|
|
#include "UObject/ObjectMacros.h"
|
|
#include "UObject/UObjectGlobals.h"
|
|
|
|
#include "ExternalRpcRegistry.generated.h"
|
|
|
|
DECLARE_LOG_CATEGORY_EXTERN(LogExternalRpcRegistry, Log, All);
|
|
|
|
USTRUCT()
|
|
struct FExternalRpcArgumentDesc
|
|
{
|
|
GENERATED_BODY()
|
|
public:
|
|
FString Name;
|
|
FString Type;
|
|
FString Desc;
|
|
bool bIsOptional = false;
|
|
|
|
FExternalRpcArgumentDesc() = default;
|
|
FExternalRpcArgumentDesc(FString InName, FString InType, FString InDesc, bool bInIsOptional = false)
|
|
{
|
|
Name = InName;
|
|
Type = InType;
|
|
Desc = InDesc;
|
|
bIsOptional = bInIsOptional;
|
|
}
|
|
|
|
bool operator==(const FExternalRpcArgumentDesc& Other) const
|
|
{
|
|
return
|
|
Name == Other.Name &&
|
|
Type == Other.Type &&
|
|
Desc == Other.Desc &&
|
|
bIsOptional == Other.bIsOptional;
|
|
}
|
|
|
|
bool operator!=(const FExternalRpcArgumentDesc& Other) const
|
|
{
|
|
return !(*this == Other);
|
|
}
|
|
};
|
|
|
|
USTRUCT()
|
|
struct FExternalRouteInfo
|
|
{
|
|
GENERATED_BODY()
|
|
public:
|
|
FName RouteName;
|
|
FHttpPath RoutePath;
|
|
EHttpServerRequestVerbs RequestVerbs = EHttpServerRequestVerbs::VERB_NONE;
|
|
FString InputContentType;
|
|
TArray<FExternalRpcArgumentDesc> ExpectedArguments;
|
|
FString RpcCategory = TEXT("Unknown");
|
|
bool bAlwaysOn = false;
|
|
|
|
FExternalRouteInfo() = default;
|
|
|
|
FExternalRouteInfo(FName InRouteName, FHttpPath InRoutePath, EHttpServerRequestVerbs InRequestVerbs, FString InCategory = TEXT("Unknown"), bool bInAlwaysOn = false, FString InContentType = {}, TArray<FExternalRpcArgumentDesc> InArguments = TArray<FExternalRpcArgumentDesc>())
|
|
{
|
|
RouteName = InRouteName;
|
|
RoutePath = InRoutePath;
|
|
RequestVerbs = InRequestVerbs;
|
|
InputContentType = InContentType;
|
|
ExpectedArguments = InArguments;
|
|
RpcCategory = InCategory;
|
|
bAlwaysOn = false;
|
|
}
|
|
|
|
bool operator==(const FExternalRouteInfo& Other) const
|
|
{
|
|
return
|
|
RouteName == Other.RouteName &&
|
|
RoutePath == Other.RoutePath &&
|
|
RequestVerbs == Other.RequestVerbs &&
|
|
InputContentType == Other.InputContentType &&
|
|
ExpectedArguments == Other.ExpectedArguments &&
|
|
RpcCategory == Other.RpcCategory &&
|
|
bAlwaysOn == Other.bAlwaysOn;
|
|
}
|
|
|
|
bool operator!=(const FExternalRouteInfo& Other) const
|
|
{
|
|
return !(*this == Other);
|
|
}
|
|
};
|
|
|
|
USTRUCT()
|
|
struct FExternalRouteDesc
|
|
{
|
|
GENERATED_BODY()
|
|
public:
|
|
FHttpRouteHandle Handle;
|
|
FString InputContentType;
|
|
FString RpcCategory;
|
|
TArray<FExternalRpcArgumentDesc> ExpectedArguments;
|
|
FExternalRouteDesc() = default;
|
|
FExternalRouteDesc(FHttpRouteHandle InHandle, FString InContentType, TArray<FExternalRpcArgumentDesc> InArguments, FString InCategory = "")
|
|
{
|
|
Handle = InHandle;
|
|
InputContentType = InContentType;
|
|
ExpectedArguments = InArguments;
|
|
RpcCategory = InCategory;
|
|
}
|
|
};
|
|
|
|
USTRUCT()
|
|
struct FRpcLedgerEntry
|
|
{
|
|
GENERATED_BODY()
|
|
public:
|
|
FString RpcName;
|
|
FString RequestBody;
|
|
FDateTime RequestTime;
|
|
FRpcLedgerEntry() = default;
|
|
FRpcLedgerEntry(FString InName, FString InBody)
|
|
{
|
|
RpcName = InName;
|
|
RequestBody = InBody;
|
|
RequestTime = FDateTime::UtcNow();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* This class is designed to be a singleton that handles registry, maintenance, and cleanup of any REST endpoints exposed on the process
|
|
* for use in communicating with the process externally.
|
|
*/
|
|
UCLASS(MinimalAPI)
|
|
class UExternalRpcRegistry : public UObject
|
|
{
|
|
GENERATED_BODY()
|
|
protected:
|
|
static EXTERNALRPCREGISTRY_API UExternalRpcRegistry * ObjectInstance;
|
|
TMap<FName, FExternalRouteDesc> RegisteredRoutes;
|
|
TArray<FString> ActiveRpcCategories;
|
|
TArray<FRpcLedgerEntry> RequestLedger;
|
|
|
|
public:
|
|
static EXTERNALRPCREGISTRY_API UExternalRpcRegistry * GetInstance();
|
|
static EXTERNALRPCREGISTRY_API bool IsEnabled();
|
|
EXTERNALRPCREGISTRY_API ~UExternalRpcRegistry();
|
|
|
|
int PortToUse = 11223;
|
|
int RequestLedgerCapacity = 10;
|
|
|
|
/**
|
|
* Check if this Rpc is from a category that is meant to be enabled.
|
|
*/
|
|
EXTERNALRPCREGISTRY_API bool IsActiveRpcCategory(FString InCategory);
|
|
|
|
/**
|
|
* Try to get a route registered under given friendly name. Returns false if could not be found.
|
|
*/
|
|
EXTERNALRPCREGISTRY_API bool GetRegisteredRoute(FName RouteName, FExternalRouteInfo& OutRouteInfo);
|
|
|
|
EXTERNALRPCREGISTRY_API void RegisterNewRoute(FExternalRouteInfo InRouteInfo, const FHttpRequestHandler& Handler, bool bOverrideIfBound = false);
|
|
|
|
/**
|
|
* Register a new route.
|
|
* Will override existing routes if option is set, otherwise will error and fail to bind.
|
|
*/
|
|
EXTERNALRPCREGISTRY_API void RegisterNewRouteWithArguments(FName RouteName, const FHttpPath& HttpPath, const EHttpServerRequestVerbs& RequestVerbs, const FHttpRequestHandler& Handler, TArray<FExternalRpcArgumentDesc> InArguments, bool bOverrideIfBound = false, bool bIsAlwaysOn = false, FString OptionalCategory = TEXT("Unknown"), FString OptionalContentType = {});
|
|
|
|
/**
|
|
* Deprecated way to register a new route.
|
|
* Will override existing routes if option is set, otherwise will error and fail to bind.
|
|
*/
|
|
EXTERNALRPCREGISTRY_API void RegisterNewRoute(FName RouteName, const FHttpPath& HttpPath, const EHttpServerRequestVerbs& RequestVerbs, const FHttpRequestHandler& Handler, bool bOverrideIfBound = false, bool bIsAlwaysOn = false, FString OptionalCategory = TEXT("Unknown"), FString OptionalContentType = {}, FString OptionalExpectedFormat = {});
|
|
|
|
/**
|
|
* Clean up all routes - generally called as part of the destructor to make sure we don't have any function pointers dangling around.
|
|
*/
|
|
EXTERNALRPCREGISTRY_API void CleanUpAllRoutes();
|
|
|
|
/**
|
|
* Clean up a route.
|
|
* Can be set to fail if trying to unbind an unbound route.
|
|
*/
|
|
EXTERNALRPCREGISTRY_API void CleanUpRoute(FName RouteName, bool bFailIfUnbound = false);
|
|
|
|
/**
|
|
* Default Route Listing http call. Spits out all registered routes and describes them via a REST API call.
|
|
* Always registered at /listrpcs GET by default
|
|
*/
|
|
EXTERNALRPCREGISTRY_API bool HttpListOpenRoutes(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete);
|
|
/**
|
|
* Records an RPC call into the ledger, plus trims the ledger if it is too large.
|
|
*/
|
|
EXTERNALRPCREGISTRY_API void AddRequestToLedger(const FHttpServerRequest& Request);
|
|
|
|
/**
|
|
* Default request history call. Lists all calls recorded in the ledger, showing RPC name, request time, request body
|
|
* Always registered at /requesthistory GET by default
|
|
*/
|
|
EXTERNALRPCREGISTRY_API bool HttpPrintRequestLedger(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete);
|
|
|
|
/**
|
|
* Route Listing http, formatted for Swagger OASv3. Spits out all registered routes and describes them via a REST API call.
|
|
* Always registered at /swagger.json GET by default
|
|
*/
|
|
EXTERNALRPCREGISTRY_API bool HttpListOASv3JSONRoutes(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete);
|
|
|
|
|
|
/**
|
|
* Route Showing SwaggerUI using /swagger.json to describe the current REST API.
|
|
* Always registered at /swagger/html.index GET by default
|
|
*/
|
|
EXTERNALRPCREGISTRY_API bool HttpSwaggerUI(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete);
|
|
|
|
};
|