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 {
|
namespace Cloud {
|
||||||
|
|
||||||
DownloadRequest::DownloadRequest(Storage *storage, Storage::BoolCallback callback, Common::String remoteFile, Common::DumpFile *dumpFile):
|
DownloadRequest::DownloadRequest(Storage *storage, Storage::BoolCallback callback, Networking::ErrorCallback ecb, Common::String remoteFile, Common::DumpFile *dumpFile):
|
||||||
Request(0), _boolCallback(callback), _remoteFileStream(0), _localFile(dumpFile) {
|
Request(nullptr, ecb), _boolCallback(callback), _localFile(dumpFile), _remoteFileName(remoteFile), _storage(storage),
|
||||||
storage->streamFile(remoteFile, new Common::Callback<DownloadRequest, Networking::NetworkReadStreamResponse>(this, &DownloadRequest::streamCallback));
|
_remoteFileStream(nullptr), _workingRequest(nullptr), _ignoreCallback(false) {
|
||||||
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadRequest::streamCallback(Networking::NetworkReadStreamResponse pair) {
|
DownloadRequest::~DownloadRequest() {
|
||||||
if (!pair.value) {
|
_ignoreCallback = true;
|
||||||
warning("DownloadRequest: no ReadStream passed");
|
if (_workingRequest) _workingRequest->finish();
|
||||||
finish();
|
delete _boolCallback;
|
||||||
return;
|
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() {
|
void DownloadRequest::handle() {
|
||||||
if (!_localFile) {
|
if (!_localFile) {
|
||||||
warning("DownloadRequest: no file to write");
|
warning("DownloadRequest: no file to write");
|
||||||
finish();
|
finishError(Networking::ErrorResponse(this, false, true, "", -1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_localFile->isOpen()) {
|
if (!_localFile->isOpen()) {
|
||||||
warning("DownloadRequest: failed to open file to write");
|
warning("DownloadRequest: failed to open file to write");
|
||||||
finish();
|
finishError(Networking::ErrorResponse(this, false, true, "", -1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +91,7 @@ void DownloadRequest::handle() {
|
||||||
if (readBytes != 0)
|
if (readBytes != 0)
|
||||||
if (_localFile->write(buf, readBytes) != readBytes) {
|
if (_localFile->write(buf, readBytes) != readBytes) {
|
||||||
warning("DownloadRequest: unable to write all received bytes into output file");
|
warning("DownloadRequest: unable to write all received bytes into output file");
|
||||||
finish();
|
finishError(Networking::ErrorResponse(this, false, true, "", -1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,26 +101,20 @@ void DownloadRequest::handle() {
|
||||||
//TODO: do something about it actually
|
//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()
|
_localFile->close(); //yes, I know it's closed automatically in ~DumpFile()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadRequest::restart() {
|
void DownloadRequest::restart() {
|
||||||
//this request doesn't know anything about the _remoteFileStream it's reading
|
warning("DownloadRequest: can't restart as there are no means to reopen DumpFile");
|
||||||
//thus, it can't restart it
|
finishError(Networking::ErrorResponse(this, false, true, "", -1));
|
||||||
warning("DownloadRequest: cannot be restarted");
|
//start();
|
||||||
finish();
|
|
||||||
//TODO: fix that
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadRequest::finish() {
|
void DownloadRequest::finishSuccess(bool success) {
|
||||||
finishBool(false);
|
Request::finishSuccess();
|
||||||
}
|
|
||||||
|
|
||||||
void DownloadRequest::finishBool(bool success) {
|
|
||||||
Request::finish();
|
|
||||||
if (_boolCallback) (*_boolCallback)(Storage::BoolResponse(this, success));
|
if (_boolCallback) (*_boolCallback)(Storage::BoolResponse(this, success));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,22 +32,23 @@ namespace Cloud {
|
||||||
|
|
||||||
class DownloadRequest: public Networking::Request {
|
class DownloadRequest: public Networking::Request {
|
||||||
Storage::BoolCallback _boolCallback;
|
Storage::BoolCallback _boolCallback;
|
||||||
Networking::NetworkReadStream *_remoteFileStream;
|
|
||||||
Common::DumpFile *_localFile;
|
Common::DumpFile *_localFile;
|
||||||
|
Common::String _remoteFileName;
|
||||||
|
Storage *_storage;
|
||||||
|
Networking::NetworkReadStream *_remoteFileStream;
|
||||||
|
Request *_workingRequest;
|
||||||
|
bool _ignoreCallback;
|
||||||
|
|
||||||
void streamCallback(Networking::NetworkReadStreamResponse pair);
|
void start();
|
||||||
|
void streamCallback(Networking::NetworkReadStreamResponse response);
|
||||||
void finishBool(bool success);
|
void streamErrorCallback(Networking::ErrorResponse error);
|
||||||
|
void finishSuccess(bool success);
|
||||||
public:
|
public:
|
||||||
DownloadRequest(Storage *storage, Storage::BoolCallback callback, Common::String remoteFile, Common::DumpFile *dumpFile);
|
DownloadRequest(Storage *storage, Storage::BoolCallback callback, Networking::ErrorCallback ecb, Common::String remoteFile, Common::DumpFile *dumpFile);
|
||||||
virtual ~DownloadRequest() {
|
virtual ~DownloadRequest();
|
||||||
delete _boolCallback;
|
|
||||||
delete _localFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void handle();
|
virtual void handle();
|
||||||
virtual void restart();
|
virtual void restart();
|
||||||
virtual void finish();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Cloud
|
} // End of namespace Cloud
|
||||||
|
|
|
@ -31,8 +31,8 @@
|
||||||
namespace Cloud {
|
namespace Cloud {
|
||||||
namespace Dropbox {
|
namespace Dropbox {
|
||||||
|
|
||||||
DropboxListDirectoryRequest::DropboxListDirectoryRequest(Common::String token, Common::String path, Storage::ListDirectoryCallback cb, bool recursive):
|
DropboxListDirectoryRequest::DropboxListDirectoryRequest(Common::String token, Common::String path, Storage::ListDirectoryCallback cb, Networking::ErrorCallback ecb, bool recursive):
|
||||||
Networking::Request(0), _requestedPath(path), _requestedRecursive(recursive), _listDirectoryCallback(cb),
|
Networking::Request(nullptr, ecb), _requestedPath(path), _requestedRecursive(recursive), _listDirectoryCallback(cb),
|
||||||
_token(token), _workingRequest(nullptr), _ignoreCallback(false) {
|
_token(token), _workingRequest(nullptr), _ignoreCallback(false) {
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
@ -49,8 +49,9 @@ void DropboxListDirectoryRequest::start() {
|
||||||
_files.clear();
|
_files.clear();
|
||||||
_ignoreCallback = false;
|
_ignoreCallback = false;
|
||||||
|
|
||||||
Networking::JsonCallback innerCallback = new Common::Callback<DropboxListDirectoryRequest, Networking::JsonResponse>(this, &DropboxListDirectoryRequest::responseCallback);
|
Networking::JsonCallback callback = 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::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("Authorization: Bearer " + _token);
|
||||||
request->addHeader("Content-Type: application/json");
|
request->addHeader("Content-Type: application/json");
|
||||||
|
|
||||||
|
@ -66,33 +67,32 @@ void DropboxListDirectoryRequest::start() {
|
||||||
_workingRequest = ConnMan.addRequest(request);
|
_workingRequest = ConnMan.addRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DropboxListDirectoryRequest::responseCallback(Networking::JsonResponse response) {
|
||||||
void DropboxListDirectoryRequest::responseCallback(Networking::JsonResponse pair) {
|
|
||||||
_workingRequest = nullptr;
|
_workingRequest = nullptr;
|
||||||
if (_ignoreCallback) return;
|
if (_ignoreCallback) return;
|
||||||
|
|
||||||
ListDirectoryStatus status(_files);
|
Networking::ErrorResponse error(this);
|
||||||
Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)pair.request;
|
Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request;
|
||||||
if (rq && rq->getNetworkReadStream())
|
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) {
|
if (json) {
|
||||||
Common::JSONObject response = json->asObject();
|
Common::JSONObject responseObjecct = json->asObject();
|
||||||
|
|
||||||
if (response.contains("error") || response.contains("error_summary")) {
|
if (responseObjecct.contains("error") || responseObjecct.contains("error_summary")) {
|
||||||
warning("Dropbox returned error: %s", response.getVal("error_summary")->asString().c_str());
|
warning("Dropbox returned error: %s", responseObjecct.getVal("error_summary")->asString().c_str());
|
||||||
status.failed = true;
|
error.failed = true;
|
||||||
status.response = json->stringify();
|
error.response = json->stringify();
|
||||||
finishStatus(status);
|
finishError(error);
|
||||||
delete json;
|
delete json;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: check that ALL keys exist AND HAVE RIGHT TYPE to avoid segfaults
|
//TODO: check that ALL keys exist AND HAVE RIGHT TYPE to avoid segfaults
|
||||||
|
|
||||||
if (response.contains("entries")) {
|
if (responseObjecct.contains("entries")) {
|
||||||
Common::JSONArray items = response.getVal("entries")->asArray();
|
Common::JSONArray items = responseObjecct.getVal("entries")->asArray();
|
||||||
for (uint32 i = 0; i < items.size(); ++i) {
|
for (uint32 i = 0; i < items.size(); ++i) {
|
||||||
Common::JSONObject item = items[i]->asObject();
|
Common::JSONObject item = items[i]->asObject();
|
||||||
Common::String path = item.getVal("path_lower")->asString();
|
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) {
|
if (hasMore) {
|
||||||
Networking::JsonCallback innerCallback = new Common::Callback<DropboxListDirectoryRequest, Networking::JsonResponse>(this, &DropboxListDirectoryRequest::responseCallback);
|
Networking::JsonCallback callback = 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");
|
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("Authorization: Bearer " + _token);
|
||||||
request->addHeader("Content-Type: application/json");
|
request->addHeader("Content-Type: application/json");
|
||||||
|
|
||||||
Common::JSONObject jsonRequestParameters;
|
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);
|
Common::JSONValue value(jsonRequestParameters);
|
||||||
request->addPostField(Common::JSON::stringify(&value));
|
request->addPostField(Common::JSON::stringify(&value));
|
||||||
|
|
||||||
_workingRequest = ConnMan.addRequest(request);
|
_workingRequest = ConnMan.addRequest(request);
|
||||||
} else {
|
} else {
|
||||||
finishStatus(status);
|
finishSuccess(_files);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warning("null, not json");
|
warning("null, not json");
|
||||||
status.failed = true;
|
error.failed = true;
|
||||||
finishStatus(status);
|
finishError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete json;
|
delete json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DropboxListDirectoryRequest::errorCallback(Networking::ErrorResponse error) {
|
||||||
|
_workingRequest = nullptr;
|
||||||
|
if (_ignoreCallback) return;
|
||||||
|
finishError(error);
|
||||||
|
}
|
||||||
|
|
||||||
void DropboxListDirectoryRequest::handle() {}
|
void DropboxListDirectoryRequest::handle() {}
|
||||||
|
|
||||||
void DropboxListDirectoryRequest::restart() { start(); }
|
void DropboxListDirectoryRequest::restart() { start(); }
|
||||||
|
|
||||||
void DropboxListDirectoryRequest::finish() {
|
void DropboxListDirectoryRequest::finishSuccess(Common::Array<StorageFile> &files) {
|
||||||
Common::Array<StorageFile> files;
|
Request::finishSuccess();
|
||||||
ListDirectoryStatus status(files);
|
if (_listDirectoryCallback) (*_listDirectoryCallback)(Storage::ListDirectoryResponse(this, files));
|
||||||
status.interrupted = true;
|
|
||||||
finishStatus(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DropboxListDirectoryRequest::finishStatus(ListDirectoryStatus status) {
|
|
||||||
Request::finish();
|
|
||||||
if (_listDirectoryCallback) (*_listDirectoryCallback)(Storage::ListDirectoryResponse(this, status));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End of namespace Dropbox
|
} // End of namespace Dropbox
|
||||||
|
|
|
@ -42,15 +42,15 @@ class DropboxListDirectoryRequest: public Networking::Request {
|
||||||
bool _ignoreCallback;
|
bool _ignoreCallback;
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
void responseCallback(Networking::JsonResponse pair);
|
void responseCallback(Networking::JsonResponse response);
|
||||||
void finishStatus(ListDirectoryStatus status);
|
void errorCallback(Networking::ErrorResponse error);
|
||||||
|
void finishSuccess(Common::Array<StorageFile> &files);
|
||||||
public:
|
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 ~DropboxListDirectoryRequest();
|
||||||
|
|
||||||
virtual void handle();
|
virtual void handle();
|
||||||
virtual void restart();
|
virtual void restart();
|
||||||
virtual void finish();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Dropbox
|
} // End of namespace Dropbox
|
||||||
|
|
|
@ -96,118 +96,93 @@ void DropboxStorage::saveConfig(Common::String keyPrefix) {
|
||||||
ConfMan.set(keyPrefix + "user_id", _uid, "cloud");
|
ConfMan.set(keyPrefix + "user_id", _uid, "cloud");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DropboxStorage::printFiles(FileArrayResponse pair) {
|
void DropboxStorage::printFiles(FileArrayResponse response) {
|
||||||
debug("files:");
|
debug("files:");
|
||||||
Common::Array<StorageFile> &files = pair.value;
|
Common::Array<StorageFile> &files = response.value;
|
||||||
for (uint32 i = 0; i < files.size(); ++i)
|
for (uint32 i = 0; i < files.size(); ++i)
|
||||||
debug("\t%s", files[i].name().c_str());
|
debug("\t%s", files[i].name().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DropboxStorage::printBool(BoolResponse pair) {
|
void DropboxStorage::printBool(BoolResponse response) {
|
||||||
debug("bool: %s", (pair.value?"true":"false"));
|
debug("bool: %s", (response.value?"true":"false"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DropboxStorage::printUploadStatus(UploadResponse pair) {
|
void DropboxStorage::printStorageFile(UploadResponse response) {
|
||||||
debug(" ");
|
debug("\nuploaded file info:");
|
||||||
UploadStatus status = pair.value;
|
debug("\tpath: %s", response.value.path().c_str());
|
||||||
if (status.interrupted) {
|
debug("\tsize: %u", response.value.size());
|
||||||
debug("upload interrupted by user");
|
debug("\ttimestamp: %u", response.value.timestamp());
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Networking::Request *DropboxStorage::listDirectory(Common::String path, ListDirectoryCallback outerCallback, bool recursive) {
|
void DropboxStorage::printErrorResponse(Networking::ErrorResponse error) {
|
||||||
return ConnMan.addRequest(new DropboxListDirectoryRequest(_token, path, outerCallback, recursive));
|
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) {
|
Networking::ErrorCallback DropboxStorage::getErrorPrintingCallback() {
|
||||||
return ConnMan.addRequest(new DropboxUploadRequest(_token, path, contents, callback));
|
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();
|
Common::File *f = new Common::File();
|
||||||
if (!f->open(localPath)) {
|
if (!f->open(localPath)) {
|
||||||
warning("DropboxStorage: unable to open file to upload from");
|
warning("DropboxStorage: unable to open file to upload from");
|
||||||
UploadStatus status(false, true, StorageFile(), "", -1);
|
if (errorCallback) (*errorCallback)(Networking::ErrorResponse(nullptr, false, true, "", -1));
|
||||||
if (callback) (*callback)(UploadResponse(nullptr, status));
|
delete errorCallback;
|
||||||
|
delete callback;
|
||||||
delete f;
|
delete f;
|
||||||
return nullptr;
|
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;
|
Common::JSONObject jsonRequestParameters;
|
||||||
jsonRequestParameters.setVal("path", new Common::JSONValue(path));
|
jsonRequestParameters.setVal("path", new Common::JSONValue(path));
|
||||||
Common::JSONValue value(jsonRequestParameters);
|
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("Authorization: Bearer " + _token);
|
||||||
request->addHeader("Dropbox-API-Arg: " + Common::JSON::stringify(&value));
|
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)
|
request->addHeader("Content-Type: "); //required to be empty (as we do POST, it's usually app/form-url-encoded)
|
||||||
|
|
||||||
Networking::NetworkReadStreamResponse pair = request->execute();
|
Networking::NetworkReadStreamResponse response = request->execute();
|
||||||
if (callback) (*callback)(pair);
|
if (callback) (*callback)(response);
|
||||||
return pair.request;
|
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();
|
Common::DumpFile *f = new Common::DumpFile();
|
||||||
if (!f->open(localPath, true)) {
|
if (!f->open(localPath, true)) {
|
||||||
warning("DropboxStorage: unable to open file to download into");
|
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;
|
delete f;
|
||||||
return nullptr;
|
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) {
|
Networking::Request *DropboxStorage::downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, Networking::ErrorCallback errorCallback, bool recursive) {
|
||||||
return ConnMan.addRequest(new FolderDownloadRequest(this, callback, remotePath, localPath, recursive));
|
return ConnMan.addRequest(new FolderDownloadRequest(this, callback, errorCallback, remotePath, localPath, recursive));
|
||||||
}
|
}
|
||||||
|
|
||||||
Networking::Request *DropboxStorage::syncSaves(BoolCallback callback) {
|
Networking::Request *DropboxStorage::syncSaves(BoolCallback callback, Networking::ErrorCallback errorCallback) {
|
||||||
//this is not the real syncSaves() implementation
|
//this might be the real syncSaves() implementation
|
||||||
//"" is root in Dropbox, not "/"
|
return ConnMan.addRequest(new SavesSyncRequest(this, new Common::Callback<DropboxStorage, BoolResponse>(this, &DropboxStorage::printBool), getErrorPrintingCallback())); //TODO
|
||||||
//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::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::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);
|
request->addHeader("Authorization: Bearer " + _token);
|
||||||
return ConnMan.addRequest(request);
|
return ConnMan.addRequest(request);
|
||||||
//that callback bridge wraps the outerCallback (passed in arguments from user) into innerCallback
|
//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 *)
|
//and then calls the outerCallback (which wants to receive StorageInfo, not void *)
|
||||||
}
|
}
|
||||||
|
|
||||||
void DropboxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse pair) {
|
void DropboxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse response) {
|
||||||
Common::JSONValue *json = pair.value;
|
Common::JSONValue *json = response.value;
|
||||||
if (!json) {
|
if (!json) {
|
||||||
warning("NULL passed instead of JSON");
|
warning("NULL passed instead of JSON");
|
||||||
delete outerCallback;
|
delete outerCallback;
|
||||||
|
@ -241,11 +216,11 @@ void DropboxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networ
|
||||||
delete json;
|
delete json;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DropboxStorage::infoMethodCallback(StorageInfoResponse pair) {
|
void DropboxStorage::infoMethodCallback(StorageInfoResponse response) {
|
||||||
debug("\nStorage info:");
|
debug("\nStorage info:");
|
||||||
debug("User name: %s", pair.value.name().c_str());
|
debug("User name: %s", response.value.name().c_str());
|
||||||
debug("Email: %s", pair.value.email().c_str());
|
debug("Email: %s", response.value.email().c_str());
|
||||||
debug("Disk usage: %u/%u", pair.value.used(), pair.value.available());
|
debug("Disk usage: %u/%u", response.value.used(), response.value.available());
|
||||||
}
|
}
|
||||||
|
|
||||||
DropboxStorage *DropboxStorage::loadFromConfig(Common::String keyPrefix) {
|
DropboxStorage *DropboxStorage::loadFromConfig(Common::String keyPrefix) {
|
||||||
|
@ -298,7 +273,7 @@ void DropboxStorage::authThroughConsole() {
|
||||||
|
|
||||||
void DropboxStorage::getAccessToken(Common::String code) {
|
void DropboxStorage::getAccessToken(Common::String code) {
|
||||||
Networking::JsonCallback callback = new Common::GlobalFunctionCallback<Networking::JsonResponse>(saveAccessTokenCallback);
|
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("code=" + code);
|
||||||
request->addPostField("grant_type=authorization_code");
|
request->addPostField("grant_type=authorization_code");
|
||||||
request->addPostField("client_id=" + Common::String(KEY));
|
request->addPostField("client_id=" + Common::String(KEY));
|
||||||
|
|
|
@ -45,9 +45,12 @@ class DropboxStorage: public Cloud::Storage {
|
||||||
/** Constructs StorageInfo based on JSON response from cloud. */
|
/** Constructs StorageInfo based on JSON response from cloud. */
|
||||||
void infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse json);
|
void infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse json);
|
||||||
|
|
||||||
void printFiles(FileArrayResponse pair);
|
void printFiles(FileArrayResponse response);
|
||||||
void printBool(BoolResponse pair);
|
void printBool(BoolResponse response);
|
||||||
void printUploadStatus(UploadResponse pair);
|
void printStorageFile(UploadResponse response);
|
||||||
|
void printErrorResponse(Networking::ErrorResponse error);
|
||||||
|
|
||||||
|
Networking::ErrorCallback getErrorPrintingCallback();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~DropboxStorage();
|
virtual ~DropboxStorage();
|
||||||
|
@ -68,38 +71,38 @@ public:
|
||||||
/** Public Cloud API comes down there. */
|
/** Public Cloud API comes down there. */
|
||||||
|
|
||||||
/** Returns ListDirectoryStatus struct with list of files. */
|
/** 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. */
|
/** 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 path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback);
|
||||||
virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback);
|
virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback);
|
||||||
|
|
||||||
/** Returns pointer to Networking::NetworkReadStream. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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) */
|
/** This method is passed into info(). (Temporary) */
|
||||||
void infoMethodCallback(StorageInfoResponse pair);
|
void infoMethodCallback(StorageInfoResponse response);
|
||||||
|
|
||||||
/** Returns whether saves sync process is running. */
|
/** Returns whether saves sync process is running. */
|
||||||
virtual bool isSyncing() { return false; } //TODO
|
virtual bool isSyncing() { return false; } //TODO
|
||||||
|
|
|
@ -32,8 +32,8 @@
|
||||||
namespace Cloud {
|
namespace Cloud {
|
||||||
namespace Dropbox {
|
namespace Dropbox {
|
||||||
|
|
||||||
DropboxUploadRequest::DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::UploadCallback callback):
|
DropboxUploadRequest::DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::UploadCallback callback, Networking::ErrorCallback ecb):
|
||||||
Networking::Request(0), _token(token), _savePath(path), _contentsStream(contents), _uploadCallback(callback),
|
Networking::Request(nullptr, ecb), _token(token), _savePath(path), _contentsStream(contents), _uploadCallback(callback),
|
||||||
_workingRequest(nullptr), _ignoreCallback(false) {
|
_workingRequest(nullptr), _ignoreCallback(false) {
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ void DropboxUploadRequest::start() {
|
||||||
if (_workingRequest) _workingRequest->finish();
|
if (_workingRequest) _workingRequest->finish();
|
||||||
if (!_contentsStream->seek(0)) {
|
if (!_contentsStream->seek(0)) {
|
||||||
warning("DropboxUploadRequest: cannot restart because stream couldn't seek(0)");
|
warning("DropboxUploadRequest: cannot restart because stream couldn't seek(0)");
|
||||||
finish();
|
finishError(Networking::ErrorResponse(this, false, true, "", -1));
|
||||||
}
|
}
|
||||||
_ignoreCallback = false;
|
_ignoreCallback = false;
|
||||||
|
|
||||||
|
@ -97,8 +97,9 @@ void DropboxUploadRequest::uploadNextPart() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::JSONValue value(jsonRequestParameters);
|
Common::JSONValue value(jsonRequestParameters);
|
||||||
Networking::JsonCallback innerCallback = new Common::Callback<DropboxUploadRequest, Networking::JsonResponse>(this, &DropboxUploadRequest::partUploadedCallback);
|
Networking::JsonCallback callback = new Common::Callback<DropboxUploadRequest, Networking::JsonResponse>(this, &DropboxUploadRequest::partUploadedCallback);
|
||||||
Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, url);
|
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("Authorization: Bearer " + _token);
|
||||||
request->addHeader("Content-Type: application/octet-stream");
|
request->addHeader("Content-Type: application/octet-stream");
|
||||||
request->addHeader("Dropbox-API-Arg: " + Common::JSON::stringify(&value));
|
request->addHeader("Dropbox-API-Arg: " + Common::JSON::stringify(&value));
|
||||||
|
@ -110,46 +111,45 @@ void DropboxUploadRequest::uploadNextPart() {
|
||||||
_workingRequest = ConnMan.addRequest(request);
|
_workingRequest = ConnMan.addRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DropboxUploadRequest::partUploadedCallback(Networking::JsonResponse pair) {
|
void DropboxUploadRequest::partUploadedCallback(Networking::JsonResponse response) {
|
||||||
if (_ignoreCallback) return;
|
debug("partUploadedCallback");
|
||||||
_workingRequest = nullptr;
|
_workingRequest = nullptr;
|
||||||
|
if (_ignoreCallback) return;
|
||||||
|
|
||||||
UploadStatus status;
|
Networking::ErrorResponse error(this, false, true, "", -1);
|
||||||
Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)pair.request;
|
Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request;
|
||||||
if (rq && rq->getNetworkReadStream())
|
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) {
|
if (json) {
|
||||||
bool needsFinishRequest = false;
|
bool needsFinishRequest = false;
|
||||||
|
|
||||||
if (json->isObject()) {
|
if (json->isObject()) {
|
||||||
Common::JSONObject response = json->asObject();
|
Common::JSONObject object = json->asObject();
|
||||||
|
|
||||||
//debug("%s", json->stringify(true).c_str());
|
//debug("%s", json->stringify(true).c_str());
|
||||||
|
|
||||||
if (response.contains("error") || response.contains("error_summary")) {
|
if (object.contains("error") || object.contains("error_summary")) {
|
||||||
warning("Dropbox returned error: %s", response.getVal("error_summary")->asString().c_str());
|
warning("Dropbox returned error: %s", object.getVal("error_summary")->asString().c_str());
|
||||||
delete json;
|
delete json;
|
||||||
status.failed = true;
|
error.response = json->stringify(true);
|
||||||
status.response = json->stringify(true);
|
finishError(error);
|
||||||
finishUpload(status);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.contains("server_modified")) {
|
if (object.contains("server_modified")) {
|
||||||
//finished
|
//finished
|
||||||
Common::String path = response.getVal("path_lower")->asString();
|
Common::String path = object.getVal("path_lower")->asString();
|
||||||
uint32 size = response.getVal("size")->asIntegerNumber();
|
uint32 size = object.getVal("size")->asIntegerNumber();
|
||||||
uint32 timestamp = ISO8601::convertToTimestamp(response.getVal("server_modified")->asString());
|
uint32 timestamp = ISO8601::convertToTimestamp(object.getVal("server_modified")->asString());
|
||||||
status.file = StorageFile(path, size, timestamp, false);
|
finishSuccess(StorageFile(path, size, timestamp, false));
|
||||||
finishUpload(status);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_sessionId == "") {
|
if (_sessionId == "") {
|
||||||
if (response.contains("session_id"))
|
if (object.contains("session_id"))
|
||||||
_sessionId = response.getVal("session_id")->asString();
|
_sessionId = object.getVal("session_id")->asString();
|
||||||
else
|
else
|
||||||
warning("no session_id found in Dropbox's response");
|
warning("no session_id found in Dropbox's response");
|
||||||
needsFinishRequest = true;
|
needsFinishRequest = true;
|
||||||
|
@ -157,36 +157,33 @@ void DropboxUploadRequest::partUploadedCallback(Networking::JsonResponse pair) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!needsFinishRequest && (_contentsStream->eos() || _contentsStream->pos() >= _contentsStream->size() - 1)) {
|
if (!needsFinishRequest && (_contentsStream->eos() || _contentsStream->pos() >= _contentsStream->size() - 1)) {
|
||||||
if (status.file.name() == "") {
|
warning("no file info to return");
|
||||||
status.file = StorageFile(_savePath, 0, 0, false);
|
finishSuccess(StorageFile(_savePath, 0, 0, false));
|
||||||
warning("no file info to put into status");
|
|
||||||
}
|
|
||||||
finishUpload(status);
|
|
||||||
} else {
|
} else {
|
||||||
uploadNextPart();
|
uploadNextPart();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warning("null, not json");
|
warning("null, not json");
|
||||||
status.failed = true;
|
finishError(error);
|
||||||
finishUpload(status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete json;
|
delete json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DropboxUploadRequest::partUploadedErrorCallback(Networking::ErrorResponse error) {
|
||||||
|
debug("partUploadedErrorCallback");
|
||||||
|
_workingRequest = nullptr;
|
||||||
|
if (_ignoreCallback) return;
|
||||||
|
finishError(error);
|
||||||
|
}
|
||||||
|
|
||||||
void DropboxUploadRequest::handle() {}
|
void DropboxUploadRequest::handle() {}
|
||||||
|
|
||||||
void DropboxUploadRequest::restart() { start(); }
|
void DropboxUploadRequest::restart() { start(); }
|
||||||
|
|
||||||
void DropboxUploadRequest::finish() {
|
void DropboxUploadRequest::finishSuccess(StorageFile file) {
|
||||||
UploadStatus status;
|
Request::finishSuccess();
|
||||||
status.interrupted = true;
|
if (_uploadCallback) (*_uploadCallback)(Storage::UploadResponse(this, file));
|
||||||
finishUpload(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DropboxUploadRequest::finishUpload(UploadStatus status) {
|
|
||||||
Request::finish();
|
|
||||||
if (_uploadCallback) (*_uploadCallback)(Storage::UploadResponse(this, status));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End of namespace Dropbox
|
} // End of namespace Dropbox
|
||||||
|
|
|
@ -42,16 +42,16 @@ class DropboxUploadRequest: public Networking::Request {
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
void uploadNextPart();
|
void uploadNextPart();
|
||||||
void partUploadedCallback(Networking::JsonResponse pair);
|
void partUploadedCallback(Networking::JsonResponse response);
|
||||||
void finishUpload(UploadStatus status);
|
void partUploadedErrorCallback(Networking::ErrorResponse error);
|
||||||
|
void finishSuccess(StorageFile status);
|
||||||
|
|
||||||
public:
|
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 ~DropboxUploadRequest();
|
||||||
|
|
||||||
virtual void handle();
|
virtual void handle();
|
||||||
virtual void restart();
|
virtual void restart();
|
||||||
virtual void finish();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Dropbox
|
} // End of namespace Dropbox
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
|
|
||||||
namespace Cloud {
|
namespace Cloud {
|
||||||
|
|
||||||
FolderDownloadRequest::FolderDownloadRequest(Storage *storage, Storage::FileArrayCallback callback, Common::String remoteDirectoryPath, Common::String localDirectoryPath, bool recursive):
|
FolderDownloadRequest::FolderDownloadRequest(Storage *storage, Storage::FileArrayCallback callback, Networking::ErrorCallback ecb, Common::String remoteDirectoryPath, Common::String localDirectoryPath, bool recursive):
|
||||||
Request(nullptr), _storage(storage), _fileArrayCallback(callback),
|
Request(nullptr, ecb), _storage(storage), _fileArrayCallback(callback),
|
||||||
_remoteDirectoryPath(remoteDirectoryPath), _localDirectoryPath(localDirectoryPath), _recursive(recursive),
|
_remoteDirectoryPath(remoteDirectoryPath), _localDirectoryPath(localDirectoryPath), _recursive(recursive),
|
||||||
_workingRequest(nullptr), _ignoreCallback(false) {
|
_workingRequest(nullptr), _ignoreCallback(false) {
|
||||||
start();
|
start();
|
||||||
|
@ -51,33 +51,39 @@ void FolderDownloadRequest::start() {
|
||||||
_workingRequest = _storage->listDirectory(
|
_workingRequest = _storage->listDirectory(
|
||||||
_remoteDirectoryPath,
|
_remoteDirectoryPath,
|
||||||
new Common::Callback<FolderDownloadRequest, Storage::ListDirectoryResponse>(this, &FolderDownloadRequest::directoryListedCallback),
|
new Common::Callback<FolderDownloadRequest, Storage::ListDirectoryResponse>(this, &FolderDownloadRequest::directoryListedCallback),
|
||||||
|
new Common::Callback<FolderDownloadRequest, Networking::ErrorResponse>(this, &FolderDownloadRequest::directoryListedErrorCallback),
|
||||||
_recursive
|
_recursive
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderDownloadRequest::directoryListedCallback(Storage::ListDirectoryResponse pair) {
|
void FolderDownloadRequest::directoryListedCallback(Storage::ListDirectoryResponse response) {
|
||||||
|
_workingRequest = nullptr;
|
||||||
if (_ignoreCallback) return;
|
if (_ignoreCallback) return;
|
||||||
|
_files = response.value;
|
||||||
ListDirectoryStatus status = pair.value;
|
|
||||||
if (status.failed || status.interrupted) {
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_files = pair.value.files;
|
|
||||||
downloadNextFile();
|
downloadNextFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderDownloadRequest::fileDownloadedCallback(Storage::BoolResponse pair) {
|
void FolderDownloadRequest::directoryListedErrorCallback(Networking::ErrorResponse error) {
|
||||||
|
_workingRequest = nullptr;
|
||||||
if (_ignoreCallback) return;
|
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();
|
downloadNextFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FolderDownloadRequest::fileDownloadedErrorCallback(Networking::ErrorResponse error) {
|
||||||
|
fileDownloadedCallback(Storage::BoolResponse(error.request, false));
|
||||||
|
}
|
||||||
|
|
||||||
void FolderDownloadRequest::downloadNextFile() {
|
void FolderDownloadRequest::downloadNextFile() {
|
||||||
do {
|
do {
|
||||||
if (_files.empty()) {
|
if (_files.empty()) {
|
||||||
finishFiles(_failedFiles);
|
finishSuccess(_failedFiles);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,18 +111,17 @@ void FolderDownloadRequest::downloadNextFile() {
|
||||||
debug("%s -> %s", remotePath.c_str(), localPath.c_str());
|
debug("%s -> %s", remotePath.c_str(), localPath.c_str());
|
||||||
_workingRequest = _storage->download(
|
_workingRequest = _storage->download(
|
||||||
remotePath, localPath,
|
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() {
|
void FolderDownloadRequest::handle() {}
|
||||||
//TODO: somehow indicate that request was interrupted
|
|
||||||
Common::Array<StorageFile> files;
|
|
||||||
finishFiles(files);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FolderDownloadRequest::finishFiles(Common::Array<StorageFile> &files) {
|
void FolderDownloadRequest::restart() { start(); }
|
||||||
Request::finish();
|
|
||||||
|
void FolderDownloadRequest::finishSuccess(Common::Array<StorageFile> &files) {
|
||||||
|
Request::finishSuccess();
|
||||||
if (_fileArrayCallback) (*_fileArrayCallback)(Storage::FileArrayResponse(this, files));
|
if (_fileArrayCallback) (*_fileArrayCallback)(Storage::FileArrayResponse(this, files));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,17 +40,18 @@ class FolderDownloadRequest: public Networking::Request {
|
||||||
bool _ignoreCallback;
|
bool _ignoreCallback;
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
void directoryListedCallback(Storage::ListDirectoryResponse pair);
|
void directoryListedCallback(Storage::ListDirectoryResponse response);
|
||||||
void fileDownloadedCallback(Storage::BoolResponse pair);
|
void directoryListedErrorCallback(Networking::ErrorResponse error);
|
||||||
|
void fileDownloadedCallback(Storage::BoolResponse response);
|
||||||
|
void fileDownloadedErrorCallback(Networking::ErrorResponse error);
|
||||||
void downloadNextFile();
|
void downloadNextFile();
|
||||||
void finishFiles(Common::Array<StorageFile> &files);
|
void finishSuccess(Common::Array<StorageFile> &files);
|
||||||
public:
|
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 ~FolderDownloadRequest();
|
||||||
|
|
||||||
virtual void handle() {}
|
virtual void handle();
|
||||||
virtual void restart() { start(); }
|
virtual void restart();
|
||||||
virtual void finish();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Cloud
|
} // End of namespace Cloud
|
||||||
|
|
|
@ -110,9 +110,9 @@ Storage *Manager::getCurrentStorage() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::syncSaves(Storage::BoolCallback callback) {
|
void Manager::syncSaves(Storage::BoolCallback callback, Networking::ErrorCallback errorCallback) {
|
||||||
Storage *storage = getCurrentStorage();
|
Storage *storage = getCurrentStorage();
|
||||||
if (storage) storage->syncSaves(callback);
|
if (storage) storage->syncSaves(callback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End of namespace Cloud
|
} // End of namespace Cloud
|
||||||
|
|
|
@ -42,7 +42,7 @@ public:
|
||||||
virtual void addStorage(Cloud::Storage *storage, bool makeCurrent = true, bool saveConfig = true);
|
virtual void addStorage(Cloud::Storage *storage, bool makeCurrent = true, bool saveConfig = true);
|
||||||
|
|
||||||
virtual Storage *getCurrentStorage();
|
virtual Storage *getCurrentStorage();
|
||||||
virtual void syncSaves(Storage::BoolCallback callback);
|
virtual void syncSaves(Storage::BoolCallback callback, Networking::ErrorCallback errorCallback);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Cloud
|
} // End of namespace Cloud
|
||||||
|
|
|
@ -31,8 +31,8 @@
|
||||||
namespace Cloud {
|
namespace Cloud {
|
||||||
namespace OneDrive {
|
namespace OneDrive {
|
||||||
|
|
||||||
OneDriveListDirectoryRequest::OneDriveListDirectoryRequest(OneDriveStorage *storage, Common::String path, Storage::ListDirectoryCallback cb, bool recursive):
|
OneDriveListDirectoryRequest::OneDriveListDirectoryRequest(OneDriveStorage *storage, Common::String path, Storage::ListDirectoryCallback cb, Networking::ErrorCallback ecb, bool recursive):
|
||||||
Networking::Request(0),
|
Networking::Request(nullptr, ecb),
|
||||||
_requestedPath(path), _requestedRecursive(recursive), _storage(storage), _listDirectoryCallback(cb),
|
_requestedPath(path), _requestedRecursive(recursive), _storage(storage), _listDirectoryCallback(cb),
|
||||||
_workingRequest(nullptr), _ignoreCallback(false) {
|
_workingRequest(nullptr), _ignoreCallback(false) {
|
||||||
start();
|
start();
|
||||||
|
@ -55,12 +55,12 @@ void OneDriveListDirectoryRequest::start() {
|
||||||
_ignoreCallback = false;
|
_ignoreCallback = false;
|
||||||
|
|
||||||
_directoriesQueue.push_back(_requestedPath);
|
_directoriesQueue.push_back(_requestedPath);
|
||||||
listNextDirectory(_files);
|
listNextDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveListDirectoryRequest::listNextDirectory(ListDirectoryStatus status) {
|
void OneDriveListDirectoryRequest::listNextDirectory() {
|
||||||
if (_directoriesQueue.empty()) {
|
if (_directoriesQueue.empty()) {
|
||||||
finishStatus(status);
|
finishSuccess(_files);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,36 +78,37 @@ void OneDriveListDirectoryRequest::listNextDirectory(ListDirectoryStatus status)
|
||||||
|
|
||||||
void OneDriveListDirectoryRequest::makeRequest(Common::String url) {
|
void OneDriveListDirectoryRequest::makeRequest(Common::String url) {
|
||||||
Networking::JsonCallback callback = new Common::Callback<OneDriveListDirectoryRequest, Networking::JsonResponse>(this, &OneDriveListDirectoryRequest::listedDirectoryCallback);
|
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());
|
request->addHeader("Authorization: Bearer " + _storage->accessToken());
|
||||||
_workingRequest = ConnMan.addRequest(request);
|
_workingRequest = ConnMan.addRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveListDirectoryRequest::listedDirectoryCallback(Networking::JsonResponse pair) {
|
void OneDriveListDirectoryRequest::listedDirectoryCallback(Networking::JsonResponse response) {
|
||||||
_workingRequest = nullptr;
|
_workingRequest = nullptr;
|
||||||
Common::JSONValue *json = pair.value;
|
Common::JSONValue *json = response.value;
|
||||||
|
|
||||||
if (_ignoreCallback) {
|
if (_ignoreCallback) {
|
||||||
delete json;
|
delete json;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListDirectoryStatus status(_files);
|
Networking::ErrorResponse error(this);
|
||||||
Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)pair.request;
|
Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request;
|
||||||
if (rq && rq->getNetworkReadStream())
|
if (rq && rq->getNetworkReadStream())
|
||||||
status.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode();
|
error.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode();
|
||||||
|
|
||||||
if (!json) {
|
if (!json) {
|
||||||
status.failed = true;
|
error.failed = true;
|
||||||
finishStatus(status);
|
finishError(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::JSONObject response = json->asObject();
|
Common::JSONObject object = json->asObject();
|
||||||
|
|
||||||
//TODO: check that ALL keys exist AND HAVE RIGHT TYPE to avoid segfaults
|
//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) {
|
for (uint32 i = 0; i < items.size(); ++i) {
|
||||||
Common::JSONObject item = items[i]->asObject();
|
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) {
|
if (hasMore) {
|
||||||
makeRequest(response.getVal("@odata.nextLink")->asString());
|
makeRequest(object.getVal("@odata.nextLink")->asString());
|
||||||
} else {
|
} else {
|
||||||
listNextDirectory(status);
|
listNextDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
delete json;
|
delete json;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveListDirectoryRequest::finish() {
|
void OneDriveListDirectoryRequest::listedDirectoryErrorCallback(Networking::ErrorResponse error) {
|
||||||
Common::Array<StorageFile> files;
|
_workingRequest = nullptr;
|
||||||
ListDirectoryStatus status(files);
|
if (_ignoreCallback) return;
|
||||||
status.interrupted = true;
|
finishError(error);
|
||||||
finishStatus(status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveListDirectoryRequest::finishStatus(ListDirectoryStatus status) {
|
void OneDriveListDirectoryRequest::handle() {}
|
||||||
Request::finish();
|
|
||||||
if (_listDirectoryCallback) (*_listDirectoryCallback)(Storage::ListDirectoryResponse(this, status));
|
void OneDriveListDirectoryRequest::restart() { start(); }
|
||||||
|
|
||||||
|
void OneDriveListDirectoryRequest::finishSuccess(Common::Array<StorageFile> &files) {
|
||||||
|
Request::finishSuccess();
|
||||||
|
if (_listDirectoryCallback) (*_listDirectoryCallback)(Storage::ListDirectoryResponse(this, files));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End of namespace OneDrive
|
} // End of namespace OneDrive
|
||||||
|
|
|
@ -45,17 +45,17 @@ class OneDriveListDirectoryRequest: public Networking::Request {
|
||||||
bool _ignoreCallback;
|
bool _ignoreCallback;
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
void listNextDirectory(ListDirectoryStatus status);
|
void listNextDirectory();
|
||||||
void listedDirectoryCallback(Networking::JsonResponse pair);
|
void listedDirectoryCallback(Networking::JsonResponse response);
|
||||||
|
void listedDirectoryErrorCallback(Networking::ErrorResponse error);
|
||||||
void makeRequest(Common::String url);
|
void makeRequest(Common::String url);
|
||||||
void finishStatus(ListDirectoryStatus status);
|
void finishSuccess(Common::Array<StorageFile> &files);
|
||||||
public:
|
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 ~OneDriveListDirectoryRequest();
|
||||||
|
|
||||||
virtual void handle() {}
|
virtual void handle();
|
||||||
virtual void restart() { start(); }
|
virtual void restart();
|
||||||
virtual void finish();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace OneDrive
|
} // 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::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) {
|
if (codeFlow) {
|
||||||
request->addPostField("code=" + code);
|
request->addPostField("code=" + code);
|
||||||
request->addPostField("grant_type=authorization_code");
|
request->addPostField("grant_type=authorization_code");
|
||||||
|
@ -88,8 +88,8 @@ void OneDriveStorage::getAccessToken(BoolCallback callback, Common::String code)
|
||||||
ConnMan.addRequest(request);
|
ConnMan.addRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResponse pair) {
|
void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResponse response) {
|
||||||
Common::JSONValue *json = pair.value;
|
Common::JSONValue *json = response.value;
|
||||||
if (!json) {
|
if (!json) {
|
||||||
warning("OneDriveStorage: got NULL instead of JSON");
|
warning("OneDriveStorage: got NULL instead of JSON");
|
||||||
if (callback) (*callback)(BoolResponse(nullptr, false));
|
if (callback) (*callback)(BoolResponse(nullptr, false));
|
||||||
|
@ -111,8 +111,8 @@ void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResp
|
||||||
delete json;
|
delete json;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveStorage::codeFlowComplete(BoolResponse pair) {
|
void OneDriveStorage::codeFlowComplete(BoolResponse response) {
|
||||||
if (!pair.value) {
|
if (!response.value) {
|
||||||
warning("OneDriveStorage: failed to get access token through code flow");
|
warning("OneDriveStorage: failed to get access token through code flow");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -130,8 +130,8 @@ void OneDriveStorage::saveConfig(Common::String keyPrefix) {
|
||||||
ConfMan.set(keyPrefix + "refresh_token", _refreshToken, "cloud");
|
ConfMan.set(keyPrefix + "refresh_token", _refreshToken, "cloud");
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveStorage::printJson(Networking::JsonResponse pair) {
|
void OneDriveStorage::printJson(Networking::JsonResponse response) {
|
||||||
Common::JSONValue *json = pair.value;
|
Common::JSONValue *json = response.value;
|
||||||
if (!json) {
|
if (!json) {
|
||||||
warning("printJson: NULL");
|
warning("printJson: NULL");
|
||||||
return;
|
return;
|
||||||
|
@ -141,77 +141,85 @@ void OneDriveStorage::printJson(Networking::JsonResponse pair) {
|
||||||
delete json;
|
delete json;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveStorage::fileInfoCallback(Networking::NetworkReadStreamCallback outerCallback, Networking::JsonResponse pair) {
|
void OneDriveStorage::fileInfoCallback(Networking::NetworkReadStreamCallback outerCallback, Networking::JsonResponse response) {
|
||||||
if (!pair.value) {
|
if (!response.value) {
|
||||||
warning("fileInfoCallback: NULL");
|
warning("fileInfoCallback: NULL");
|
||||||
if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(pair.request, 0));
|
if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(response.request, 0));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::JSONObject result = pair.value->asObject();
|
Common::JSONObject result = response.value->asObject();
|
||||||
if (result.contains("@content.downloadUrl")) {
|
if (result.contains("@content.downloadUrl")) {
|
||||||
const char *url = result.getVal("@content.downloadUrl")->asString().c_str();
|
const char *url = result.getVal("@content.downloadUrl")->asString().c_str();
|
||||||
if (outerCallback)
|
if (outerCallback)
|
||||||
(*outerCallback)(Networking::NetworkReadStreamResponse(
|
(*outerCallback)(Networking::NetworkReadStreamResponse(
|
||||||
pair.request,
|
response.request,
|
||||||
new Networking::NetworkReadStream(url, 0, "")
|
new Networking::NetworkReadStream(url, 0, "")
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
warning("downloadUrl not found in passed JSON");
|
warning("downloadUrl not found in passed JSON");
|
||||||
debug("%s", pair.value->stringify().c_str());
|
debug("%s", response.value->stringify().c_str());
|
||||||
if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(pair.request, 0));
|
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) {
|
Networking::Request *OneDriveStorage::listDirectory(Common::String path, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback, bool recursive) {
|
||||||
return ConnMan.addRequest(new OneDriveListDirectoryRequest(this, path, callback, 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;
|
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::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);
|
request->addHeader("Authorization: Bearer " + _token);
|
||||||
return ConnMan.addRequest(request);
|
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();
|
Common::DumpFile *f = new Common::DumpFile();
|
||||||
if (!f->open(localPath, true)) {
|
if (!f->open(localPath, true)) {
|
||||||
warning("OneDriveStorage: unable to open file to download into");
|
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;
|
delete f;
|
||||||
return nullptr;
|
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. */
|
/** 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) {
|
Networking::Request *OneDriveStorage::downloadFolder(Common::String remotePath, Common::String localPath, FileArrayCallback callback, Networking::ErrorCallback errorCallback, bool recursive) {
|
||||||
return ConnMan.addRequest(new FolderDownloadRequest(this, callback, remotePath, localPath, recursive));
|
return ConnMan.addRequest(new FolderDownloadRequest(this, callback, errorCallback, remotePath, localPath, recursive));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveStorage::fileDownloaded(BoolResponse pair) {
|
void OneDriveStorage::fileDownloaded(BoolResponse response) {
|
||||||
if (pair.value) debug("file downloaded!");
|
if (response.value) debug("file downloaded!");
|
||||||
else debug("download failed!");
|
else debug("download failed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveStorage::printFiles(FileArrayResponse pair) {
|
void OneDriveStorage::printFiles(FileArrayResponse response) {
|
||||||
debug("files:");
|
debug("files:");
|
||||||
Common::Array<StorageFile> &files = pair.value;
|
Common::Array<StorageFile> &files = response.value;
|
||||||
for (uint32 i = 0; i < files.size(); ++i)
|
for (uint32 i = 0; i < files.size(); ++i)
|
||||||
debug("\t%s", files[i].path().c_str());
|
debug("\t%s", files[i].path().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveStorage::printBool(BoolResponse pair) {
|
void OneDriveStorage::printBool(BoolResponse response) {
|
||||||
debug("bool: %s", pair.value ? "true" : "false");
|
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
|
//this is not the real syncSaves() implementation
|
||||||
/*
|
/*
|
||||||
Networking::JsonCallback innerCallback = new Common::Callback<OneDriveStorage, Networking::RequestJsonPair>(this, &OneDriveStorage::printJson);
|
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 ConnMan.addRequest(request);
|
||||||
*/
|
*/
|
||||||
//return downloadFolder("subfolder", "local/onedrive/subfolder_downloaded", new Common::Callback<OneDriveStorage, FileArrayResponse>(this, &OneDriveStorage::printFiles), false);
|
//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) {
|
OneDriveStorage *OneDriveStorage::loadFromConfig(Common::String keyPrefix) {
|
||||||
|
|
|
@ -46,15 +46,18 @@ class OneDriveStorage: public Cloud::Storage {
|
||||||
*/
|
*/
|
||||||
OneDriveStorage(Common::String code);
|
OneDriveStorage(Common::String code);
|
||||||
|
|
||||||
void tokenRefreshed(BoolCallback callback, Networking::JsonResponse pair);
|
void tokenRefreshed(BoolCallback callback, Networking::JsonResponse response);
|
||||||
void codeFlowComplete(BoolResponse pair);
|
void codeFlowComplete(BoolResponse response);
|
||||||
|
|
||||||
void printJson(Networking::JsonResponse pair);
|
void printJson(Networking::JsonResponse response);
|
||||||
void fileDownloaded(BoolResponse pair);
|
void fileDownloaded(BoolResponse response);
|
||||||
void printFiles(FileArrayResponse pair);
|
void printFiles(FileArrayResponse response);
|
||||||
void printBool(BoolResponse pair);
|
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:
|
public:
|
||||||
virtual ~OneDriveStorage();
|
virtual ~OneDriveStorage();
|
||||||
|
|
||||||
|
@ -74,35 +77,35 @@ public:
|
||||||
/** Public Cloud API comes down there. */
|
/** Public Cloud API comes down there. */
|
||||||
|
|
||||||
/** Returns ListDirectoryStatus struct with list of files. */
|
/** 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. */
|
/** 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 path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO
|
||||||
virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback) { return nullptr; }
|
virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback) { return nullptr; } //TODO
|
||||||
|
|
||||||
/** Returns pointer to Networking::NetworkReadStream. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** Returns whether saves sync process is running. */
|
||||||
virtual bool isSyncing() { return false; } //TODO
|
virtual bool isSyncing() { return false; } //TODO
|
||||||
|
|
|
@ -31,16 +31,16 @@
|
||||||
namespace Cloud {
|
namespace Cloud {
|
||||||
namespace OneDrive {
|
namespace OneDrive {
|
||||||
|
|
||||||
OneDriveTokenRefresher::OneDriveTokenRefresher(OneDriveStorage *parent, Networking::JsonCallback callback, const char *url):
|
OneDriveTokenRefresher::OneDriveTokenRefresher(OneDriveStorage *parent, Networking::JsonCallback callback, Networking::ErrorCallback ecb, const char *url):
|
||||||
CurlJsonRequest(callback, url), _parentStorage(parent) {}
|
CurlJsonRequest(callback, ecb, url), _parentStorage(parent) {}
|
||||||
|
|
||||||
OneDriveTokenRefresher::~OneDriveTokenRefresher() {}
|
OneDriveTokenRefresher::~OneDriveTokenRefresher() {}
|
||||||
|
|
||||||
void OneDriveTokenRefresher::tokenRefreshed(Storage::BoolResponse pair) {
|
void OneDriveTokenRefresher::tokenRefreshed(Storage::BoolResponse response) {
|
||||||
if (!pair.value) {
|
if (!response.value) {
|
||||||
//failed to refresh token, notify user with NULL in original callback
|
//failed to refresh token, notify user with NULL in original callback
|
||||||
warning("OneDriveTokenRefresher: failed to refresh token");
|
warning("OneDriveTokenRefresher: failed to refresh token");
|
||||||
finish();
|
finishError(Networking::ErrorResponse(this, false, true, "", -1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,11 +56,10 @@ void OneDriveTokenRefresher::tokenRefreshed(Storage::BoolResponse pair) {
|
||||||
retry(0);
|
retry(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveTokenRefresher::finishJson(Common::JSONValue *json) {
|
void OneDriveTokenRefresher::finishSuccess(Common::JSONValue *json) {
|
||||||
if (!json) {
|
if (!json) {
|
||||||
//notify user of failure
|
//that's probably not an error (200 OK)
|
||||||
warning("OneDriveTokenRefresher: got NULL instead of JSON");
|
CurlJsonRequest::finishSuccess(nullptr);
|
||||||
CurlJsonRequest::finishJson(nullptr);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,19 +73,26 @@ void OneDriveTokenRefresher::finishJson(Common::JSONValue *json) {
|
||||||
Common::JSONObject error = result.getVal("error")->asObject();
|
Common::JSONObject error = result.getVal("error")->asObject();
|
||||||
bool irrecoverable = true;
|
bool irrecoverable = true;
|
||||||
|
|
||||||
|
Common::String code, message;
|
||||||
if (error.contains("code")) {
|
if (error.contains("code")) {
|
||||||
Common::String code = error.getVal("code")->asString();
|
code = error.getVal("code")->asString();
|
||||||
debug("code = %s", code.c_str());
|
debug("code = %s", code.c_str());
|
||||||
//if (code == "itemNotFound") irrecoverable = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error.contains("message")) {
|
if (error.contains("message")) {
|
||||||
Common::String message = error.getVal("message")->asString();
|
message = error.getVal("message")->asString();
|
||||||
debug("message = %s", message.c_str());
|
debug("message = %s", message.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//determine whether token refreshing would help in this situation
|
||||||
|
if (code == "itemNotFound") {
|
||||||
|
if (message.contains("application ID"))
|
||||||
|
irrecoverable = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (irrecoverable) {
|
if (irrecoverable) {
|
||||||
CurlJsonRequest::finishJson(nullptr);
|
finishError(Networking::ErrorResponse(this, false, true, json->stringify(true), -1)); //TODO: httpCode
|
||||||
|
delete json;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +103,7 @@ void OneDriveTokenRefresher::finishJson(Common::JSONValue *json) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//notify user of success
|
//notify user of success
|
||||||
CurlJsonRequest::finishJson(json);
|
CurlJsonRequest::finishSuccess(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneDriveTokenRefresher::setHeaders(Common::Array<Common::String> &headers) {
|
void OneDriveTokenRefresher::setHeaders(Common::Array<Common::String> &headers) {
|
||||||
|
@ -108,6 +114,10 @@ void OneDriveTokenRefresher::setHeaders(Common::Array<Common::String> &headers)
|
||||||
CurlJsonRequest::addHeader(headers[i]);
|
CurlJsonRequest::addHeader(headers[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OneDriveTokenRefresher::addHeader(Common::String header) {
|
||||||
|
_headers.push_back(header);
|
||||||
|
CurlJsonRequest::addHeader(header);
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace OneDrive
|
} // End of namespace OneDrive
|
||||||
} // End of namespace Cloud
|
} // End of namespace Cloud
|
||||||
|
|
|
@ -35,19 +35,15 @@ class OneDriveTokenRefresher: public Networking::CurlJsonRequest {
|
||||||
OneDriveStorage *_parentStorage;
|
OneDriveStorage *_parentStorage;
|
||||||
Common::Array<Common::String> _headers;
|
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:
|
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 ~OneDriveTokenRefresher();
|
||||||
|
|
||||||
virtual void setHeaders(Common::Array<Common::String> &headers);
|
virtual void setHeaders(Common::Array<Common::String> &headers);
|
||||||
|
virtual void addHeader(Common::String header);
|
||||||
virtual void addHeader(Common::String header) {
|
|
||||||
_headers.push_back(header);
|
|
||||||
CurlJsonRequest::addHeader(header);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace OneDrive
|
} // End of namespace OneDrive
|
||||||
|
|
|
@ -32,8 +32,8 @@ namespace Cloud {
|
||||||
|
|
||||||
const char *SavesSyncRequest::TIMESTAMPS_FILENAME = "timestamps";
|
const char *SavesSyncRequest::TIMESTAMPS_FILENAME = "timestamps";
|
||||||
|
|
||||||
SavesSyncRequest::SavesSyncRequest(Storage *storage, Storage::BoolCallback callback):
|
SavesSyncRequest::SavesSyncRequest(Storage *storage, Storage::BoolCallback callback, Networking::ErrorCallback ecb):
|
||||||
Request(nullptr), _storage(storage), _boolCallback(callback),
|
Request(nullptr, ecb), _storage(storage), _boolCallback(callback),
|
||||||
_workingRequest(nullptr), _ignoreCallback(false) {
|
_workingRequest(nullptr), _ignoreCallback(false) {
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
@ -59,48 +59,35 @@ void SavesSyncRequest::start() {
|
||||||
loadTimestamps();
|
loadTimestamps();
|
||||||
|
|
||||||
//list saves directory
|
//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;
|
_workingRequest = nullptr;
|
||||||
if (_ignoreCallback) return;
|
if (_ignoreCallback) return;
|
||||||
|
|
||||||
ListDirectoryStatus status = pair.value;
|
Common::HashMap<Common::String, bool> localFileNotAvailableInCloud;
|
||||||
bool irrecoverable = status.interrupted || status.failed;
|
for (Common::HashMap<Common::String, uint32>::iterator i = _localFilesTimestamps.begin(); i != _localFilesTimestamps.end(); ++i) {
|
||||||
if (status.failed) {
|
localFileNotAvailableInCloud[i->_key] = true;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (irrecoverable) {
|
|
||||||
finishBool(false);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//determine which files to download and which files to upload
|
//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) {
|
for (uint32 i = 0; i < remoteFiles.size(); ++i) {
|
||||||
StorageFile &file = remoteFiles[i];
|
StorageFile &file = remoteFiles[i];
|
||||||
if (file.isDirectory()) continue;
|
if (file.isDirectory()) continue;
|
||||||
if (file.name() == TIMESTAMPS_FILENAME) continue;
|
if (file.name() == TIMESTAMPS_FILENAME) continue;
|
||||||
|
|
||||||
Common::String name = file.name();
|
Common::String name = file.name();
|
||||||
if (!_localFilesTimestamps.contains(name))
|
if (!_localFilesTimestamps.contains(name))
|
||||||
_filesToDownload.push_back(file);
|
_filesToDownload.push_back(file);
|
||||||
else {
|
else {
|
||||||
|
localFileNotAvailableInCloud[name] = false;
|
||||||
|
|
||||||
if (_localFilesTimestamps[name] != INVALID_TIMESTAMP) {
|
if (_localFilesTimestamps[name] != INVALID_TIMESTAMP) {
|
||||||
if (_localFilesTimestamps[name] == file.timestamp())
|
if (_localFilesTimestamps[name] == file.timestamp())
|
||||||
continue;
|
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)
|
//upload files which are unavailable in cloud
|
||||||
for (Common::HashMap<Common::String, uint32>::iterator i = _localFilesTimestamps.begin(); i != _localFilesTimestamps.end(); ++i) {
|
for (Common::HashMap<Common::String, bool>::iterator i = localFileNotAvailableInCloud.begin(); i != localFileNotAvailableInCloud.end(); ++i) {
|
||||||
if (i->_key == TIMESTAMPS_FILENAME) continue;
|
if (i->_key == TIMESTAMPS_FILENAME) continue;
|
||||||
if (i->_value == INVALID_TIMESTAMP)
|
if (i->_value) _filesToUpload.push_back(i->_key);
|
||||||
_filesToUpload.push_back(i->_key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////
|
///////
|
||||||
|
@ -137,6 +123,50 @@ void SavesSyncRequest::directoryListedCallback(Storage::ListDirectoryResponse pa
|
||||||
downloadNextFile();
|
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() {
|
void SavesSyncRequest::downloadNextFile() {
|
||||||
if (_filesToDownload.empty()) {
|
if (_filesToDownload.empty()) {
|
||||||
uploadNextFile();
|
uploadNextFile();
|
||||||
|
@ -150,17 +180,18 @@ void SavesSyncRequest::downloadNextFile() {
|
||||||
debug("downloading %s", _currentDownloadingFile.name().c_str());
|
debug("downloading %s", _currentDownloadingFile.name().c_str());
|
||||||
///////
|
///////
|
||||||
_workingRequest = _storage->download(_currentDownloadingFile.path(), concatWithSavesPath(_currentDownloadingFile.name()),
|
_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;
|
_workingRequest = nullptr;
|
||||||
if (_ignoreCallback) return;
|
if (_ignoreCallback) return;
|
||||||
|
|
||||||
//stop syncing if download failed
|
//stop syncing if download failed
|
||||||
if (!pair.value) {
|
if (!response.value) {
|
||||||
finish();
|
finishError(Networking::ErrorResponse(this, false, true, "", -1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,9 +202,17 @@ void SavesSyncRequest::fileDownloadedCallback(Storage::BoolResponse pair) {
|
||||||
downloadNextFile();
|
downloadNextFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SavesSyncRequest::fileDownloadedErrorCallback(Networking::ErrorResponse error) {
|
||||||
|
_workingRequest = nullptr;
|
||||||
|
if (_ignoreCallback) return;
|
||||||
|
|
||||||
|
//stop syncing if download failed
|
||||||
|
finishError(error);
|
||||||
|
}
|
||||||
|
|
||||||
void SavesSyncRequest::uploadNextFile() {
|
void SavesSyncRequest::uploadNextFile() {
|
||||||
if (_filesToUpload.empty()) {
|
if (_filesToUpload.empty()) {
|
||||||
finishBool(true);
|
finishSuccess(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,36 +223,45 @@ void SavesSyncRequest::uploadNextFile() {
|
||||||
debug("uploading %s", _currentUploadingFile.c_str());
|
debug("uploading %s", _currentUploadingFile.c_str());
|
||||||
///////
|
///////
|
||||||
_workingRequest = _storage->upload("/saves/" + _currentUploadingFile, g_system->getSavefileManager()->openRawFile(_currentUploadingFile),
|
_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;
|
_workingRequest = nullptr;
|
||||||
if (_ignoreCallback) return;
|
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
|
//update local timestamp for the uploaded file
|
||||||
_localFilesTimestamps[_currentUploadingFile] = status.file.timestamp();
|
_localFilesTimestamps[_currentUploadingFile] = response.value.timestamp();
|
||||||
|
|
||||||
//continue uploading files
|
//continue uploading files
|
||||||
uploadNextFile();
|
uploadNextFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SavesSyncRequest::fileUploadedErrorCallback(Networking::ErrorResponse error) {
|
||||||
|
_workingRequest = nullptr;
|
||||||
|
if (_ignoreCallback) return;
|
||||||
|
|
||||||
|
//stop syncing if upload failed
|
||||||
|
finishError(error);
|
||||||
|
}
|
||||||
|
|
||||||
void SavesSyncRequest::handle() {}
|
void SavesSyncRequest::handle() {}
|
||||||
|
|
||||||
void SavesSyncRequest::restart() { start(); }
|
void SavesSyncRequest::restart() { start(); }
|
||||||
|
|
||||||
void SavesSyncRequest::finish() { finishBool(false); }
|
void SavesSyncRequest::finishError(Networking::ErrorResponse error) {
|
||||||
|
debug("SavesSync::finishError");
|
||||||
|
|
||||||
void SavesSyncRequest::finishBool(bool success) {
|
//save updated timestamps (even if Request failed, there would be only valid timestamps)
|
||||||
Request::finish();
|
saveTimestamps();
|
||||||
|
|
||||||
|
Request::finishError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavesSyncRequest::finishSuccess(bool success) {
|
||||||
|
Request::finishSuccess();
|
||||||
|
|
||||||
//save updated timestamps (even if Request failed, there would be only valid timestamps)
|
//save updated timestamps (even if Request failed, there would be only valid timestamps)
|
||||||
saveTimestamps();
|
saveTimestamps();
|
||||||
|
@ -234,7 +282,6 @@ void SavesSyncRequest::loadTimestamps() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while (!file->eos()) {
|
while (!file->eos()) {
|
||||||
//read filename into buffer (reading until the first ' ')
|
//read filename into buffer (reading until the first ' ')
|
||||||
Common::String buffer;
|
Common::String buffer;
|
||||||
|
|
|
@ -45,22 +45,25 @@ class SavesSyncRequest: public Networking::Request {
|
||||||
bool _ignoreCallback;
|
bool _ignoreCallback;
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
void directoryListedCallback(Storage::ListDirectoryResponse pair);
|
void directoryListedCallback(Storage::ListDirectoryResponse response);
|
||||||
void fileDownloadedCallback(Storage::BoolResponse pair);
|
void directoryListedErrorCallback(Networking::ErrorResponse error);
|
||||||
void fileUploadedCallback(Storage::UploadResponse pair);
|
void fileDownloadedCallback(Storage::BoolResponse response);
|
||||||
|
void fileDownloadedErrorCallback(Networking::ErrorResponse error);
|
||||||
|
void fileUploadedCallback(Storage::UploadResponse response);
|
||||||
|
void fileUploadedErrorCallback(Networking::ErrorResponse error);
|
||||||
void downloadNextFile();
|
void downloadNextFile();
|
||||||
void uploadNextFile();
|
void uploadNextFile();
|
||||||
void finishBool(bool success);
|
virtual void finishError(Networking::ErrorResponse error);
|
||||||
|
void finishSuccess(bool success);
|
||||||
void loadTimestamps();
|
void loadTimestamps();
|
||||||
void saveTimestamps();
|
void saveTimestamps();
|
||||||
Common::String concatWithSavesPath(Common::String name);
|
Common::String concatWithSavesPath(Common::String name);
|
||||||
public:
|
public:
|
||||||
SavesSyncRequest(Storage *storage, Storage::BoolCallback callback);
|
SavesSyncRequest(Storage *storage, Storage::BoolCallback callback, Networking::ErrorCallback ecb);
|
||||||
virtual ~SavesSyncRequest();
|
virtual ~SavesSyncRequest();
|
||||||
|
|
||||||
virtual void handle();
|
virtual void handle();
|
||||||
virtual void restart();
|
virtual void restart();
|
||||||
virtual void finish();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Cloud
|
} // End of namespace Cloud
|
||||||
|
|
|
@ -34,53 +34,13 @@
|
||||||
|
|
||||||
namespace Cloud {
|
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 {
|
class Storage {
|
||||||
public:
|
public:
|
||||||
typedef Networking::Response<Common::Array<StorageFile>&> FileArrayResponse;
|
typedef Networking::Response<Common::Array<StorageFile>&> FileArrayResponse;
|
||||||
typedef Networking::Response<StorageInfo> StorageInfoResponse;
|
typedef Networking::Response<StorageInfo> StorageInfoResponse;
|
||||||
typedef Networking::Response<bool> BoolResponse;
|
typedef Networking::Response<bool> BoolResponse;
|
||||||
typedef Networking::Response<UploadStatus> UploadResponse;
|
typedef Networking::Response<StorageFile> UploadResponse;
|
||||||
typedef Networking::Response<ListDirectoryStatus> ListDirectoryResponse;
|
typedef Networking::Response<Common::Array<StorageFile> &> ListDirectoryResponse;
|
||||||
|
|
||||||
typedef Common::BaseCallback<FileArrayResponse> *FileArrayCallback;
|
typedef Common::BaseCallback<FileArrayResponse> *FileArrayCallback;
|
||||||
typedef Common::BaseCallback<StorageInfoResponse> *StorageInfoCallback;
|
typedef Common::BaseCallback<StorageInfoResponse> *StorageInfoCallback;
|
||||||
|
@ -113,35 +73,35 @@ public:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Returns ListDirectoryStatus struct with list of files. */
|
/** 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. */
|
/** 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 path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback) = 0;
|
||||||
virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback) = 0;
|
virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback, Networking::ErrorCallback errorCallback) = 0;
|
||||||
|
|
||||||
/** Returns pointer to Networking::NetworkReadStream. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** 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. */
|
/** Returns whether saves sync process is running. */
|
||||||
virtual bool isSyncing() = 0;
|
virtual bool isSyncing() = 0;
|
||||||
|
|
|
@ -40,7 +40,8 @@ MODULE_OBJS += \
|
||||||
networking/curl/connectionmanager.o \
|
networking/curl/connectionmanager.o \
|
||||||
networking/curl/networkreadstream.o \
|
networking/curl/networkreadstream.o \
|
||||||
networking/curl/curlrequest.o \
|
networking/curl/curlrequest.o \
|
||||||
networking/curl/curljsonrequest.o
|
networking/curl/curljsonrequest.o \
|
||||||
|
networking/curl/request.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef USE_ELF_LOADER
|
ifdef USE_ELF_LOADER
|
||||||
|
|
|
@ -31,8 +31,8 @@
|
||||||
|
|
||||||
namespace Networking {
|
namespace Networking {
|
||||||
|
|
||||||
CurlJsonRequest::CurlJsonRequest(JsonCallback cb, Common::String url):
|
CurlJsonRequest::CurlJsonRequest(JsonCallback cb, ErrorCallback ecb, Common::String url):
|
||||||
CurlRequest(0, url), _jsonCallback(cb), _contentsStream(DisposeAfterUse::YES) {}
|
CurlRequest(nullptr, ecb, url), _jsonCallback(cb), _contentsStream(DisposeAfterUse::YES) {}
|
||||||
|
|
||||||
CurlJsonRequest::~CurlJsonRequest() { delete _jsonCallback; }
|
CurlJsonRequest::~CurlJsonRequest() { delete _jsonCallback; }
|
||||||
|
|
||||||
|
@ -66,33 +66,31 @@ void CurlJsonRequest::handle() {
|
||||||
warning("MemoryWriteStreamDynamic was unable to write all the bytes");
|
warning("MemoryWriteStreamDynamic was unable to write all the bytes");
|
||||||
|
|
||||||
if (_stream->eos()) {
|
if (_stream->eos()) {
|
||||||
if (_stream->httpResponseCode() != 200)
|
|
||||||
warning("HTTP response code is not 200 OK (it's %ld)", _stream->httpResponseCode());
|
|
||||||
|
|
||||||
char *contents = getPreparedContents();
|
char *contents = getPreparedContents();
|
||||||
if (_stream->httpResponseCode() != 200)
|
|
||||||
debug("%s", contents);
|
|
||||||
Common::JSONValue *json = Common::JSON::parse(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() {
|
void CurlJsonRequest::restart() {
|
||||||
if (_stream) delete _stream;
|
if (_stream) delete _stream;
|
||||||
_stream = 0;
|
_stream = nullptr;
|
||||||
_contentsStream = Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
|
_contentsStream = Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
|
||||||
//with no stream available next handle() will create another one
|
//with no stream available next handle() will create another one
|
||||||
}
|
}
|
||||||
|
|
||||||
void CurlJsonRequest::finishJson(Common::JSONValue *json) {
|
void CurlJsonRequest::finishSuccess(Common::JSONValue *json) {
|
||||||
Request::finish();
|
Request::finishSuccess();
|
||||||
if (_jsonCallback) (*_jsonCallback)(JsonResponse(this, json)); //potential memory leak, free it in your callbacks!
|
if (_jsonCallback) (*_jsonCallback)(JsonResponse(this, json)); //potential memory leak, free it in your callbacks!
|
||||||
else delete json;
|
else delete json;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CurlJsonRequest::finish() {
|
|
||||||
finishJson(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // End of namespace Networking
|
} // End of namespace Networking
|
||||||
|
|
|
@ -41,15 +41,14 @@ protected:
|
||||||
char *getPreparedContents();
|
char *getPreparedContents();
|
||||||
|
|
||||||
/** Sets FINISHED state and passes the JSONValue * into user's callback in JsonResponse. */
|
/** 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:
|
public:
|
||||||
CurlJsonRequest(JsonCallback cb, Common::String url);
|
CurlJsonRequest(JsonCallback cb, ErrorCallback ecb, Common::String url);
|
||||||
virtual ~CurlJsonRequest();
|
virtual ~CurlJsonRequest();
|
||||||
|
|
||||||
virtual void handle();
|
virtual void handle();
|
||||||
virtual void restart();
|
virtual void restart();
|
||||||
virtual void finish();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Networking
|
} // End of namespace Networking
|
||||||
|
|
|
@ -30,8 +30,8 @@
|
||||||
|
|
||||||
namespace Networking {
|
namespace Networking {
|
||||||
|
|
||||||
CurlRequest::CurlRequest(DataCallback cb, Common::String url):
|
CurlRequest::CurlRequest(DataCallback cb, ErrorCallback ecb, Common::String url):
|
||||||
Request(cb), _url(url), _stream(nullptr), _headersList(nullptr), _bytesBuffer(nullptr), _bytesBufferSize(0) {}
|
Request(cb, ecb), _url(url), _stream(nullptr), _headersList(nullptr), _bytesBuffer(nullptr), _bytesBufferSize(0) {}
|
||||||
|
|
||||||
CurlRequest::~CurlRequest() {
|
CurlRequest::~CurlRequest() {
|
||||||
delete _stream;
|
delete _stream;
|
||||||
|
@ -49,9 +49,14 @@ void CurlRequest::handle() {
|
||||||
if (!_stream) _stream = makeStream();
|
if (!_stream) _stream = makeStream();
|
||||||
|
|
||||||
if (_stream && _stream->eos()) {
|
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());
|
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);
|
return NetworkReadStreamResponse(this, _stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NetworkReadStream *CurlRequest::getNetworkReadStream() const { return _stream; }
|
||||||
|
|
||||||
} // End of namespace Networking
|
} // End of namespace Networking
|
||||||
|
|
|
@ -48,7 +48,7 @@ protected:
|
||||||
virtual NetworkReadStream *makeStream();
|
virtual NetworkReadStream *makeStream();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CurlRequest(DataCallback cb, Common::String url);
|
CurlRequest(DataCallback cb, ErrorCallback ecb, Common::String url);
|
||||||
virtual ~CurlRequest();
|
virtual ~CurlRequest();
|
||||||
|
|
||||||
virtual void handle();
|
virtual void handle();
|
||||||
|
@ -73,7 +73,7 @@ public:
|
||||||
virtual NetworkReadStreamResponse execute();
|
virtual NetworkReadStreamResponse execute();
|
||||||
|
|
||||||
/** Returns Request's NetworkReadStream. */
|
/** Returns Request's NetworkReadStream. */
|
||||||
const NetworkReadStream *getNetworkReadStream() const { return _stream; }
|
const NetworkReadStream *getNetworkReadStream() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Networking
|
} // 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/callback.h"
|
||||||
#include "common/scummsys.h"
|
#include "common/scummsys.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
namespace Networking {
|
namespace Networking {
|
||||||
|
|
||||||
|
@ -51,8 +52,39 @@ template<typename T> struct Response {
|
||||||
Response(Request *rq, T v) : request(rq), value(v) {}
|
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 Response<void *> DataReponse;
|
||||||
typedef Common::BaseCallback<DataReponse> *DataCallback;
|
typedef Common::BaseCallback<DataReponse> *DataCallback;
|
||||||
|
typedef Common::BaseCallback<ErrorResponse> *ErrorCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RequestState is used to indicate current Request state.
|
* 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,
|
* After this state is set, but before ConnectionManager deletes the Request,
|
||||||
* Request calls user's callback. User can ask Request to change its state
|
* 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.
|
* 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 {
|
enum RequestState {
|
||||||
PROCESSING,
|
PROCESSING,
|
||||||
|
@ -93,6 +128,13 @@ protected:
|
||||||
*/
|
*/
|
||||||
DataCallback _callback;
|
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
|
* Request state, which is used by ConnectionManager to determine
|
||||||
* whether request might be deleted or it's still working.
|
* 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(). */
|
/** In RETRY state this indicates whether it's time to call restart(). */
|
||||||
uint32 _retryInSeconds;
|
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:
|
public:
|
||||||
Request(DataCallback cb): _callback(cb), _state(PROCESSING), _retryInSeconds(0) {}
|
Request(DataCallback cb, ErrorCallback ecb);
|
||||||
virtual ~Request() { delete _callback; }
|
virtual ~Request();
|
||||||
|
|
||||||
/** Method, which does actual work. Depends on what this Request is doing. */
|
/** Method, which does actual work. Depends on what this Request is doing. */
|
||||||
virtual void handle() = 0;
|
virtual void handle() = 0;
|
||||||
|
|
||||||
/** Method, which is called by ConnectionManager when Request's state is RETRY. */
|
/** Method, which is called by ConnectionManager when Request's state is RETRY. */
|
||||||
virtual void handleRetry() {
|
virtual void handleRetry();
|
||||||
if (_retryInSeconds > 0) --_retryInSeconds;
|
|
||||||
else {
|
|
||||||
_state = PROCESSING;
|
|
||||||
restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Method, which is used to restart the Request. */
|
/** Method, which is used to restart the Request. */
|
||||||
virtual void restart() = 0;
|
virtual void restart() = 0;
|
||||||
|
|
||||||
/** Method, which is called to pause the Request. */
|
/** Method, which is called to pause the Request. */
|
||||||
virtual void pause() { _state = PAUSED; }
|
virtual void pause();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method, which is called to *interrupt* the Request.
|
* Method, which is called to *interrupt* the Request.
|
||||||
* When it's called, Request must stop its work and
|
* 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. */
|
/** Method, which is called to retry the Request. */
|
||||||
virtual void retry(uint32 seconds) {
|
virtual void retry(uint32 seconds);
|
||||||
_state = RETRY;
|
|
||||||
_retryInSeconds = seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns Request's current state. */
|
/** Returns Request's current state. */
|
||||||
RequestState state() const { return _state; }
|
RequestState state() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Cloud
|
} // End of namespace Networking
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -64,7 +64,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Starts saves syncing process in currently active storage if there is any.
|
* 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
|
} // End of namespace Common
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue