From b9e3730ccd9a76101ef0cb8812f41c371a24d0d6 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Mon, 30 May 2016 13:35:53 +0600 Subject: CLOUD: Add UploadStatus struct It contains not just "success" flag, but also "file" struct, so the caller can find out some information about uploaded file - like timestamp. --- .../cloud/dropbox/dropboxlistdirectoryrequest.cpp | 4 +- backends/cloud/dropbox/dropboxstorage.cpp | 50 ++++++++++++++++------ backends/cloud/dropbox/dropboxstorage.h | 4 +- backends/cloud/dropbox/dropboxuploadrequest.cpp | 49 +++++++++++++++------ backends/cloud/dropbox/dropboxuploadrequest.h | 6 +-- backends/cloud/onedrive/onedrivestorage.h | 3 +- backends/cloud/savessyncrequest.cpp | 23 ++++++---- backends/cloud/savessyncrequest.h | 2 +- backends/cloud/storage.h | 25 ++++++++++- 9 files changed, 124 insertions(+), 42 deletions(-) (limited to 'backends/cloud') diff --git a/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp b/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp index 6ea90c150d..89e92facb8 100644 --- a/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp +++ b/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp @@ -76,11 +76,11 @@ void DropboxListDirectoryRequest::responseCallback(Networking::JsonResponse pair Common::JSONArray items = response.getVal("entries")->asArray(); for (uint32 i = 0; i < items.size(); ++i) { Common::JSONObject item = items[i]->asObject(); - Common::String path = item.getVal("path_lower")->asString(); + Common::String path = item.getVal("path_lower")->asString(); bool isDirectory = (item.getVal(".tag")->asString() == "folder"); uint32 size = 0, timestamp = 0; if (!isDirectory) { - size = item.getVal("size")->asNumber(); + size = item.getVal("size")->asIntegerNumber(); timestamp = ISO8601::convertToTimestamp(item.getVal("server_modified")->asString()); } _files.push_back(StorageFile(path, size, timestamp, isDirectory)); diff --git a/backends/cloud/dropbox/dropboxstorage.cpp b/backends/cloud/dropbox/dropboxstorage.cpp index 1220a99035..1f983cec67 100644 --- a/backends/cloud/dropbox/dropboxstorage.cpp +++ b/backends/cloud/dropbox/dropboxstorage.cpp @@ -104,14 +104,46 @@ void DropboxStorage::printBool(BoolResponse pair) { debug("bool: %s", (pair.value?"true":"false")); } +void DropboxStorage::printUploadStatus(UploadResponse pair) { + UploadStatus status = pair.value; + if (status.interrupted) { + debug("upload interrupted by user"); + return; + } + if (status.failed) { + debug("upload failed with following response:"); + debug("%s", status.response.c_str()); + return; + } + debug("upload HTTP response code = %ld", status.httpResponseCode); + if (!status.failed) { + debug("uploaded file info:"); + debug("path: %s", status.file.path().c_str()); + debug("size: %u", status.file.size()); + debug("timestamp: %u", status.file.timestamp()); + } +} + Networking::Request *DropboxStorage::listDirectory(Common::String path, FileArrayCallback outerCallback, bool recursive) { return ConnMan.addRequest(new DropboxListDirectoryRequest(_token, path, outerCallback, recursive)); } -Networking::Request *DropboxStorage::upload(Common::String path, Common::SeekableReadStream *contents, BoolCallback callback) { +Networking::Request *DropboxStorage::upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback) { return ConnMan.addRequest(new DropboxUploadRequest(_token, path, contents, callback)); } +Networking::Request *DropboxStorage::upload(Common::String remotePath, Common::String localPath, UploadCallback callback) { + Common::File *f = new Common::File(); + if (!f->open(localPath)) { + warning("DropboxStorage: unable to open file to upload from"); + UploadStatus status(false, true, StorageFile(), "", -1); + if (callback) (*callback)(UploadResponse(nullptr, status)); + delete f; + return nullptr; + } + return upload(remotePath, f, callback); +} + Networking::Request *DropboxStorage::streamFile(Common::String path, Networking::NetworkReadStreamCallback callback) { Common::JSONObject jsonRequestParameters; jsonRequestParameters.setVal("path", new Common::JSONValue(path)); @@ -155,13 +187,7 @@ Networking::Request *DropboxStorage::syncSaves(BoolCallback callback) { false ); */ - Common::File *file = new Common::File(); - if (!file->open("final.bmp")) { - warning("no such file"); - delete file; - return nullptr; - } - return upload("/remote/test3.bmp", file, new Common::Callback(this, &DropboxStorage::printBool)); + return upload("/remote/test4.bmp", "final.bmp", new Common::Callback(this, &DropboxStorage::printUploadStatus)); } Networking::Request *DropboxStorage::info(StorageInfoCallback outerCallback) { @@ -186,13 +212,13 @@ void DropboxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networ if (outerCallback) { //Dropbox documentation states there is no errors for this API method Common::JSONObject info = json->asObject(); - Common::String uid = Common::String::format("%d", (int)info.getVal("uid")->asNumber()); + Common::String uid = Common::String::format("%d", (int)info.getVal("uid")->asIntegerNumber()); Common::String name = info.getVal("display_name")->asString(); Common::String email = info.getVal("email")->asString(); Common::JSONObject quota = info.getVal("quota_info")->asObject(); - uint32 quotaNormal = quota.getVal("normal")->asNumber(); - uint32 quotaShared = quota.getVal("shared")->asNumber(); - uint32 quotaAllocated = quota.getVal("quota")->asNumber(); + uint32 quotaNormal = quota.getVal("normal")->asIntegerNumber(); + uint32 quotaShared = quota.getVal("shared")->asIntegerNumber(); + uint32 quotaAllocated = quota.getVal("quota")->asIntegerNumber(); (*outerCallback)(StorageInfoResponse(nullptr, StorageInfo(uid, name, email, quotaNormal+quotaShared, quotaAllocated))); delete outerCallback; } diff --git a/backends/cloud/dropbox/dropboxstorage.h b/backends/cloud/dropbox/dropboxstorage.h index cc515fef41..ca285802a4 100644 --- a/backends/cloud/dropbox/dropboxstorage.h +++ b/backends/cloud/dropbox/dropboxstorage.h @@ -47,6 +47,7 @@ class DropboxStorage: public Cloud::Storage { void printFiles(FileArrayResponse pair); void printBool(BoolResponse pair); + void printUploadStatus(UploadResponse pair); public: virtual ~DropboxStorage(); @@ -70,7 +71,8 @@ public: virtual Networking::Request *listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false); /** Calls the callback when finished. */ - virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, BoolCallback callback); + virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback); + virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback); /** Returns pointer to Networking::NetworkReadStream. */ virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback); diff --git a/backends/cloud/dropbox/dropboxuploadrequest.cpp b/backends/cloud/dropbox/dropboxuploadrequest.cpp index d068078502..18e1173eef 100644 --- a/backends/cloud/dropbox/dropboxuploadrequest.cpp +++ b/backends/cloud/dropbox/dropboxuploadrequest.cpp @@ -21,17 +21,19 @@ */ #include "backends/cloud/dropbox/dropboxuploadrequest.h" +#include "backends/cloud/iso8601.h" #include "backends/cloud/storage.h" #include "backends/networking/curl/connectionmanager.h" #include "backends/networking/curl/curljsonrequest.h" +#include "backends/networking/curl/networkreadstream.h" #include "common/json.h" #include "common/debug.h" namespace Cloud { namespace Dropbox { -DropboxUploadRequest::DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::BoolCallback callback): - Networking::Request(0), _token(token), _savePath(path), _contentsStream(contents), _boolCallback(callback), +DropboxUploadRequest::DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::UploadCallback callback): + Networking::Request(0), _token(token), _savePath(path), _contentsStream(contents), _uploadCallback(callback), _workingRequest(nullptr), _ignoreCallback(false) { start(); } @@ -40,7 +42,7 @@ DropboxUploadRequest::~DropboxUploadRequest() { _ignoreCallback = true; if (_workingRequest) _workingRequest->finish(); delete _contentsStream; - delete _boolCallback; + delete _uploadCallback; } @@ -105,6 +107,11 @@ void DropboxUploadRequest::partUploadedCallback(Networking::JsonResponse pair) { if (_ignoreCallback) return; _workingRequest = nullptr; + UploadStatus status; + Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)pair.request; + if (rq && rq->getNetworkReadStream()) + status.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); + Common::JSONValue *json = pair.value; if (json) { bool needsFinishRequest = false; @@ -117,13 +124,19 @@ void DropboxUploadRequest::partUploadedCallback(Networking::JsonResponse pair) { if (response.contains("error") || response.contains("error_summary")) { warning("Dropbox returned error: %s", response.getVal("error_summary")->asString().c_str()); delete json; - finish(); + status.failed = true; + status.response = json->stringify(true); + finishUpload(status); return; } if (response.contains("server_modified")) { //finished - finishBool(true); + Common::String path = response.getVal("path_lower")->asString(); + uint32 size = response.getVal("size")->asIntegerNumber(); + uint32 timestamp = ISO8601::convertToTimestamp(response.getVal("server_modified")->asString()); + status.file = StorageFile(path, size, timestamp, false); + finishUpload(status); return; } @@ -136,13 +149,19 @@ void DropboxUploadRequest::partUploadedCallback(Networking::JsonResponse pair) { } } - if (!needsFinishRequest && (_contentsStream->eos() || _contentsStream->pos() >= _contentsStream->size() - 1)) - finishBool(true); - else + if (!needsFinishRequest && (_contentsStream->eos() || _contentsStream->pos() >= _contentsStream->size() - 1)) { + if (status.file.name() == "") { + status.file = StorageFile(_savePath, 0, 0, false); + warning("no file info to put into status"); + } + finishUpload(status); + } else { uploadNextPart(); + } } else { - warning("null, not json"); - finish(); + warning("null, not json"); + status.failed = true; + finishUpload(status); } delete json; @@ -152,11 +171,15 @@ void DropboxUploadRequest::handle() {} void DropboxUploadRequest::restart() { start(); } -void DropboxUploadRequest::finish() { finishBool(false); } +void DropboxUploadRequest::finish() { + UploadStatus status; + status.interrupted = true; + finishUpload(status); +} -void DropboxUploadRequest::finishBool(bool success) { +void DropboxUploadRequest::finishUpload(UploadStatus status) { Request::finish(); - if (_boolCallback) (*_boolCallback)(Storage::BoolResponse(this, success)); + if (_uploadCallback) (*_uploadCallback)(Storage::UploadResponse(this, status)); } } // End of namespace Dropbox diff --git a/backends/cloud/dropbox/dropboxuploadrequest.h b/backends/cloud/dropbox/dropboxuploadrequest.h index a7d7a6c581..9b68995969 100644 --- a/backends/cloud/dropbox/dropboxuploadrequest.h +++ b/backends/cloud/dropbox/dropboxuploadrequest.h @@ -35,7 +35,7 @@ class DropboxUploadRequest: public Networking::Request { Common::String _token; Common::String _savePath; Common::SeekableReadStream *_contentsStream; - Storage::BoolCallback _boolCallback; + Storage::UploadCallback _uploadCallback; Request *_workingRequest; bool _ignoreCallback; Common::String _sessionId; @@ -43,10 +43,10 @@ class DropboxUploadRequest: public Networking::Request { void start(); void uploadNextPart(); void partUploadedCallback(Networking::JsonResponse pair); - void finishBool(bool success); + void finishUpload(UploadStatus status); public: - DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::BoolCallback callback); + DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::UploadCallback callback); virtual ~DropboxUploadRequest(); virtual void handle(); diff --git a/backends/cloud/onedrive/onedrivestorage.h b/backends/cloud/onedrive/onedrivestorage.h index 41d84f9770..7028667819 100644 --- a/backends/cloud/onedrive/onedrivestorage.h +++ b/backends/cloud/onedrive/onedrivestorage.h @@ -76,7 +76,8 @@ public: virtual Networking::Request *listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false); /** Calls the callback when finished. */ - virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, BoolCallback callback) { return nullptr; } //TODO + virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback) { return nullptr; } //TODO + virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback) { return nullptr; } /** Returns pointer to Networking::NetworkReadStream. */ virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback); diff --git a/backends/cloud/savessyncrequest.cpp b/backends/cloud/savessyncrequest.cpp index d48ec6ba45..be1075cb4d 100644 --- a/backends/cloud/savessyncrequest.cpp +++ b/backends/cloud/savessyncrequest.cpp @@ -23,6 +23,8 @@ #include "backends/cloud/savessyncrequest.h" #include "common/debug.h" #include "common/file.h" +#include "common/system.h" +#include "common/savefile.h" namespace Cloud { @@ -85,6 +87,8 @@ void SavesSyncRequest::directoryListedCallback(Storage::FileArrayResponse pair) } } + //TODO: upload files which are added to local directory (not available on cloud), but have no timestamp + //upload files with invalid timestamp (the ones we've added - means they might not have any remote version) for (Common::HashMap::iterator i = _localFilesTimestamps.begin(); i != _localFilesTimestamps.end(); ++i) { if (i->_value == INVALID_TIMESTAMP) @@ -104,7 +108,7 @@ void SavesSyncRequest::downloadNextFile() { _currentDownloadingFile = _filesToDownload.back(); _filesToDownload.pop_back(); - _workingRequest = _storage->download(_currentDownloadingFile.path(), "saves/" + _currentDownloadingFile.name(), + _workingRequest = _storage->download(_currentDownloadingFile.path(), "saves/" + _currentDownloadingFile.name(), //TODO: real saves folder here new Common::Callback(this, &SavesSyncRequest::fileDownloadedCallback) ); } @@ -133,23 +137,24 @@ void SavesSyncRequest::uploadNextFile() { _currentUploadingFile = _filesToUpload.back(); _filesToUpload.pop_back(); - - _workingRequest = _storage->upload("saves/" + _currentUploadingFile, nullptr, //TODO: pass save's read stream - new Common::Callback(this, &SavesSyncRequest::fileUploadedCallback) + + _workingRequest = _storage->upload("saves/" + _currentUploadingFile, g_system->getSavefileManager()->openForLoading(_currentUploadingFile), + new Common::Callback(this, &SavesSyncRequest::fileUploadedCallback) ); } -void SavesSyncRequest::fileUploadedCallback(Storage::BoolResponse pair) { +void SavesSyncRequest::fileUploadedCallback(Storage::UploadResponse pair) { if (_ignoreCallback) return; + UploadStatus status = pair.value; //stop syncing if upload failed - if (!pair.value) { + if (status.interrupted || status.failed) { finish(); return; } - //TODO: update local timestamp for the uploaded file - //_localFilesTimestamps[_currentUploadingFile] = pair.request.; + //update local timestamp for the uploaded file + _localFilesTimestamps[_currentUploadingFile] = status.file.timestamp(); //continue uploading files uploadNextFile(); @@ -172,6 +177,7 @@ void SavesSyncRequest::finishBool(bool success) { void SavesSyncRequest::loadTimestamps() { Common::File f; + //TODO: real saves folder here if (!f.open("saves/timestamps")) error("SavesSyncRequest: failed to open 'saves/timestamps' file to load timestamps"); @@ -215,6 +221,7 @@ void SavesSyncRequest::loadTimestamps() { void SavesSyncRequest::saveTimestamps() { Common::DumpFile f; + //TODO: real saves folder here if (!f.open("saves/timestamps", true)) error("SavesSyncRequest: failed to open 'saves/timestamps' file to save timestamps"); Common::String data; diff --git a/backends/cloud/savessyncrequest.h b/backends/cloud/savessyncrequest.h index dd43cab2a0..dca1fb750b 100644 --- a/backends/cloud/savessyncrequest.h +++ b/backends/cloud/savessyncrequest.h @@ -44,7 +44,7 @@ class SavesSyncRequest: public Networking::Request { void start(); void directoryListedCallback(Storage::FileArrayResponse pair); void fileDownloadedCallback(Storage::BoolResponse pair); - void fileUploadedCallback(Storage::BoolResponse pair); + void fileUploadedCallback(Storage::UploadResponse pair); void downloadNextFile(); void uploadNextFile(); void finishBool(bool success); diff --git a/backends/cloud/storage.h b/backends/cloud/storage.h index dbd862822b..1749881a7d 100644 --- a/backends/cloud/storage.h +++ b/backends/cloud/storage.h @@ -34,15 +34,37 @@ 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) {} +}; + class Storage { public: typedef Networking::Response&> FileArrayResponse; typedef Networking::Response StorageInfoResponse; typedef Networking::Response BoolResponse; + typedef Networking::Response UploadResponse; typedef Common::BaseCallback *FileArrayCallback; typedef Common::BaseCallback *StorageInfoCallback; typedef Common::BaseCallback *BoolCallback; + typedef Common::BaseCallback *UploadCallback; Storage() {} virtual ~Storage() {} @@ -72,7 +94,8 @@ public: virtual Networking::Request *listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false) = 0; /** Calls the callback when finished. */ - virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, BoolCallback callback) = 0; + virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback) = 0; + virtual Networking::Request *upload(Common::String remotePath, Common::String localPath, UploadCallback callback) = 0; /** Returns pointer to Networking::NetworkReadStream. */ virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback) = 0; -- cgit v1.2.3