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.
This commit is contained in:
Alexander Tkachev 2016-05-30 13:35:53 +06:00
parent d917592099
commit b9e3730ccd
9 changed files with 124 additions and 42 deletions

View file

@ -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));

View file

@ -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<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) {
@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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();

View file

@ -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);

View file

@ -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<Common::String, uint32>::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<SavesSyncRequest, Storage::BoolResponse>(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<SavesSyncRequest, Storage::BoolResponse>(this, &SavesSyncRequest::fileUploadedCallback)
_workingRequest = _storage->upload("saves/" + _currentUploadingFile, g_system->getSavefileManager()->openForLoading(_currentUploadingFile),
new Common::Callback<SavesSyncRequest, Storage::UploadResponse>(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.<what?>;
//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;

View file

@ -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);

View file

@ -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<Common::Array<StorageFile>&> FileArrayResponse;
typedef Networking::Response<StorageInfo> StorageInfoResponse;
typedef Networking::Response<bool> BoolResponse;
typedef Networking::Response<UploadStatus> UploadResponse;
typedef Common::BaseCallback<FileArrayResponse> *FileArrayCallback;
typedef Common::BaseCallback<StorageInfoResponse> *StorageInfoCallback;
typedef Common::BaseCallback<BoolResponse> *BoolCallback;
typedef Common::BaseCallback<UploadResponse> *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;