diff options
author | Alexander Tkachev | 2016-05-31 01:51:32 +0600 |
---|---|---|
committer | Alexander Tkachev | 2016-08-24 16:07:55 +0600 |
commit | eb63b50b7f0841e40365f3fbafa9810e8b190872 (patch) | |
tree | 4f348f12298c15e8a5885b5a74ce3788493b9a7e | |
parent | 001b417f33beeb3b2da11f58105b971dc7e6f600 (diff) | |
download | scummvm-rg350-eb63b50b7f0841e40365f3fbafa9810e8b190872.tar.gz scummvm-rg350-eb63b50b7f0841e40365f3fbafa9810e8b190872.tar.bz2 scummvm-rg350-eb63b50b7f0841e40365f3fbafa9810e8b190872.zip |
CLOUD: Refactor Request
Added ErrorResponse and ErrorCallback. Each Request now has an
ErrorCallback, which should be called instead of usual callback in case
of failure.
29 files changed, 652 insertions, 507 deletions
diff --git a/backends/cloud/downloadrequest.cpp b/backends/cloud/downloadrequest.cpp index 8d5e244e45..7dde74f88d 100644 --- a/backends/cloud/downloadrequest.cpp +++ b/backends/cloud/downloadrequest.cpp @@ -27,31 +27,55 @@ namespace Cloud { -DownloadRequest::DownloadRequest(Storage *storage, Storage::BoolCallback callback, Common::String remoteFile, Common::DumpFile *dumpFile): - Request(0), _boolCallback(callback), _remoteFileStream(0), _localFile(dumpFile) { - storage->streamFile(remoteFile, new Common::Callback<DownloadRequest, Networking::NetworkReadStreamResponse>(this, &DownloadRequest::streamCallback)); +DownloadRequest::DownloadRequest(Storage *storage, Storage::BoolCallback callback, Networking::ErrorCallback ecb, Common::String remoteFile, Common::DumpFile *dumpFile): + Request(nullptr, ecb), _boolCallback(callback), _localFile(dumpFile), _remoteFileName(remoteFile), _storage(storage), + _remoteFileStream(nullptr), _workingRequest(nullptr), _ignoreCallback(false) { + start(); } -void DownloadRequest::streamCallback(Networking::NetworkReadStreamResponse pair) { - if (!pair.value) { - warning("DownloadRequest: no ReadStream passed"); - finish(); - return; - } +DownloadRequest::~DownloadRequest() { + _ignoreCallback = true; + if (_workingRequest) _workingRequest->finish(); + delete _boolCallback; + delete _localFile; +} + +void DownloadRequest::start() { + _ignoreCallback = true; + if (_workingRequest) _workingRequest->finish(); + _remoteFileStream = nullptr; + //TODO: reopen DumpFile + _ignoreCallback = false; + + _workingRequest = _storage->streamFile( + _remoteFileName, + new Common::Callback<DownloadRequest, Networking::NetworkReadStreamResponse>(this, &DownloadRequest::streamCallback), + new Common::Callback<DownloadRequest, Networking::ErrorResponse>(this, &DownloadRequest::streamErrorCallback) + ); +} - _remoteFileStream = (Networking::NetworkReadStream *)pair.value; +void DownloadRequest::streamCallback(Networking::NetworkReadStreamResponse response) { + _workingRequest = nullptr; + if (_ignoreCallback) return; + _remoteFileStream = (Networking::NetworkReadStream *)response.value; +} + +void DownloadRequest::streamErrorCallback(Networking::ErrorResponse error) { + _workingRequest = nullptr; + if (_ignoreCallback) return; + finishError(error); } void DownloadRequest::handle() { if (!_localFile) { warning("DownloadRequest: no file to write"); - finish(); + finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } if (!_localFile->isOpen()) { warning("DownloadRequest: failed to open file to write"); - finish(); + finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } @@ -67,7 +91,7 @@ void DownloadRequest::handle() { if (readBytes != 0) if (_localFile->write(buf, readBytes) != readBytes) { warning("DownloadRequest: unable to write all received bytes into output file"); - finish(); + finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } @@ -77,26 +101,20 @@ void DownloadRequest::handle() { //TODO: do something about it actually } - finishBool(_remoteFileStream->httpResponseCode() == 200); + finishSuccess(_remoteFileStream->httpResponseCode() == 200); _localFile->close(); //yes, I know it's closed automatically in ~DumpFile() } } void DownloadRequest::restart() { - //this request doesn't know anything about the _remoteFileStream it's reading - //thus, it can't restart it - warning("DownloadRequest: cannot be restarted"); - finish(); - //TODO: fix that -} - -void DownloadRequest::finish() { - finishBool(false); + warning("DownloadRequest: can't restart as there are no means to reopen DumpFile"); + finishError(Networking::ErrorResponse(this, false, true, "", -1)); + //start(); } -void DownloadRequest::finishBool(bool success) { - Request::finish(); +void DownloadRequest::finishSuccess(bool success) { + Request::finishSuccess(); if (_boolCallback) (*_boolCallback)(Storage::BoolResponse(this, success)); } diff --git a/backends/cloud/downloadrequest.h b/backends/cloud/downloadrequest.h index 0bad5df279..9e3421d777 100644 --- a/backends/cloud/downloadrequest.h +++ b/backends/cloud/downloadrequest.h @@ -31,23 +31,24 @@ namespace Cloud { class DownloadRequest: public Networking::Request { - Storage::BoolCallback _boolCallback; + Storage::BoolCallback _boolCallback; + Common::DumpFile *_localFile; + Common::String _remoteFileName; + Storage *_storage; Networking::NetworkReadStream *_remoteFileStream; - Common::DumpFile *_localFile; + Request *_workingRequest; + bool _ignoreCallback; - void streamCallback(Networking::NetworkReadStreamResponse pair); - - void finishBool(bool success); + void start(); + void streamCallback(Networking::NetworkReadStreamResponse response); + void streamErrorCallback(Networking::ErrorResponse error); + void finishSuccess(bool success); public: - DownloadRequest(Storage *storage, Storage::BoolCallback callback, Common::String remoteFile, Common::DumpFile *dumpFile); - virtual ~DownloadRequest() { - delete _boolCallback; - delete _localFile; - } + DownloadRequest(Storage *storage, Storage::BoolCallback callback, Networking::ErrorCallback ecb, Common::String remoteFile, Common::DumpFile *dumpFile); + virtual ~DownloadRequest(); virtual void handle(); virtual void restart(); - virtual void finish(); }; } // End of namespace Cloud diff --git a/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp b/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp index 2796a4c19e..d782f81a69 100644 --- a/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp +++ b/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp @@ -31,8 +31,8 @@ namespace Cloud { namespace Dropbox { -DropboxListDirectoryRequest::DropboxListDirectoryRequest(Common::String token, Common::String path, Storage::ListDirectoryCallback cb, bool recursive): - Networking::Request(0), _requestedPath(path), _requestedRecursive(recursive), _listDirectoryCallback(cb), +DropboxListDirectoryRequest::DropboxListDirectoryRequest(Common::String token, Common::String path, Storage::ListDirectoryCallback cb, Networking::ErrorCallback ecb, bool recursive): + Networking::Request(nullptr, ecb), _requestedPath(path), _requestedRecursive(recursive), _listDirectoryCallback(cb), _token(token), _workingRequest(nullptr), _ignoreCallback(false) { start(); } @@ -49,8 +49,9 @@ void DropboxListDirectoryRequest::start() { _files.clear(); _ignoreCallback = false; - Networking::JsonCallback innerCallback = new Common::Callback<DropboxListDirectoryRequest, Networking::JsonResponse>(this, &DropboxListDirectoryRequest::responseCallback); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://api.dropboxapi.com/2/files/list_folder"); + Networking::JsonCallback callback = new Common::Callback<DropboxListDirectoryRequest, Networking::JsonResponse>(this, &DropboxListDirectoryRequest::responseCallback); + Networking::ErrorCallback failureCallback = new Common::Callback<DropboxListDirectoryRequest, Networking::ErrorResponse>(this, &DropboxListDirectoryRequest::errorCallback); + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, failureCallback, "https://api.dropboxapi.com/2/files/list_folder"); request->addHeader("Authorization: Bearer " + _token); request->addHeader("Content-Type: application/json"); @@ -66,33 +67,32 @@ void DropboxListDirectoryRequest::start() { _workingRequest = ConnMan.addRequest(request); } - -void DropboxListDirectoryRequest::responseCallback(Networking::JsonResponse pair) { +void DropboxListDirectoryRequest::responseCallback(Networking::JsonResponse response) { _workingRequest = nullptr; if (_ignoreCallback) return; - ListDirectoryStatus status(_files); - Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)pair.request; + Networking::ErrorResponse error(this); + Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; if (rq && rq->getNetworkReadStream()) - status.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); + error.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); - Common::JSONValue *json = pair.value; + Common::JSONValue *json = response.value; if (json) { - Common::JSONObject response = json->asObject(); + Common::JSONObject responseObjecct = json->asObject(); - if (response.contains("error") || response.contains("error_summary")) { - warning("Dropbox returned error: %s", response.getVal("error_summary")->asString().c_str()); - status.failed = true; - status.response = json->stringify(); - finishStatus(status); + if (responseObjecct.contains("error") || responseObjecct.contains("error_summary")) { + warning("Dropbox returned error: %s", responseObjecct.getVal("error_summary")->asString().c_str()); + error.failed = true; + error.response = json->stringify(); + finishError(error); delete json; return; } //TODO: check that ALL keys exist AND HAVE RIGHT TYPE to avoid segfaults - if (response.contains("entries")) { - Common::JSONArray items = response.getVal("entries")->asArray(); + if (responseObjecct.contains("entries")) { + Common::JSONArray items = responseObjecct.getVal("entries")->asArray(); for (uint32 i = 0; i < items.size(); ++i) { Common::JSONObject item = items[i]->asObject(); Common::String path = item.getVal("path_lower")->asString(); @@ -106,47 +106,47 @@ void DropboxListDirectoryRequest::responseCallback(Networking::JsonResponse pair } } - bool hasMore = (response.contains("has_more") && response.getVal("has_more")->asBool()); + bool hasMore = (responseObjecct.contains("has_more") && responseObjecct.getVal("has_more")->asBool()); - if (hasMore) { - Networking::JsonCallback innerCallback = new Common::Callback<DropboxListDirectoryRequest, Networking::JsonResponse>(this, &DropboxListDirectoryRequest::responseCallback); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://api.dropboxapi.com/2/files/list_folder/continue"); + if (hasMore) { + Networking::JsonCallback callback = new Common::Callback<DropboxListDirectoryRequest, Networking::JsonResponse>(this, &DropboxListDirectoryRequest::responseCallback); + Networking::ErrorCallback failureCallback = new Common::Callback<DropboxListDirectoryRequest, Networking::ErrorResponse>(this, &DropboxListDirectoryRequest::errorCallback); + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, failureCallback, "https://api.dropboxapi.com/2/files/list_folder/continue"); request->addHeader("Authorization: Bearer " + _token); request->addHeader("Content-Type: application/json"); Common::JSONObject jsonRequestParameters; - jsonRequestParameters.setVal("cursor", new Common::JSONValue(response.getVal("cursor")->asString())); + jsonRequestParameters.setVal("cursor", new Common::JSONValue(responseObjecct.getVal("cursor")->asString())); Common::JSONValue value(jsonRequestParameters); request->addPostField(Common::JSON::stringify(&value)); _workingRequest = ConnMan.addRequest(request); } else { - finishStatus(status); + finishSuccess(_files); } } else { warning("null, not json"); - status.failed = true; - finishStatus(status); + error.failed = true; + finishError(error); } delete json; } +void DropboxListDirectoryRequest::errorCallback(Networking::ErrorResponse error) { + _workingRequest = nullptr; + if (_ignoreCallback) return; + finishError(error); +} + void DropboxListDirectoryRequest::handle() {} void DropboxListDirectoryRequest::restart() { start(); } -void DropboxListDirectoryRequest::finish() { - Common::Array<StorageFile> files; - ListDirectoryStatus status(files); - status.interrupted = true; - finishStatus(status); -} - -void DropboxListDirectoryRequest::finishStatus(ListDirectoryStatus status) { - Request::finish(); - if (_listDirectoryCallback) (*_listDirectoryCallback)(Storage::ListDirectoryResponse(this, status)); +void DropboxListDirectoryRequest::finishSuccess(Common::Array<StorageFile> &files) { + Request::finishSuccess(); + if (_listDirectoryCallback) (*_listDirectoryCallback)(Storage::ListDirectoryResponse(this, files)); } } // End of namespace Dropbox diff --git a/backends/cloud/dropbox/dropboxlistdirectoryrequest.h b/backends/cloud/dropbox/dropboxlistdirectoryrequest.h index 3c7c1fd464..3a83af06aa 100644 --- a/backends/cloud/dropbox/dropboxlistdirectoryrequest.h +++ b/backends/cloud/dropbox/dropboxlistdirectoryrequest.h @@ -42,15 +42,15 @@ class DropboxListDirectoryRequest: public Networking::Request { bool _ignoreCallback; void start(); - void responseCallback(Networking::JsonResponse pair); - void finishStatus(ListDirectoryStatus status); + void responseCallback(Networking::JsonResponse response); + void errorCallback(Networking::ErrorResponse error); + void finishSuccess(Common::Array<StorageFile> &files); public: - DropboxListDirectoryRequest(Common::String token, Common::String path, Storage::ListDirectoryCallback cb, bool recursive = false); + DropboxListDirectoryRequest(Common::String token, Common::String path, Storage::ListDirectoryCallback cb, Networking::ErrorCallback ecb, bool recursive = false); virtual ~DropboxListDirectoryRequest(); virtual void handle(); virtual void restart(); - virtual void finish(); }; } // End of namespace Dropbox diff --git a/backends/cloud/dropbox/dropboxstorage.cpp b/backends/cloud/dropbox/dropboxstorage.cpp index b33e2b6776..d22e0abf60 100644 --- a/backends/cloud/dropbox/dropboxstorage.cpp +++ b/backends/cloud/dropbox/dropboxstorage.cpp @@ -96,118 +96,93 @@ void DropboxStorage::saveConfig(Common::String keyPrefix) { ConfMan.set(keyPrefix + "user_id", _uid, "cloud"); } -void DropboxStorage::printFiles(FileArrayResponse pair) { +void DropboxStorage::printFiles(FileArrayResponse response) { debug("files:"); - Common::Array<StorageFile> &files = pair.value; + Common::Array<StorageFile> &files = response.value; for (uint32 i = 0; i < files.size(); ++i) debug("\t%s", files[i].name().c_str()); } -void DropboxStorage::printBool(BoolResponse pair) { - debug("bool: %s", (pair.value?"true":"false")); +void DropboxStorage::printBool(BoolResponse response) { + debug("bool: %s", (response.value?"true":"false")); } -void DropboxStorage::printUploadStatus(UploadResponse pair) { - debug(" "); - UploadStatus status = pair.value; - if (status.interrupted) { - debug("upload interrupted by user"); - return; - } - if (status.failed) { - debug("upload failed with following response:"); - debug("%s", status.response.c_str()); - return; - } - debug("upload HTTP response code = %ld", status.httpResponseCode); - if (!status.failed) { - debug("uploaded file info:"); - debug("\tpath: %s", status.file.path().c_str()); - debug("\tsize: %u", status.file.size()); - debug("\ttimestamp: %u", status.file.timestamp()); - } +void DropboxStorage::printStorageFile(UploadResponse response) { + debug("\nuploaded file info:"); + debug("\tpath: %s", response.value.path().c_str()); + debug("\tsize: %u", response.value.size()); + debug("\ttimestamp: %u", response.value.timestamp()); } -Networking::Request *DropboxStorage::listDirectory(Common::String path, ListDirectoryCallback outerCallback, bool recursive) { - return ConnMan.addRequest(new DropboxListDirectoryRequest(_token, path, outerCallback, recursive)); +void DropboxStorage::printErrorResponse(Networking::ErrorResponse error) { + debug("error response (%s, %ld):", (error.failed ? "failed" : "interrupted"), error.httpResponseCode); + debug("%s", error.response.c_str()); } -Networking::Request *DropboxStorage::upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback) { - return ConnMan.addRequest(new DropboxUploadRequest(_token, path, contents, callback)); +Networking::ErrorCallback DropboxStorage::getErrorPrintingCallback() { + return new Common::Callback<DropboxStorage, Networking::ErrorResponse>(this, &DropboxStorage::printErrorResponse); } -Networking::Request *DropboxStorage::upload(Common::String remotePath, Common::String localPath, UploadCallback callback) { +Networking::Request *DropboxStorage::listDirectory(Common::String path, ListDirectoryCallback outerCallback, Networking::ErrorCallback errorCallback, bool recursive) { + return ConnMan.addRequest(new DropboxListDirectoryRequest(_token, path, outerCallback, errorCallback, recursive)); +} + +Networking::Request *DropboxStorage::upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback) { + return ConnMan.addRequest(new DropboxUploadRequest(_token, path, contents, callback, errorCallback)); +} + +Networking::Request *DropboxStorage::upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback) { Common::File *f = new Common::File(); if (!f->open(localPath)) { warning("DropboxStorage: unable to open file to upload from"); - UploadStatus status(false, true, StorageFile(), "", -1); - if (callback) (*callback)(UploadResponse(nullptr, status)); + if (errorCallback) (*errorCallback)(Networking::ErrorResponse(nullptr, false, true, "", -1)); + delete errorCallback; + delete callback; delete f; return nullptr; } - return upload(remotePath, f, callback); + return upload(remotePath, f, callback, errorCallback); } -Networking::Request *DropboxStorage::streamFile(Common::String path, Networking::NetworkReadStreamCallback callback) { +Networking::Request *DropboxStorage::streamFile(Common::String path, Networking::NetworkReadStreamCallback callback, Networking::ErrorCallback errorCallback) { Common::JSONObject jsonRequestParameters; jsonRequestParameters.setVal("path", new Common::JSONValue(path)); Common::JSONValue value(jsonRequestParameters); - Networking::CurlRequest *request = new Networking::CurlRequest(0, "https://content.dropboxapi.com/2/files/download"); + Networking::CurlRequest *request = new Networking::CurlRequest(nullptr, nullptr, "https://content.dropboxapi.com/2/files/download"); //TODO: is it right? request->addHeader("Authorization: Bearer " + _token); request->addHeader("Dropbox-API-Arg: " + Common::JSON::stringify(&value)); request->addHeader("Content-Type: "); //required to be empty (as we do POST, it's usually app/form-url-encoded) - Networking::NetworkReadStreamResponse pair = request->execute(); - if (callback) (*callback)(pair); - return pair.request; + Networking::NetworkReadStreamResponse response = request->execute(); + if (callback) (*callback)(response); + return response.request; } -Networking::Request *DropboxStorage::download(Common::String remotePath, Common::String localPath, BoolCallback callback) { +Networking::Request *DropboxStorage::download(Common::String remotePath, Common::String localPath, BoolCallback callback, Networking::ErrorCallback errorCallback) { Common::DumpFile *f = new Common::DumpFile(); if (!f->open(localPath, true)) { warning("DropboxStorage: unable to open file to download into"); - if (callback) (*callback)(BoolResponse(nullptr, false)); + if (errorCallback) (*errorCallback)(Networking::ErrorResponse(nullptr, false, true, "", -1)); delete f; return nullptr; } - return ConnMan.addRequest(new DownloadRequest(this, callback, remotePath, f)); + return ConnMan.addRequest(new DownloadRequest(this, callback, errorCallback, remotePath, f)); } -Networking::Request *DropboxStorage::downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, bool recursive) { - return ConnMan.addRequest(new FolderDownloadRequest(this, callback, remotePath, localPath, recursive)); +Networking::Request *DropboxStorage::downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, Networking::ErrorCallback errorCallback, bool recursive) { + return ConnMan.addRequest(new FolderDownloadRequest(this, callback, errorCallback, remotePath, localPath, recursive)); } -Networking::Request *DropboxStorage::syncSaves(BoolCallback callback) { - //this is not the real syncSaves() implementation - //"" is root in Dropbox, not "/" - //this must create all these directories: - //return download("/remote/test.jpg", "local/a/b/c/d/test.jpg", 0); - /* - return downloadFolder( - "/not_flat", "local/not_flat_1_level/", - new Common::Callback<DropboxStorage, FileArrayResponse>(this, &DropboxStorage::printFiles), - false - ); - */ - /* - debug("%s", ConfMan.get("savepath").c_str()); - Common::StringArray arr = g_system->getSavefileManager()->listSavefiles("*"); - for (uint32 i = 0; i < arr.size(); ++i) { - debug("%s", arr[i].c_str()); - } - debug("EOL"); - */ - //return upload("/remote/backslash", "C:\\Users\\Tkachov\\AppData\\Roaming\\ScummVM\\Saved games\\sword25.000", new Common::Callback<DropboxStorage, UploadResponse>(this, &DropboxStorage::printUploadStatus)); - //return upload("/remote/slash", "C:/Users/Tkachov/AppData/Roaming/ScummVM/Saved games/sword25.000", new Common::Callback<DropboxStorage, UploadResponse>(this, &DropboxStorage::printUploadStatus)); - return ConnMan.addRequest(new SavesSyncRequest(this, new Common::Callback<DropboxStorage, BoolResponse>(this, &DropboxStorage::printBool))); - //return upload("/remote/test4.bmp", "final.bmp", new Common::Callback<DropboxStorage, UploadResponse>(this, &DropboxStorage::printUploadStatus)); +Networking::Request *DropboxStorage::syncSaves(BoolCallback callback, Networking::ErrorCallback errorCallback) { + //this might be the real syncSaves() implementation + return ConnMan.addRequest(new SavesSyncRequest(this, new Common::Callback<DropboxStorage, BoolResponse>(this, &DropboxStorage::printBool), getErrorPrintingCallback())); //TODO } -Networking::Request *DropboxStorage::info(StorageInfoCallback outerCallback) { +Networking::Request *DropboxStorage::info(StorageInfoCallback outerCallback, Networking::ErrorCallback errorCallback) { Networking::JsonCallback innerCallback = new Common::CallbackBridge<DropboxStorage, StorageInfoResponse, Networking::JsonResponse>(this, &DropboxStorage::infoInnerCallback, outerCallback); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://api.dropboxapi.com/1/account/info"); + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, errorCallback, "https://api.dropboxapi.com/1/account/info"); request->addHeader("Authorization: Bearer " + _token); return ConnMan.addRequest(request); //that callback bridge wraps the outerCallback (passed in arguments from user) into innerCallback @@ -216,8 +191,8 @@ Networking::Request *DropboxStorage::info(StorageInfoCallback outerCallback) { //and then calls the outerCallback (which wants to receive StorageInfo, not void *) } -void DropboxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse pair) { - Common::JSONValue *json = pair.value; +void DropboxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse response) { + Common::JSONValue *json = response.value; if (!json) { warning("NULL passed instead of JSON"); delete outerCallback; @@ -241,11 +216,11 @@ void DropboxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networ delete json; } -void DropboxStorage::infoMethodCallback(StorageInfoResponse pair) { +void DropboxStorage::infoMethodCallback(StorageInfoResponse response) { debug("\nStorage info:"); - debug("User name: %s", pair.value.name().c_str()); - debug("Email: %s", pair.value.email().c_str()); - debug("Disk usage: %u/%u", pair.value.used(), pair.value.available()); + debug("User name: %s", response.value.name().c_str()); + debug("Email: %s", response.value.email().c_str()); + debug("Disk usage: %u/%u", response.value.used(), response.value.available()); } DropboxStorage *DropboxStorage::loadFromConfig(Common::String keyPrefix) { @@ -298,7 +273,7 @@ void DropboxStorage::authThroughConsole() { void DropboxStorage::getAccessToken(Common::String code) { Networking::JsonCallback callback = new Common::GlobalFunctionCallback<Networking::JsonResponse>(saveAccessTokenCallback); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, "https://api.dropboxapi.com/1/oauth2/token"); + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, nullptr, "https://api.dropboxapi.com/1/oauth2/token"); //TODO request->addPostField("code=" + code); request->addPostField("grant_type=authorization_code"); request->addPostField("client_id=" + Common::String(KEY)); diff --git a/backends/cloud/dropbox/dropboxstorage.h b/backends/cloud/dropbox/dropboxstorage.h index d9967d69f6..0082e5cebd 100644 --- a/backends/cloud/dropbox/dropboxstorage.h +++ b/backends/cloud/dropbox/dropboxstorage.h @@ -45,9 +45,12 @@ class DropboxStorage: public Cloud::Storage { /** Constructs StorageInfo based on JSON response from cloud. */ void infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse json); - void printFiles(FileArrayResponse pair); - void printBool(BoolResponse pair); - void printUploadStatus(UploadResponse pair); + void printFiles(FileArrayResponse response); + void printBool(BoolResponse response); + void printStorageFile(UploadResponse response); + void printErrorResponse(Networking::ErrorResponse error); + + Networking::ErrorCallback getErrorPrintingCallback(); public: virtual ~DropboxStorage(); @@ -68,38 +71,38 @@ public: /** Public Cloud API comes down there. */ /** Returns ListDirectoryStatus struct with list of files. */ - virtual Networking::Request *listDirectory(Common::String path, ListDirectoryCallback callback, bool recursive = false); + virtual Networking::Request *listDirectory(Common::String path, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback, bool recursive = false); /** Returns UploadStatus struct with info about uploaded file. */ - virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback); - virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback); + virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback); + virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback); /** Returns pointer to Networking::NetworkReadStream. */ - virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback); + virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback, Networking::ErrorCallback errorCallback); /** Calls the callback when finished. */ - virtual Networking::Request *download(Common::String remotePath, Common::String localPath, BoolCallback callback); + virtual Networking::Request *download(Common::String remotePath, Common::String localPath, BoolCallback callback, Networking::ErrorCallback errorCallback); /** Returns Common::Array<StorageFile> with list of files, which were not downloaded. */ - virtual Networking::Request *downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, bool recursive = false); + virtual Networking::Request *downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, Networking::ErrorCallback errorCallback, bool recursive = false); /** Calls the callback when finished. */ - virtual Networking::Request *remove(Common::String path, BoolCallback callback) { return nullptr; } //TODO + virtual Networking::Request *remove(Common::String path, BoolCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO /** Calls the callback when finished. */ - virtual Networking::Request *syncSaves(BoolCallback callback); + virtual Networking::Request *syncSaves(BoolCallback callback, Networking::ErrorCallback errorCallback); /** Calls the callback when finished. */ - virtual Networking::Request *createDirectory(Common::String path, BoolCallback callback) { return nullptr; } //TODO + virtual Networking::Request *createDirectory(Common::String path, BoolCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO /** Calls the callback when finished. */ - virtual Networking::Request *touch(Common::String path, BoolCallback callback) { return nullptr; } //TODO + virtual Networking::Request *touch(Common::String path, BoolCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO /** Returns the StorageInfo struct. */ - virtual Networking::Request *info(StorageInfoCallback callback); + virtual Networking::Request *info(StorageInfoCallback callback, Networking::ErrorCallback errorCallback); /** This method is passed into info(). (Temporary) */ - void infoMethodCallback(StorageInfoResponse pair); + void infoMethodCallback(StorageInfoResponse response); /** Returns whether saves sync process is running. */ virtual bool isSyncing() { return false; } //TODO diff --git a/backends/cloud/dropbox/dropboxuploadrequest.cpp b/backends/cloud/dropbox/dropboxuploadrequest.cpp index e64a8837b8..50a1b8a612 100644 --- a/backends/cloud/dropbox/dropboxuploadrequest.cpp +++ b/backends/cloud/dropbox/dropboxuploadrequest.cpp @@ -32,8 +32,8 @@ namespace Cloud { namespace Dropbox { -DropboxUploadRequest::DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::UploadCallback callback): - Networking::Request(0), _token(token), _savePath(path), _contentsStream(contents), _uploadCallback(callback), +DropboxUploadRequest::DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::UploadCallback callback, Networking::ErrorCallback ecb): + Networking::Request(nullptr, ecb), _token(token), _savePath(path), _contentsStream(contents), _uploadCallback(callback), _workingRequest(nullptr), _ignoreCallback(false) { start(); } @@ -50,7 +50,7 @@ void DropboxUploadRequest::start() { if (_workingRequest) _workingRequest->finish(); if (!_contentsStream->seek(0)) { warning("DropboxUploadRequest: cannot restart because stream couldn't seek(0)"); - finish(); + finishError(Networking::ErrorResponse(this, false, true, "", -1)); } _ignoreCallback = false; @@ -97,8 +97,9 @@ void DropboxUploadRequest::uploadNextPart() { } Common::JSONValue value(jsonRequestParameters); - Networking::JsonCallback innerCallback = new Common::Callback<DropboxUploadRequest, Networking::JsonResponse>(this, &DropboxUploadRequest::partUploadedCallback); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, url); + Networking::JsonCallback callback = new Common::Callback<DropboxUploadRequest, Networking::JsonResponse>(this, &DropboxUploadRequest::partUploadedCallback); + Networking::ErrorCallback failureCallback = new Common::Callback<DropboxUploadRequest, Networking::ErrorResponse>(this, &DropboxUploadRequest::partUploadedErrorCallback); + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, failureCallback, url); request->addHeader("Authorization: Bearer " + _token); request->addHeader("Content-Type: application/octet-stream"); request->addHeader("Dropbox-API-Arg: " + Common::JSON::stringify(&value)); @@ -110,46 +111,45 @@ void DropboxUploadRequest::uploadNextPart() { _workingRequest = ConnMan.addRequest(request); } -void DropboxUploadRequest::partUploadedCallback(Networking::JsonResponse pair) { - if (_ignoreCallback) return; +void DropboxUploadRequest::partUploadedCallback(Networking::JsonResponse response) { + debug("partUploadedCallback"); _workingRequest = nullptr; + if (_ignoreCallback) return; - UploadStatus status; - Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)pair.request; + Networking::ErrorResponse error(this, false, true, "", -1); + Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; if (rq && rq->getNetworkReadStream()) - status.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); + error.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); - Common::JSONValue *json = pair.value; + Common::JSONValue *json = response.value; if (json) { bool needsFinishRequest = false; if (json->isObject()) { - Common::JSONObject response = json->asObject(); + Common::JSONObject object = json->asObject(); //debug("%s", json->stringify(true).c_str()); - if (response.contains("error") || response.contains("error_summary")) { - warning("Dropbox returned error: %s", response.getVal("error_summary")->asString().c_str()); + if (object.contains("error") || object.contains("error_summary")) { + warning("Dropbox returned error: %s", object.getVal("error_summary")->asString().c_str()); delete json; - status.failed = true; - status.response = json->stringify(true); - finishUpload(status); + error.response = json->stringify(true); + finishError(error); return; } - if (response.contains("server_modified")) { + if (object.contains("server_modified")) { //finished - Common::String path = response.getVal("path_lower")->asString(); - uint32 size = response.getVal("size")->asIntegerNumber(); - uint32 timestamp = ISO8601::convertToTimestamp(response.getVal("server_modified")->asString()); - status.file = StorageFile(path, size, timestamp, false); - finishUpload(status); + Common::String path = object.getVal("path_lower")->asString(); + uint32 size = object.getVal("size")->asIntegerNumber(); + uint32 timestamp = ISO8601::convertToTimestamp(object.getVal("server_modified")->asString()); + finishSuccess(StorageFile(path, size, timestamp, false)); return; } if (_sessionId == "") { - if (response.contains("session_id")) - _sessionId = response.getVal("session_id")->asString(); + if (object.contains("session_id")) + _sessionId = object.getVal("session_id")->asString(); else warning("no session_id found in Dropbox's response"); needsFinishRequest = true; @@ -157,36 +157,33 @@ void DropboxUploadRequest::partUploadedCallback(Networking::JsonResponse pair) { } if (!needsFinishRequest && (_contentsStream->eos() || _contentsStream->pos() >= _contentsStream->size() - 1)) { - if (status.file.name() == "") { - status.file = StorageFile(_savePath, 0, 0, false); - warning("no file info to put into status"); - } - finishUpload(status); + warning("no file info to return"); + finishSuccess(StorageFile(_savePath, 0, 0, false)); } else { uploadNextPart(); } } else { - warning("null, not json"); - status.failed = true; - finishUpload(status); + warning("null, not json"); + finishError(error); } delete json; } +void DropboxUploadRequest::partUploadedErrorCallback(Networking::ErrorResponse error) { + debug("partUploadedErrorCallback"); + _workingRequest = nullptr; + if (_ignoreCallback) return; + finishError(error); +} + void DropboxUploadRequest::handle() {} void DropboxUploadRequest::restart() { start(); } -void DropboxUploadRequest::finish() { - UploadStatus status; - status.interrupted = true; - finishUpload(status); -} - -void DropboxUploadRequest::finishUpload(UploadStatus status) { - Request::finish(); - if (_uploadCallback) (*_uploadCallback)(Storage::UploadResponse(this, status)); +void DropboxUploadRequest::finishSuccess(StorageFile file) { + Request::finishSuccess(); + if (_uploadCallback) (*_uploadCallback)(Storage::UploadResponse(this, file)); } } // End of namespace Dropbox diff --git a/backends/cloud/dropbox/dropboxuploadrequest.h b/backends/cloud/dropbox/dropboxuploadrequest.h index 9b68995969..a85d7ef883 100644 --- a/backends/cloud/dropbox/dropboxuploadrequest.h +++ b/backends/cloud/dropbox/dropboxuploadrequest.h @@ -42,16 +42,16 @@ class DropboxUploadRequest: public Networking::Request { void start(); void uploadNextPart(); - void partUploadedCallback(Networking::JsonResponse pair); - void finishUpload(UploadStatus status); + void partUploadedCallback(Networking::JsonResponse response); + void partUploadedErrorCallback(Networking::ErrorResponse error); + void finishSuccess(StorageFile status); public: - DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::UploadCallback callback); + DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::UploadCallback callback, Networking::ErrorCallback ecb); virtual ~DropboxUploadRequest(); virtual void handle(); virtual void restart(); - virtual void finish(); }; } // End of namespace Dropbox diff --git a/backends/cloud/folderdownloadrequest.cpp b/backends/cloud/folderdownloadrequest.cpp index db132ffc8a..19f6c6c9b7 100644 --- a/backends/cloud/folderdownloadrequest.cpp +++ b/backends/cloud/folderdownloadrequest.cpp @@ -25,8 +25,8 @@ namespace Cloud { -FolderDownloadRequest::FolderDownloadRequest(Storage *storage, Storage::FileArrayCallback callback, Common::String remoteDirectoryPath, Common::String localDirectoryPath, bool recursive): - Request(nullptr), _storage(storage), _fileArrayCallback(callback), +FolderDownloadRequest::FolderDownloadRequest(Storage *storage, Storage::FileArrayCallback callback, Networking::ErrorCallback ecb, Common::String remoteDirectoryPath, Common::String localDirectoryPath, bool recursive): + Request(nullptr, ecb), _storage(storage), _fileArrayCallback(callback), _remoteDirectoryPath(remoteDirectoryPath), _localDirectoryPath(localDirectoryPath), _recursive(recursive), _workingRequest(nullptr), _ignoreCallback(false) { start(); @@ -51,33 +51,39 @@ void FolderDownloadRequest::start() { _workingRequest = _storage->listDirectory( _remoteDirectoryPath, new Common::Callback<FolderDownloadRequest, Storage::ListDirectoryResponse>(this, &FolderDownloadRequest::directoryListedCallback), + new Common::Callback<FolderDownloadRequest, Networking::ErrorResponse>(this, &FolderDownloadRequest::directoryListedErrorCallback), _recursive ); } -void FolderDownloadRequest::directoryListedCallback(Storage::ListDirectoryResponse pair) { +void FolderDownloadRequest::directoryListedCallback(Storage::ListDirectoryResponse response) { + _workingRequest = nullptr; if (_ignoreCallback) return; - - ListDirectoryStatus status = pair.value; - if (status.failed || status.interrupted) { - finish(); - return; - } - - _files = pair.value.files; + _files = response.value; downloadNextFile(); } -void FolderDownloadRequest::fileDownloadedCallback(Storage::BoolResponse pair) { +void FolderDownloadRequest::directoryListedErrorCallback(Networking::ErrorResponse error) { + _workingRequest = nullptr; + if (_ignoreCallback) return; + finishError(error); +} + +void FolderDownloadRequest::fileDownloadedCallback(Storage::BoolResponse response) { + _workingRequest = nullptr; if (_ignoreCallback) return; - if (!pair.value) _failedFiles.push_back(_currentFile); + if (!response.value) _failedFiles.push_back(_currentFile); downloadNextFile(); } +void FolderDownloadRequest::fileDownloadedErrorCallback(Networking::ErrorResponse error) { + fileDownloadedCallback(Storage::BoolResponse(error.request, false)); +} + void FolderDownloadRequest::downloadNextFile() { do { if (_files.empty()) { - finishFiles(_failedFiles); + finishSuccess(_failedFiles); return; } @@ -105,18 +111,17 @@ void FolderDownloadRequest::downloadNextFile() { debug("%s -> %s", remotePath.c_str(), localPath.c_str()); _workingRequest = _storage->download( remotePath, localPath, - new Common::Callback<FolderDownloadRequest, Storage::BoolResponse>(this, &FolderDownloadRequest::fileDownloadedCallback) + new Common::Callback<FolderDownloadRequest, Storage::BoolResponse>(this, &FolderDownloadRequest::fileDownloadedCallback), + new Common::Callback<FolderDownloadRequest, Networking::ErrorResponse>(this, &FolderDownloadRequest::fileDownloadedErrorCallback) ); } -void FolderDownloadRequest::finish() { - //TODO: somehow indicate that request was interrupted - Common::Array<StorageFile> files; - finishFiles(files); -} +void FolderDownloadRequest::handle() {} + +void FolderDownloadRequest::restart() { start(); } -void FolderDownloadRequest::finishFiles(Common::Array<StorageFile> &files) { - Request::finish(); +void FolderDownloadRequest::finishSuccess(Common::Array<StorageFile> &files) { + Request::finishSuccess(); if (_fileArrayCallback) (*_fileArrayCallback)(Storage::FileArrayResponse(this, files)); } diff --git a/backends/cloud/folderdownloadrequest.h b/backends/cloud/folderdownloadrequest.h index 779ea3334f..8fa3b1188b 100644 --- a/backends/cloud/folderdownloadrequest.h +++ b/backends/cloud/folderdownloadrequest.h @@ -40,17 +40,18 @@ class FolderDownloadRequest: public Networking::Request { bool _ignoreCallback; void start(); - void directoryListedCallback(Storage::ListDirectoryResponse pair); - void fileDownloadedCallback(Storage::BoolResponse pair); + void directoryListedCallback(Storage::ListDirectoryResponse response); + void directoryListedErrorCallback(Networking::ErrorResponse error); + void fileDownloadedCallback(Storage::BoolResponse response); + void fileDownloadedErrorCallback(Networking::ErrorResponse error); void downloadNextFile(); - void finishFiles(Common::Array<StorageFile> &files); + void finishSuccess(Common::Array<StorageFile> &files); public: - FolderDownloadRequest(Storage *storage, Storage::FileArrayCallback callback, Common::String remoteDirectoryPath, Common::String localDirectoryPath, bool recursive); + FolderDownloadRequest(Storage *storage, Storage::FileArrayCallback callback, Networking::ErrorCallback ecb, Common::String remoteDirectoryPath, Common::String localDirectoryPath, bool recursive); virtual ~FolderDownloadRequest(); - virtual void handle() {} - virtual void restart() { start(); } - virtual void finish(); + virtual void handle(); + virtual void restart(); }; } // End of namespace Cloud diff --git a/backends/cloud/manager.cpp b/backends/cloud/manager.cpp index 13f23b8e6e..2f1533c50d 100644 --- a/backends/cloud/manager.cpp +++ b/backends/cloud/manager.cpp @@ -110,9 +110,9 @@ Storage *Manager::getCurrentStorage() { return nullptr; } -void Manager::syncSaves(Storage::BoolCallback callback) { +void Manager::syncSaves(Storage::BoolCallback callback, Networking::ErrorCallback errorCallback) { Storage *storage = getCurrentStorage(); - if (storage) storage->syncSaves(callback); + if (storage) storage->syncSaves(callback, errorCallback); } } // End of namespace Cloud diff --git a/backends/cloud/manager.h b/backends/cloud/manager.h index f472b80ae3..013e117046 100644 --- a/backends/cloud/manager.h +++ b/backends/cloud/manager.h @@ -42,7 +42,7 @@ public: virtual void addStorage(Cloud::Storage *storage, bool makeCurrent = true, bool saveConfig = true); virtual Storage *getCurrentStorage(); - virtual void syncSaves(Storage::BoolCallback callback); + virtual void syncSaves(Storage::BoolCallback callback, Networking::ErrorCallback errorCallback); }; } // End of namespace Cloud diff --git a/backends/cloud/onedrive/onedrivelistdirectoryrequest.cpp b/backends/cloud/onedrive/onedrivelistdirectoryrequest.cpp index dbd5e44c0b..e362600389 100644 --- a/backends/cloud/onedrive/onedrivelistdirectoryrequest.cpp +++ b/backends/cloud/onedrive/onedrivelistdirectoryrequest.cpp @@ -31,8 +31,8 @@ namespace Cloud { namespace OneDrive { -OneDriveListDirectoryRequest::OneDriveListDirectoryRequest(OneDriveStorage *storage, Common::String path, Storage::ListDirectoryCallback cb, bool recursive): - Networking::Request(0), +OneDriveListDirectoryRequest::OneDriveListDirectoryRequest(OneDriveStorage *storage, Common::String path, Storage::ListDirectoryCallback cb, Networking::ErrorCallback ecb, bool recursive): + Networking::Request(nullptr, ecb), _requestedPath(path), _requestedRecursive(recursive), _storage(storage), _listDirectoryCallback(cb), _workingRequest(nullptr), _ignoreCallback(false) { start(); @@ -55,12 +55,12 @@ void OneDriveListDirectoryRequest::start() { _ignoreCallback = false; _directoriesQueue.push_back(_requestedPath); - listNextDirectory(_files); + listNextDirectory(); } -void OneDriveListDirectoryRequest::listNextDirectory(ListDirectoryStatus status) { +void OneDriveListDirectoryRequest::listNextDirectory() { if (_directoriesQueue.empty()) { - finishStatus(status); + finishSuccess(_files); return; } @@ -78,36 +78,37 @@ void OneDriveListDirectoryRequest::listNextDirectory(ListDirectoryStatus status) void OneDriveListDirectoryRequest::makeRequest(Common::String url) { Networking::JsonCallback callback = new Common::Callback<OneDriveListDirectoryRequest, Networking::JsonResponse>(this, &OneDriveListDirectoryRequest::listedDirectoryCallback); - Networking::CurlJsonRequest *request = new OneDriveTokenRefresher(_storage, callback, url.c_str()); + Networking::ErrorCallback failureCallback = new Common::Callback<OneDriveListDirectoryRequest, Networking::ErrorResponse>(this, &OneDriveListDirectoryRequest::listedDirectoryErrorCallback); + Networking::CurlJsonRequest *request = new OneDriveTokenRefresher(_storage, callback, failureCallback, url.c_str()); request->addHeader("Authorization: Bearer " + _storage->accessToken()); _workingRequest = ConnMan.addRequest(request); } -void OneDriveListDirectoryRequest::listedDirectoryCallback(Networking::JsonResponse pair) { +void OneDriveListDirectoryRequest::listedDirectoryCallback(Networking::JsonResponse response) { _workingRequest = nullptr; - Common::JSONValue *json = pair.value; + Common::JSONValue *json = response.value; if (_ignoreCallback) { delete json; return; } - ListDirectoryStatus status(_files); - Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)pair.request; + Networking::ErrorResponse error(this); + Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; if (rq && rq->getNetworkReadStream()) - status.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); + error.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); if (!json) { - status.failed = true; - finishStatus(status); + error.failed = true; + finishError(error); return; } - Common::JSONObject response = json->asObject(); + Common::JSONObject object = json->asObject(); //TODO: check that ALL keys exist AND HAVE RIGHT TYPE to avoid segfaults - Common::JSONArray items = response.getVal("value")->asArray(); + Common::JSONArray items = object.getVal("value")->asArray(); for (uint32 i = 0; i < items.size(); ++i) { Common::JSONObject item = items[i]->asObject(); @@ -123,26 +124,29 @@ void OneDriveListDirectoryRequest::listedDirectoryCallback(Networking::JsonRespo } } - bool hasMore = response.contains("@odata.nextLink"); + bool hasMore = object.contains("@odata.nextLink"); if (hasMore) { - makeRequest(response.getVal("@odata.nextLink")->asString()); + makeRequest(object.getVal("@odata.nextLink")->asString()); } else { - listNextDirectory(status); + listNextDirectory(); } delete json; } -void OneDriveListDirectoryRequest::finish() { - Common::Array<StorageFile> files; - ListDirectoryStatus status(files); - status.interrupted = true; - finishStatus(status); +void OneDriveListDirectoryRequest::listedDirectoryErrorCallback(Networking::ErrorResponse error) { + _workingRequest = nullptr; + if (_ignoreCallback) return; + finishError(error); } -void OneDriveListDirectoryRequest::finishStatus(ListDirectoryStatus status) { - Request::finish(); - if (_listDirectoryCallback) (*_listDirectoryCallback)(Storage::ListDirectoryResponse(this, status)); +void OneDriveListDirectoryRequest::handle() {} + +void OneDriveListDirectoryRequest::restart() { start(); } + +void OneDriveListDirectoryRequest::finishSuccess(Common::Array<StorageFile> &files) { + Request::finishSuccess(); + if (_listDirectoryCallback) (*_listDirectoryCallback)(Storage::ListDirectoryResponse(this, files)); } } // End of namespace OneDrive diff --git a/backends/cloud/onedrive/onedrivelistdirectoryrequest.h b/backends/cloud/onedrive/onedrivelistdirectoryrequest.h index a05dd871dd..b8adfe7ef0 100644 --- a/backends/cloud/onedrive/onedrivelistdirectoryrequest.h +++ b/backends/cloud/onedrive/onedrivelistdirectoryrequest.h @@ -45,17 +45,17 @@ class OneDriveListDirectoryRequest: public Networking::Request { bool _ignoreCallback; void start(); - void listNextDirectory(ListDirectoryStatus status); - void listedDirectoryCallback(Networking::JsonResponse pair); + void listNextDirectory(); + void listedDirectoryCallback(Networking::JsonResponse response); + void listedDirectoryErrorCallback(Networking::ErrorResponse error); void makeRequest(Common::String url); - void finishStatus(ListDirectoryStatus status); + void finishSuccess(Common::Array<StorageFile> &files); public: - OneDriveListDirectoryRequest(OneDriveStorage *storage, Common::String path, Storage::ListDirectoryCallback cb, bool recursive = false); + OneDriveListDirectoryRequest(OneDriveStorage *storage, Common::String path, Storage::ListDirectoryCallback cb, Networking::ErrorCallback ecb, bool recursive = false); virtual ~OneDriveListDirectoryRequest(); - virtual void handle() {} - virtual void restart() { start(); } - virtual void finish(); + virtual void handle(); + virtual void restart(); }; } // End of namespace OneDrive diff --git a/backends/cloud/onedrive/onedrivestorage.cpp b/backends/cloud/onedrive/onedrivestorage.cpp index b0f4f7be65..8746b7ab33 100644 --- a/backends/cloud/onedrive/onedrivestorage.cpp +++ b/backends/cloud/onedrive/onedrivestorage.cpp @@ -74,7 +74,7 @@ void OneDriveStorage::getAccessToken(BoolCallback callback, Common::String code) } Networking::JsonCallback innerCallback = new Common::CallbackBridge<OneDriveStorage, BoolResponse, Networking::JsonResponse>(this, &OneDriveStorage::tokenRefreshed, callback); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://login.live.com/oauth20_token.srf"); + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, getErrorPrintingCallback(), "https://login.live.com/oauth20_token.srf"); //TODO if (codeFlow) { request->addPostField("code=" + code); request->addPostField("grant_type=authorization_code"); @@ -88,8 +88,8 @@ void OneDriveStorage::getAccessToken(BoolCallback callback, Common::String code) ConnMan.addRequest(request); } -void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResponse pair) { - Common::JSONValue *json = pair.value; +void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResponse response) { + Common::JSONValue *json = response.value; if (!json) { warning("OneDriveStorage: got NULL instead of JSON"); if (callback) (*callback)(BoolResponse(nullptr, false)); @@ -111,8 +111,8 @@ void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResp delete json; } -void OneDriveStorage::codeFlowComplete(BoolResponse pair) { - if (!pair.value) { +void OneDriveStorage::codeFlowComplete(BoolResponse response) { + if (!response.value) { warning("OneDriveStorage: failed to get access token through code flow"); return; } @@ -130,8 +130,8 @@ void OneDriveStorage::saveConfig(Common::String keyPrefix) { ConfMan.set(keyPrefix + "refresh_token", _refreshToken, "cloud"); } -void OneDriveStorage::printJson(Networking::JsonResponse pair) { - Common::JSONValue *json = pair.value; +void OneDriveStorage::printJson(Networking::JsonResponse response) { + Common::JSONValue *json = response.value; if (!json) { warning("printJson: NULL"); return; @@ -141,77 +141,85 @@ void OneDriveStorage::printJson(Networking::JsonResponse pair) { delete json; } -void OneDriveStorage::fileInfoCallback(Networking::NetworkReadStreamCallback outerCallback, Networking::JsonResponse pair) { - if (!pair.value) { +void OneDriveStorage::fileInfoCallback(Networking::NetworkReadStreamCallback outerCallback, Networking::JsonResponse response) { + if (!response.value) { warning("fileInfoCallback: NULL"); - if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(pair.request, 0)); + if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(response.request, 0)); return; } - Common::JSONObject result = pair.value->asObject(); + Common::JSONObject result = response.value->asObject(); if (result.contains("@content.downloadUrl")) { const char *url = result.getVal("@content.downloadUrl")->asString().c_str(); if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse( - pair.request, + response.request, new Networking::NetworkReadStream(url, 0, "") )); } else { warning("downloadUrl not found in passed JSON"); - debug("%s", pair.value->stringify().c_str()); - if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(pair.request, 0)); + debug("%s", response.value->stringify().c_str()); + if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(response.request, 0)); } - delete pair.value; + delete response.value; } -Networking::Request *OneDriveStorage::listDirectory(Common::String path, ListDirectoryCallback callback, bool recursive) { - return ConnMan.addRequest(new OneDriveListDirectoryRequest(this, path, callback, recursive)); +Networking::Request *OneDriveStorage::listDirectory(Common::String path, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback, bool recursive) { + return ConnMan.addRequest(new OneDriveListDirectoryRequest(this, path, callback, errorCallback, recursive)); } -Networking::Request *OneDriveStorage::streamFile(Common::String path, Networking::NetworkReadStreamCallback outerCallback) { +Networking::Request *OneDriveStorage::streamFile(Common::String path, Networking::NetworkReadStreamCallback outerCallback, Networking::ErrorCallback errorCallback) { Common::String url = "https://api.onedrive.com/v1.0/drive/special/approot:/" + path; Networking::JsonCallback innerCallback = new Common::CallbackBridge<OneDriveStorage, Networking::NetworkReadStreamResponse, Networking::JsonResponse>(this, &OneDriveStorage::fileInfoCallback, outerCallback); - Networking::CurlJsonRequest *request = new OneDriveTokenRefresher(this, innerCallback, url.c_str()); + Networking::CurlJsonRequest *request = new OneDriveTokenRefresher(this, innerCallback, errorCallback, url.c_str()); request->addHeader("Authorization: Bearer " + _token); return ConnMan.addRequest(request); } -Networking::Request *OneDriveStorage::download(Common::String remotePath, Common::String localPath, BoolCallback callback) { +Networking::Request *OneDriveStorage::download(Common::String remotePath, Common::String localPath, BoolCallback callback, Networking::ErrorCallback errorCallback) { Common::DumpFile *f = new Common::DumpFile(); if (!f->open(localPath, true)) { warning("OneDriveStorage: unable to open file to download into"); - if (callback) (*callback)(BoolResponse(nullptr, false)); + if (errorCallback) (*errorCallback)(Networking::ErrorResponse(nullptr, false, true, "", -1)); delete f; return nullptr; } - return ConnMan.addRequest(new DownloadRequest(this, callback, remotePath, f)); + return ConnMan.addRequest(new DownloadRequest(this, callback, errorCallback, remotePath, f)); } /** Returns Common::Array<StorageFile> with list of files, which were not downloaded. */ -Networking::Request *OneDriveStorage::downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, bool recursive) { - return ConnMan.addRequest(new FolderDownloadRequest(this, callback, remotePath, localPath, recursive)); +Networking::Request *OneDriveStorage::downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, Networking::ErrorCallback errorCallback, bool recursive) { + return ConnMan.addRequest(new FolderDownloadRequest(this, callback, errorCallback, remotePath, localPath, recursive)); } -void OneDriveStorage::fileDownloaded(BoolResponse pair) { - if (pair.value) debug("file downloaded!"); +void OneDriveStorage::fileDownloaded(BoolResponse response) { + if (response.value) debug("file downloaded!"); else debug("download failed!"); } -void OneDriveStorage::printFiles(FileArrayResponse pair) { +void OneDriveStorage::printFiles(FileArrayResponse response) { debug("files:"); - Common::Array<StorageFile> &files = pair.value; + Common::Array<StorageFile> &files = response.value; for (uint32 i = 0; i < files.size(); ++i) debug("\t%s", files[i].path().c_str()); } -void OneDriveStorage::printBool(BoolResponse pair) { - debug("bool: %s", pair.value ? "true" : "false"); +void OneDriveStorage::printBool(BoolResponse response) { + debug("bool: %s", response.value ? "true" : "false"); +} + +void OneDriveStorage::printErrorResponse(Networking::ErrorResponse error) { + debug("error response (%s, %ld):", (error.failed ? "failed" : "interrupted"), error.httpResponseCode); + debug("%s", error.response.c_str()); } +Networking::ErrorCallback OneDriveStorage::getErrorPrintingCallback() { + return new Common::Callback<OneDriveStorage, Networking::ErrorResponse>(this, &OneDriveStorage::printErrorResponse); +} -Networking::Request *OneDriveStorage::syncSaves(BoolCallback callback) { +Networking::Request *OneDriveStorage::syncSaves(BoolCallback callback, Networking::ErrorCallback errorCallback) { //this is not the real syncSaves() implementation /* Networking::JsonCallback innerCallback = new Common::Callback<OneDriveStorage, Networking::RequestJsonPair>(this, &OneDriveStorage::printJson); @@ -220,7 +228,7 @@ Networking::Request *OneDriveStorage::syncSaves(BoolCallback callback) { return ConnMan.addRequest(request); */ //return downloadFolder("subfolder", "local/onedrive/subfolder_downloaded", new Common::Callback<OneDriveStorage, FileArrayResponse>(this, &OneDriveStorage::printFiles), false); - return ConnMan.addRequest(new SavesSyncRequest(this, new Common::Callback<OneDriveStorage, BoolResponse>(this, &OneDriveStorage::printBool))); + return ConnMan.addRequest(new SavesSyncRequest(this, new Common::Callback<OneDriveStorage, BoolResponse>(this, &OneDriveStorage::printBool), getErrorPrintingCallback())); //TODO } OneDriveStorage *OneDriveStorage::loadFromConfig(Common::String keyPrefix) { diff --git a/backends/cloud/onedrive/onedrivestorage.h b/backends/cloud/onedrive/onedrivestorage.h index 43675fbfa5..f95ea89bc1 100644 --- a/backends/cloud/onedrive/onedrivestorage.h +++ b/backends/cloud/onedrive/onedrivestorage.h @@ -46,15 +46,18 @@ class OneDriveStorage: public Cloud::Storage { */ OneDriveStorage(Common::String code); - void tokenRefreshed(BoolCallback callback, Networking::JsonResponse pair); - void codeFlowComplete(BoolResponse pair); + void tokenRefreshed(BoolCallback callback, Networking::JsonResponse response); + void codeFlowComplete(BoolResponse response); - void printJson(Networking::JsonResponse pair); - void fileDownloaded(BoolResponse pair); - void printFiles(FileArrayResponse pair); - void printBool(BoolResponse pair); + void printJson(Networking::JsonResponse response); + void fileDownloaded(BoolResponse response); + void printFiles(FileArrayResponse response); + void printBool(BoolResponse response); + void printErrorResponse(Networking::ErrorResponse error); - void fileInfoCallback(Networking::NetworkReadStreamCallback outerCallback, Networking::JsonResponse pair); + Networking::ErrorCallback getErrorPrintingCallback(); + + void fileInfoCallback(Networking::NetworkReadStreamCallback outerCallback, Networking::JsonResponse response); public: virtual ~OneDriveStorage(); @@ -74,35 +77,35 @@ public: /** Public Cloud API comes down there. */ /** Returns ListDirectoryStatus struct with list of files. */ - virtual Networking::Request *listDirectory(Common::String path, ListDirectoryCallback callback, bool recursive = false); + virtual Networking::Request *listDirectory(Common::String path, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback, bool recursive = false); /** Returns UploadStatus struct with info about uploaded file. */ - virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback) { return nullptr; } //TODO - virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback) { return nullptr; } + virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO + virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO /** Returns pointer to Networking::NetworkReadStream. */ - virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback); + virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback, Networking::ErrorCallback errorCallback); /** Calls the callback when finished. */ - virtual Networking::Request *download(Common::String remotePath, Common::String localPath, BoolCallback callback); + virtual Networking::Request *download(Common::String remotePath, Common::String localPath, BoolCallback callback, Networking::ErrorCallback errorCallback); /** Returns Common::Array<StorageFile> with list of files, which were not downloaded. */ - virtual Networking::Request *downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, bool recursive = false); + virtual Networking::Request *downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, Networking::ErrorCallback errorCallback, bool recursive = false); /** Calls the callback when finished. */ - virtual Networking::Request *remove(Common::String path, BoolCallback callback) { return nullptr; } //TODO + virtual Networking::Request *remove(Common::String path, BoolCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO /** Calls the callback when finished. */ - virtual Networking::Request *syncSaves(BoolCallback callback); + virtual Networking::Request *syncSaves(BoolCallback callback, Networking::ErrorCallback errorCallback); /** Calls the callback when finished. */ - virtual Networking::Request *createDirectory(Common::String path, BoolCallback callback) { return nullptr; } //TODO + virtual Networking::Request *createDirectory(Common::String path, BoolCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO /** Calls the callback when finished. */ - virtual Networking::Request *touch(Common::String path, BoolCallback callback) { return nullptr; } //TODO + virtual Networking::Request *touch(Common::String path, BoolCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO /** Returns the StorageInfo struct. */ - virtual Networking::Request *info(StorageInfoCallback callback) { return nullptr; } //TODO + virtual Networking::Request *info(StorageInfoCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO /** Returns whether saves sync process is running. */ virtual bool isSyncing() { return false; } //TODO diff --git a/backends/cloud/onedrive/onedrivetokenrefresher.cpp b/backends/cloud/onedrive/onedrivetokenrefresher.cpp index a0c41ff471..bc7bd74dbe 100644 --- a/backends/cloud/onedrive/onedrivetokenrefresher.cpp +++ b/backends/cloud/onedrive/onedrivetokenrefresher.cpp @@ -31,16 +31,16 @@ namespace Cloud { namespace OneDrive { -OneDriveTokenRefresher::OneDriveTokenRefresher(OneDriveStorage *parent, Networking::JsonCallback callback, const char *url): - CurlJsonRequest(callback, url), _parentStorage(parent) {} +OneDriveTokenRefresher::OneDriveTokenRefresher(OneDriveStorage *parent, Networking::JsonCallback callback, Networking::ErrorCallback ecb, const char *url): + CurlJsonRequest(callback, ecb, url), _parentStorage(parent) {} OneDriveTokenRefresher::~OneDriveTokenRefresher() {} -void OneDriveTokenRefresher::tokenRefreshed(Storage::BoolResponse pair) { - if (!pair.value) { +void OneDriveTokenRefresher::tokenRefreshed(Storage::BoolResponse response) { + if (!response.value) { //failed to refresh token, notify user with NULL in original callback warning("OneDriveTokenRefresher: failed to refresh token"); - finish(); + finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } @@ -56,11 +56,10 @@ void OneDriveTokenRefresher::tokenRefreshed(Storage::BoolResponse pair) { retry(0); } -void OneDriveTokenRefresher::finishJson(Common::JSONValue *json) { +void OneDriveTokenRefresher::finishSuccess(Common::JSONValue *json) { if (!json) { - //notify user of failure - warning("OneDriveTokenRefresher: got NULL instead of JSON"); - CurlJsonRequest::finishJson(nullptr); + //that's probably not an error (200 OK) + CurlJsonRequest::finishSuccess(nullptr); return; } @@ -74,19 +73,26 @@ void OneDriveTokenRefresher::finishJson(Common::JSONValue *json) { Common::JSONObject error = result.getVal("error")->asObject(); bool irrecoverable = true; + Common::String code, message; if (error.contains("code")) { - Common::String code = error.getVal("code")->asString(); - debug("code = %s", code.c_str()); - //if (code == "itemNotFound") irrecoverable = true; + code = error.getVal("code")->asString(); + debug("code = %s", code.c_str()); } if (error.contains("message")) { - Common::String message = error.getVal("message")->asString(); + message = error.getVal("message")->asString(); debug("message = %s", message.c_str()); } - if (irrecoverable) { - CurlJsonRequest::finishJson(nullptr); + //determine whether token refreshing would help in this situation + if (code == "itemNotFound") { + if (message.contains("application ID")) + irrecoverable = false; + } + + if (irrecoverable) { + finishError(Networking::ErrorResponse(this, false, true, json->stringify(true), -1)); //TODO: httpCode + delete json; return; } @@ -97,7 +103,7 @@ void OneDriveTokenRefresher::finishJson(Common::JSONValue *json) { } //notify user of success - CurlJsonRequest::finishJson(json); + CurlJsonRequest::finishSuccess(json); } void OneDriveTokenRefresher::setHeaders(Common::Array<Common::String> &headers) { @@ -108,6 +114,10 @@ void OneDriveTokenRefresher::setHeaders(Common::Array<Common::String> &headers) CurlJsonRequest::addHeader(headers[i]); } +void OneDriveTokenRefresher::addHeader(Common::String header) { + _headers.push_back(header); + CurlJsonRequest::addHeader(header); +} } // End of namespace OneDrive } // End of namespace Cloud diff --git a/backends/cloud/onedrive/onedrivetokenrefresher.h b/backends/cloud/onedrive/onedrivetokenrefresher.h index 90ca9d603a..04b0bf26b8 100644 --- a/backends/cloud/onedrive/onedrivetokenrefresher.h +++ b/backends/cloud/onedrive/onedrivetokenrefresher.h @@ -35,19 +35,15 @@ class OneDriveTokenRefresher: public Networking::CurlJsonRequest { OneDriveStorage *_parentStorage; Common::Array<Common::String> _headers; - void tokenRefreshed(Storage::BoolResponse pair); + void tokenRefreshed(Storage::BoolResponse response); - virtual void finishJson(Common::JSONValue *json); + virtual void finishSuccess(Common::JSONValue *json); public: - OneDriveTokenRefresher(OneDriveStorage *parent, Networking::JsonCallback callback, const char *url); + OneDriveTokenRefresher(OneDriveStorage *parent, Networking::JsonCallback callback, Networking::ErrorCallback ecb, const char *url); virtual ~OneDriveTokenRefresher(); virtual void setHeaders(Common::Array<Common::String> &headers); - - virtual void addHeader(Common::String header) { - _headers.push_back(header); - CurlJsonRequest::addHeader(header); - } + virtual void addHeader(Common::String header); }; } // End of namespace OneDrive diff --git a/backends/cloud/savessyncrequest.cpp b/backends/cloud/savessyncrequest.cpp index e632bfff84..b48a99a48c 100644 --- a/backends/cloud/savessyncrequest.cpp +++ b/backends/cloud/savessyncrequest.cpp @@ -32,8 +32,8 @@ namespace Cloud { const char *SavesSyncRequest::TIMESTAMPS_FILENAME = "timestamps"; -SavesSyncRequest::SavesSyncRequest(Storage *storage, Storage::BoolCallback callback): - Request(nullptr), _storage(storage), _boolCallback(callback), +SavesSyncRequest::SavesSyncRequest(Storage *storage, Storage::BoolCallback callback, Networking::ErrorCallback ecb): + Request(nullptr, ecb), _storage(storage), _boolCallback(callback), _workingRequest(nullptr), _ignoreCallback(false) { start(); } @@ -59,48 +59,35 @@ void SavesSyncRequest::start() { loadTimestamps(); //list saves directory - _workingRequest = _storage->listDirectory("/saves", new Common::Callback<SavesSyncRequest, Storage::ListDirectoryResponse>(this, &SavesSyncRequest::directoryListedCallback)); + _workingRequest = _storage->listDirectory( + "/saves", + new Common::Callback<SavesSyncRequest, Storage::ListDirectoryResponse>(this, &SavesSyncRequest::directoryListedCallback), + new Common::Callback<SavesSyncRequest, Networking::ErrorResponse>(this, &SavesSyncRequest::directoryListedErrorCallback) + ); } -void SavesSyncRequest::directoryListedCallback(Storage::ListDirectoryResponse pair) { +void SavesSyncRequest::directoryListedCallback(Storage::ListDirectoryResponse response) { _workingRequest = nullptr; if (_ignoreCallback) return; - ListDirectoryStatus status = pair.value; - bool irrecoverable = status.interrupted || status.failed; - if (status.failed) { - Common::JSONValue *value = Common::JSON::parse(status.response.c_str()); - if (value) { - if (value->isObject()) { - Common::JSONObject object = value->asObject(); - //Dropbox-related error: - if (object.contains("error_summary")) { - Common::String summary = object.getVal("error_summary")->asString(); - if (summary.contains("not_found")) { - //oh how lucky we are! It's just user don't have /cloud/ folder yet! - irrecoverable = false; - } - } - } - delete value; - } + Common::HashMap<Common::String, bool> localFileNotAvailableInCloud; + for (Common::HashMap<Common::String, uint32>::iterator i = _localFilesTimestamps.begin(); i != _localFilesTimestamps.end(); ++i) { + localFileNotAvailableInCloud[i->_key] = true; } - if (irrecoverable) { - finishBool(false); - return; - } - //determine which files to download and which files to upload - Common::Array<StorageFile> &remoteFiles = status.files; + Common::Array<StorageFile> &remoteFiles = response.value; for (uint32 i = 0; i < remoteFiles.size(); ++i) { StorageFile &file = remoteFiles[i]; if (file.isDirectory()) continue; if (file.name() == TIMESTAMPS_FILENAME) continue; + Common::String name = file.name(); if (!_localFilesTimestamps.contains(name)) _filesToDownload.push_back(file); else { + localFileNotAvailableInCloud[name] = false; + if (_localFilesTimestamps[name] != INVALID_TIMESTAMP) { if (_localFilesTimestamps[name] == file.timestamp()) continue; @@ -115,11 +102,10 @@ void SavesSyncRequest::directoryListedCallback(Storage::ListDirectoryResponse pa } } - //upload files with invalid timestamp (the ones we've added - means they might not have any remote version) - for (Common::HashMap<Common::String, uint32>::iterator i = _localFilesTimestamps.begin(); i != _localFilesTimestamps.end(); ++i) { + //upload files which are unavailable in cloud + for (Common::HashMap<Common::String, bool>::iterator i = localFileNotAvailableInCloud.begin(); i != localFileNotAvailableInCloud.end(); ++i) { if (i->_key == TIMESTAMPS_FILENAME) continue; - if (i->_value == INVALID_TIMESTAMP) - _filesToUpload.push_back(i->_key); + if (i->_value) _filesToUpload.push_back(i->_key); } /////// @@ -137,6 +123,50 @@ void SavesSyncRequest::directoryListedCallback(Storage::ListDirectoryResponse pa downloadNextFile(); } +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")) { + 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 (errorNode.contains("code") && errorNode.contains("message")) { + Common::String code = errorNode.getVal("code")->asString(); + if (code == "itemNotFound") { + irrecoverable = false; + } + } + } + } + delete value; + } + } + + if (irrecoverable) { + finishError(error); + return; + } + + //we're lucky - user just lacks his "/cloud/" folder + Common::Array<StorageFile> files; + directoryListedCallback(Storage::ListDirectoryResponse(error.request, files)); +} + void SavesSyncRequest::downloadNextFile() { if (_filesToDownload.empty()) { uploadNextFile(); @@ -150,17 +180,18 @@ void SavesSyncRequest::downloadNextFile() { debug("downloading %s", _currentDownloadingFile.name().c_str()); /////// _workingRequest = _storage->download(_currentDownloadingFile.path(), concatWithSavesPath(_currentDownloadingFile.name()), - new Common::Callback<SavesSyncRequest, Storage::BoolResponse>(this, &SavesSyncRequest::fileDownloadedCallback) + new Common::Callback<SavesSyncRequest, Storage::BoolResponse>(this, &SavesSyncRequest::fileDownloadedCallback), + new Common::Callback<SavesSyncRequest, Networking::ErrorResponse>(this, &SavesSyncRequest::fileDownloadedErrorCallback) ); } -void SavesSyncRequest::fileDownloadedCallback(Storage::BoolResponse pair) { +void SavesSyncRequest::fileDownloadedCallback(Storage::BoolResponse response) { _workingRequest = nullptr; if (_ignoreCallback) return; //stop syncing if download failed - if (!pair.value) { - finish(); + if (!response.value) { + finishError(Networking::ErrorResponse(this, false, true, "", -1)); return; } @@ -171,9 +202,17 @@ void SavesSyncRequest::fileDownloadedCallback(Storage::BoolResponse pair) { downloadNextFile(); } +void SavesSyncRequest::fileDownloadedErrorCallback(Networking::ErrorResponse error) { + _workingRequest = nullptr; + if (_ignoreCallback) return; + + //stop syncing if download failed + finishError(error); +} + void SavesSyncRequest::uploadNextFile() { if (_filesToUpload.empty()) { - finishBool(true); + finishSuccess(true); return; } @@ -184,36 +223,45 @@ void SavesSyncRequest::uploadNextFile() { debug("uploading %s", _currentUploadingFile.c_str()); /////// _workingRequest = _storage->upload("/saves/" + _currentUploadingFile, g_system->getSavefileManager()->openRawFile(_currentUploadingFile), - new Common::Callback<SavesSyncRequest, Storage::UploadResponse>(this, &SavesSyncRequest::fileUploadedCallback) + new Common::Callback<SavesSyncRequest, Storage::UploadResponse>(this, &SavesSyncRequest::fileUploadedCallback), + new Common::Callback<SavesSyncRequest, Networking::ErrorResponse>(this, &SavesSyncRequest::fileUploadedErrorCallback) ); } -void SavesSyncRequest::fileUploadedCallback(Storage::UploadResponse pair) { +void SavesSyncRequest::fileUploadedCallback(Storage::UploadResponse response) { _workingRequest = nullptr; if (_ignoreCallback) return; - UploadStatus status = pair.value; - - //stop syncing if upload failed - if (status.interrupted || status.failed) { - finish(); - return; - } - + //update local timestamp for the uploaded file - _localFilesTimestamps[_currentUploadingFile] = status.file.timestamp(); + _localFilesTimestamps[_currentUploadingFile] = response.value.timestamp(); //continue uploading files uploadNextFile(); } +void SavesSyncRequest::fileUploadedErrorCallback(Networking::ErrorResponse error) { + _workingRequest = nullptr; + if (_ignoreCallback) return; + + //stop syncing if upload failed + finishError(error); +} + void SavesSyncRequest::handle() {} void SavesSyncRequest::restart() { start(); } -void SavesSyncRequest::finish() { finishBool(false); } +void SavesSyncRequest::finishError(Networking::ErrorResponse error) { + debug("SavesSync::finishError"); + + //save updated timestamps (even if Request failed, there would be only valid timestamps) + saveTimestamps(); + + Request::finishError(error); +} -void SavesSyncRequest::finishBool(bool success) { - Request::finish(); +void SavesSyncRequest::finishSuccess(bool success) { + Request::finishSuccess(); //save updated timestamps (even if Request failed, there would be only valid timestamps) saveTimestamps(); @@ -233,7 +281,6 @@ void SavesSyncRequest::loadTimestamps() { warning("SavesSyncRequest: failed to open '%s' file to load timestamps", TIMESTAMPS_FILENAME); return; } - while (!file->eos()) { //read filename into buffer (reading until the first ' ') diff --git a/backends/cloud/savessyncrequest.h b/backends/cloud/savessyncrequest.h index da7b27e9b6..bf44b70390 100644 --- a/backends/cloud/savessyncrequest.h +++ b/backends/cloud/savessyncrequest.h @@ -45,22 +45,25 @@ class SavesSyncRequest: public Networking::Request { bool _ignoreCallback; void start(); - void directoryListedCallback(Storage::ListDirectoryResponse pair); - void fileDownloadedCallback(Storage::BoolResponse pair); - void fileUploadedCallback(Storage::UploadResponse pair); + void directoryListedCallback(Storage::ListDirectoryResponse response); + void directoryListedErrorCallback(Networking::ErrorResponse error); + void fileDownloadedCallback(Storage::BoolResponse response); + void fileDownloadedErrorCallback(Networking::ErrorResponse error); + void fileUploadedCallback(Storage::UploadResponse response); + void fileUploadedErrorCallback(Networking::ErrorResponse error); void downloadNextFile(); void uploadNextFile(); - void finishBool(bool success); + virtual void finishError(Networking::ErrorResponse error); + void finishSuccess(bool success); void loadTimestamps(); void saveTimestamps(); Common::String concatWithSavesPath(Common::String name); public: - SavesSyncRequest(Storage *storage, Storage::BoolCallback callback); + SavesSyncRequest(Storage *storage, Storage::BoolCallback callback, Networking::ErrorCallback ecb); virtual ~SavesSyncRequest(); virtual void handle(); - virtual void restart(); - virtual void finish(); + virtual void restart(); }; } // End of namespace Cloud diff --git a/backends/cloud/storage.h b/backends/cloud/storage.h index 311b3fdc9f..32c437857c 100644 --- a/backends/cloud/storage.h +++ b/backends/cloud/storage.h @@ -34,53 +34,13 @@ namespace Cloud { -/** Struct to represent upload() resulting status. */ -struct UploadStatus { - /** true if Request was interrupted (finished by user with finish()) */ - bool interrupted; - /** true if Request has failed (bad server response or some other error occurred) */ - bool failed; - /** Contains uploaded file description (empty if failed) */ - StorageFile file; - /** Server's original response (empty if not failed) */ - Common::String response; - /** Server's HTTP response code. */ - long httpResponseCode; - - UploadStatus(): - interrupted(false), failed(false), file(), response(), httpResponseCode(-1) {} - - UploadStatus(bool interrupt, bool failure, StorageFile f, Common::String resp, long code): - interrupted(interrupt), failed(failure), file(f), response(resp), httpResponseCode(code) {} -}; - -/** Struct to represent upload() resulting status. */ -struct ListDirectoryStatus { - /** true if Request was interrupted (finished by user with finish()) */ - bool interrupted; - /** true if Request has failed (bad server response or some other error occurred) */ - bool failed; - /** Contains listed files (might be incomplete if failed or interrupted) */ - Common::Array<StorageFile> &files; - /** Server's original response (empty if not failed) */ - Common::String response; - /** Server's HTTP response code. */ - long httpResponseCode; - - ListDirectoryStatus(Common::Array<StorageFile> &f) : - interrupted(false), failed(false), files(f), response(), httpResponseCode(-1) {} - - ListDirectoryStatus(bool interrupt, bool failure, Common::Array<StorageFile> &f, Common::String resp, long code) : - interrupted(interrupt), failed(failure), files(f), response(resp), httpResponseCode(code) {} -}; - class Storage { public: typedef Networking::Response<Common::Array<StorageFile>&> FileArrayResponse; typedef Networking::Response<StorageInfo> StorageInfoResponse; typedef Networking::Response<bool> BoolResponse; - typedef Networking::Response<UploadStatus> UploadResponse; - typedef Networking::Response<ListDirectoryStatus> ListDirectoryResponse; + typedef Networking::Response<StorageFile> UploadResponse; + typedef Networking::Response<Common::Array<StorageFile> &> ListDirectoryResponse; typedef Common::BaseCallback<FileArrayResponse> *FileArrayCallback; typedef Common::BaseCallback<StorageInfoResponse> *StorageInfoCallback; @@ -113,35 +73,35 @@ public: */ /** Returns ListDirectoryStatus struct with list of files. */ - virtual Networking::Request *listDirectory(Common::String path, ListDirectoryCallback callback, bool recursive = false) = 0; + virtual Networking::Request *listDirectory(Common::String path, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback, bool recursive = false) = 0; /** Returns UploadStatus struct with info about uploaded file. */ - virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback) = 0; - virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback) = 0; + virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback) = 0; + virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback) = 0; /** Returns pointer to Networking::NetworkReadStream. */ - virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback) = 0; + virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback, Networking::ErrorCallback errorCallback) = 0; /** Calls the callback when finished. */ - virtual Networking::Request *download(Common::String remotePath, Common::String localPath, BoolCallback callback) = 0; + virtual Networking::Request *download(Common::String remotePath, Common::String localPath, BoolCallback callback, Networking::ErrorCallback errorCallback) = 0; /** Returns Common::Array<StorageFile> with list of files, which were not downloaded. */ - virtual Networking::Request *downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, bool recursive = false) = 0; + virtual Networking::Request *downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, Networking::ErrorCallback errorCallback, bool recursive = false) = 0; /** Calls the callback when finished. */ - virtual Networking::Request *remove(Common::String path, BoolCallback callback) = 0; + virtual Networking::Request *remove(Common::String path, BoolCallback callback, Networking::ErrorCallback errorCallback) = 0; /** Calls the callback when finished. */ - virtual Networking::Request *syncSaves(BoolCallback callback) = 0; + virtual Networking::Request *syncSaves(BoolCallback callback, Networking::ErrorCallback errorCallback) = 0; /** Calls the callback when finished. */ - virtual Networking::Request *createDirectory(Common::String path, BoolCallback callback) = 0; + virtual Networking::Request *createDirectory(Common::String path, BoolCallback callback, Networking::ErrorCallback errorCallback) = 0; /** Calls the callback when finished. */ - virtual Networking::Request *touch(Common::String path, BoolCallback callback) = 0; + virtual Networking::Request *touch(Common::String path, BoolCallback callback, Networking::ErrorCallback errorCallback) = 0; /** Returns the StorageInfo struct. */ - virtual Networking::Request *info(StorageInfoCallback callback) = 0; + virtual Networking::Request *info(StorageInfoCallback callback, Networking::ErrorCallback errorCallback) = 0; /** Returns whether saves sync process is running. */ virtual bool isSyncing() = 0; diff --git a/backends/module.mk b/backends/module.mk index 281c6a9060..c40781d63a 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -40,7 +40,8 @@ MODULE_OBJS += \ networking/curl/connectionmanager.o \ networking/curl/networkreadstream.o \ networking/curl/curlrequest.o \ - networking/curl/curljsonrequest.o + networking/curl/curljsonrequest.o \ + networking/curl/request.o endif ifdef USE_ELF_LOADER diff --git a/backends/networking/curl/curljsonrequest.cpp b/backends/networking/curl/curljsonrequest.cpp index fee0932129..df982bc814 100644 --- a/backends/networking/curl/curljsonrequest.cpp +++ b/backends/networking/curl/curljsonrequest.cpp @@ -31,8 +31,8 @@ namespace Networking { -CurlJsonRequest::CurlJsonRequest(JsonCallback cb, Common::String url): - CurlRequest(0, url), _jsonCallback(cb), _contentsStream(DisposeAfterUse::YES) {} +CurlJsonRequest::CurlJsonRequest(JsonCallback cb, ErrorCallback ecb, Common::String url): + CurlRequest(nullptr, ecb, url), _jsonCallback(cb), _contentsStream(DisposeAfterUse::YES) {} CurlJsonRequest::~CurlJsonRequest() { delete _jsonCallback; } @@ -65,34 +65,32 @@ void CurlJsonRequest::handle() { if (_contentsStream.write(buf, readBytes) != readBytes) warning("MemoryWriteStreamDynamic was unable to write all the bytes"); - if (_stream->eos()) { - if (_stream->httpResponseCode() != 200) - warning("HTTP response code is not 200 OK (it's %ld)", _stream->httpResponseCode()); - + if (_stream->eos()) { char *contents = getPreparedContents(); - if (_stream->httpResponseCode() != 200) - debug("%s", contents); Common::JSONValue *json = Common::JSON::parse(contents); - finishJson(json); + if (json) { + finishSuccess(json); //it's JSON even if's not 200 OK? That's fine!.. + } else { + if (_stream->httpResponseCode() == 200) //no JSON, but 200 OK? That's fine!.. + finishSuccess(nullptr); + else + finishError(ErrorResponse(this, false, true, contents, _stream->httpResponseCode())); + } } } } void CurlJsonRequest::restart() { if (_stream) delete _stream; - _stream = 0; + _stream = nullptr; _contentsStream = Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES); //with no stream available next handle() will create another one } -void CurlJsonRequest::finishJson(Common::JSONValue *json) { - Request::finish(); +void CurlJsonRequest::finishSuccess(Common::JSONValue *json) { + Request::finishSuccess(); if (_jsonCallback) (*_jsonCallback)(JsonResponse(this, json)); //potential memory leak, free it in your callbacks! else delete json; } -void CurlJsonRequest::finish() { - finishJson(0); -} - } // End of namespace Networking diff --git a/backends/networking/curl/curljsonrequest.h b/backends/networking/curl/curljsonrequest.h index 5e08be24c9..83005a79d5 100644 --- a/backends/networking/curl/curljsonrequest.h +++ b/backends/networking/curl/curljsonrequest.h @@ -41,15 +41,14 @@ protected: char *getPreparedContents(); /** Sets FINISHED state and passes the JSONValue * into user's callback in JsonResponse. */ - virtual void finishJson(Common::JSONValue *json); + virtual void finishSuccess(Common::JSONValue *json); public: - CurlJsonRequest(JsonCallback cb, Common::String url); + CurlJsonRequest(JsonCallback cb, ErrorCallback ecb, Common::String url); virtual ~CurlJsonRequest(); virtual void handle(); virtual void restart(); - virtual void finish(); }; } // End of namespace Networking diff --git a/backends/networking/curl/curlrequest.cpp b/backends/networking/curl/curlrequest.cpp index 64f6c26fb9..861546b906 100644 --- a/backends/networking/curl/curlrequest.cpp +++ b/backends/networking/curl/curlrequest.cpp @@ -30,8 +30,8 @@ namespace Networking { -CurlRequest::CurlRequest(DataCallback cb, Common::String url): - Request(cb), _url(url), _stream(nullptr), _headersList(nullptr), _bytesBuffer(nullptr), _bytesBufferSize(0) {} +CurlRequest::CurlRequest(DataCallback cb, ErrorCallback ecb, Common::String url): + Request(cb, ecb), _url(url), _stream(nullptr), _headersList(nullptr), _bytesBuffer(nullptr), _bytesBufferSize(0) {} CurlRequest::~CurlRequest() { delete _stream; @@ -49,9 +49,14 @@ void CurlRequest::handle() { if (!_stream) _stream = makeStream(); if (_stream && _stream->eos()) { - if (_stream->httpResponseCode() != 200) + if (_stream->httpResponseCode() != 200) { warning("HTTP response code is not 200 OK (it's %ld)", _stream->httpResponseCode()); - finish(); + ErrorResponse error(this, false, true, "", _stream->httpResponseCode()); + finishError(error); + return; + } + + finishSuccess(); //note that this Request doesn't call its callback on success (that's because it has nothing to return) } } @@ -101,4 +106,6 @@ NetworkReadStreamResponse CurlRequest::execute() { return NetworkReadStreamResponse(this, _stream); } +const NetworkReadStream *CurlRequest::getNetworkReadStream() const { return _stream; } + } // End of namespace Networking diff --git a/backends/networking/curl/curlrequest.h b/backends/networking/curl/curlrequest.h index 461f153b9d..660479e34a 100644 --- a/backends/networking/curl/curlrequest.h +++ b/backends/networking/curl/curlrequest.h @@ -48,7 +48,7 @@ protected: virtual NetworkReadStream *makeStream(); public: - CurlRequest(DataCallback cb, Common::String url); + CurlRequest(DataCallback cb, ErrorCallback ecb, Common::String url); virtual ~CurlRequest(); virtual void handle(); @@ -73,7 +73,7 @@ public: virtual NetworkReadStreamResponse execute(); /** Returns Request's NetworkReadStream. */ - const NetworkReadStream *getNetworkReadStream() const { return _stream; } + const NetworkReadStream *getNetworkReadStream() const; }; } // End of namespace Networking diff --git a/backends/networking/curl/request.cpp b/backends/networking/curl/request.cpp new file mode 100644 index 0000000000..d2f91586a0 --- /dev/null +++ b/backends/networking/curl/request.cpp @@ -0,0 +1,70 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "backends/networking/curl/request.h" + +namespace Networking { + +ErrorResponse::ErrorResponse(Request *rq): + request(rq), interrupted(false), failed(true), response(""), httpResponseCode(-1) {} + +ErrorResponse::ErrorResponse(Request *rq, bool interrupt, bool failure, Common::String resp, long httpCode): + request(rq), interrupted(interrupt), failed(failure), response(resp), httpResponseCode(httpCode) {} + +Request::Request(DataCallback cb, ErrorCallback ecb): + _callback(cb), _errorCallback(ecb), _state(PROCESSING), _retryInSeconds(0) {} + +Request::~Request() { + delete _callback; + delete _errorCallback; +} + +void Request::handleRetry() { + if (_retryInSeconds > 0) --_retryInSeconds; + else { + _state = PROCESSING; + restart(); + } +} + +void Request::pause() { _state = PAUSED; } + +void Request::finish() { + ErrorResponse error(this, true, false, "", -1); + finishError(error); +} + +void Request::retry(uint32 seconds) { + _state = RETRY; + _retryInSeconds = seconds; +} + +RequestState Request::state() const { return _state; } + +void Request::finishError(ErrorResponse error) { + _state = FINISHED; + if (_errorCallback) (*_errorCallback)(error); +} + +void Request::finishSuccess() { _state = FINISHED; } + +} // End of namespace Networking diff --git a/backends/networking/curl/request.h b/backends/networking/curl/request.h index a3c723d218..de5308fa52 100644 --- a/backends/networking/curl/request.h +++ b/backends/networking/curl/request.h @@ -25,6 +25,7 @@ #include "common/callback.h" #include "common/scummsys.h" +#include "common/str.h" namespace Networking { @@ -51,8 +52,39 @@ template<typename T> struct Response { Response(Request *rq, T v) : request(rq), value(v) {} }; +/** + * ErrorResponse is a struct to be returned from Request + * to user's failure callbacks. + * + * It keeps a Request pointer together with some useful + * information fields, which would explain why failure + * callback was called. + * + * <interrupted> flag is set when Request was interrupted, + * i.e. finished by user with finish() call. + * + * <failed> flag is set when Request has failed because of + * some error (bad server response, for example). + * + * <response> contains server's original response. + * + * <httpResponseCode> contains server's HTTP response code. + */ + +struct ErrorResponse { + Request *request; + bool interrupted; + bool failed; + Common::String response; + long httpResponseCode; + + ErrorResponse(Request *rq); + ErrorResponse(Request *rq, bool interrupt, bool failure, Common::String resp, long httpCode); +}; + typedef Response<void *> DataReponse; typedef Common::BaseCallback<DataReponse> *DataCallback; +typedef Common::BaseCallback<ErrorResponse> *ErrorCallback; /** * RequestState is used to indicate current Request state. @@ -74,6 +106,9 @@ typedef Common::BaseCallback<DataReponse> *DataCallback; * After this state is set, but before ConnectionManager deletes the Request, * Request calls user's callback. User can ask Request to change its state * by calling retry() or pause() methods and Request won't be deleted. + * + * Request get a success and failure callbacks. Request must call one + * (and only one!) of these callbacks when it sets FINISHED state. */ enum RequestState { PROCESSING, @@ -94,6 +129,13 @@ protected: DataCallback _callback; /** + * Callback, which should be called when Request is failed/interrupted. + * That's the way Requests pass error information to the code which asked to create this request. + * @note callback must be called in finish() or similar method. + */ + ErrorCallback _errorCallback; + + /** * Request state, which is used by ConnectionManager to determine * whether request might be deleted or it's still working. * @@ -106,45 +148,42 @@ protected: /** In RETRY state this indicates whether it's time to call restart(). */ uint32 _retryInSeconds; + /** Sets FINISHED state and calls the _errorCallback with given error. */ + virtual void finishError(ErrorResponse error); + + /** Sets FINISHED state. Implementations might extend it if needed. */ + virtual void finishSuccess(); + public: - Request(DataCallback cb): _callback(cb), _state(PROCESSING), _retryInSeconds(0) {} - virtual ~Request() { delete _callback; } + Request(DataCallback cb, ErrorCallback ecb); + virtual ~Request(); /** Method, which does actual work. Depends on what this Request is doing. */ virtual void handle() = 0; /** Method, which is called by ConnectionManager when Request's state is RETRY. */ - virtual void handleRetry() { - if (_retryInSeconds > 0) --_retryInSeconds; - else { - _state = PROCESSING; - restart(); - } - } + virtual void handleRetry(); /** Method, which is used to restart the Request. */ virtual void restart() = 0; /** Method, which is called to pause the Request. */ - virtual void pause() { _state = PAUSED; } + virtual void pause(); /** * Method, which is called to *interrupt* the Request. * When it's called, Request must stop its work and - * call the callback to notify user of failure. + * call the failure callback to notify user. */ - virtual void finish() { _state = FINISHED; } + virtual void finish(); /** Method, which is called to retry the Request. */ - virtual void retry(uint32 seconds) { - _state = RETRY; - _retryInSeconds = seconds; - } + virtual void retry(uint32 seconds); /** Returns Request's current state. */ - RequestState state() const { return _state; } + RequestState state() const; }; -} // End of namespace Cloud +} // End of namespace Networking #endif diff --git a/common/cloudmanager.h b/common/cloudmanager.h index 350901e35f..51c98e7d0c 100644 --- a/common/cloudmanager.h +++ b/common/cloudmanager.h @@ -64,7 +64,7 @@ public: /** * Starts saves syncing process in currently active storage if there is any. */ - virtual void syncSaves(Cloud::Storage::BoolCallback callback = 0) = 0; + virtual void syncSaves(Cloud::Storage::BoolCallback callback = nullptr, Networking::ErrorCallback errorCallback = nullptr) = 0; }; } // End of namespace Common |