From 17eb5f91433f2414dc73f89abfdd316407259b61 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Sat, 21 May 2016 00:44:09 +0600 Subject: [PATCH] CLOUD: Add complex callbacks Originally, I intended to add Storage API, StorageFile and StorageInfo stubs. When I tried to implement a simple info() call, I ended up fixing Request to contain some pointer field and all callbacks to have Request* parameter. And, now I have to place callback pointer into Request. which calls another callback. And, eventually, these "simple" callbacks would again require another pointer (to some caller class). --- backends/cloud/dropbox/dropboxstorage.cpp | 42 ++++++++-- backends/cloud/dropbox/dropboxstorage.h | 33 +++++++- backends/cloud/manager.cpp | 4 +- backends/cloud/manager.h | 2 +- backends/cloud/storage.h | 85 ++++++++++++++++---- backends/networking/curl/curljsonrequest.cpp | 2 +- backends/networking/curl/request.h | 12 ++- common/cloudmanager.h | 2 +- 8 files changed, 149 insertions(+), 33 deletions(-) diff --git a/backends/cloud/dropbox/dropboxstorage.cpp b/backends/cloud/dropbox/dropboxstorage.cpp index 93f0eebcf6c..f2270f79cd9 100644 --- a/backends/cloud/dropbox/dropboxstorage.cpp +++ b/backends/cloud/dropbox/dropboxstorage.cpp @@ -35,7 +35,7 @@ namespace Dropbox { Common::String DropboxStorage::KEY; //can't use ConfMan there yet, loading it on instance creation/auth Common::String DropboxStorage::SECRET; //TODO: hide these secrets somehow -static void printJsonCallback(void *ptr) { +static void printJsonCallback(Networking::Request* rq, void *ptr) { Common::JSONValue *json = (Common::JSONValue *)ptr; if (json) { debug("printJsonCallback:"); @@ -46,7 +46,7 @@ static void printJsonCallback(void *ptr) { } } -static void saveAccessTokenCallback(void *ptr) { +static void saveAccessTokenCallback(Networking::Request* rq, void *ptr) { Common::JSONValue *json = (Common::JSONValue *)ptr; if (json) { debug("saveAccessTokenCallback:"); @@ -69,6 +69,29 @@ static void saveAccessTokenCallback(void *ptr) { } } +void infoCallback(Networking::Request* request, void *jsonPointer) { + if (!request) { + warning("infoCallback: got NULL instead of Request"); + + Common::JSONValue *json = (Common::JSONValue *)jsonPointer; + if (json) delete json; //yeah I know we can delete NULL safely + return; + } + + Storage::InfoCallback callback = (Storage::InfoCallback)request->pointer(); + + Common::JSONValue *json = (Common::JSONValue *)jsonPointer; + if (json) { + //Common::JSONObject result = json->asObject(); + if (callback) { + callback(StorageInfo(json->stringify())); + } + delete json; + } else { + warning("infoCallback: got NULL instead of JSON!"); + } +} + DropboxStorage::DropboxStorage(Common::String accessToken, Common::String userId): _token(accessToken), _uid(userId) { curl_global_init(CURL_GLOBAL_ALL); } @@ -77,18 +100,21 @@ DropboxStorage::~DropboxStorage() { curl_global_cleanup(); } -void DropboxStorage::listDirectory(Common::String path) { +void syncSavesInfoCallback(StorageInfo info) { + debug("info: %s", info.info().c_str()); } -void DropboxStorage::syncSaves() { - //not syncing, but already something: - printInfo(); +void DropboxStorage::syncSaves(OperationCallback callback) { + //this is not the real syncSaves() implementation + info(syncSavesInfoCallback); } -void DropboxStorage::printInfo() { - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(printJsonCallback, "https://api.dropboxapi.com/1/account/info"); +void DropboxStorage::info(InfoCallback callback) { + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(infoCallback, "https://api.dropboxapi.com/1/account/info"); request->addHeader("Authorization: Bearer " + _token); ConnMan.addRequest(request); + + request->setPointer(callback); } DropboxStorage *DropboxStorage::loadFromConfig() { diff --git a/backends/cloud/dropbox/dropboxstorage.h b/backends/cloud/dropbox/dropboxstorage.h index afa9447566a..d60dec29def 100644 --- a/backends/cloud/dropbox/dropboxstorage.h +++ b/backends/cloud/dropbox/dropboxstorage.h @@ -42,9 +42,36 @@ class DropboxStorage: public Cloud::Storage { public: virtual ~DropboxStorage(); - virtual void listDirectory(Common::String path); - virtual void syncSaves(); - virtual void printInfo(); + /** Returns pointer to Common::Array. */ + virtual void listDirectory(Common::String path, ListDirectoryCallback callback) {} //TODO + + /** Calls the callback when finished. */ + virtual void upload(Common::String path, Common::ReadStream* contents, OperationCallback callback) {} //TODO + + /** Returns pointer to Common::ReadStream. */ + virtual void download(Common::String path, DownloadCallback callback) {} //TODO + + /** Calls the callback when finished. */ + virtual void remove(Common::String path, OperationCallback callback) {} //TODO + + /** Calls the callback when finished. */ + virtual void syncSaves(OperationCallback callback); + + /** Calls the callback when finished. */ + virtual void createDirectory(Common::String path, OperationCallback callback) {} //TODO + + /** Calls the callback when finished. */ + virtual void touch(Common::String path, OperationCallback callback) {} //TODO + + /** Returns pointer to the ServiceInfo struct. */ + virtual void info(InfoCallback callback); + + /** Returns whether saves sync process is running. */ + virtual bool isSyncing() { return false; } //TODO + + /** Returns whether there are any requests running. */ + virtual bool isWorking() { return false; } //TODO + /** * Load token and user id from configs and return DropboxStorage for those. * @return pointer to the newly created DropboxStorage or 0 if some problem occured. diff --git a/backends/cloud/manager.cpp b/backends/cloud/manager.cpp index 08340e9288a..fc271485bfa 100644 --- a/backends/cloud/manager.cpp +++ b/backends/cloud/manager.cpp @@ -46,9 +46,9 @@ Storage* Manager::getCurrentStorage() { return _currentStorage; } -void Manager::syncSaves() { +void Manager::syncSaves(Storage::OperationCallback callback) { Storage* storage = getCurrentStorage(); - if (storage) storage->syncSaves(); + if (storage) storage->syncSaves(callback); } } //end of namespace Cloud diff --git a/backends/cloud/manager.h b/backends/cloud/manager.h index a1f046d71d4..47109cc1468 100644 --- a/backends/cloud/manager.h +++ b/backends/cloud/manager.h @@ -38,7 +38,7 @@ public: virtual void init(); virtual Storage* getCurrentStorage(); - virtual void syncSaves(); + virtual void syncSaves(Storage::OperationCallback callback); }; } //end of namespace Cloud diff --git a/backends/cloud/storage.h b/backends/cloud/storage.h index 9e23e977618..4fb06f6a9d7 100644 --- a/backends/cloud/storage.h +++ b/backends/cloud/storage.h @@ -23,37 +23,90 @@ #ifndef BACKENDS_CLOUD_STORAGE_H #define BACKENDS_CLOUD_STORAGE_H +#include "common/array.h" +#include "common/stream.h" #include "common/str.h" namespace Cloud { +class StorageFile { + Common::String _path, _name; + uint32 _size, _timestamp; + bool _isDirectory; + +public: + StorageFile(Common::String pth, uint32 sz, uint32 ts, bool dir) { + _path = pth; + + _name = pth; + for (uint32 i = _name.size() - 1; i >= 0; --i) { + if (_name[i] == '/' || _name[i] == '\\') { + _name.erase(0, i); + break; + } + if (i == 0) break; //OK, I admit that's strange + } + + _size = sz; + _timestamp = ts; + _isDirectory = dir; + } + + Common::String path() const { return _path; } + Common::String name() const { return _name; } + uint32 size() const { return _size; } + uint32 timestamp() const { return _timestamp; } + bool isDirectory() const { return _isDirectory; } +}; + +class StorageInfo { + Common::String _info; + +public: + StorageInfo(Common::String info): _info(info) {} + + Common::String info() const { return _info; } +}; + class Storage { public: + typedef void(*ListDirectoryCallback)(Common::Array& result); + typedef void(*DownloadCallback)(Common::ReadStream* result); + typedef void(*InfoCallback)(StorageInfo result); + typedef void(*OperationCallback)(bool successed); + Storage() {} virtual ~Storage() {} - /** - * Lists given directory. - * - * @param path directory to list - */ + /** Returns pointer to Common::Array. */ + virtual void listDirectory(Common::String path, ListDirectoryCallback callback) = 0; - //TODO: actually make it list directories - //TODO: add some callback to pass gathered files list + /** Calls the callback when finished. */ + virtual void upload(Common::String path, Common::ReadStream* contents, OperationCallback callback) = 0; - virtual void listDirectory(Common::String path) = 0; + /** Returns pointer to Common::ReadStream. */ + virtual void download(Common::String path, DownloadCallback callback) = 0; - /** - * Starts saves syncing process. - */ + /** Calls the callback when finished. */ + virtual void remove(Common::String path, OperationCallback callback) = 0; - virtual void syncSaves() = 0; + /** Calls the callback when finished. */ + virtual void syncSaves(OperationCallback callback) = 0; - /** - * Prints user info on console. (Temporary) - */ + /** Calls the callback when finished. */ + virtual void createDirectory(Common::String path, OperationCallback callback) = 0; - virtual void printInfo() = 0; + /** Calls the callback when finished. */ + virtual void touch(Common::String path, OperationCallback callback) = 0; + + /** Returns pointer to the ServiceInfo struct. */ + virtual void info(InfoCallback callback) = 0; + + /** Returns whether saves sync process is running. */ + virtual bool isSyncing() = 0; + + /** Returns whether there are any requests running. */ + virtual bool isWorking() = 0; }; } //end of namespace Cloud diff --git a/backends/networking/curl/curljsonrequest.cpp b/backends/networking/curl/curljsonrequest.cpp index 59bc8306920..929723c6717 100644 --- a/backends/networking/curl/curljsonrequest.cpp +++ b/backends/networking/curl/curljsonrequest.cpp @@ -75,7 +75,7 @@ bool CurlJsonRequest::handle() { if (_callback) { char *contents = getPreparedContents(); Common::JSONValue *json = Common::JSON::parse(contents); - _callback(json); //potential memory leak, free it in your callbacks! + _callback(this, json); //potential memory leak, free it in your callbacks! } return true; } diff --git a/backends/networking/curl/request.h b/backends/networking/curl/request.h index 4f901f7c941..d405ec85519 100644 --- a/backends/networking/curl/request.h +++ b/backends/networking/curl/request.h @@ -27,7 +27,7 @@ namespace Networking { class Request { protected: - typedef void(*Callback)(void *result); + typedef void(*Callback)(Request* request, void *result); /** * Callback, which should be called before Request returns true in handle(). @@ -36,6 +36,13 @@ protected: Callback _callback; + /** + * Pointer, which could be set by Request creating code. It might be accessed + * from this Request when callback is called, for example. + */ + + void *_pointer; + public: Request(Callback cb): _callback(cb) {}; virtual ~Request() {}; @@ -47,6 +54,9 @@ public: */ virtual bool handle() = 0; + + void setPointer(void *ptr) { _pointer = ptr; } + void *pointer() const { return _pointer; } }; } //end of namespace Cloud diff --git a/common/cloudmanager.h b/common/cloudmanager.h index 8a10a1a3c79..08ba928f342 100644 --- a/common/cloudmanager.h +++ b/common/cloudmanager.h @@ -53,7 +53,7 @@ public: * Starts saves syncing process in currently active storage if there is any. */ - virtual void syncSaves() = 0; + virtual void syncSaves(Cloud::Storage::OperationCallback callback = 0) = 0; }; } //end of namespace Common