void FWebJSScripting::InvokeJSFunction(FGuid FunctionId, int32 ArgCount, FWebJSParam Arguments[], bool bIsError) { CefRefPtr<CefListValue> FunctionArguments = CefListValue::Create(); for ( int32 i=0; i<ArgCount; i++) { SetConverted(FunctionArguments, i, Arguments[i]); } InvokeJSFunction(FunctionId, FunctionArguments, bIsError); }
void FWebJSScripting::InvokeJSErrorResult(FGuid FunctionId, const FString& Error) { FWebJSParam Arguments[1] = {FWebJSParam(Error)}; InvokeJSFunction(FunctionId, 1, Arguments, true); }
bool FWebJSScripting::HandleExecuteUObjectMethodMessage(CefRefPtr<CefListValue> MessageArguments) { FGuid ObjectKey; // Message arguments are Name, Value, bGlobal if (MessageArguments->GetSize() != 4 || MessageArguments->GetType(0) != VTYPE_STRING || MessageArguments->GetType(1) != VTYPE_STRING || MessageArguments->GetType(2) != VTYPE_STRING || MessageArguments->GetType(3) != VTYPE_LIST ) { // Wrong message argument types or count return false; } if (!FGuid::Parse(FString(MessageArguments->GetString(0).ToWString().c_str()), ObjectKey)) { // Invalid GUID return false; } // Get the promise callback and use that to report any results from executing this function. FGuid ResultCallbackId; if (!FGuid::Parse(FString(MessageArguments->GetString(2).ToWString().c_str()), ResultCallbackId)) { // Invalid GUID return false; } UObject* Object = GuidToPtr(ObjectKey); if (Object == nullptr) { // Unknown uobject id InvokeJSErrorResult(ResultCallbackId, TEXT("Unknown UObject ID")); return true; } FName MethodName = MessageArguments->GetString(1).ToWString().c_str(); UFunction* Function = Object->FindFunction(MethodName); if (!Function) { InvokeJSErrorResult(ResultCallbackId, TEXT("Unknown UObject Function")); return true; } // Coerce arguments to function arguments. uint16 ParamsSize = Function->ParmsSize; TArray<uint8> Params; UProperty* ReturnParam = nullptr; // Convert cef argument list to a dictionary, so we can use FStructDeserializer to convert it for us CefRefPtr<CefDictionaryValue> NamedArgs = CefDictionaryValue::Create(); { int32 CurrentArg = 0; CefRefPtr<CefListValue> CefArgs = MessageArguments->GetList(3); for ( TFieldIterator<UProperty> It(Function); It; ++It ) { UProperty* Param = *It; if (Param->PropertyFlags & CPF_Parm) { if (Param->PropertyFlags & CPF_ReturnParm) { ReturnParam = Param; } else { CopyContainerValue(NamedArgs, CefArgs, CefString(*Param->GetName()), CurrentArg); CurrentArg++; } } } if (ParamsSize > 0) { // UFunction is a subclass of UStruct, so we can treat the arguments as a struct for deserialization UStruct* TypeInfo = Cast<UStruct>(Function); Params.AddUninitialized(ParamsSize); TypeInfo->InitializeStruct(Params.GetData()); FWebJSStructDeserializerBackend Backend = FWebJSStructDeserializerBackend(SharedThis(this), NamedArgs); FStructDeserializer::Deserialize(Params.GetData(), *TypeInfo, Backend); } } Object->ProcessEvent(Function, Params.GetData()); if ( ReturnParam ) { FWebJSParam Results[1] = {ConvertResult(ReturnParam, Params.GetData())}; InvokeJSFunction(ResultCallbackId, 1, Results, false); } else { InvokeJSFunction(ResultCallbackId, 0, nullptr, false); } return true; }
void FWebJSScripting::InvokeJSErrorResult(FGuid FunctionId, const FString& Error) { CefRefPtr<CefListValue> FunctionArguments = CefListValue::Create(); FunctionArguments->SetString(0, *Error); InvokeJSFunction(FunctionId, FunctionArguments, true); }
bool FWebJSScripting::HandleExecuteUObjectMethodMessage(CefRefPtr<CefListValue> MessageArguments) { FGuid ObjectKey; // Message arguments are Name, Value, bGlobal if (MessageArguments->GetSize() != 4 || MessageArguments->GetType(0) != VTYPE_STRING || MessageArguments->GetType(1) != VTYPE_STRING || MessageArguments->GetType(2) != VTYPE_STRING || MessageArguments->GetType(3) != VTYPE_LIST ) { // Wrong message argument types or count return false; } if (!FGuid::Parse(FString(MessageArguments->GetString(0).ToWString().c_str()), ObjectKey)) { // Invalid GUID return false; } // Get the promise callback and use that to report any results from executing this function. FGuid ResultCallbackId; if (!FGuid::Parse(FString(MessageArguments->GetString(2).ToWString().c_str()), ResultCallbackId)) { // Invalid GUID return false; } UObject* Object = GuidToPtr(ObjectKey); if (Object == nullptr) { // Unknown uobject id InvokeJSErrorResult(ResultCallbackId, TEXT("Unknown UObject ID")); return true; } FName MethodName = MessageArguments->GetString(1).ToWString().c_str(); UFunction* Function = Object->FindFunction(MethodName); if (!Function) { InvokeJSErrorResult(ResultCallbackId, TEXT("Unknown UObject Function")); return true; } // Coerce arguments to function arguments. uint16 ParamsSize = Function->ParmsSize; TArray<uint8> Params; UProperty* ReturnParam = nullptr; UProperty* PromiseParam = nullptr; // Convert cef argument list to a dictionary, so we can use FStructDeserializer to convert it for us if (ParamsSize > 0) { CefRefPtr<CefDictionaryValue> NamedArgs = CefDictionaryValue::Create(); int32 CurrentArg = 0; CefRefPtr<CefListValue> CefArgs = MessageArguments->GetList(3); for ( TFieldIterator<UProperty> It(Function); It; ++It ) { UProperty* Param = *It; if (Param->PropertyFlags & CPF_Parm) { if (Param->PropertyFlags & CPF_ReturnParm) { ReturnParam = Param; } else { UStructProperty *StructProperty = Cast<UStructProperty>(Param); if (StructProperty && StructProperty->Struct->IsChildOf(FWebJSResponse::StaticStruct())) { PromiseParam = Param; } else { CopyContainerValue(NamedArgs, CefArgs, CefString(*Param->GetName()), CurrentArg); CurrentArg++; } } } } // UFunction is a subclass of UStruct, so we can treat the arguments as a struct for deserialization Params.AddUninitialized(ParamsSize); Function->InitializeStruct(Params.GetData()); FWebJSStructDeserializerBackend Backend = FWebJSStructDeserializerBackend(SharedThis(this), NamedArgs); FStructDeserializer::Deserialize(Params.GetData(), *Function, Backend); } if (PromiseParam) { FWebJSResponse* PromisePtr = PromiseParam->ContainerPtrToValuePtr<FWebJSResponse>(Params.GetData()); if (PromisePtr) { *PromisePtr = FWebJSResponse(SharedThis(this), ResultCallbackId); } } Object->ProcessEvent(Function, Params.GetData()); CefRefPtr<CefListValue> Results = CefListValue::Create(); if ( ! PromiseParam ) // If PromiseParam is set, we assume that the UFunction will ensure it is called with the result { if ( ReturnParam ) { FStructSerializerPolicies ReturnPolicies; ReturnPolicies.PropertyFilter = [&](const UProperty* CandidateProperty, const UProperty* ParentProperty) { return ParentProperty != nullptr || CandidateProperty == ReturnParam; }; FWebJSStructSerializerBackend ReturnBackend(SharedThis(this)); FStructSerializer::Serialize(Params.GetData(), *Function, ReturnBackend, ReturnPolicies); CefRefPtr<CefDictionaryValue> ResultDict = ReturnBackend.GetResult(); // Extract the single return value from the serialized dictionary to an array CopyContainerValue(Results, ResultDict, 0, CefString(*ReturnParam->GetName())); } InvokeJSFunction(ResultCallbackId, Results, false); } return true; }