Beispiel #1
0
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);
}
Beispiel #4
0
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);
}
Beispiel #6
0
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));
}
Beispiel #7
0
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);
}
Beispiel #10
0
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();
}
Beispiel #12
0
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()
	}
}
Beispiel #13
0
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);
}
Beispiel #16
0
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);
}
Beispiel #19
0
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));
}
Beispiel #20
0
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;
}
Beispiel #25
0
void Request::finish() {
	ErrorResponse error(this, true, false, "", -1);
	finishError(error);
}
Beispiel #26
0
void DownloadRequest::streamErrorCallback(Networking::ErrorResponse error) {
	_workingRequest = nullptr;
	if (_ignoreCallback)
		return;
	finishError(error);
}