aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Tkachev2016-05-31 01:51:32 +0600
committerAlexander Tkachev2016-08-24 16:07:55 +0600
commiteb63b50b7f0841e40365f3fbafa9810e8b190872 (patch)
tree4f348f12298c15e8a5885b5a74ce3788493b9a7e
parent001b417f33beeb3b2da11f58105b971dc7e6f600 (diff)
downloadscummvm-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.
-rw-r--r--backends/cloud/downloadrequest.cpp68
-rw-r--r--backends/cloud/downloadrequest.h23
-rw-r--r--backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp72
-rw-r--r--backends/cloud/dropbox/dropboxlistdirectoryrequest.h8
-rw-r--r--backends/cloud/dropbox/dropboxstorage.cpp123
-rw-r--r--backends/cloud/dropbox/dropboxstorage.h33
-rw-r--r--backends/cloud/dropbox/dropboxuploadrequest.cpp81
-rw-r--r--backends/cloud/dropbox/dropboxuploadrequest.h8
-rw-r--r--backends/cloud/folderdownloadrequest.cpp49
-rw-r--r--backends/cloud/folderdownloadrequest.h15
-rw-r--r--backends/cloud/manager.cpp4
-rw-r--r--backends/cloud/manager.h2
-rw-r--r--backends/cloud/onedrive/onedrivelistdirectoryrequest.cpp56
-rw-r--r--backends/cloud/onedrive/onedrivelistdirectoryrequest.h14
-rw-r--r--backends/cloud/onedrive/onedrivestorage.cpp72
-rw-r--r--backends/cloud/onedrive/onedrivestorage.h39
-rw-r--r--backends/cloud/onedrive/onedrivetokenrefresher.cpp42
-rw-r--r--backends/cloud/onedrive/onedrivetokenrefresher.h12
-rw-r--r--backends/cloud/savessyncrequest.cpp151
-rw-r--r--backends/cloud/savessyncrequest.h17
-rw-r--r--backends/cloud/storage.h66
-rw-r--r--backends/module.mk3
-rw-r--r--backends/networking/curl/curljsonrequest.cpp30
-rw-r--r--backends/networking/curl/curljsonrequest.h5
-rw-r--r--backends/networking/curl/curlrequest.cpp15
-rw-r--r--backends/networking/curl/curlrequest.h4
-rw-r--r--backends/networking/curl/request.cpp70
-rw-r--r--backends/networking/curl/request.h75
-rw-r--r--common/cloudmanager.h2
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