You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#jira UETOOL-4463 #rb none #preflight 629419761154108e88b6cf20 [CL 20428236 by George Rolfe in ue5-main branch]
825 lines
30 KiB
C++
825 lines
30 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "WebAPILiquidJSCodeGenerator.h"
|
|
|
|
#include "HttpModule.h"
|
|
#include "WebAPILiquidJSModule.h"
|
|
#include "WebAPILiquidJSSettings.h"
|
|
#include "Algo/ForEach.h"
|
|
#include "Algo/Transform.h"
|
|
#include "Async/Async.h"
|
|
#include "CodeGen/WebAPICodeGenerator.h"
|
|
#include "CodeGen/Dom/WebAPICodeGenFile.h"
|
|
#include "CodeGen/Dom/WebAPICodeGenFunction.h"
|
|
#include "CodeGen/Dom/WebAPICodeGenSettings.h"
|
|
#include "Dom/WebAPIType.h"
|
|
#include "Interfaces/IHttpResponse.h"
|
|
#include "Misc/FileHelper.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "Policies/CondensedJsonPrintPolicy.h"
|
|
#include "Serialization/JsonSerializer.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "WebAPILiquidJSCodeGenerator"
|
|
|
|
namespace UE
|
|
{
|
|
namespace WebAPI
|
|
{
|
|
namespace Generator
|
|
{
|
|
namespace LiquidJS
|
|
{
|
|
/** Various functionality for converting the provided CodeGen objects to implementation-specific Json objects. */
|
|
namespace Private
|
|
{
|
|
template <typename CodeGenType>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<CodeGenType>& InCodeGenObject);
|
|
|
|
template <typename CodeGenType>
|
|
TSharedPtr<FJsonObject> ToJson(const CodeGenType& InCodeGenObject);
|
|
|
|
template <typename CodeGenType>
|
|
void ToJson(const TArray<TSharedPtr<CodeGenType>>& InCodeGenObjects, TArray<TSharedPtr<FJsonValue>>& OutJson)
|
|
{
|
|
OutJson.Reserve(InCodeGenObjects.Num());
|
|
for(const TSharedPtr<CodeGenType>& Element : InCodeGenObjects)
|
|
{
|
|
TSharedPtr<FJsonObject> ElementJson = ToJson(Element);
|
|
OutJson.Add(MakeShared<FJsonValueObject>(ElementJson));
|
|
}
|
|
}
|
|
|
|
template <>
|
|
void ToJson<FWebAPICodeGenBase>(const TArray<TSharedPtr<FWebAPICodeGenBase>>& InCodeGenObjects, TArray<TSharedPtr<FJsonValue>>& OutJson);
|
|
|
|
void ToJson(const TSet<FString>& InArray, TArray<TSharedPtr<FJsonValue>>& OutJson)
|
|
{
|
|
OutJson.Reserve(InArray.Num());
|
|
for(const FString& Element : InArray)
|
|
{
|
|
TSharedPtr<FJsonValueString> ElementJson = MakeShared<FJsonValueString>(Element);
|
|
OutJson.Add(MoveTemp(ElementJson));
|
|
}
|
|
}
|
|
|
|
void ToJson(const TArray<FString>& InArray, TArray<TSharedPtr<FJsonValue>>& OutJson)
|
|
{
|
|
OutJson.Reserve(InArray.Num());
|
|
for(const FString& Element : InArray)
|
|
{
|
|
TSharedPtr<FJsonValueString> ElementJson = MakeShared<FJsonValueString>(Element);
|
|
OutJson.Add(MoveTemp(ElementJson));
|
|
}
|
|
}
|
|
|
|
/** EnumValue Array ToJson */
|
|
void ToJson(const TArray<FWebAPICodeGenEnumValue>& InArray, TArray<TSharedPtr<FJsonValue>>& OutJson)
|
|
{
|
|
OutJson.Reserve(InArray.Num());
|
|
for(const FWebAPICodeGenEnumValue& Element : InArray)
|
|
{
|
|
TSharedPtr<FJsonObject> ElementJson = MakeShared<FJsonObject>();
|
|
ElementJson->SetStringField(TEXT("name"), Element.Name);
|
|
ElementJson->SetStringField(TEXT("displayName"), Element.DisplayName);
|
|
ElementJson->SetStringField(TEXT("jsonName"), Element.JsonName);
|
|
ElementJson->SetStringField(TEXT("description"), Element.Description);
|
|
if(Element.IntegralValue >= 0)
|
|
{
|
|
ElementJson->SetNumberField(TEXT("explicitValue"), Element.IntegralValue);
|
|
}
|
|
OutJson.Add(MakeShared<FJsonValueObject>(ElementJson));
|
|
}
|
|
}
|
|
|
|
void ToJson(const TMap<FString, FString>& InMap, TArray<TSharedPtr<FJsonValue>>& OutJson)
|
|
{
|
|
OutJson.Reserve(InMap.Num());
|
|
for(const TPair<FString, FString>& Element : InMap)
|
|
{
|
|
const TSharedPtr<FJsonObject> ElementJson = MakeShared<FJsonObject>();
|
|
ElementJson->SetStringField(TEXT("key"), Element.Key);
|
|
if(!Element.Value.IsEmpty())
|
|
{
|
|
ElementJson->SetStringField(TEXT("value"), Element.Value);
|
|
}
|
|
OutJson.Add(MakeShared<FJsonValueObject>(ElementJson));
|
|
}
|
|
}
|
|
|
|
/** TypeNameVariant ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const FWebAPITypeNameVariant& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject.IsValid());
|
|
|
|
TSharedPtr<FJsonObject> JsonObject = MakeShared<FJsonObject>();
|
|
if(InCodeGenObject.HasTypeInfo())
|
|
{
|
|
JsonObject->SetStringField(TEXT("name"), InCodeGenObject.TypeInfo->Name);
|
|
JsonObject->SetStringField(TEXT("jsonName"), InCodeGenObject.TypeInfo->JsonName);
|
|
JsonObject->SetStringField(TEXT("jsonType"), InCodeGenObject.TypeInfo->JsonType.ToString());
|
|
JsonObject->SetStringField(TEXT("jsonPropertyToSerialize"), InCodeGenObject.TypeInfo->JsonPropertyToSerialize);
|
|
JsonObject->SetStringField(TEXT("printFormatSpecifier"), InCodeGenObject.TypeInfo->PrintFormatSpecifier);
|
|
JsonObject->SetStringField(TEXT("printFormatExpression"), InCodeGenObject.TypeInfo->PrintFormatExpression);
|
|
JsonObject->SetStringField(TEXT("namespace"), InCodeGenObject.TypeInfo->Namespace);
|
|
JsonObject->SetStringField(TEXT("prefix"), InCodeGenObject.TypeInfo->Prefix);
|
|
JsonObject->SetStringField(TEXT("declarationType"), InCodeGenObject.TypeInfo->DeclarationType.ToString());
|
|
JsonObject->SetBoolField(TEXT("isBuiltinType"), InCodeGenObject.TypeInfo->bIsBuiltinType);
|
|
}
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** NameVariant ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const FWebAPINameVariant& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject.IsValid());
|
|
|
|
TSharedPtr<FJsonObject> JsonObject = MakeShared<FJsonObject>();
|
|
if(InCodeGenObject.HasNameInfo())
|
|
{
|
|
JsonObject->SetStringField(TEXT("name"), InCodeGenObject.NameInfo.Name);
|
|
JsonObject->SetStringField(TEXT("jsonName"), InCodeGenObject.NameInfo.JsonName);
|
|
JsonObject->SetStringField(TEXT("prefix"), InCodeGenObject.NameInfo.Prefix);
|
|
}
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** Base ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenBase>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
TSharedPtr<FJsonObject> JsonObject = MakeShared<FJsonObject>();
|
|
|
|
JsonObject->SetStringField(TEXT("description"), InCodeGenObject->Description);
|
|
JsonObject->SetStringField(TEXT("module"), InCodeGenObject->Module);
|
|
JsonObject->SetStringField(TEXT("namespace"), InCodeGenObject->Namespace);
|
|
|
|
TArray<TSharedPtr<FJsonValue>> SpecifiersJson;
|
|
ToJson(InCodeGenObject->Specifiers, SpecifiersJson);
|
|
JsonObject->SetArrayField(TEXT("specifiers"), SpecifiersJson);
|
|
|
|
TArray<TSharedPtr<FJsonValue>> MetadataJson;
|
|
ToJson(InCodeGenObject->Metadata, MetadataJson);
|
|
JsonObject->SetArrayField(TEXT("metadata"), MetadataJson);
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** Property ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenProperty>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = ToJson<FWebAPICodeGenBase>(StaticCastSharedPtr<FWebAPICodeGenBase>(InCodeGenObject));
|
|
|
|
if(InCodeGenObject->Name.HasNameInfo())
|
|
{
|
|
const TSharedPtr<FJsonObject> NameJson = ToJson(InCodeGenObject->Name);
|
|
JsonObject->SetObjectField(TEXT("name"), NameJson);
|
|
}
|
|
else
|
|
{
|
|
JsonObject->SetStringField(TEXT("name"), InCodeGenObject->Name.ToString(true));
|
|
}
|
|
|
|
if(InCodeGenObject->Type.HasTypeInfo())
|
|
{
|
|
const TSharedPtr<FJsonObject> TypeJson = ToJson(InCodeGenObject->Type);
|
|
JsonObject->SetObjectField(TEXT("type"), TypeJson);
|
|
|
|
FString DefaultValue = InCodeGenObject->Type.TypeInfo->DefaultValue;
|
|
// Wrap in array initializer, if it's an array
|
|
if(InCodeGenObject->bIsArray)
|
|
{
|
|
DefaultValue = TEXT("{ }");
|
|
}
|
|
JsonObject->SetStringField(TEXT("defaultValue"), DefaultValue);
|
|
}
|
|
else
|
|
{
|
|
JsonObject->SetStringField(TEXT("type"), InCodeGenObject->Type.ToString(true));
|
|
}
|
|
|
|
if(!InCodeGenObject->DefaultValue.IsEmpty())
|
|
{
|
|
JsonObject->SetStringField(TEXT("defaultValue"), InCodeGenObject->DefaultValue);
|
|
}
|
|
|
|
JsonObject->SetBoolField(TEXT("isRequired"), InCodeGenObject->bIsRequired);
|
|
JsonObject->SetBoolField(TEXT("isArray"), InCodeGenObject->bIsArray);
|
|
JsonObject->SetBoolField(TEXT("isMixin"), InCodeGenObject->bIsMixin);
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** Enum ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenEnum>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = ToJson<FWebAPICodeGenBase>(StaticCastSharedPtr<FWebAPICodeGenBase>(InCodeGenObject));
|
|
|
|
if(InCodeGenObject->Name.HasTypeInfo())
|
|
{
|
|
const TSharedPtr<FJsonObject> NameJson = ToJson(InCodeGenObject->Name);
|
|
JsonObject->SetObjectField(TEXT("name"), NameJson);
|
|
}
|
|
else
|
|
{
|
|
JsonObject->SetStringField(TEXT("name"), InCodeGenObject->Name.ToString(true));
|
|
}
|
|
|
|
TArray<TSharedPtr<FJsonValue>> ValuesJson;
|
|
ToJson(InCodeGenObject->Values, ValuesJson);
|
|
JsonObject->SetArrayField(TEXT("values"), ValuesJson);
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** Struct ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenStruct>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = ToJson<FWebAPICodeGenBase>(StaticCastSharedPtr<FWebAPICodeGenBase>(InCodeGenObject));
|
|
|
|
if(InCodeGenObject->Name.HasTypeInfo())
|
|
{
|
|
const TSharedPtr<FJsonObject> NameJson = ToJson(InCodeGenObject->Name);
|
|
JsonObject->SetObjectField(TEXT("name"), NameJson);
|
|
}
|
|
else
|
|
{
|
|
JsonObject->SetStringField(TEXT("name"), InCodeGenObject->Name.ToString(true));
|
|
}
|
|
|
|
TArray<TSharedPtr<FJsonValue>> PropertiesJson;
|
|
ToJson(InCodeGenObject->Properties, PropertiesJson);
|
|
JsonObject->SetArrayField(TEXT("properties"), PropertiesJson);
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** Class ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenClass>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = ToJson<FWebAPICodeGenStruct>(StaticCastSharedPtr<FWebAPICodeGenStruct>(InCodeGenObject));
|
|
|
|
TArray<TSharedPtr<FJsonValue>> FunctionsJson;
|
|
ToJson(InCodeGenObject->Functions, FunctionsJson);
|
|
JsonObject->SetArrayField(TEXT("functions"), FunctionsJson);
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** FunctionParameter ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenFunctionParameter>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = ToJson<FWebAPICodeGenProperty>(StaticCastSharedPtr<FWebAPICodeGenProperty>(InCodeGenObject));
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** Function ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenFunction>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = ToJson<FWebAPICodeGenBase>(StaticCastSharedPtr<FWebAPICodeGenBase>(InCodeGenObject));
|
|
|
|
if(InCodeGenObject->Name.HasNameInfo())
|
|
{
|
|
const TSharedPtr<FJsonObject> NameJson = ToJson(InCodeGenObject->Name);
|
|
JsonObject->SetObjectField(TEXT("name"), NameJson);
|
|
}
|
|
else
|
|
{
|
|
JsonObject->SetStringField(TEXT("name"), InCodeGenObject->Name.ToString(true));
|
|
}
|
|
|
|
JsonObject->SetBoolField(TEXT("isOverride"), InCodeGenObject->bIsOverride);
|
|
JsonObject->SetBoolField(TEXT("isConst"), InCodeGenObject->bIsOverride);
|
|
|
|
if(InCodeGenObject->ReturnType.HasTypeInfo())
|
|
{
|
|
const TSharedPtr<FJsonObject> TypeJson = ToJson(InCodeGenObject->ReturnType);
|
|
JsonObject->SetObjectField(TEXT("returnType"), TypeJson);
|
|
}
|
|
else
|
|
{
|
|
JsonObject->SetStringField(TEXT("returnType"), InCodeGenObject->ReturnType.ToString(true));
|
|
}
|
|
|
|
JsonObject->SetBoolField(TEXT("isReturnTypeConst"), InCodeGenObject->bIsConstReturnType);
|
|
JsonObject->SetStringField(TEXT("body"), InCodeGenObject->Body);
|
|
|
|
TArray<TSharedPtr<FJsonValue>> ParameterJson;
|
|
ToJson(InCodeGenObject->Parameters, ParameterJson);
|
|
JsonObject->SetArrayField(TEXT("parameters"), ParameterJson);
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** OperationParameter ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenOperationParameter>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = ToJson<FWebAPICodeGenProperty>(StaticCastSharedPtr<FWebAPICodeGenProperty>(InCodeGenObject));
|
|
|
|
JsonObject->SetStringField(TEXT("storage"), UE::WebAPI::WebAPIParameterStorage::ToString(InCodeGenObject->Storage));
|
|
JsonObject->SetStringField(TEXT("mediaType"), InCodeGenObject->MediaType);
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** OperationRequest ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenOperationRequest>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = ToJson<FWebAPICodeGenBase>(StaticCastSharedPtr<FWebAPICodeGenBase>(InCodeGenObject));
|
|
|
|
if(InCodeGenObject->Name.HasTypeInfo())
|
|
{
|
|
const TSharedPtr<FJsonObject> NameJson = ToJson(InCodeGenObject->Name);
|
|
JsonObject->SetObjectField(TEXT("name"), NameJson);
|
|
}
|
|
else
|
|
{
|
|
JsonObject->SetStringField(TEXT("name"), InCodeGenObject->Name.ToString(true));
|
|
}
|
|
|
|
TArray<TSharedPtr<FJsonValue>> ParametersJson;
|
|
ToJson(InCodeGenObject->Parameters, ParametersJson);
|
|
JsonObject->SetArrayField(TEXT("properties"), ParametersJson); // encode as properties
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** OperationResponse ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenOperationResponse>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = ToJson<FWebAPICodeGenStruct>(StaticCastSharedPtr<FWebAPICodeGenStruct>(InCodeGenObject));
|
|
|
|
if(InCodeGenObject->Name.HasTypeInfo())
|
|
{
|
|
const TSharedPtr<FJsonObject> NameJson = ToJson(InCodeGenObject->Name);
|
|
JsonObject->SetObjectField(TEXT("name"), NameJson);
|
|
}
|
|
else
|
|
{
|
|
JsonObject->SetStringField(TEXT("name"), InCodeGenObject->Name.ToString(true));
|
|
}
|
|
|
|
JsonObject->SetNumberField(TEXT("responseCode"), InCodeGenObject->ResponseCode);
|
|
JsonObject->SetStringField(TEXT("message"), InCodeGenObject->Message);
|
|
|
|
checkf(InCodeGenObject->Base.IsValid(), TEXT("OperationResponse should have a base type set."));
|
|
|
|
const TSharedPtr<FJsonObject> BaseJson = ToJson(InCodeGenObject->Base);
|
|
JsonObject->SetObjectField(TEXT("base"), BaseJson);
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** Operation ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenOperation>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = ToJson<FWebAPICodeGenBase>(StaticCastSharedPtr<FWebAPICodeGenBase>(InCodeGenObject));
|
|
|
|
if(InCodeGenObject->Name.HasTypeInfo())
|
|
{
|
|
const TSharedPtr<FJsonObject> NameJson = ToJson(InCodeGenObject->Name);
|
|
JsonObject->SetObjectField(TEXT("name"), NameJson);
|
|
}
|
|
else
|
|
{
|
|
JsonObject->SetStringField(TEXT("name"), InCodeGenObject->Name.ToString(true));
|
|
}
|
|
|
|
JsonObject->SetStringField(TEXT("path"), InCodeGenObject->Path);
|
|
JsonObject->SetStringField(TEXT("service"), InCodeGenObject->ServiceName);
|
|
JsonObject->SetStringField(TEXT("verb"), InCodeGenObject->Verb);
|
|
|
|
TArray<TSharedPtr<FJsonValue>> RequestsJson;
|
|
ToJson(InCodeGenObject->Requests, RequestsJson);
|
|
JsonObject->SetArrayField(TEXT("requests"), RequestsJson);
|
|
|
|
TArray<TSharedPtr<FJsonValue>> ResponsesJson;
|
|
ToJson(InCodeGenObject->Responses, ResponsesJson);
|
|
JsonObject->SetArrayField(TEXT("responses"), ResponsesJson);
|
|
|
|
JsonObject->SetStringField(TEXT("settingsTypeName"), InCodeGenObject->SettingsTypeName);
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** Settings ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenSettings>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = ToJson<FWebAPICodeGenBase>(StaticCastSharedPtr<FWebAPICodeGenBase>(InCodeGenObject));
|
|
|
|
if(InCodeGenObject->Name.HasTypeInfo())
|
|
{
|
|
const TSharedPtr<FJsonObject> NameJson = ToJson(InCodeGenObject->Name);
|
|
JsonObject->SetObjectField(TEXT("name"), NameJson);
|
|
}
|
|
else
|
|
{
|
|
JsonObject->SetStringField(TEXT("name"), InCodeGenObject->Name.ToString(true));
|
|
}
|
|
|
|
if(InCodeGenObject->ParentType.IsValid())
|
|
{
|
|
JsonObject->SetStringField(TEXT("base"), InCodeGenObject->ParentType->GetName());
|
|
}
|
|
JsonObject->SetStringField(TEXT("host"), InCodeGenObject->Host);
|
|
JsonObject->SetStringField(TEXT("baseUrl"), InCodeGenObject->BaseUrl);
|
|
JsonObject->SetStringField(TEXT("userAgent"), InCodeGenObject->UserAgent);
|
|
JsonObject->SetStringField(TEXT("dateTimeFormat"), InCodeGenObject->DateTimeFormat);
|
|
|
|
TArray<TSharedPtr<FJsonValue>> SchemesJson;
|
|
ToJson(InCodeGenObject->Schemes, SchemesJson);
|
|
JsonObject->SetArrayField(TEXT("schemes"), SchemesJson);
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
/** File ToJson */
|
|
template <>
|
|
TSharedPtr<FJsonObject> ToJson(const TSharedPtr<FWebAPICodeGenFile>& InCodeGenObject)
|
|
{
|
|
check(InCodeGenObject);
|
|
|
|
const TFunction<FString(FWebAPITypeNameVariant)> MakeForwardDeclarationString =
|
|
[](const FWebAPITypeNameVariant& InTypeName)
|
|
{
|
|
const FString ObjectType = InTypeName.TypeInfo->IsEnum()
|
|
? TEXT("enum class")
|
|
: InTypeName.TypeInfo->Prefix == TEXT("F")
|
|
? TEXT("struct")
|
|
: TEXT("class");
|
|
|
|
const FString Suffix = InTypeName.TypeInfo->IsEnum() ? TEXT(" : uint8") : TEXT("");
|
|
|
|
return FString::Printf(TEXT("%s %s%s"), *ObjectType, *InTypeName.ToString(), *Suffix);
|
|
};
|
|
|
|
const TSharedPtr<FJsonObject> JsonObject = MakeShared<FJsonObject>();
|
|
|
|
JsonObject->SetStringField(TEXT("baseFilePath"), InCodeGenObject->BaseFilePath);
|
|
JsonObject->SetStringField(TEXT("relativeFilePath"), InCodeGenObject->RelativeFilePath);
|
|
JsonObject->SetStringField(TEXT("fileName"), InCodeGenObject->FileName);
|
|
JsonObject->SetStringField(TEXT("fileType"), InCodeGenObject->FileType);
|
|
JsonObject->SetStringField(TEXT("namespace"), InCodeGenObject->Namespace);
|
|
JsonObject->SetStringField(TEXT("module"), InCodeGenObject->Module);
|
|
JsonObject->SetStringField(TEXT("copyrightNotice"), InCodeGenObject->CopyrightNotice);
|
|
|
|
TArray<TSharedPtr<FJsonValue>> IncludePathJson;
|
|
ToJson(InCodeGenObject->IncludePaths, IncludePathJson);
|
|
JsonObject->SetArrayField(TEXT("includePaths"), IncludePathJson);
|
|
|
|
TArray<FString> ForwardDeclarations;
|
|
|
|
// Find and transform Enums
|
|
TArray<TSharedPtr<FJsonValue>> EnumsJson;
|
|
Algo::TransformIf(
|
|
InCodeGenObject->SubItems,
|
|
EnumsJson,
|
|
[](const TSharedPtr<FWebAPICodeGenBase>& InItem)
|
|
{
|
|
return InItem->GetTypeName() == TEXT("Enum");
|
|
},
|
|
[&](const TSharedPtr<FWebAPICodeGenBase>& InItem)
|
|
{
|
|
const TSharedPtr<FWebAPICodeGenEnum> Enum = StaticCastSharedPtr<FWebAPICodeGenEnum>(InItem);
|
|
ForwardDeclarations.Add(MakeForwardDeclarationString(Enum->Name));
|
|
|
|
TSharedPtr<FJsonObject> EnumJson = UE::WebAPI::Generator::LiquidJS::Private::ToJson(Enum);
|
|
return MakeShared<FJsonValueObject>(EnumJson);
|
|
});
|
|
|
|
// Find and transform Structs
|
|
TArray<TSharedPtr<FJsonValue>> StructsJson;
|
|
Algo::TransformIf(
|
|
InCodeGenObject->SubItems,
|
|
StructsJson,
|
|
[](const TSharedPtr<FWebAPICodeGenBase>& InItem)
|
|
{
|
|
return InItem->GetTypeName() == TEXT("Struct");
|
|
},
|
|
[&](const TSharedPtr<FWebAPICodeGenBase>& InItem)
|
|
{
|
|
const TSharedPtr<FWebAPICodeGenStruct> Struct = StaticCastSharedPtr<FWebAPICodeGenStruct>(InItem);
|
|
ForwardDeclarations.Add(MakeForwardDeclarationString(Struct->Name));
|
|
|
|
TSharedPtr<FJsonObject> StructJson = UE::WebAPI::Generator::LiquidJS::Private::ToJson(Struct);
|
|
return MakeShared<FJsonValueObject>(StructJson);
|
|
});
|
|
|
|
// Find and transform Classes
|
|
TArray<TSharedPtr<FJsonValue>> ClassesJson;
|
|
Algo::TransformIf(
|
|
InCodeGenObject->SubItems,
|
|
ClassesJson,
|
|
[](const TSharedPtr<FWebAPICodeGenBase>& InItem)
|
|
{
|
|
return InItem->GetTypeName() == TEXT("Class");
|
|
},
|
|
[&](const TSharedPtr<FWebAPICodeGenBase>& InItem)
|
|
{
|
|
const TSharedPtr<FWebAPICodeGenClass> Class = StaticCastSharedPtr<FWebAPICodeGenClass>(InItem);
|
|
ForwardDeclarations.Add(MakeForwardDeclarationString(Class->Name));
|
|
|
|
TSharedPtr<FJsonObject> ClassJson = UE::WebAPI::Generator::LiquidJS::Private::ToJson(Class);
|
|
return MakeShared<FJsonValueObject>(ClassJson);
|
|
});
|
|
|
|
// Find and transform Operations
|
|
TArray<TSharedPtr<FJsonValue>> OperationsJson;
|
|
TArray<TSharedPtr<FJsonValue>> RequestsJson;
|
|
TArray<TSharedPtr<FJsonValue>> ResponsesJson;
|
|
Algo::TransformIf(
|
|
InCodeGenObject->SubItems,
|
|
OperationsJson,
|
|
[](const TSharedPtr<FWebAPICodeGenBase>& InItem)
|
|
{
|
|
return InItem->GetTypeName() == TEXT("Operation");
|
|
},
|
|
[&](const TSharedPtr<FWebAPICodeGenBase>& InItem)
|
|
{
|
|
const TSharedPtr<FWebAPICodeGenOperation> Operation = StaticCastSharedPtr<FWebAPICodeGenOperation>(InItem);
|
|
TSharedPtr<FJsonObject> OperationJson = UE::WebAPI::Generator::LiquidJS::Private::ToJson(Operation);
|
|
|
|
ForwardDeclarations.Add(MakeForwardDeclarationString(Operation->Name));
|
|
|
|
RequestsJson.Append(OperationJson->GetArrayField(TEXT("requests")));
|
|
ResponsesJson.Append(OperationJson->GetArrayField(TEXT("responses")));
|
|
|
|
return MakeShared<FJsonValueObject>(OperationJson);
|
|
});
|
|
|
|
// Find and transform Settings
|
|
TArray<TSharedPtr<FJsonObject>> SettingsJsonArray;
|
|
Algo::TransformIf(
|
|
InCodeGenObject->SubItems,
|
|
SettingsJsonArray,
|
|
[](const TSharedPtr<FWebAPICodeGenBase>& InItem)
|
|
{
|
|
return InItem->GetTypeName() == TEXT("Settings");
|
|
},
|
|
[](const TSharedPtr<FWebAPICodeGenBase>& InItem)
|
|
{
|
|
const TSharedPtr<FWebAPICodeGenSettings> Settings = StaticCastSharedPtr<FWebAPICodeGenSettings>(InItem);
|
|
TSharedPtr<FJsonObject> SettingsJson = UE::WebAPI::Generator::LiquidJS::Private::ToJson(Settings);
|
|
return SettingsJson;
|
|
});
|
|
|
|
// Set here as Operations can add additional structs/enums
|
|
JsonObject->SetArrayField(TEXT("enums"), EnumsJson);
|
|
JsonObject->SetArrayField(TEXT("structs"), StructsJson);
|
|
JsonObject->SetArrayField(TEXT("classes"), ClassesJson);
|
|
JsonObject->SetArrayField(TEXT("operations"), OperationsJson);
|
|
JsonObject->SetArrayField(TEXT("requests"), RequestsJson);
|
|
JsonObject->SetArrayField(TEXT("responses"), ResponsesJson);
|
|
|
|
TArray<TSharedPtr<FJsonValue>> ForwardDeclarationsJson;
|
|
ToJson(ForwardDeclarations, ForwardDeclarationsJson);
|
|
JsonObject->SetArrayField(TEXT("forwardDeclarations"), ForwardDeclarationsJson);
|
|
|
|
if(!SettingsJsonArray.IsEmpty())
|
|
{
|
|
JsonObject->SetObjectField(TEXT("settings"), SettingsJsonArray.Last());
|
|
}
|
|
|
|
return JsonObject;
|
|
}
|
|
|
|
template <>
|
|
void ToJson<FWebAPICodeGenBase>(const TArray<TSharedPtr<FWebAPICodeGenBase>>& InCodeGenObjects, TArray<TSharedPtr<FJsonValue>>& OutJson)
|
|
{
|
|
OutJson.Reserve(InCodeGenObjects.Num());
|
|
for(const TSharedPtr<FWebAPICodeGenBase>& CodeGenObject : InCodeGenObjects)
|
|
{
|
|
TSharedPtr<FJsonObject> ElementJson = MakeShared<FJsonObject>();
|
|
const FName& CodeGenObjectType = CodeGenObject->GetTypeName();
|
|
if(CodeGenObjectType == TEXT("Enum"))
|
|
{
|
|
ElementJson = ToJson(StaticCastSharedPtr<FWebAPICodeGenEnum>(CodeGenObject));
|
|
}
|
|
else if(CodeGenObjectType == TEXT("Struct"))
|
|
{
|
|
ElementJson = ToJson(StaticCastSharedPtr<FWebAPICodeGenStruct>(CodeGenObject));
|
|
}
|
|
else if(CodeGenObjectType == TEXT("Operation"))
|
|
{
|
|
ElementJson = ToJson(StaticCastSharedPtr<FWebAPICodeGenOperation>(CodeGenObject));
|
|
}
|
|
else if(CodeGenObjectType == TEXT("Class"))
|
|
{
|
|
ElementJson = ToJson(StaticCastSharedPtr<FWebAPICodeGenClass>(CodeGenObject));
|
|
}
|
|
OutJson.Add(MakeShared<FJsonValueObject>(ElementJson));
|
|
}
|
|
}
|
|
|
|
/** Runs the given function on the GameThread, returning a Future. */
|
|
template<typename ResultType>
|
|
static TFuture<ResultType> ExecuteOnGameThread(const TFunction<ResultType()>& Function)
|
|
{
|
|
TSharedRef<TPromise<ResultType>, ESPMode::ThreadSafe> Promise = MakeShared<TPromise<ResultType>>();
|
|
TFunction<void()> PromiseKeeper =
|
|
[Promise, Function]
|
|
{
|
|
Promise->SetValue(Function());
|
|
};
|
|
|
|
if (!IsInGameThread())
|
|
{
|
|
AsyncTask(ENamedThreads::GameThread, MoveTemp(PromiseKeeper));
|
|
}
|
|
else
|
|
{
|
|
PromiseKeeper();
|
|
}
|
|
return Promise->GetFuture();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TFuture<bool> UWebAPILiquidJSCodeGenerator::IsAvailable()
|
|
{
|
|
const TSharedRef<TPromise<bool>, ESPMode::ThreadSafe> Promise = MakeShared<TPromise<bool>, ESPMode::ThreadSafe>();
|
|
|
|
FHttpModule& HttpModule = FHttpModule::Get();
|
|
|
|
const FString URL = GetMutableDefault<UWebAPILiquidJSSettings>()->GetServiceUrl(TEXT("/api/ping"));
|
|
|
|
const TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = HttpModule.CreateRequest();
|
|
Request->SetVerb(TEXT("GET"));
|
|
Request->SetURL(URL);
|
|
Request->SetHeader(TEXT("User-Agent"), TEXT("X-UnrealEngine-Agent"));
|
|
Request->SetHeader(TEXT("Accept"), TEXT("application/json"));
|
|
Request->SetHeader(TEXT("Accept-Encoding"), TEXT("identity"));
|
|
Request->SetTimeout(10.0f); // 10 second timeout
|
|
|
|
std::atomic<bool> bHasRetried = false;
|
|
|
|
Request->OnProcessRequestComplete().BindLambda(
|
|
[Promise, &bHasRetried, Request](FHttpRequestPtr, FHttpResponsePtr InResponse, bool bInWasSuccessful)
|
|
{
|
|
if(bInWasSuccessful && EHttpResponseCodes::IsOk(InResponse->GetResponseCode()))
|
|
{
|
|
Promise->SetValue(true);
|
|
}
|
|
else
|
|
{
|
|
if(!bHasRetried.load(std::memory_order_relaxed))
|
|
{
|
|
// Try starting
|
|
bool bRetryResult = FModuleManager::Get().GetModulePtr<FWebAPILiquidJSModule>(TEXT("WebAPILiquidJS"))->TryStartWebApp();
|
|
bHasRetried.store(true, std::memory_order_relaxed);
|
|
Request->ProcessRequest();
|
|
return;
|
|
}
|
|
|
|
Promise->SetValue(false);
|
|
}
|
|
});
|
|
|
|
Request->ProcessRequest();
|
|
|
|
return Promise->GetFuture();
|
|
}
|
|
|
|
TFuture<EWebAPIGenerationResult> UWebAPILiquidJSCodeGenerator::GenerateFile(const TWeakObjectPtr<UWebAPIDefinition>& InDefinition, const TSharedPtr<FWebAPICodeGenFile>& InFile)
|
|
{
|
|
check(InDefinition.IsValid());
|
|
|
|
const TSharedRef<TPromise<EWebAPIGenerationResult>, ESPMode::ThreadSafe> Promise = MakeShared<TPromise<EWebAPIGenerationResult>, ESPMode::ThreadSafe>();
|
|
|
|
FHttpModule& HttpModule = FHttpModule::Get();
|
|
|
|
const FString FileType = InFile->FileType.EndsWith(TEXT("h"))
|
|
? TEXT("decl")
|
|
: TEXT("defn");
|
|
|
|
const FString URL = GetDefault<UWebAPILiquidJSSettings>()->GetServiceUrl(TEXT("api/gen/") + FileType);
|
|
|
|
const TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = HttpModule.CreateRequest();
|
|
Request->SetVerb(TEXT("POST"));
|
|
Request->SetURL(URL);
|
|
Request->SetHeader(TEXT("User-Agent"), TEXT("X-UnrealEngine-Agent"));
|
|
Request->SetHeader(TEXT("Content-Type"), TEXT("application/json"));
|
|
Request->SetHeader(TEXT("Accept"), TEXT("application/json"));
|
|
Request->SetHeader(TEXT("Accept-Encoding"), TEXT("identity"));
|
|
|
|
const TSharedPtr<FJsonObject> FileJson = UE::WebAPI::Generator::LiquidJS::Private::ToJson(InFile);
|
|
#if WITH_WEBAPI_DEBUG
|
|
bool bWriteResult = InDefinition->GetGeneratorSettings().bWriteResult;
|
|
#else
|
|
bool bWriteResult = true;
|
|
#endif
|
|
|
|
FString JsonString;
|
|
const TSharedRef<TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>> Writer = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>::Create(&JsonString);
|
|
FJsonSerializer::Serialize(FileJson.ToSharedRef(), Writer);
|
|
|
|
Request->SetContentAsString(JsonString);
|
|
|
|
Request->OnProcessRequestComplete().BindLambda(
|
|
[Promise, InFile, bWriteResult, InDefinition](FHttpRequestPtr, FHttpResponsePtr InResponse, bool bInWasSuccessful)
|
|
{
|
|
if(bInWasSuccessful && InResponse->GetResponseCode() == 200)
|
|
{
|
|
const FString GeneratedCodeString = InResponse->GetContentAsString();
|
|
|
|
// Write the result to the original schema objects (allows for visualization and debug of generated code)
|
|
Algo::ForEach(InFile->SchemaObjects, [&GeneratedCodeString](const TWeakObjectPtr<UObject>& InSchemaObject)
|
|
{
|
|
if(InSchemaObject.IsValid())
|
|
{
|
|
const TScriptInterface<IWebAPISchemaObjectInterface> AsInterface = InSchemaObject.Get();
|
|
AsInterface.GetInterface()->AppendCodeText(GeneratedCodeString);
|
|
}
|
|
});
|
|
|
|
if(bWriteResult)
|
|
{
|
|
FFileHelper::SaveStringToFile(GeneratedCodeString, *InFile->GetFullPath());
|
|
}
|
|
|
|
Promise->SetValue(EWebAPIGenerationResult::Succeeded);
|
|
}
|
|
else
|
|
{
|
|
const FString JsonString = InResponse->GetContentAsString();
|
|
const TSharedRef<TJsonReader<TCHAR>> Reader = TJsonReaderFactory<TCHAR>::Create(JsonString);
|
|
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("Code"), InResponse->GetResponseCode());
|
|
Args.Add(TEXT("Url"), FText::FromString(InResponse->GetURL()));
|
|
|
|
TSharedPtr<FJsonObject> JsonObject;
|
|
if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
|
|
{
|
|
FString ErrorName;
|
|
JsonObject->TryGetStringField(TEXT("errorName"), ErrorName);
|
|
|
|
FString Message;
|
|
JsonObject->TryGetStringField(TEXT("message"), Message);
|
|
|
|
FString Stack;
|
|
JsonObject->TryGetStringField(TEXT("stack"), Stack);
|
|
|
|
Args.Add(TEXT("Error"), FText::FromString(ErrorName));
|
|
Args.Add(TEXT("Message"), FText::FromString(Message));
|
|
Args.Add(TEXT("StackTrace"), FText::FromString(Stack));
|
|
InDefinition->GetMessageLog()->LogError(FText::Format(LOCTEXT("HttpErrorWithMessage", "HTTP Response Code: {Code}\nError: {Error}\nMessage: {Message}\nStackTrace: {StackTrace}"), Args), UWebAPILiquidJSCodeGenerator::LogName);
|
|
}
|
|
else
|
|
{
|
|
InDefinition->GetMessageLog()->LogError(FText::Format(LOCTEXT("HttpError", "HTTP Response Code: {Code}\nUrl: {Url}"), Args), UWebAPILiquidJSCodeGenerator::LogName);
|
|
}
|
|
|
|
Promise->SetValue(EWebAPIGenerationResult::Failed);
|
|
}
|
|
});
|
|
|
|
Request->ProcessRequest();
|
|
|
|
return Promise->GetFuture();
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|