void SavesSyncRequest::directoryListedErrorCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; bool irrecoverable = error.interrupted || error.failed; if (error.failed) { Common::JSONValue *value = Common::JSON::parse(error.response.c_str()); if (value) { if (value->isObject()) { Common::JSONObject object = value->asObject(); //Dropbox-related error: if (object.contains("error_summary") && object.getVal("error_summary")->isString()) { Common::String summary = object.getVal("error_summary")->asString(); if (summary.contains("not_found")) { irrecoverable = false; } } //OneDrive-related error: if (object.contains("error") && object.getVal("error")->isObject()) { Common::JSONObject errorNode = object.getVal("error")->asObject(); if (Networking::CurlJsonRequest::jsonContainsString(errorNode, "code", "SavesSyncRequest")) { Common::String code = errorNode.getVal("code")->asString(); if (code == "itemNotFound") { irrecoverable = false; } } } } delete value; } //Google Drive and Box-related ScummVM-based error if (error.response.contains("subdirectory not found")) { irrecoverable = false; //base "/ScummVM/" folder not found } else if (error.response.contains("no such file found in its parent directory")) { irrecoverable = false; //"Saves" folder within "/ScummVM/" not found } } if (irrecoverable) { finishError(error); return; } //we're lucky - user just lacks his "/cloud/" folder - let's create one Common::String dir = _storage->savesDirectoryPath(); if (dir.lastChar() == '/') dir.deleteLastChar(); debug(9, "SavesSyncRequest: creating %s", dir.c_str()); _workingRequest = _storage->createDirectory( dir, new Common::Callback<SavesSyncRequest, Storage::BoolResponse>(this, &SavesSyncRequest::directoryCreatedCallback), new Common::Callback<SavesSyncRequest, Networking::ErrorResponse>(this, &SavesSyncRequest::directoryCreatedErrorCallback) ); if (!_workingRequest) finishError(Networking::ErrorResponse(this)); }
void OneDriveUploadRequest::partUploadedCallback(Networking::JsonResponse response) { _workingRequest = nullptr; if (_ignoreCallback) return; Networking::ErrorResponse error(this, false, true, "", -1); Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; if (rq && rq->getNetworkReadStream()) error.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); Common::JSONValue *json = response.value; if (json == nullptr) { error.response = "Failed to parse JSON, null passed!"; finishError(error); return; } if (json->isObject()) { Common::JSONObject object = json->asObject(); if (object.contains("error")) { warning("OneDriveUploadRequest: error: %s", json->stringify(true).c_str()); error.response = json->stringify(true); finishError(error); delete json; return; } if (Networking::CurlJsonRequest::jsonContainsString(object, "id", "OneDriveUploadRequest") && Networking::CurlJsonRequest::jsonContainsString(object, "name", "OneDriveUploadRequest") && Networking::CurlJsonRequest::jsonContainsIntegerNumber(object, "size", "OneDriveUploadRequest") && Networking::CurlJsonRequest::jsonContainsString(object, "lastModifiedDateTime", "OneDriveUploadRequest")) { //finished Common::String path = _savePath; uint32 size = object.getVal("size")->asIntegerNumber(); uint32 timestamp = ISO8601::convertToTimestamp(object.getVal("lastModifiedDateTime")->asString()); finishUpload(StorageFile(path, size, timestamp, false)); return; } if (_uploadUrl == "") { if (Networking::CurlJsonRequest::jsonContainsString(object, "uploadUrl", "OneDriveUploadRequest")) _uploadUrl = object.getVal("uploadUrl")->asString(); } } if (_contentsStream->eos() || _contentsStream->pos() >= _contentsStream->size() - 1) { warning("OneDriveUploadRequest: no file info to return"); finishUpload(StorageFile(_savePath, 0, 0, false)); } else { uploadNextPart(); } delete json; }
void IdCreateDirectoryRequest::idResolveFailedCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; if (error.request) _date = error.request->date(); //not resolved => folder not exists if (error.response.contains("no such file found in its parent directory")) { //parent's id after the '\n' Common::String parentId = error.response; for (uint32 i = 0; i < parentId.size(); ++i) if (parentId[i] == '\n') { parentId.erase(0, i + 1); break; } Storage::BoolCallback callback = new Common::Callback<IdCreateDirectoryRequest, Storage::BoolResponse>(this, &IdCreateDirectoryRequest::createdDirectoryCallback); Networking::ErrorCallback failureCallback = new Common::Callback<IdCreateDirectoryRequest, Networking::ErrorResponse>(this, &IdCreateDirectoryRequest::createdDirectoryErrorCallback); _workingRequest = _storage->createDirectoryWithParentId(parentId, _requestedDirectoryName, callback, failureCallback); return; } finishError(error); }
void SavesSyncRequest::start() { //cleanup _ignoreCallback = true; if (_workingRequest) _workingRequest->finish(); _currentDownloadingFile = StorageFile(); _currentUploadingFile = ""; _filesToDownload.clear(); _filesToUpload.clear(); _localFilesTimestamps.clear(); _totalFilesToHandle = 0; _ignoreCallback = false; //load timestamps _localFilesTimestamps = DefaultSaveFileManager::loadTimestamps(); //list saves directory Common::String dir = _storage->savesDirectoryPath(); if (dir.lastChar() == '/') dir.deleteLastChar(); _workingRequest = _storage->listDirectory( dir, new Common::Callback<SavesSyncRequest, Storage::ListDirectoryResponse>(this, &SavesSyncRequest::directoryListedCallback), new Common::Callback<SavesSyncRequest, Networking::ErrorResponse>(this, &SavesSyncRequest::directoryListedErrorCallback) ); if (!_workingRequest) finishError(Networking::ErrorResponse(this)); }
void GoogleDriveUploadRequest::uploadNextPart() { const uint32 UPLOAD_PER_ONE_REQUEST = 10 * 1024 * 1024; Common::String url = _uploadUrl; Networking::JsonCallback callback = new Common::Callback<GoogleDriveUploadRequest, Networking::JsonResponse>(this, &GoogleDriveUploadRequest::partUploadedCallback); Networking::ErrorCallback failureCallback = new Common::Callback<GoogleDriveUploadRequest, Networking::ErrorResponse>(this, &GoogleDriveUploadRequest::partUploadedErrorCallback); Networking::CurlJsonRequest *request = new GoogleDriveTokenRefresher(_storage, callback, failureCallback, url.c_str()); request->addHeader("Authorization: Bearer " + _storage->accessToken()); request->usePut(); uint32 oldPos = _contentsStream->pos(); if (oldPos != _serverReceivedBytes) { if (!_contentsStream->seek(_serverReceivedBytes)) { warning("GoogleDriveUploadRequest: cannot upload because stream couldn't seek(%lu)", _serverReceivedBytes); finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } oldPos = _serverReceivedBytes; } byte *buffer = new byte[UPLOAD_PER_ONE_REQUEST]; uint32 size = _contentsStream->read(buffer, UPLOAD_PER_ONE_REQUEST); if (size != 0) request->setBuffer(buffer, size); if (_uploadUrl != "") { if (_contentsStream->pos() == 0) request->addHeader(Common::String::format("Content-Length: 0")); else request->addHeader(Common::String::format("Content-Range: bytes %u-%u/%u", oldPos, _contentsStream->pos() - 1, _contentsStream->size())); } _workingRequest = ConnMan.addRequest(request); }
void SavesSyncRequest::uploadNextFile() { if (_filesToUpload.empty()) { finishSync(true); return; } _currentUploadingFile = _filesToUpload.back(); _filesToUpload.pop_back(); debug(9, "SavesSyncRequest: uploading %s (%d %%)", _currentUploadingFile.c_str(), (int)(getProgress() * 100)); if (_storage->uploadStreamSupported()) { _workingRequest = _storage->upload( _storage->savesDirectoryPath() + _currentUploadingFile, g_system->getSavefileManager()->openRawFile(_currentUploadingFile), new Common::Callback<SavesSyncRequest, Storage::UploadResponse>(this, &SavesSyncRequest::fileUploadedCallback), new Common::Callback<SavesSyncRequest, Networking::ErrorResponse>(this, &SavesSyncRequest::fileUploadedErrorCallback) ); } else { _workingRequest = _storage->upload( _storage->savesDirectoryPath() + _currentUploadingFile, DefaultSaveFileManager::concatWithSavesPath(_currentUploadingFile), new Common::Callback<SavesSyncRequest, Storage::UploadResponse>(this, &SavesSyncRequest::fileUploadedCallback), new Common::Callback<SavesSyncRequest, Networking::ErrorResponse>(this, &SavesSyncRequest::fileUploadedErrorCallback) ); } if (!_workingRequest) finishError(Networking::ErrorResponse(this)); }
void SavesSyncRequest::directoryCreatedErrorCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; //stop syncing if failed to create saves directory finishError(error); }
void OneDriveListDirectoryRequest::listedDirectoryErrorCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; if (error.request) _date = error.request->date(); finishError(error); }
void IdCreateDirectoryRequest::createdBaseDirectoryErrorCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; if (error.request) _date = error.request->date(); finishError(error); }
void SavesSyncRequest::fileUploadedErrorCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; //stop syncing if upload failed finishError(error); }
void OneDriveUploadRequest::start() { _ignoreCallback = true; if (_workingRequest) _workingRequest->finish(); if (_contentsStream == nullptr) { warning("OneDriveUploadRequest: cannot restart because no stream given"); finishError(Networking::ErrorResponse(this, false, true, "No stream given", -1)); return; } if (!_contentsStream->seek(0)) { warning("OneDriveUploadRequest: cannot restart because stream couldn't seek(0)"); finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } _ignoreCallback = false; uploadNextPart(); }
void DownloadRequest::handle() { if (!_localFile) { warning("DownloadRequest: no file to write"); finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } if (!_localFile->isOpen()) { warning("DownloadRequest: failed to open file to write"); finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } if (!_remoteFileStream) { //waiting for callback return; } uint32 readBytes = _remoteFileStream->read(_buffer, DOWNLOAD_REQUEST_BUFFER_SIZE); if (readBytes != 0) if (_localFile->write(_buffer, readBytes) != readBytes) { warning("DownloadRequest: unable to write all received bytes into output file"); finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } if (_remoteFileStream->eos()) { if (_remoteFileStream->httpResponseCode() != 200) { warning("DownloadRequest: HTTP response code is not 200 OK (it's %ld)", _remoteFileStream->httpResponseCode()); //TODO: do something about it actually // the problem is file's already downloaded, stream is over // so we can't return error message anymore } finishDownload(_remoteFileStream->httpResponseCode() == 200); _localFile->close(); //yes, I know it's closed automatically in ~DumpFile() } }
void SavesSyncRequest::directoryCreatedCallback(Storage::BoolResponse response) { _workingRequest = nullptr; if (_ignoreCallback) return; //stop syncing if failed to create saves directory if (!response.value) { finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } //continue with empty files list Common::Array<StorageFile> files; directoryListedCallback(Storage::ListDirectoryResponse(response.request, files)); }
void GoogleDriveUploadRequest::start() { _ignoreCallback = true; if (_workingRequest) _workingRequest->finish(); if (_contentsStream == nullptr || !_contentsStream->seek(0)) { warning("GoogleDriveUploadRequest: cannot restart because stream couldn't seek(0)"); finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } _resolvedId = ""; //used to update file contents _parentId = ""; //used to create file within parent directory _serverReceivedBytes = 0; _ignoreCallback = false; resolveId(); }
void GoogleDriveUploadRequest::partUploadedErrorCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)error.request; if (rq) { const Networking::NetworkReadStream *stream = rq->getNetworkReadStream(); if (stream) { long code = stream->httpResponseCode(); if (code == 308 && handleHttp308(stream)) { return; } } } finishError(error); }
void SavesSyncRequest::fileDownloadedCallback(Storage::BoolResponse response) { _workingRequest = nullptr; if (_ignoreCallback) return; //stop syncing if download failed if (!response.value) { //delete the incomplete file g_system->getSavefileManager()->removeSavefile(_currentDownloadingFile.name()); finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } //update local timestamp for downloaded file _localFilesTimestamps = DefaultSaveFileManager::loadTimestamps(); _localFilesTimestamps[_currentDownloadingFile.name()] = _currentDownloadingFile.timestamp(); DefaultSaveFileManager::saveTimestamps(_localFilesTimestamps); //continue downloading files downloadNextFile(); }
void GoogleDriveUploadRequest::idResolveFailedCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; //not resolved => error or no such file if (error.response.contains("no such file found in its parent directory")) { //parent's id after the '\n' Common::String parentId = error.response; for (uint32 i = 0; i < parentId.size(); ++i) if (parentId[i] == '\n') { parentId.erase(0, i + 1); break; } _parentId = parentId; startUpload(); return; } finishError(error); }
void GoogleDriveUploadRequest::startUploadCallback(Networking::JsonResponse response) { _workingRequest = nullptr; if (_ignoreCallback) return; Networking::ErrorResponse error(this, false, true, "", -1); Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; if (rq) { const Networking::NetworkReadStream *stream = rq->getNetworkReadStream(); if (stream) { long code = stream->httpResponseCode(); Common::String headers = stream->responseHeaders(); if (code == 200) { const char *cstr = headers.c_str(); const char *position = strstr(cstr, "Location: "); if (position) { Common::String result = ""; char c; for (const char *i = position + 10; c = *i, c != 0; ++i) { if (c == '\n' || c == '\r') break; result += c; } _uploadUrl = result; uploadNextPart(); return; } } error.httpResponseCode = code; } } Common::JSONValue *json = response.value; delete json; finishError(error); }
void SavesSyncRequest::downloadNextFile() { if (_filesToDownload.empty()) { _currentDownloadingFile = StorageFile("", 0, 0, false); //so getFilesToDownload() would return an empty array sendCommand(GUI::kSavesSyncEndedCmd, 0); uploadNextFile(); return; } _currentDownloadingFile = _filesToDownload.back(); _filesToDownload.pop_back(); sendCommand(GUI::kSavesSyncProgressCmd, (int)(getDownloadingProgress() * 100)); debug(9, "SavesSyncRequest: downloading %s (%d %%)", _currentDownloadingFile.name().c_str(), (int)(getProgress() * 100)); _workingRequest = _storage->downloadById( _currentDownloadingFile.id(), DefaultSaveFileManager::concatWithSavesPath(_currentDownloadingFile.name()), new Common::Callback<SavesSyncRequest, Storage::BoolResponse>(this, &SavesSyncRequest::fileDownloadedCallback), new Common::Callback<SavesSyncRequest, Networking::ErrorResponse>(this, &SavesSyncRequest::fileDownloadedErrorCallback) ); if (!_workingRequest) finishError(Networking::ErrorResponse(this)); }
void DownloadRequest::restart() { warning("DownloadRequest: can't restart as there are no means to reopen DumpFile"); finishError(Networking::ErrorResponse(this, false, true, "", -1)); //start(); }
void GoogleDriveUploadRequest::partUploadedCallback(Networking::JsonResponse response) { _workingRequest = nullptr; if (_ignoreCallback) return; Networking::ErrorResponse error(this, false, true, "", -1); Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; if (rq) { const Networking::NetworkReadStream *stream = rq->getNetworkReadStream(); if (stream) { long code = stream->httpResponseCode(); error.httpResponseCode = code; if (code == 308 && handleHttp308(stream)) { delete (Common::JSONValue *)response.value; return; } } } Common::JSONValue *json = response.value; if (json == nullptr) { error.response = "Failed to parse JSON, null passed!"; finishError(error); return; } if (json->isObject()) { Common::JSONObject object = json->asObject(); if (object.contains("error")) { warning("GoogleDrive returned error: %s", json->stringify(true).c_str()); error.response = json->stringify(true); finishError(error); delete json; return; } if (Networking::CurlJsonRequest::jsonContainsString(object, "id", "GoogleDriveUploadRequest") && Networking::CurlJsonRequest::jsonContainsString(object, "name", "GoogleDriveUploadRequest") && Networking::CurlJsonRequest::jsonContainsString(object, "mimeType", "GoogleDriveUploadRequest")) { //finished Common::String id = object.getVal("id")->asString(); Common::String name = object.getVal("name")->asString(); bool isDirectory = (object.getVal("mimeType")->asString() == "application/vnd.google-apps.folder"); uint32 size = 0, timestamp = 0; if (Networking::CurlJsonRequest::jsonContainsString(object, "size", "GoogleDriveUploadRequest", true)) size = object.getVal("size")->asString().asUint64(); if (Networking::CurlJsonRequest::jsonContainsString(object, "modifiedTime", "GoogleDriveUploadRequest", true)) timestamp = ISO8601::convertToTimestamp(object.getVal("modifiedTime")->asString()); finishUpload(StorageFile(id, _savePath, name, size, timestamp, isDirectory)); return; } } if (_contentsStream->eos() || _contentsStream->pos() >= _contentsStream->size() - 1) { warning("GoogleDriveUploadRequest: no file info to return"); finishUpload(StorageFile(_savePath, 0, 0, false)); } else { uploadNextPart(); } delete json; }
void OneDriveUploadRequest::partUploadedErrorCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; finishError(error); }
void FolderDownloadRequest::directoryListedErrorCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; finishError(error); }
void OneDriveListDirectoryRequest::listedDirectoryCallback(Networking::JsonResponse response) { _workingRequest = nullptr; Common::JSONValue *json = response.value; if (_ignoreCallback) { delete json; return; } if (response.request) _date = response.request->date(); Networking::ErrorResponse error(this); Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; if (rq && rq->getNetworkReadStream()) error.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); if (json == nullptr) { error.response = "Failed to parse JSON, null passed!"; finishError(error); return; } if (!json->isObject()) { error.response = "Passed JSON is not an object!"; finishError(error); delete json; return; } Common::JSONObject object = json->asObject(); //check that ALL keys exist AND HAVE RIGHT TYPE to avoid segfaults if (!Networking::CurlJsonRequest::jsonContainsArray(object, "value", "OneDriveListDirectoryRequest")) { error.response = "\"value\" not found or that's not an array!"; finishError(error); delete json; return; } Common::JSONArray items = object.getVal("value")->asArray(); for (uint32 i = 0; i < items.size(); ++i) { if (!Networking::CurlJsonRequest::jsonIsObject(items[i], "OneDriveListDirectoryRequest")) continue; Common::JSONObject item = items[i]->asObject(); if (!Networking::CurlJsonRequest::jsonContainsAttribute(item, "folder", "OneDriveListDirectoryRequest", true)) continue; if (!Networking::CurlJsonRequest::jsonContainsString(item, "name", "OneDriveListDirectoryRequest")) continue; if (!Networking::CurlJsonRequest::jsonContainsIntegerNumber(item, "size", "OneDriveListDirectoryRequest")) continue; if (!Networking::CurlJsonRequest::jsonContainsString(item, "lastModifiedDateTime", "OneDriveListDirectoryRequest")) continue; Common::String path = _currentDirectory + item.getVal("name")->asString(); bool isDirectory = item.contains("folder"); uint32 size = item.getVal("size")->asIntegerNumber(); uint32 timestamp = ISO8601::convertToTimestamp(item.getVal("lastModifiedDateTime")->asString()); StorageFile file(path, size, timestamp, isDirectory); _files.push_back(file); if (_requestedRecursive && file.isDirectory()) { _directoriesQueue.push_back(file.path()); } } bool hasMore = object.contains("@odata.nextLink"); if (hasMore) { if (!Networking::CurlJsonRequest::jsonContainsString(object, "@odata.nextLink", "OneDriveListDirectoryRequest")) { error.response = "\"@odata.nextLink\" is not a string!"; finishError(error); delete json; return; } makeRequest(object.getVal("@odata.nextLink")->asString()); } else { listNextDirectory(); } delete json; }
void Request::finish() { ErrorResponse error(this, true, false, "", -1); finishError(error); }
void DownloadRequest::streamErrorCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; finishError(error); }