// 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 dataArray; TArray 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(asyncNodeHttpRequest); if (asyncNodeGoogleInfoRequest) { asyncNodeGoogleInfoRequest->httpRequestCompleteGoogleFileInfo("", 0, statusCode, downloadIDGlobal, requestIDP); } } else { UAsyncNodeHttpDownloadUpload* asyncNodeDownloadUpload = dynamic_cast(asyncNodeHttpRequest); if (asyncNodeDownloadUpload) { asyncNodeDownloadUpload->httpRequestDownloadUploadComplete(dataString,dataArray,TArray(), statusCode, requestIDP); } else { asyncNodeHttpRequest->httpRequestComplete(dataString,dataArray, TArray(), statusCode, byteArray, requestIDP); } } } else { if (multistepGlobal == EMultiStepType::GOOGLE_INFO) { webcom->onhttpRequestCompleteGoogleInfoDelegate.Broadcast("", 0, statusCode, downloadIDGlobal, requestIDP); } else { webcom->onhttpRequestCompleteDelegate.Broadcast(dataString, dataArray, TArray(), 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 byteArray = response->GetContent(); FString dataString = response->GetContentAsString(); TArray 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 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(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(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 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(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 dataArray; TArray 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(asyncNodeHttpRequest); if (asyncNodeDownloadUpload) { asyncNodeDownloadUpload->httpRequestDownloadUploadComplete(dataString, dataArray, TArray(), statusCode, requestIDP); } else { asyncNodeHttpRequest->httpRequestComplete(dataString, dataArray, TArray(), statusCode, byteArray, requestIDP); } } else { webcom->onhttpRequestCompleteDelegate.Broadcast(dataString, dataArray, TArray(), 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 byteArray; TArray dataArray; TArray 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(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(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(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 httpRequestsBack; FString requestIDBack; TArray 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(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 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 httpRequestsBack; FString requestIDBack; TArray 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(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 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 dataArray; TArray 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(), statusCode, byteArray, requestIDP); } else { webcom->onhttpRequestCompleteDelegate.Broadcast(dataString, dataArray, TArray(), statusCode, byteArray, requestIDP); } }); return; } TArray byteArray = response->GetContent(); FString dataString = response->GetContentAsString(); TArray dataArray; dataString.ParseIntoArray(dataArray, TEXT("\r\n"), true); int32 statusCode = response->GetResponseCode(); TArray 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 otherHttpRequests; TArray httpRequests; UWebCommunicationRequestCompleteObject* requestObject = NewObject(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("", &left, &right); FString sizeStr = left; FString left2; FString right2; sizeStr.Split("", &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("", &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); }