October3d55/M/HTTPWebCommunication/Source/WebCommunication/Private/WebCommunicationRequestComp...

1174 lines
42 KiB
C++

// Copyright 2017-2020 David Romanski(Socke). All Rights Reserved.
#include "WebCommunicationRequestCompleteObject.h"
UWebCommunicationRequestCompleteObject::UWebCommunicationRequestCompleteObject(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {
}
UWebCommunicationRequestCompleteObject::~UWebCommunicationRequestCompleteObject() {
}
void UWebCommunicationRequestCompleteObject::BeginDestroy(){
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: BeginDestroy "));
if (thread != nullptr) {
thread->Stop();
delete thread;
thread = nullptr;
}
Super::BeginDestroy();
}
void UWebCommunicationRequestCompleteObject::initWebCom(){
this->AddToRoot();
thread = new FWebcomThread(this);
}
void UWebCommunicationRequestCompleteObject::requestComplete(FHttpRequestPtr request, FHttpResponsePtr response, bool bWasSuccessful) {
FWebcomTheadJob* job = new FWebcomTheadJob();
job->request = request;
job->response = response;
job->bWasSuccessful = bWasSuccessful;
job->type = 0;
thread->addJob(job);
}
void UWebCommunicationRequestCompleteObject::requestCompleteInternal(FHttpRequestPtr Request, FHttpResponsePtr response, bool bWasSuccessful){
if (webCommunicationBPLibrary == nullptr) {
UE_LOG(LogTemp, Error, TEXT("UWebCommunicationBPLibrary: Missing Object instance (12)."));
return;
}
if ((httpRequest.requestType == EHTTPWebComRequestType::PUT_STREAM_MP || httpRequest.requestType == EHTTPWebComRequestType::PUT_STREAM_COPY)
&& !httpRequest.filePath.IsEmpty() && httpRequest.originalFileSize > 0) {
webCommunicationBPLibrary->addRequestToTruncateThread(httpRequest);
}
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: RequestID %s"), *requestID);
UWebCommunicationBPLibrary* webcom = webCommunicationBPLibrary;
FString requestIDP = requestID;
if (webcom->removeHeaders) {
webcom->additionalHeader.Empty();
}
UAsyncNodeWebCom* asyncNodeHttpRequest = webcom->getUAsyncNodeHttpRequest(requestID);
EMultiStepType multistepGlobal = multiStepDownloadType;
FString downloadIDGlobal = downloadID;
if (!bWasSuccessful || !response.IsValid()) {
//UE_LOG(LogTemp, Display, TEXT("Request unsuccessful, check the url. %i"),response->GetResponseCode());
TArray<FString> dataArray;
TArray<uint8> byteArray;
FString dataString = "No Response";
int32 statusCode = 500;
if (response.IsValid()) {
dataString = response->GetContentAsString();
dataString.ParseIntoArray(dataArray, TEXT("\r\n"), true);
statusCode = response->GetResponseCode();
}
else {
dataArray.Add(dataString);
}
//switch to gamethread
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest, webcom, dataString, dataArray, statusCode, byteArray, downloadIDGlobal, requestIDP, multistepGlobal]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
if (multistepGlobal == EMultiStepType::GOOGLE_INFO) {
UAsyncNodeHttpGoogleFileInfoRequest* asyncNodeGoogleInfoRequest = dynamic_cast<UAsyncNodeHttpGoogleFileInfoRequest*>(asyncNodeHttpRequest);
if (asyncNodeGoogleInfoRequest) {
asyncNodeGoogleInfoRequest->httpRequestCompleteGoogleFileInfo("", 0, statusCode, downloadIDGlobal, requestIDP);
}
}
else {
UAsyncNodeHttpDownloadUpload* asyncNodeDownloadUpload = dynamic_cast<UAsyncNodeHttpDownloadUpload*>(asyncNodeHttpRequest);
if (asyncNodeDownloadUpload) {
asyncNodeDownloadUpload->httpRequestDownloadUploadComplete(dataString,dataArray,TArray<FString>(), statusCode, requestIDP);
}
else {
asyncNodeHttpRequest->httpRequestComplete(dataString,dataArray, TArray<FString>(), statusCode, byteArray, requestIDP);
}
}
}
else {
if (multistepGlobal == EMultiStepType::GOOGLE_INFO) {
webcom->onhttpRequestCompleteGoogleInfoDelegate.Broadcast("", 0, statusCode, downloadIDGlobal, requestIDP);
}
else {
webcom->onhttpRequestCompleteDelegate.Broadcast(dataString, dataArray, TArray<FString>(), statusCode, byteArray, requestIDP);
}
}
});
//write download to file
if (fileCancelResumeDownloadDir.IsEmpty() == false && downloadDataCopy.Num() > 0) {
FArchive* writer = IFileManager::Get().CreateFileWriter(*fileCancelResumeDownloadDir, EFileWrite::FILEWRITE_Append);
if (writer) {
writer->Seek(writer->TotalSize());
writer->Serialize(downloadDataCopy.GetData(), downloadDataCopy.Num());
downloadDataCopy.Empty();
writer->Close();
}
}
return;
}
TArray<uint8> byteArray = response->GetContent();
FString dataString = response->GetContentAsString();
TArray<FString> dataArray;
dataString.ParseIntoArray(dataArray, TEXT("\r\n"), true);
if (multiStepDownloadType == EMultiStepType::GOOGLE_INFO) {
//UE_LOG(LogTemp, Warning, TEXT("UWebCommunicationBPLibrary: %s"),*dataString);
//read fileinfos from google drive html/javascript view page
FString left;
FString right;
dataString.Split("itemJson:", &left, &right);
TArray<FString> lines;
int32 lineCount = right.ParseIntoArray(lines, TEXT(","), true);
if (lineCount > 27) {
FString fileName = lines[1];
fileName = fileName.Replace(TEXT("\""), TEXT(""));
FString fileSizeString = lines[27];
fileSizeString = fileSizeString.Replace(TEXT("\""), TEXT(""));
fileSizeString = fileSizeString.Replace(TEXT("]"), TEXT(""));
int64 fileSize = FCString::Atoi64(*fileSizeString);
int32 statusCode = response->GetResponseCode();
/*UE_LOG(LogTemp, Warning, TEXT("FileName: %s"),*fileName);
UE_LOG(LogTemp, Warning, TEXT("FileSize: %i"),fileSize);*/
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest,webcom, fileName, fileSize,statusCode, downloadIDGlobal, requestIDP, multistepGlobal]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
UAsyncNodeHttpGoogleFileInfoRequest* asyncNodeGoogleInfoRequest = dynamic_cast<UAsyncNodeHttpGoogleFileInfoRequest*>(asyncNodeHttpRequest);
if (asyncNodeGoogleInfoRequest) {
asyncNodeGoogleInfoRequest->httpRequestCompleteGoogleFileInfo(fileName, fileSize, statusCode, downloadIDGlobal, requestIDP);
}
}
else {
webcom->onhttpRequestCompleteGoogleInfoDelegate.Broadcast(fileName, fileSize, statusCode, downloadIDGlobal, requestIDP);
}
});
return;
}
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest, webcom, downloadIDGlobal, requestIDP, multistepGlobal]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
UAsyncNodeHttpGoogleFileInfoRequest* asyncNodeGoogleInfoRequest = dynamic_cast<UAsyncNodeHttpGoogleFileInfoRequest*>(asyncNodeHttpRequest);
if (asyncNodeGoogleInfoRequest) {
asyncNodeGoogleInfoRequest->httpRequestCompleteGoogleFileInfo("", 0, 452, downloadIDGlobal, requestIDP);
}
}
else {
webcom->onhttpRequestCompleteGoogleInfoDelegate.Broadcast("", 0, 452, downloadIDGlobal, requestIDP);
}
});
return;
}
//if its a resume download and the existing file is => then the file on server then empty data
if (fileCancelResumeDownloadDir.IsEmpty() == false) {
//Content-Range: bytes 0-0/104857600
FString responseSize = response->GetHeader("Content-Range");
if (responseSize.IsEmpty()) {
responseSize = response->GetHeader("content-range");
}
else {
if (responseSize.IsEmpty()) {
responseSize = response->GetHeader("Content-range");
}
else {
if (responseSize.IsEmpty()) {
responseSize = response->GetHeader("content-Range");
}
}
}
if (responseSize.IsEmpty() == false) {
FString left;
FString right;
responseSize.Split("/", &left, &right);
responseSize = right;
int32 fullSize = FCString::Atoi(*responseSize);
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary filesize: %i"), FPlatformFileManager::Get().GetPlatformFile().FileSize(*fileCancelResumeDownloadDir));
if (FPlatformFileManager::Get().GetPlatformFile().FileSize(*fileCancelResumeDownloadDir) >= fullSize) {
byteArray.Empty();
dataArray.Empty();
}
}
if (byteArray.Num() > 0) {
FArchive* writer = IFileManager::Get().CreateFileWriter(*fileCancelResumeDownloadDir, EFileWrite::FILEWRITE_Append);
if (writer) {
writer->Seek(writer->TotalSize());
writer->Serialize(byteArray.GetData(), byteArray.Num());
writer->Close();
}
delete writer;
byteArray.Empty();
}
}
int32 statusCode = response->GetResponseCode();
TArray<FString> headerData = response->GetAllHeaders();
//switch to gamethread
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest,webcom, dataString, dataArray, headerData, statusCode, byteArray, requestIDP]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
UAsyncNodeHttpDownloadUpload* asyncNodeDownloadUpload = dynamic_cast<UAsyncNodeHttpDownloadUpload*>(asyncNodeHttpRequest);
if (asyncNodeDownloadUpload) {
asyncNodeDownloadUpload->httpRequestDownloadUploadComplete(dataString, dataArray, headerData, statusCode, requestIDP);
}
else {
asyncNodeHttpRequest->httpRequestComplete(dataString, dataArray, headerData, statusCode, byteArray, requestIDP);
}
}
else {
webcom->onhttpRequestCompleteDelegate.Broadcast(dataString, dataArray, headerData, statusCode, byteArray, requestIDP);
}
});
byteArray.Empty();
}
void UWebCommunicationRequestCompleteObject::requestCompleteLowRam(FHttpRequestPtr request, FHttpResponsePtr response, bool bWasSuccessful) {
FWebcomTheadJob* job = new FWebcomTheadJob();
job->request = request;
job->response = response;
job->bWasSuccessful = bWasSuccessful;
job->type = 1;
thread->addJob(job);
}
void UWebCommunicationRequestCompleteObject::requestCompleteLowRamInternal(FHttpRequestPtr request, FHttpResponsePtr response, bool bWasSuccessful){
if (webCommunicationBPLibrary == nullptr) {
UE_LOG(LogTemp, Error, TEXT("UWebCommunicationBPLibrary: Missing Object instance (12)."));
return;
}
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: RequestID %s"), *requestID);
UWebCommunicationBPLibrary* webcom = webCommunicationBPLibrary;
FString requestIDP = requestID;
if (webcom->removeHeaders) {
webcom->additionalHeader.Empty();
}
UAsyncNodeWebCom* asyncNodeHttpRequest = webcom->getUAsyncNodeHttpRequest(requestID);
if (!bWasSuccessful || !response.IsValid()) {
//UE_LOG(LogTemp, Display, TEXT("Request unsuccessful, check the url"));
TArray<FString> dataArray;
TArray<uint8> byteArray;
FString dataString = "No Response";
int32 statusCode = 500;
if (response.IsValid()) {
dataString = response->GetContentAsString();
dataString.ParseIntoArray(dataArray, TEXT("\r\n"), true);
statusCode = response->GetResponseCode();
}
else {
dataArray.Add(dataString);
}
//switch to gamethread
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest, webcom, dataString, dataArray, statusCode, byteArray, requestIDP]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
UAsyncNodeHttpDownloadUpload* asyncNodeDownloadUpload = dynamic_cast<UAsyncNodeHttpDownloadUpload*>(asyncNodeHttpRequest);
if (asyncNodeDownloadUpload) {
asyncNodeDownloadUpload->httpRequestDownloadUploadComplete(dataString, dataArray, TArray<FString>(), statusCode, requestIDP);
}
else {
asyncNodeHttpRequest->httpRequestComplete(dataString, dataArray, TArray<FString>(), statusCode, byteArray, requestIDP);
}
}
else {
webcom->onhttpRequestCompleteDelegate.Broadcast(dataString, dataArray, TArray<FString>(), statusCode, byteArray, requestIDP);
}
});
return;
}
//Content-Range: bytes 0-0/104857600
FString responseSize = response->GetHeader("Content-Range");
if (responseSize.IsEmpty()) {
responseSize = response->GetHeader("content-range");
}
else {
if (responseSize.IsEmpty()) {
responseSize = response->GetHeader("Content-range");
}
else {
if (responseSize.IsEmpty()) {
responseSize = response->GetHeader("content-Range");
}
}
}
TArray<uint8> byteArray;
TArray<FString> dataArray;
TArray<FString> headerData = response->GetAllHeaders();
int32 statusCode = response->GetResponseCode();
if (responseSize.IsEmpty()) {
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest,webcom, dataArray, headerData, statusCode, byteArray, requestIDP]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
UAsyncNodeHttpDownloadUpload* asyncNodeDownloadUpload = dynamic_cast<UAsyncNodeHttpDownloadUpload*>(asyncNodeHttpRequest);
if (asyncNodeDownloadUpload) {
asyncNodeDownloadUpload->httpRequestDownloadUploadComplete("", dataArray,headerData, statusCode, requestIDP);
}
else {
asyncNodeHttpRequest->httpRequestComplete("", dataArray, headerData, statusCode, byteArray, requestIDP);
}
}
else {
webcom->onhttpRequestCompleteDelegate.Broadcast("", dataArray, headerData, statusCode, byteArray, requestIDP);
}
});
UE_LOG(LogTemp, Error, TEXT("File Download: Server does not suport download range or wrong url. Cancel Download"));
return;
}
FString left;
FString right;
responseSize.Split("/", &left, &right);
responseSize = right;
int64 fullSize = FCString::Atoi64(*responseSize);
if (responseSize.IsEmpty() || fullSize < 1 || fileCancelResumeDownloadBytePartSize < 1) {
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest, webcom, dataArray, headerData, statusCode, byteArray, requestIDP]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
UAsyncNodeHttpDownloadUpload* asyncNodeDownloadUpload = dynamic_cast<UAsyncNodeHttpDownloadUpload*>(asyncNodeHttpRequest);
if (asyncNodeDownloadUpload) {
asyncNodeDownloadUpload->httpRequestDownloadUploadComplete("", dataArray,headerData, statusCode, requestIDP);
}
else {
asyncNodeHttpRequest->httpRequestComplete("", dataArray, headerData, statusCode, byteArray, requestIDP);
}
}
else {
webcom->onhttpRequestCompleteDelegate.Broadcast("", dataArray, headerData, statusCode, byteArray, requestIDP);
}
});
UE_LOG(LogTemp, Error, TEXT("File Download: Server does not suport download range or wrong url. Cancel Download"));
return;
}
if (FPlatformFileManager::Get().GetPlatformFile().FileSize(*fileCancelResumeDownloadDir) >= fullSize) {
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest, webcom, dataArray, headerData, statusCode, byteArray, requestIDP]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
UAsyncNodeHttpDownloadUpload* asyncNodeDownloadUpload = dynamic_cast<UAsyncNodeHttpDownloadUpload*>(asyncNodeHttpRequest);
if (asyncNodeDownloadUpload) {
asyncNodeDownloadUpload->httpRequestDownloadUploadComplete("", dataArray, headerData, statusCode, requestIDP);
}
else {
asyncNodeHttpRequest->httpRequestComplete("", dataArray, headerData, statusCode, byteArray, requestIDP);
}
}
else {
webcom->onhttpRequestCompleteDelegate.Broadcast("", dataArray, headerData, statusCode, byteArray, requestIDP);
}
});
UE_LOG(LogTemp, Error, TEXT("File Download: File size equal to or larger than on the server. Cancel Download"));
return;
}
if (fileCancelResumeDownloadByteFullSize == 0) {
if (fileCancelResumeDownloadBytePartSize > fullSize)
fullSize = fileCancelResumeDownloadBytePartSize;
TArray<struct FhttpRequest> httpRequestsBack;
FString requestIDBack;
TArray<struct FhttpRequest> otherHttpRequests;
webcom->CreateHttpRequestGETLowRamDownload(httpRequestsBack, requestIDBack, otherHttpRequests, request->GetURL(), httpRequest.header, EHTTPWebComFileDownloadResumeType::E_RESUME, EHTTPWebComFileUpload::E_ad, fileCancelResumeDownloadDir, (fileCancelResumeDownloadBytePartSize), requestID);
if (httpRequestsBack.Num() > 0) {
FhttpRequest createdRequest = httpRequestsBack.Last();
createdRequest.request->setFileCancelResumeDownloadByteFullSize(fullSize);
webcom->executeHttpRequests(httpRequestsBack, webcom);
}
else {
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest, webcom, dataArray, headerData, statusCode, byteArray, requestIDP]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
UAsyncNodeHttpDownloadUpload* asyncNodeDownloadUpload = dynamic_cast<UAsyncNodeHttpDownloadUpload*>(asyncNodeHttpRequest);
if (asyncNodeDownloadUpload) {
asyncNodeDownloadUpload->httpRequestDownloadUploadComplete("", dataArray, headerData, statusCode, requestIDP);
}
else {
asyncNodeHttpRequest->httpRequestComplete("", dataArray, headerData, statusCode, byteArray, requestIDP);
}
}
else {
webcom->onhttpRequestCompleteDelegate.Broadcast("", dataArray, headerData, statusCode, byteArray, requestIDP);
}
});
UE_LOG(LogTemp, Error, TEXT("Something's went wrong. download is aborted "));
}
return;
}
FArchive* writer = IFileManager::Get().CreateFileWriter(*fileCancelResumeDownloadDir, EFileWrite::FILEWRITE_Append);
if (!writer) {
UE_LOG(LogTemp, Error, TEXT("File Download: Can't write into %s "), *fileCancelResumeDownloadDir);
}
else {
if (response.IsValid()) {
TArray<uint8> data = response->GetContent();
bool finish = false;
if ((writer->TotalSize() + data.Num()) >= fullSize)
finish = true;
writer->Seek(writer->TotalSize());
writer->Serialize(data.GetData(), data.Num());
if (!finish) {
TArray<struct FhttpRequest> httpRequestsBack;
FString requestIDBack;
TArray<struct FhttpRequest> otherHttpRequests;
/*if ((writer->TotalSize() + fileCancelResumeDownloadBytePartSize) > fileCancelResumeDownloadByteFullSize) {
fileCancelResumeDownloadBytePartSize = fileCancelResumeDownloadByteFullSize - writer->TotalSize();
}*/
webcom->CreateHttpRequestGETLowRamDownload(httpRequestsBack, requestIDBack, otherHttpRequests, request->GetURL(), httpRequest.header, EHTTPWebComFileDownloadResumeType::E_RESUME, EHTTPWebComFileUpload::E_ad, fileCancelResumeDownloadDir, (fileCancelResumeDownloadBytePartSize), requestID);
if (httpRequestsBack.Num() > 0) {
FhttpRequest createdRequest = httpRequestsBack.Last();
//httpRequestsBack.RemoveAt(httpRequestsBack.Num()-1);
createdRequest.request->setFileCancelResumeDownloadByteFullSize(fileCancelResumeDownloadByteFullSize);
createdRequest.request->setFileCancelResumeDownloadByteStart(fileCancelResumeDownloadByteStart + data.Num());
//httpRequestsBack.Add(createdRequest);
webcom->executeHttpRequests(httpRequestsBack, webcom);
}
else {
UE_LOG(LogTemp, Error, TEXT("Something's went wrong. download is aborted "));
}
}
else {
//switch to gamethread
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest,webcom, dataArray, headerData, statusCode, byteArray, requestIDP]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
UAsyncNodeHttpDownloadUpload* asyncNodeDownloadUpload = dynamic_cast<UAsyncNodeHttpDownloadUpload*>(asyncNodeHttpRequest);
if (asyncNodeDownloadUpload) {
asyncNodeDownloadUpload->httpRequestDownloadUploadComplete("", dataArray, headerData, statusCode, requestIDP);
}
else {
asyncNodeHttpRequest->httpRequestComplete("", dataArray, headerData, statusCode, byteArray, requestIDP);
}
}
else {
webcom->onhttpRequestCompleteDelegate.Broadcast("", dataArray, headerData, statusCode, byteArray, requestIDP);
}
});
}
//UE_LOG(LogTemp, Display, TEXT("Cancel1: %i | %i"), fileCancelResumeDownloadByteStart+data.Num(), writer->TotalSize());
data.Empty();
}
/* else {
UE_LOG(LogTemp, Display, TEXT("Cancel3: Request successful"));
}*/
writer->Close();
return;
}
}
#if ENGINE_MAJOR_VERSION >= 5 & ENGINE_MINOR_VERSION >= 4
void UWebCommunicationRequestCompleteObject::requestProgressUpload(FHttpRequestPtr request, uint64 bytesSent, uint64 bytesReceived) {
#else
void UWebCommunicationRequestCompleteObject::requestProgressUpload(FHttpRequestPtr request, int32 bytesSent, int32 bytesReceived) {
#endif
FWebcomTheadJob* job = new FWebcomTheadJob();
job->request = request;
job->bytesSent = bytesSent;
job->bytesReceived = bytesReceived;
job->type = 3;
thread->addJob(job);
}
void UWebCommunicationRequestCompleteObject::requestProgressUploadInternal(FHttpRequestPtr request, uint64 bytesSent, uint64 bytesReceived){
if (webCommunicationBPLibrary == nullptr) {
UE_LOG(LogTemp, Error, TEXT("UWebCommunicationBPLibrary: Missing Object instance (53)."));
return;
}
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: RequestID %s"), *requestID);
UWebCommunicationBPLibrary* webcom = webCommunicationBPLibrary;
FString requestIDP = requestID;
if (request.IsValid()) {
if (webCommunicationBPLibrary->toCancelRequests.Find(requestID) != nullptr) {
AsyncTask(ENamedThreads::GameThread, [request]() {
request->CancelRequest();
});
webCommunicationBPLibrary->toCancelRequests.Remove(requestID);
UE_LOG(LogTemp, Warning, TEXT("Request has been canceled. %s"),*requestID);
return;
}
float size = (float)request->GetContentLength();
if (size <= 0)
size = 1;
float percentUpload = ((float)bytesSent / size) * 100;
float percentDownload = 0;
AsyncTask(ENamedThreads::GameThread, [webcom,size, bytesSent, percentUpload, bytesReceived, percentDownload, requestIDP]() {
webcom->onhttpFileUploadDelegate.Broadcast(size, bytesSent, percentUpload, requestIDP);
});
//UE_LOG(LogTemp, Display, TEXT("size:%f | bytesSent:%i | percentUpload:%f | bytesReceived:%i | percentDownload:%f"), size, bytesSent, percentUpload, bytesReceived, percentDownload);
}
}
#if ENGINE_MAJOR_VERSION >= 5 & ENGINE_MINOR_VERSION >= 4
void UWebCommunicationRequestCompleteObject::requestProgressDownload(FHttpRequestPtr request, uint64 bytesSent, uint64 bytesReceived) {
#else
void UWebCommunicationRequestCompleteObject::requestProgressDownload(FHttpRequestPtr request, int32 bytesSent, int32 bytesReceived) {
#endif
FWebcomTheadJob* job = new FWebcomTheadJob();
job->request = request;
job->bytesSent = bytesSent;
job->bytesReceived = bytesReceived;
job->type = 4;
thread->addJob(job);
}
void UWebCommunicationRequestCompleteObject::requestProgressDownloadInternal(FHttpRequestPtr request, uint64 bytesSent, uint64 bytesReceived){
if (webCommunicationBPLibrary == nullptr) {
UE_LOG(LogTemp, Error, TEXT("UWebCommunicationBPLibrary: Missing Object instance (83)."));
return;
}
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: Response %s"), *res);
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: RequestID %s"), *requestID);
UWebCommunicationBPLibrary* webcom = webCommunicationBPLibrary;
FString requestIDP = requestID;
if (request.IsValid()) {
if (webCommunicationBPLibrary->toCancelRequests.Find(requestID) != nullptr) {
AsyncTask(ENamedThreads::GameThread, [request]() {
request->CancelRequest();
});
webCommunicationBPLibrary->toCancelRequests.Remove(requestID);
UE_LOG(LogTemp, Warning, TEXT("Request has been canceled. %s"), *requestID);
downloadDataCopy.Append(request->GetResponse()->GetContent());
return;
}
FHttpResponsePtr response = request->GetResponse();
if (response.IsValid()) {
bytesReceived = bytesReceived + fileCancelResumeDownloadByteStart;
float size = (float)(response->GetContentLength() + fileCancelResumeDownloadByteStart);
if (size <= 0)
size = 1;
float percentUpload = 0;
float percentDownload = ((float)bytesReceived / size) * 100;
//downloadspeed
if (lastTimeTicks == 0) {
lastTimeTicks = FDateTime::Now().GetTicks();
bytesCurrent = bytesReceived;
}
else {
//one second = 10000000 ticks
if (((FDateTime::Now().GetTicks()) - lastTimeTicks) >= 10000000) {
mbit = ((float)bytesReceived - (float)bytesCurrent) / 1024 / 1024 * 8;
lastTimeTicks = FDateTime::Now().GetTicks();
bytesCurrent = bytesReceived;
}
}
float mbitGlobal = mbit;
float sizeMB = size / 1024 / 1024;
float bytesReceivedMB = (float)bytesReceived / 1024 / 1024;
AsyncTask(ENamedThreads::GameThread, [webcom, size, bytesSent, percentUpload, bytesReceived, percentDownload, requestIDP, mbitGlobal, sizeMB, bytesReceivedMB]() {
//webcom->onhttpFileProgressDelegate.Broadcast(size, bytesSent, percentUpload, bytesReceived, percentDownload);
webcom->onhttpFileDownloadDelegate.Broadcast(sizeMB, bytesReceivedMB, percentDownload, mbitGlobal, requestIDP);
});
//UE_LOG(LogTemp, Display, TEXT("size:%f | bytesSent:%i | percentUpload:%f | bytesReceived:%i | percentDownload:%f"), size, bytesSent, percentUpload, bytesReceived, percentDownload);
}
}
}
#if ENGINE_MAJOR_VERSION >= 5 & ENGINE_MINOR_VERSION >= 4
void UWebCommunicationRequestCompleteObject::requestProgressServerSendEvent(FHttpRequestPtr request, uint64 bytesSent, uint64 bytesReceived){
#else
void UWebCommunicationRequestCompleteObject::requestProgressServerSendEvent(FHttpRequestPtr request, int32 bytesSent, int32 bytesReceived){
#endif
FWebcomTheadJob* job = new FWebcomTheadJob();
job->request = request;
job->bytesSent = bytesSent;
job->bytesReceived = bytesReceived;
job->type = 5;
thread->addJob(job);
}
void UWebCommunicationRequestCompleteObject::requestProgressServerSendEventInternal(FHttpRequestPtr request, uint64 bytesSent, uint64 bytesReceived){
UWebCommunicationBPLibrary* webcom = webCommunicationBPLibrary;
FString requestIDP = requestID;
FHttpResponsePtr response = request->GetResponse();
if (response.IsValid()) {
TArray<uint8> responseBytes;
FString responseContent = FString();
int32 size = (bytesReceived - bytesReceivedLastTime);
responseBytes.AddZeroed(size+1);
FMemory::Memcpy(responseBytes.GetData(), response->GetContent().GetData() + bytesReceivedLastTime, size);
responseContent = UTF8_TO_TCHAR(responseBytes.GetData());
//UE_LOG(LogTemp, Warning, TEXT("UWebCommunicationRequestCompleteObject::requestProgressServerSendEvent: %i %i %i %i %s"),
// response->GetContent().Num(), bytesReceivedLastTime, bytesReceived, size, *responseContent);
bytesReceivedLastTime = bytesReceived;
AsyncTask(ENamedThreads::GameThread, [webcom, responseContent, requestIDP]() {
webcom->onhttpServerSendEventDelegate.Broadcast(responseContent, requestIDP);;
});
}
}
#if ENGINE_MAJOR_VERSION >= 5 & ENGINE_MINOR_VERSION >= 4
void UWebCommunicationRequestCompleteObject::requestProgressDownloadLowRam(FHttpRequestPtr request, uint64 bytesSent, uint64 bytesReceived){
#else
void UWebCommunicationRequestCompleteObject::requestProgressDownloadLowRam(FHttpRequestPtr request, int32 bytesSent, int32 bytesReceived){
#endif
FWebcomTheadJob* job = new FWebcomTheadJob();
job->request = request;
job->bytesSent = bytesSent;
job->bytesReceived = bytesReceived;
job->type = 6;
thread->addJob(job);
}
void UWebCommunicationRequestCompleteObject::requestProgressDownloadLowRamInternal(FHttpRequestPtr request, uint64 bytesSent, uint64 bytesReceived){
if (webCommunicationBPLibrary == nullptr) {
UE_LOG(LogTemp, Error, TEXT("UWebCommunicationBPLibrary: Missing Object instance (127)."));
return;
}
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: RequestID %s"), *requestID);
UWebCommunicationBPLibrary* webcom = webCommunicationBPLibrary;
FString requestIDP = requestID;
if (request.IsValid()) {
if (webCommunicationBPLibrary->toCancelRequests.Find(requestID) != nullptr) {
AsyncTask(ENamedThreads::GameThread, [request]() {
request->CancelRequest();
});
webCommunicationBPLibrary->toCancelRequests.Remove(requestID);
UE_LOG(LogTemp, Warning, TEXT("Request has been canceled. %s"), *requestID);
return;
}
FHttpResponsePtr response = request->GetResponse();
if (response.IsValid()) {
double size = (double)fileCancelResumeDownloadByteFullSize;
if (size <= 0)
size = 1;
double percentUpload = 0;
int64 bytesReceived64 = bytesReceived + fileCancelResumeDownloadByteStart;
double percentDownload = ((double)bytesReceived64 / size) * 100;
//downloadspeed
if (lastTimeTicks == 0) {
lastTimeTicks = FDateTime::Now().GetTicks();
bytesCurrent = bytesReceived;
}
else {
//one second = 10000000 ticks
if (((FDateTime::Now().GetTicks()) - lastTimeTicks) >= 10000000) {
mbit = ((float)bytesReceived - (float)bytesCurrent) / 1024 / 1024 * 8;
lastTimeTicks = FDateTime::Now().GetTicks();
bytesCurrent = bytesReceived;
}
}
float mbitGlobal = mbit;
double sizeMB = size / 1024 / 1024;
double bytesReceivedMB = (double)bytesReceived64 / 1024 / 1024;
AsyncTask(ENamedThreads::GameThread, [webcom, size, bytesSent, percentUpload, bytesReceived, percentDownload, requestIDP, mbitGlobal, sizeMB, bytesReceivedMB]() {
//webcom->onhttpFileProgressDelegate.Broadcast(size, bytesSent, (float)percentUpload, (int64)bytesReceived, (float)percentDownload);
webcom->onhttpFileDownloadDelegate.Broadcast((float)sizeMB, (float)bytesReceivedMB, (float)percentDownload, mbitGlobal, requestIDP);
});
}
}
}
void UWebCommunicationRequestCompleteObject::requestMultiStepComplete(FHttpRequestPtr Request, FHttpResponsePtr response, bool bWasSuccessful){
if (webCommunicationBPLibrary == nullptr) {
UE_LOG(LogTemp, Error, TEXT("UWebCommunicationBPLibrary: Missing Object instance (12)."));
return;
}
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: RequestID %s"), *requestID);
UWebCommunicationBPLibrary* webcom = webCommunicationBPLibrary;
FString requestIDP = requestID;
if (webcom->removeHeaders) {
webcom->additionalHeader.Empty();
}
UAsyncNodeWebCom* asyncNodeHttpRequest = webcom->getUAsyncNodeHttpRequest(requestID);
if (!bWasSuccessful || !response.IsValid()) {
//UE_LOG(LogTemp, Display, TEXT("Request unsuccessful, check the url"));
TArray<FString> dataArray;
TArray<uint8> byteArray;
FString dataString = "No Response";
int32 statusCode = 500;
if (response.IsValid()) {
dataString = response->GetContentAsString();
dataString.ParseIntoArray(dataArray, TEXT("\r\n"), true);
statusCode = response->GetResponseCode();
}
else {
dataArray.Add(dataString);
}
//switch to gamethread
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest, webcom, dataString, dataArray, statusCode, byteArray, requestIDP]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
asyncNodeHttpRequest->httpRequestComplete(dataString, dataArray, TArray<FString>(), statusCode, byteArray, requestIDP);
}
else {
webcom->onhttpRequestCompleteDelegate.Broadcast(dataString, dataArray, TArray<FString>(), statusCode, byteArray, requestIDP);
}
});
return;
}
TArray<uint8> byteArray = response->GetContent();
FString dataString = response->GetContentAsString();
TArray<FString> dataArray;
dataString.ParseIntoArray(dataArray, TEXT("\r\n"), true);
int32 statusCode = response->GetResponseCode();
TArray<FString> headerData = response->GetAllHeaders();
//gooledrive has a virus check for big files. read the confirm code from the html code and start a regluar get download request
if (multiStepDownload == 1 && dataArray.Num() > 0) {
FString dataStringTmp = dataArray.Last();
//UE_LOG(LogTemp, Error, TEXT("filesize: %s"),*sizeStr);
FString newUrl = generateURLFromHTML(dataStringTmp, Request.Get()->GetURL());
//no virus message
if (newUrl.EndsWith("confirm=")) {
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest,webcom, dataString, dataArray, headerData, statusCode, byteArray, requestIDP]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
asyncNodeHttpRequest->httpRequestComplete(dataString, dataArray, headerData, statusCode, byteArray, requestIDP);
}
else {
webcom->onhttpRequestCompleteDelegate.Broadcast(dataString, dataArray, headerData, statusCode, byteArray, requestIDP);
}
});
return;
}
TArray<struct FhttpRequest> otherHttpRequests;
TArray<struct FhttpRequest> httpRequests;
UWebCommunicationRequestCompleteObject* requestObject = NewObject<UWebCommunicationRequestCompleteObject>(UWebCommunicationRequestCompleteObject::StaticClass());
requestObject->setRequestID(requestID, httpRequest, UWebCommunicationBPLibrary::getWebCommunicationTarget());
requestObject->setDownloadID(downloadID);
requestObject->setMultiStepDownload(2);
FhttpRequest temphttpRequest;
temphttpRequest.requestType = EHTTPWebComRequestType::GET;
temphttpRequest.url = newUrl;
requestObject->setHTMLFileSize(HTMLFileSize);
temphttpRequest.request = requestObject;
otherHttpRequests.Add(temphttpRequest);
httpRequests = otherHttpRequests;
webCommunicationBPLibrary->executeHttpRequests(httpRequests, webCommunicationBPLibrary);
return;
}
//switch to gamethread
AsyncTask(ENamedThreads::GameThread, [asyncNodeHttpRequest, webcom, dataString, dataArray, headerData, statusCode, byteArray, requestIDP]() {
if (asyncNodeHttpRequest != nullptr && asyncNodeHttpRequest->IsValidLowLevel()) {
asyncNodeHttpRequest->httpRequestComplete(dataString, dataArray, headerData, statusCode, byteArray, requestIDP);
}
else {
webcom->onhttpRequestCompleteDelegate.Broadcast(dataString, dataArray, headerData, statusCode, byteArray, requestIDP);
}
});
}
#if ENGINE_MAJOR_VERSION >= 5 & ENGINE_MINOR_VERSION >= 4
void UWebCommunicationRequestCompleteObject::requestMultiStepDownload(FHttpRequestPtr request, uint64 bytesSent, uint64 bytesReceived){
#else
void UWebCommunicationRequestCompleteObject::requestMultiStepDownload(FHttpRequestPtr request, int32 bytesSent, int32 bytesReceived){
#endif
FWebcomTheadJob* job = new FWebcomTheadJob();
job->request = request;
job->bytesSent = bytesSent;
job->bytesReceived = bytesReceived;
job->type = 2;
thread->addJob(job);
}
void UWebCommunicationRequestCompleteObject::requestMultiStepDownloadInternal(FHttpRequestPtr request, uint64 bytesSent, uint64 bytesReceived){
if (webCommunicationBPLibrary == nullptr) {
UE_LOG(LogTemp, Error, TEXT("UWebCommunicationBPLibrary: Missing Object instance (83)."));
return;
}
if (multiStepDownload != 2 && HTMLFileSize <= 0)
return;
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: RequestID %s"), *requestID);
UWebCommunicationBPLibrary* webcom = webCommunicationBPLibrary;
FString requestIDP = requestID;
if (request.IsValid()) {
if (webCommunicationBPLibrary->toCancelRequests.Find(requestID) != nullptr) {
AsyncTask(ENamedThreads::GameThread, [request]() {
request->CancelRequest();
});
UE_LOG(LogTemp, Warning, TEXT("Request has been canceled. %s"), *requestID);
return;
}
FHttpResponsePtr response = request->GetResponse();
/*UE_LOG(LogTemp, Warning, TEXT("bytesReceived: %i"), response->GetContentLength());
UE_LOG(LogTemp, Warning, TEXT("GetContent: %i"), response->GetContent().Num());
UE_LOG(LogTemp, Warning, TEXT("x3x: %i"), (int32)HTMLFileSize);*/
if (response.IsValid()) {
float size = (HTMLFileSize == 0) ? response->GetContentLength() : (float)HTMLFileSize;
if (size <= 0)
size = 1;
float percentUpload = 0;
float percentDownload = ((float)bytesReceived / size) * 100;
if (percentDownload > 100) {
percentDownload = 100;
//multiStepDownload = 0;
}
//for the mbit thread
bytesCurrent = bytesReceived;
float mbitGlobal = mbit;
float sizeMB = size / 1024 / 1024;
float bytesReceivedMB = (float)bytesReceived / 1024 / 1024;
AsyncTask(ENamedThreads::GameThread, [webcom, size, bytesSent, percentUpload, bytesReceived, percentDownload, requestIDP, mbitGlobal, sizeMB, bytesReceivedMB]() {
//webcom->onhttpFileProgressDelegate.Broadcast(size, bytesSent, percentUpload, bytesReceived, percentDownload);
webcom->onhttpFileDownloadDelegate.Broadcast(sizeMB, bytesReceivedMB, percentDownload, mbitGlobal, requestIDP);
});
//UE_LOG(LogTemp, Display, TEXT("size:%f | bytesSent:%i | percentUpload:%f | bytesReceived:%i | percentDownload:%f"), size, bytesSent, percentUpload, bytesReceived, percentDownload);
}
}
}
void UWebCommunicationRequestCompleteObject::setRequestID(FString requestIDP, struct FhttpRequest& httpRequestP, UWebCommunicationBPLibrary* webCommunicationBPLibraryP) {
httpRequest = httpRequestP;
requestID = requestIDP;
webCommunicationBPLibrary = webCommunicationBPLibraryP;
}
void UWebCommunicationRequestCompleteObject::setRequestStruct(struct FhttpRequest& httpRequestP) {
httpRequest = httpRequestP;
}
FString UWebCommunicationRequestCompleteObject::getRequestID() {
return requestID;
}
void UWebCommunicationRequestCompleteObject::setDownloadID(FString downloadIDP){
downloadID = downloadIDP;
}
FString UWebCommunicationRequestCompleteObject::getDownloadID(){
return downloadID;
}
void UWebCommunicationRequestCompleteObject::setMultiStepDownload(int32 stepP) {
multiStepDownload = stepP;
//UE_LOG(LogTemp, Warning, TEXT("UWebCommunicationBPLibrary: %i."), multiStepDownload);
}
int32 UWebCommunicationRequestCompleteObject::getMultiStepDownload() {
return multiStepDownload;
}
void UWebCommunicationRequestCompleteObject::setMultiStepDownloadType(EMultiStepType multiStepDownloadTypeP){
multiStepDownloadType = multiStepDownloadTypeP;
}
EMultiStepType UWebCommunicationRequestCompleteObject::getMultiStepDownloadType(){
return multiStepDownloadType;
}
FString UWebCommunicationRequestCompleteObject::generateURLFromHTML(FString html, FString oldURL){
FString newURL;
if (multiStepDownloadType == EMultiStepType::GOOGLE) {
//get confirm id from html
FString left;
FString right;
html.Split(";confirm=", &left, &right);
right.Split("&", &left, &right);
FString linkParam = "download&confirm=" + left + "&";
newURL = oldURL + "&confirm=" + left;//oldURL.Replace(TEXT("download&"), *linkParam);
//get file size from html
if (HTMLFileSize == 0) {
html.Split("uc-name-size", &left, &right);
right.Split("</span>", &left, &right);
FString sizeStr = left;
FString left2;
FString right2;
sizeStr.Split("</a>", &left2, &right2, ESearchCase::CaseSensitive, ESearchDir::FromEnd);
sizeStr = right2.Replace(TEXT("("), TEXT("")).Replace(TEXT(")"), TEXT("")).Replace(TEXT(" "), TEXT("")).Replace(TEXT(","), TEXT("."));
if (sizeStr.Contains("M")) {
sizeStr = sizeStr.Replace(TEXT("M"), TEXT(""));
HTMLFileSize = FCString::Atof(*sizeStr) * 1024 * 1024;
}
else {
sizeStr = sizeStr.Replace(TEXT("G"), TEXT(""));
HTMLFileSize = ((double)FCString::Atof(*sizeStr)) * 1024 * 1024 * 1024;
}
}
return newURL;
}
if (multiStepDownloadType == EMultiStepType::ANONFILE) {
//get confirm id from html
FString left;
FString right;
html.Split("id=\"download-url\"", &left, &right);
right.Split("</a>", &left, &right);
FString left2;
FString right2;
left.Split("href=", &left2, &right2);
right2.Split("><", &newURL, &right);
newURL = newURL.Replace(TEXT("\""), TEXT(""));
}
return newURL;
}
void UWebCommunicationRequestCompleteObject::setFileCancelResumeDownloadByteFullSize(int64 size) {
fileCancelResumeDownloadByteFullSize = size;
}
int64 UWebCommunicationRequestCompleteObject::getFileCancelResumeDownloadByteFullSize() {
return fileCancelResumeDownloadByteFullSize;
}
void UWebCommunicationRequestCompleteObject::setFileCancelResumeDownloadBytePartSize(int64 size){
fileCancelResumeDownloadBytePartSize = size;
}
int64 UWebCommunicationRequestCompleteObject::getFileCancelResumeDownloadBytePartSize(){
return fileCancelResumeDownloadBytePartSize;
}
void UWebCommunicationRequestCompleteObject::setFileCancelResumeDownloadByteStart(int64 size){
if (size < 0) {
fileCancelResumeDownloadByteStart = 0;;
return;
}
fileCancelResumeDownloadByteStart = size;
}
int64 UWebCommunicationRequestCompleteObject::getFileCancelResumeDownloadByteStart(){
return fileCancelResumeDownloadByteStart;
}
void UWebCommunicationRequestCompleteObject::setFileCancelResumeDownloadDir(FString dir){
fileCancelResumeDownloadDir = dir;
}
FString UWebCommunicationRequestCompleteObject::getFileCancelResumeDownloadDir(){
return fileCancelResumeDownloadDir;
}
void UWebCommunicationRequestCompleteObject::setHTMLFileSize(int64 size) {
HTMLFileSize = size;
}
int64 UWebCommunicationRequestCompleteObject::getHTMLFileSize() {
return HTMLFileSize;
}
/***************************************************************/
FWebcomThread::FWebcomThread(UWebCommunicationRequestCompleteObject* parentObjectP) :
parentObject(parentObjectP){
FString threadName = "FWebcomThread" + FGuid::NewGuid().ToString();
thread = FRunnableThread::Create(this, *threadName, 0, EThreadPriority::TPri_Normal);
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: new Thead "));
}
FWebcomThread::~FWebcomThread(){
delete thread;
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: delete Thead "));
}
uint32 FWebcomThread::Run(){
while (run) {
while (jobQueue.IsEmpty() == false) {
FWebcomTheadJob* job = nullptr;
jobQueue.Dequeue(job);
if (job == nullptr || parentObject == nullptr) {
continue;
}
switch (job->type)
{
case 0:
parentObject->requestCompleteInternal(job->request, job->response, job->bWasSuccessful);
run = false;
break;
case 1:
parentObject->requestCompleteLowRamInternal(job->request, job->response, job->bWasSuccessful);
run = false;
break;
case 2:
parentObject->requestMultiStepDownloadInternal(job->request, job->bytesSent, job->bytesReceived);
break;
case 3:
parentObject->requestProgressUploadInternal(job->request, job->bytesSent, job->bytesReceived);
break;
case 4:
parentObject->requestProgressDownloadInternal(job->request, job->bytesSent, job->bytesReceived);
break;
case 5:
parentObject->requestProgressServerSendEventInternal(job->request, job->bytesSent, job->bytesReceived);
break;
case 6:
parentObject->requestProgressDownloadLowRamInternal(job->request, job->bytesSent, job->bytesReceived);
break;
}
if (job != nullptr) {
delete job;
}
}
if (run) {
pauseThread(true);
//workaround. suspend do not work on all platforms. lets sleep
while (paused && run) {
FPlatformProcess::Sleep(0.01);
}
}
}
UWebCommunicationRequestCompleteObject* parentObjectCopy = parentObject;
AsyncTask(ENamedThreads::GameThread, [parentObjectCopy]() {
if (parentObjectCopy != nullptr) {
parentObjectCopy->RemoveFromRoot();
//UE_LOG(LogTemp, Display, TEXT("UWebCommunicationBPLibrary: RemoveFromRoot "));
}
});
return 0;
}
void FWebcomThread::stopThread(){
run = false;
if (thread != nullptr) {
pauseThread(false);
}
Stop();
}
void FWebcomThread::pauseThread(bool pause){
paused = pause;
//thread->Suspend(pause);
}
void FWebcomThread::addJob(FWebcomTheadJob* job){
jobQueue.Enqueue(job);
pauseThread(false);
}