/** * Downloads the save file from CloudyWeb. * * @param Filename Filename of the save game file. * @param PlayerControllerId Player controller ID of the player who requested the file. * * @return Returns true if the file download was successful. Else, returns false. * */ bool CloudyWebConnectorImpl::DownloadFile(FString Filename, int32 PlayerControllerId) { CURL *curl; FILE *fp; CURLcode res; errno_t err; std::string SaveFileURLCString; if (GetGameId() == -1 || GetUsername(PlayerControllerId).Equals("") || PlayerControllerId < 0 || SaveFileUrls.Num() <= PlayerControllerId) { UE_LOG(CloudyWebConnectorLog, Error, TEXT("The game ID, username, or player controller ID is invalid")); return false; } // Use the game id and username of the player to GET the save file URL from CloudyWeb // Then populate SaveFileUrls (TArray) GetSaveFileUrl(GetGameId(), GetUsername(PlayerControllerId), PlayerControllerId); // Read the URL from the SaveFileUrls TArray to download the file and write to disk FString* SaveFileUrlsData = SaveFileUrls.GetData(); if (!SaveFileUrlsData[PlayerControllerId].Equals("")) { UE_LOG(CloudyWebConnectorLog, Log, TEXT("File URL obtained! Writing to disk.")); SaveFileURLCString = TCHAR_TO_UTF8(*SaveFileUrlsData[PlayerControllerId]); // Filepath of .sav file FString Filepath = FPaths::GameDir(); Filepath += "Saved/SaveGames/" + Filename + "-" + FString::FromInt(PlayerControllerId) + ".sav"; std::string filePath(TCHAR_TO_UTF8(*Filepath)); curl = curl_easy_init(); if (curl) { if ((err = fopen_s(&fp, filePath.c_str(), "wb")) == 0) { curl_easy_setopt(curl, CURLOPT_URL, SaveFileURLCString.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); res = curl_easy_perform(curl); curl_easy_cleanup(curl); fclose(fp); } else { UE_LOG(CloudyWebConnectorLog, Error, TEXT("Could not create save file!")); } } return true; } else { UE_LOG(CloudyWebConnectorLog, Warning, TEXT("There was no save file URL!")); return false; } }
/** * Uploads the save file to CloudyWeb. * * @param Filename Filename of the save game file. * @param PlayerControllerId PlayerControllerId of the player who is saving the game. * * @return Returns true if the file upload was successful. Else, returns false. * */ bool CloudyWebAPIImpl::UploadFile(FString Filename, int32 PlayerControllerId) { bool RequestSuccess = false; CURL *curl; CURLcode res; std::string readBuffer; FString Url = BaseUrl + SaveDataUrl; std::string UrlCString(TCHAR_TO_UTF8(*Url)); // Filepath of .sav file FString Filepath = FPaths::GameDir(); Filepath += "Saved/SaveGames/" + Filename + ".sav"; std::string filePath(TCHAR_TO_UTF8(*Filepath)); // Get game name FString GameName = FApp::GetGameName(); std::string gameName(TCHAR_TO_UTF8(*GameName)); // Get game ID FString GameID = FString::FromInt(GetGameId()); std::string GameIDCString(TCHAR_TO_UTF8(*GameID)); // Get username FString Username = GetUsername(PlayerControllerId); std::string UsernameCString(TCHAR_TO_UTF8(*Username)); // Convert PlayerControllerId FString playerControllerIdFString = FString::FromInt(PlayerControllerId); std::string playerControllerId(TCHAR_TO_UTF8(*playerControllerIdFString)); if (GetGameId() == -1 || Username.Equals("") || PlayerControllerId < 0) { UE_LOG(CloudyWebAPILog, Error, TEXT("The game ID, username, or player controller ID is invalid")); return false; } struct curl_httppost *formpost = NULL; struct curl_httppost *lastptr = NULL; struct curl_slist *headerlist = NULL; FString AuthHeader = "Authorization: Token " + Token; std::string AuthHeaderCString(TCHAR_TO_UTF8(*AuthHeader)); curl_global_init(CURL_GLOBAL_ALL); /* Fill in the file upload field */ curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "saved_file", CURLFORM_FILE, filePath.c_str(), CURLFORM_END); /* Fill in the player controller ID field */ curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "user", CURLFORM_COPYCONTENTS, UsernameCString.c_str(), CURLFORM_END); /* Fill in the game name field */ curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "game", CURLFORM_COPYCONTENTS, GameIDCString.c_str(), CURLFORM_END); curl = curl_easy_init(); /* initialize custom header list (stating that Expect: 100-continue is not wanted */ headerlist = curl_slist_append(headerlist, AuthHeaderCString.c_str()); if (curl) { /* what URL that receives this POST */ curl_easy_setopt(curl, CURLOPT_URL, UrlCString.c_str()); /* only disable 100-continue header if explicitly requested */ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); /* What form to send */ curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); /* Set up string to write response into */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check if the request was successful */ if (res == CURLE_OK) { RequestSuccess = true; } /* always cleanup */ curl_easy_cleanup(curl); /* then cleanup the formpost chain */ curl_formfree(formpost); /* free slist */ curl_slist_free_all(headerlist); UE_LOG(CloudyWebAPILog, Warning, TEXT("Response data: %s"), UTF8_TO_TCHAR(readBuffer.c_str())); ReadAndStoreSaveFileURL(readBuffer.c_str(), PlayerControllerId); } return RequestSuccess; }