123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- // Modifications Copyright 2018-current Getnamo. All Rights Reserved
- // Copyright 2014 Vladimir Alyamkin. All Rights Reserved.
- #include "SIOJRequestJSON.h"
- #include "ISIOJson.h"
- #include "SIOJLibrary.h"
- #include "SIOJsonValue.h"
- #include "SIOJsonObject.h"
- template <class T> void FSIOJLatentAction<T>::Cancel()
- {
- UObject *Obj = Request.Get();
- if (Obj != nullptr)
- {
- ((USIOJRequestJSON*)Obj)->Cancel();
- }
- }
- USIOJRequestJSON::USIOJRequestJSON(const class FObjectInitializer& PCIP)
- : Super(PCIP),
- BinaryContentType(TEXT("application/octet-stream"))
- {
- RequestVerb = ESIORequestVerb::GET;
- RequestContentType = ESIORequestContentType::x_www_form_urlencoded_url;
- bShouldHaveBinaryResponse = false;
- OnProcessURLCompleteCallback = nullptr;
- ResetData();
- }
- USIOJRequestJSON* USIOJRequestJSON::ConstructRequest(UObject* WorldContextObject)
- {
- return NewObject<USIOJRequestJSON>();
- }
- USIOJRequestJSON* USIOJRequestJSON::ConstructRequestExt(
- UObject* WorldContextObject,
- ESIORequestVerb Verb,
- ESIORequestContentType ContentType)
- {
- USIOJRequestJSON* Request = ConstructRequest(WorldContextObject);
- Request->SetVerb(Verb);
- Request->SetContentType(ContentType);
- return Request;
- }
- void USIOJRequestJSON::SetVerb(ESIORequestVerb Verb)
- {
- RequestVerb = Verb;
- }
- void USIOJRequestJSON::SetCustomVerb(FString Verb)
- {
- CustomVerb = Verb;
- }
- void USIOJRequestJSON::SetContentType(ESIORequestContentType ContentType)
- {
- RequestContentType = ContentType;
- }
- void USIOJRequestJSON::SetBinaryContentType(const FString &ContentType)
- {
- BinaryContentType = ContentType;
- }
- void USIOJRequestJSON::SetBinaryRequestContent(const TArray<uint8> &Bytes)
- {
- RequestBytes = Bytes;
- }
- void USIOJRequestJSON::SetHeader(const FString& HeaderName, const FString& HeaderValue)
- {
- RequestHeaders.Add(HeaderName, HeaderValue);
- }
- //////////////////////////////////////////////////////////////////////////
- // Destruction and reset
- void USIOJRequestJSON::ResetData()
- {
- ResetRequestData();
- ResetResponseData();
- }
- void USIOJRequestJSON::ResetRequestData()
- {
- if (RequestJsonObj != nullptr)
- {
- RequestJsonObj->Reset();
- }
- else
- {
- RequestJsonObj = NewObject<USIOJsonObject>();
- }
- HttpRequest = FHttpModule::Get().CreateRequest();
- }
- void USIOJRequestJSON::ResetResponseData()
- {
- if (ResponseJsonObj != nullptr)
- {
- ResponseJsonObj->Reset();
- }
- else
- {
- ResponseJsonObj = NewObject<USIOJsonObject>();
- }
- ResponseHeaders.Empty();
- ResponseCode = -1;
- bIsValidJsonResponse = false;
- }
- void USIOJRequestJSON::Cancel()
- {
- ContinueAction = nullptr;
- ResetResponseData();
- }
- //////////////////////////////////////////////////////////////////////////
- // JSON data accessors
- USIOJsonObject* USIOJRequestJSON::GetRequestObject()
- {
- return RequestJsonObj;
- }
- void USIOJRequestJSON::SetRequestObject(USIOJsonObject* JsonObject)
- {
- RequestJsonObj = JsonObject;
- }
- USIOJsonObject* USIOJRequestJSON::GetResponseObject()
- {
- return ResponseJsonObj;
- }
- void USIOJRequestJSON::SetResponseObject(USIOJsonObject* JsonObject)
- {
- ResponseJsonObj = JsonObject;
- }
- ///////////////////////////////////////////////////////////////////////////
- // Response data access
- FString USIOJRequestJSON::GetURL()
- {
- return HttpRequest->GetURL();
- }
- ESIORequestStatus USIOJRequestJSON::GetStatus()
- {
- return ESIORequestStatus((uint8)HttpRequest->GetStatus());
- }
- int32 USIOJRequestJSON::GetResponseCode()
- {
- return ResponseCode;
- }
- FString USIOJRequestJSON::GetResponseHeader(const FString HeaderName)
- {
- FString Result;
- FString* Header = ResponseHeaders.Find(HeaderName);
- if (Header != nullptr)
- {
- Result = *Header;
- }
- return Result;
- }
- TArray<FString> USIOJRequestJSON::GetAllResponseHeaders()
- {
- TArray<FString> Result;
- for (TMap<FString, FString>::TConstIterator It(ResponseHeaders); It; ++It)
- {
- Result.Add(It.Key() + TEXT(": ") + It.Value());
- }
- return Result;
- }
- //////////////////////////////////////////////////////////////////////////
- // URL processing
- void USIOJRequestJSON::ProcessURL(const FString& Url)
- {
- HttpRequest->SetURL(Url);
- ProcessRequest();
- }
- void USIOJRequestJSON::ApplyURL(const FString& Url, USIOJsonObject *&Result, UObject* WorldContextObject, FLatentActionInfo LatentInfo)
- {
- HttpRequest->SetURL(Url);
- // Prepare latent action
- if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
- {
- FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
- FSIOJLatentAction<USIOJsonObject*> *Kont = LatentActionManager.FindExistingAction<FSIOJLatentAction<USIOJsonObject*>>(LatentInfo.CallbackTarget, LatentInfo.UUID);
- if (Kont != nullptr)
- {
- Kont->Cancel();
- LatentActionManager.RemoveActionsForObject(LatentInfo.CallbackTarget);
- }
- LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, ContinueAction = new FSIOJLatentAction<USIOJsonObject*>(this, Result, LatentInfo));
- }
- ProcessRequest();
- }
- void USIOJRequestJSON::ProcessRequest()
- {
- // Set verb
- switch (RequestVerb)
- {
- case ESIORequestVerb::GET:
- HttpRequest->SetVerb(TEXT("GET"));
- break;
- case ESIORequestVerb::POST:
- HttpRequest->SetVerb(TEXT("POST"));
- break;
- case ESIORequestVerb::PUT:
- HttpRequest->SetVerb(TEXT("PUT"));
- break;
-
- case ESIORequestVerb::DEL:
- HttpRequest->SetVerb(TEXT("DELETE"));
- break;
- case ESIORequestVerb::CUSTOM:
- HttpRequest->SetVerb(CustomVerb);
- break;
- default:
- break;
- }
- // Set content-type
- switch (RequestContentType)
- {
- case ESIORequestContentType::x_www_form_urlencoded_url:
- {
- HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/x-www-form-urlencoded"));
- FString UrlParams = "";
- uint16 ParamIdx = 0;
- // Loop through all the values and prepare additional url part
- for (auto RequestIt = RequestJsonObj->GetRootObject()->Values.CreateIterator(); RequestIt; ++RequestIt)
- {
- FString Key = RequestIt.Key();
- FString Value = RequestIt.Value().Get()->AsString();
- if (!Key.IsEmpty() && !Value.IsEmpty())
- {
- UrlParams += ParamIdx == 0 ? "?" : "&";
- UrlParams += USIOJLibrary::PercentEncode(Key) + "=" + USIOJLibrary::PercentEncode(Value);
- }
- ParamIdx++;
- }
- // Apply params
- HttpRequest->SetURL(HttpRequest->GetURL() + UrlParams);
- UE_LOG(LogSIOJ, Log, TEXT("Request (urlencoded): %s %s %s"), *HttpRequest->GetVerb(), *HttpRequest->GetURL(), *UrlParams);
- break;
- }
- case ESIORequestContentType::x_www_form_urlencoded_body:
- {
- HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/x-www-form-urlencoded"));
- FString UrlParams = "";
- uint16 ParamIdx = 0;
- // Loop through all the values and prepare additional url part
- for (auto RequestIt = RequestJsonObj->GetRootObject()->Values.CreateIterator(); RequestIt; ++RequestIt)
- {
- FString Key = RequestIt.Key();
- FString Value = RequestIt.Value().Get()->AsString();
- if (!Key.IsEmpty() && !Value.IsEmpty())
- {
- UrlParams += ParamIdx == 0 ? "" : "&";
- UrlParams += USIOJLibrary::PercentEncode(Key) + "=" + USIOJLibrary::PercentEncode(Value);
- }
- ParamIdx++;
- }
- // Apply params
- HttpRequest->SetContentAsString(UrlParams);
- UE_LOG(LogSIOJ, Log, TEXT("Request (url body): %s %s %s"), *HttpRequest->GetVerb(), *HttpRequest->GetURL(), *UrlParams);
- break;
- }
- case ESIORequestContentType::binary:
- {
- HttpRequest->SetHeader(TEXT("Content-Type"), BinaryContentType);
- HttpRequest->SetContent(RequestBytes);
- UE_LOG(LogSIOJ, Log, TEXT("Request (binary): %s %s"), *HttpRequest->GetVerb(), *HttpRequest->GetURL());
- break;
- }
- case ESIORequestContentType::json:
- {
- HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json"));
- // Serialize data to json string
- FString OutputString;
- TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&OutputString);
- FJsonSerializer::Serialize(RequestJsonObj->GetRootObject().ToSharedRef(), Writer);
- // Set Json content
- HttpRequest->SetContentAsString(OutputString);
- UE_LOG(LogSIOJ, Log, TEXT("Request (json): %s %s %s"), *HttpRequest->GetVerb(), *HttpRequest->GetURL(), *OutputString);
- break;
- }
- default:
- break;
- }
- // Apply additional headers
- for (TMap<FString, FString>::TConstIterator It(RequestHeaders); It; ++It)
- {
- HttpRequest->SetHeader(It.Key(), It.Value());
- }
-
- // Bind event
- if (bShouldHaveBinaryResponse)
- {
- HttpRequest->OnProcessRequestComplete().BindUObject(this, &USIOJRequestJSON::OnProcessRequestCompleteBinaryResult);
- }
- else
- {
- HttpRequest->OnProcessRequestComplete().BindUObject(this, &USIOJRequestJSON::OnProcessRequestComplete);
- }
- // Execute the request
- HttpRequest->ProcessRequest();
- }
- //////////////////////////////////////////////////////////////////////////
- // Request callbacks
- void USIOJRequestJSON::OnProcessRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
- {
- // Be sure that we have no data from previous response
- ResetResponseData();
- // Check we have a response and save response code as int32
- if(Response.IsValid())
- {
- ResponseCode = Response->GetResponseCode();
- }
- // Check we have result to process futher
- if (!bWasSuccessful || !Response.IsValid())
- {
- UE_LOG(LogSIOJ, Error, TEXT("Request failed (%d): %s"), ResponseCode, *Request->GetURL());
- // Broadcast the result event
- OnRequestFail.Broadcast(this);
- OnStaticRequestFail.Broadcast(this);
- return;
- }
- // Save response data as a string
- ResponseContent = Response->GetContentAsString();
- // Log response state
- UE_LOG(LogSIOJ, Log, TEXT("Response (%d): %s"), ResponseCode, *ResponseContent);
- // Process response headers
- TArray<FString> Headers = Response->GetAllHeaders();
- for (FString Header : Headers)
- {
- FString Key;
- FString Value;
- if (Header.Split(TEXT(": "), &Key, &Value))
- {
- ResponseHeaders.Add(Key, Value);
- }
- }
- // Try to deserialize data to JSON
- TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(ResponseContent);
- FJsonSerializer::Deserialize(JsonReader, ResponseJsonObj->GetRootObject());
- // Decide whether the request was successful
- bIsValidJsonResponse = bWasSuccessful && ResponseJsonObj->GetRootObject().IsValid();
- // Log errors
- if (!bIsValidJsonResponse)
- {
- if (!ResponseJsonObj->GetRootObject().IsValid())
- {
- // As we assume it's recommended way to use current class, but not the only one,
- // it will be the warning instead of error
- UE_LOG(LogSIOJ, Warning, TEXT("JSON could not be decoded!"));
- }
- }
- // Broadcast the result event
- OnRequestComplete.Broadcast(this);
- OnStaticRequestComplete.Broadcast(this);
- // Finish the latent action
- if (ContinueAction)
- {
- FSIOJLatentAction<USIOJsonObject*> *K = ContinueAction;
- ContinueAction = nullptr;
- K->Call(ResponseJsonObj);
- }
- }
- void USIOJRequestJSON::OnProcessRequestCompleteBinaryResult(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
- {
- // Be sure that we have no data from previous response
- ResetResponseData();
- // Check we have a response and save response code as int32
- if (Response.IsValid())
- {
- ResponseCode = Response->GetResponseCode();
- }
- // Check we have result to process futher
- if (!bWasSuccessful || !Response.IsValid())
- {
- UE_LOG(LogSIOJ, Error, TEXT("Request failed (%d): %s"), ResponseCode, *Request->GetURL());
- // Broadcast the result event
- OnRequestFail.Broadcast(this);
- OnStaticRequestFail.Broadcast(this);
- return;
- }
- ResultBinaryData = Response->GetContent();
- // Broadcast the result event
- OnRequestComplete.Broadcast(this);
- OnStaticRequestComplete.Broadcast(this);
- if (OnProcessURLCompleteCallback)
- {
- OnProcessURLCompleteCallback(ResultBinaryData);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- // Tags
- void USIOJRequestJSON::AddTag(FName Tag)
- {
- if (Tag != NAME_None)
- {
- Tags.AddUnique(Tag);
- }
- }
- int32 USIOJRequestJSON::RemoveTag(FName Tag)
- {
- return Tags.Remove(Tag);
- }
- bool USIOJRequestJSON::HasTag(FName Tag) const
- {
- return (Tag != NAME_None) && Tags.Contains(Tag);
- }
|