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.
This commit is contained in:
parent
001b417f33
commit
eb63b50b7f
29 changed files with 652 additions and 507 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
_remoteFileStream = (Networking::NetworkReadStream *)pair.value;
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
warning("DownloadRequest: can't restart as there are no means to reopen DumpFile");
|
||||
finishError(Networking::ErrorResponse(this, false, true, "", -1));
|
||||
//start();
|
||||
}
|
||||
|
||||
void DownloadRequest::finish() {
|
||||
finishBool(false);
|
||||
}
|
||||
|
||||
void DownloadRequest::finishBool(bool success) {
|
||||
Request::finish();
|
||||
void DownloadRequest::finishSuccess(bool success) {
|
||||
Request::finishSuccess();
|
||||
if (_boolCallback) (*_boolCallback)(Storage::BoolResponse(this, success));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
if (!pair.value) _failedFiles.push_back(_currentFile);
|
||||
finishError(error);
|
||||
}
|
||||
|
||||
void FolderDownloadRequest::fileDownloadedCallback(Storage::BoolResponse response) {
|
||||
_workingRequest = nullptr;
|
||||
if (_ignoreCallback) return;
|
||||
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::finishFiles(Common::Array<StorageFile> &files) {
|
||||
Request::finish();
|
||||
void FolderDownloadRequest::restart() { start(); }
|
||||
|
||||
void FolderDownloadRequest::finishSuccess(Common::Array<StorageFile> &files) {
|
||||
Request::finishSuccess();
|
||||
if (_fileArrayCallback) (*_fileArrayCallback)(Storage::FileArrayResponse(this, files));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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::Request *OneDriveStorage::syncSaves(BoolCallback callback) {
|
||||
Networking::ErrorCallback OneDriveStorage::getErrorPrintingCallback() {
|
||||
return new Common::Callback<OneDriveStorage, Networking::ErrorResponse>(this, &OneDriveStorage::printErrorResponse);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
||||
void SavesSyncRequest::finishBool(bool success) {
|
||||
Request::finish();
|
||||
//save updated timestamps (even if Request failed, there would be only valid timestamps)
|
||||
saveTimestamps();
|
||||
|
||||
Request::finishError(error);
|
||||
}
|
||||
|
||||
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 ' ')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
70
backends/networking/curl/request.cpp
Normal file
70
backends/networking/curl/request.cpp
Normal file
|
@ -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
|
|
@ -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,
|
||||
|
@ -93,6 +128,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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue