CLOUD: Polish Callbacks

Cleaned up all example code and old callbacks.

New Callback classes are introduced in "common/callback.h" and
documented.
This commit is contained in:
Alexander Tkachev 2016-05-21 23:21:42 +06:00
parent e1109c0c32
commit 9e531e3ce7
10 changed files with 153 additions and 156 deletions

View file

@ -35,17 +35,6 @@ namespace Dropbox {
Common::String DropboxStorage::KEY; //can't use ConfMan there yet, loading it on instance creation/auth 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 Common::String DropboxStorage::SECRET; //TODO: hide these secrets somehow
static void printJsonCallback(Networking::Request* rq, void *ptr) {
Common::JSONValue *json = (Common::JSONValue *)ptr;
if (json) {
debug("printJsonCallback:");
debug("%s", json->stringify(true).c_str());
delete json;
} else {
debug("printJsonCallback: got NULL instead of JSON!");
}
}
static void saveAccessTokenCallback(void *ptr) { static void saveAccessTokenCallback(void *ptr) {
Common::JSONValue *json = (Common::JSONValue *)ptr; Common::JSONValue *json = (Common::JSONValue *)ptr;
if (json) { if (json) {
@ -69,53 +58,6 @@ 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!");
}
}
void info2Callback(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;
}
Common::BaseCallback *callback = (Common::BaseCallback *)request->pointer();
Common::JSONValue *json = (Common::JSONValue *)jsonPointer;
if (json) {
//Common::JSONObject result = json->asObject();
if (callback) {
(*callback)(new StorageInfo(json->stringify()));
delete callback;
}
delete json;
} else {
warning("infoCallback: got NULL instead of JSON!");
}
}
DropboxStorage::DropboxStorage(Common::String accessToken, Common::String userId): _token(accessToken), _uid(userId) { DropboxStorage::DropboxStorage(Common::String accessToken, Common::String userId): _token(accessToken), _uid(userId) {
curl_global_init(CURL_GLOBAL_ALL); curl_global_init(CURL_GLOBAL_ALL);
} }
@ -124,41 +66,42 @@ DropboxStorage::~DropboxStorage() {
curl_global_cleanup(); curl_global_cleanup();
} }
void syncSavesInfoCallback(StorageInfo info) { void DropboxStorage::syncSaves(Common::BaseCallback<bool> *callback) {
debug("info: %s", info.info().c_str());
}
void DropboxStorage::infoMethodCallback(void *storageInfo) {
StorageInfo *info = (StorageInfo *)storageInfo;
debug("info: %s", info->info().c_str());
}
void DropboxStorage::syncSaves(OperationCallback callback) {
//this is not the real syncSaves() implementation //this is not the real syncSaves() implementation
info2(new Common::Callback<DropboxStorage>(this, &DropboxStorage::infoMethodCallback)); info(new Common::Callback<DropboxStorage, StorageInfo>(this, &DropboxStorage::infoMethodCallback));
//that line meant the following:
//"please, do the info API request and, when it's finished, call the infoMethodCallback() of me"
} }
void DropboxStorage::info(InfoCallback callback) { void DropboxStorage::info(Common::BaseCallback<StorageInfo> *outerCallback) {
/* Common::BaseCallback<> *innerCallback = new Common::CallbackBridge<DropboxStorage, StorageInfo>(this, &DropboxStorage::infoInnerCallback, outerCallback);
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);
*/
}
void DropboxStorage::info2BridgeCallback(Common::BaseCallback *outerCallback, void *ptr) {
//no NULL checks, delete and such yet
Common::JSONValue *json = (Common::JSONValue *)ptr;
(*outerCallback)(new StorageInfo(json->stringify()));
}
void DropboxStorage::info2(Common::BaseCallback *outerCallback) {
Common::BaseCallback *innerCallback = new Common::CallbackBridge<DropboxStorage>(this, &DropboxStorage::info2BridgeCallback, outerCallback);
Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://api.dropboxapi.com/1/account/info"); Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://api.dropboxapi.com/1/account/info");
request->addHeader("Authorization: Bearer " + _token); request->addHeader("Authorization: Bearer " + _token);
ConnMan.addRequest(request); ConnMan.addRequest(request);
//that callback bridge wraps the outerCallback (passed in arguments from user) into innerCallback
//so, when CurlJsonRequest is finished, it calls the innerCallback
//innerCallback (which is DropboxStorage::infoInnerCallback in this case) processes the void *ptr
//and then calls the outerCallback (which wants to receive StorageInfo, not void *)
}
void DropboxStorage::infoInnerCallback(Common::BaseCallback<StorageInfo> *outerCallback, void *ptr) {
Common::JSONValue *json = (Common::JSONValue *)ptr;
if (!json) {
warning("NULL passed instead of JSON");
delete outerCallback;
return;
}
if (outerCallback) {
(*outerCallback)(StorageInfo(json->stringify()));
delete outerCallback;
}
delete json;
}
void DropboxStorage::infoMethodCallback(StorageInfo storageInfo) {
debug("info: %s", storageInfo.info().c_str());
} }
DropboxStorage *DropboxStorage::loadFromConfig() { DropboxStorage *DropboxStorage::loadFromConfig() {
@ -212,7 +155,7 @@ void DropboxStorage::authThroughConsole() {
} }
void DropboxStorage::getAccessToken(Common::String code) { void DropboxStorage::getAccessToken(Common::String code) {
Common::BaseCallback *callback = new Common::GlobalFunctionCallback(saveAccessTokenCallback); Common::BaseCallback<> *callback = new Common::GlobalFunctionCallback(saveAccessTokenCallback);
Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, "https://api.dropboxapi.com/1/oauth2/token"); Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, "https://api.dropboxapi.com/1/oauth2/token");
request->addPostField("code=" + code); request->addPostField("code=" + code);
request->addPostField("grant_type=authorization_code"); request->addPostField("grant_type=authorization_code");

View file

@ -24,7 +24,6 @@
#define BACKENDS_CLOUD_DROPBOX_STORAGE_H #define BACKENDS_CLOUD_DROPBOX_STORAGE_H
#include "backends/cloud/storage.h" #include "backends/cloud/storage.h"
#include "backends/cloud/manager.h"
#include "common/callback.h" #include "common/callback.h"
namespace Cloud { namespace Cloud {
@ -40,36 +39,38 @@ class DropboxStorage: public Cloud::Storage {
static void getAccessToken(Common::String code); static void getAccessToken(Common::String code);
void infoMethodCallback(void *serviceInfoPtr);
public: public:
virtual ~DropboxStorage(); virtual ~DropboxStorage();
/** Returns pointer to Common::Array<CloudFile>. */ /** Returns pointer to Common::Array<StorageFile>. */
virtual void listDirectory(Common::String path, ListDirectoryCallback callback) {} //TODO virtual void listDirectory(Common::String path, Common::BaseCallback< Common::Array<StorageFile> > *callback) {} //TODO
/** Calls the callback when finished. */ /** Calls the callback when finished. */
virtual void upload(Common::String path, Common::ReadStream* contents, OperationCallback callback) {} //TODO virtual void upload(Common::String path, Common::ReadStream* contents, Common::BaseCallback<bool> *callback) {} //TODO
/** Returns pointer to Common::ReadStream. */ /** Returns pointer to Common::ReadStream. */
virtual void download(Common::String path, DownloadCallback callback) {} //TODO virtual void download(Common::String path, Common::BaseCallback<Common::ReadStream> *callback) {} //TODO
/** Calls the callback when finished. */ /** Calls the callback when finished. */
virtual void remove(Common::String path, OperationCallback callback) {} //TODO virtual void remove(Common::String path, Common::BaseCallback<bool> *callback) {} //TODO
/** Calls the callback when finished. */ /** Calls the callback when finished. */
virtual void syncSaves(OperationCallback callback); virtual void syncSaves(Common::BaseCallback<bool> *callback);
/** Calls the callback when finished. */ /** Calls the callback when finished. */
virtual void createDirectory(Common::String path, OperationCallback callback) {} //TODO virtual void createDirectory(Common::String path, Common::BaseCallback<bool> *callback) {} //TODO
/** Calls the callback when finished. */ /** Calls the callback when finished. */
virtual void touch(Common::String path, OperationCallback callback) {} //TODO virtual void touch(Common::String path, Common::BaseCallback<bool> *callback) {} //TODO
/** Returns pointer to the ServiceInfo struct. */ /** Returns pointer to the StorageInfo struct. */
virtual void info(InfoCallback callback); virtual void info(Common::BaseCallback<StorageInfo> *callback);
void info2(Common::BaseCallback *outerCallback);
void info2BridgeCallback(Common::BaseCallback *outerCallback, void *ptr); /** This is what is called by CurlJsonRequest. */
void infoInnerCallback(Common::BaseCallback<StorageInfo> *outerCallback, void *ptr);
/** This is what is called by infoInnerCallback() (it's its outer callback). */
void infoMethodCallback(StorageInfo storageInfo);
/** 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

View file

@ -46,7 +46,7 @@ Storage* Manager::getCurrentStorage() {
return _currentStorage; return _currentStorage;
} }
void Manager::syncSaves(Storage::OperationCallback callback) { void Manager::syncSaves(Common::BaseCallback<bool> *callback) {
Storage* storage = getCurrentStorage(); Storage* storage = getCurrentStorage();
if (storage) storage->syncSaves(callback); if (storage) storage->syncSaves(callback);
} }

View file

@ -38,7 +38,7 @@ public:
virtual void init(); virtual void init();
virtual Storage* getCurrentStorage(); virtual Storage* getCurrentStorage();
virtual void syncSaves(Storage::OperationCallback callback); virtual void syncSaves(Common::BaseCallback<bool> *callback);
}; };
} //end of namespace Cloud } //end of namespace Cloud

View file

@ -26,6 +26,7 @@
#include "common/array.h" #include "common/array.h"
#include "common/stream.h" #include "common/stream.h"
#include "common/str.h" #include "common/str.h"
#include "common/callback.h"
namespace Cloud { namespace Cloud {
@ -70,37 +71,32 @@ public:
class Storage { class Storage {
public: public:
typedef void(*ListDirectoryCallback)(Common::Array<StorageFile>& result);
typedef void(*DownloadCallback)(Common::ReadStream* result);
typedef void(*InfoCallback)(StorageInfo result);
typedef void(*OperationCallback)(bool successed);
Storage() {} Storage() {}
virtual ~Storage() {} virtual ~Storage() {}
/** Returns pointer to Common::Array<CloudFile>. */ /** Returns pointer to Common::Array<StorageFile>. */
virtual void listDirectory(Common::String path, ListDirectoryCallback callback) = 0; virtual void listDirectory(Common::String path, Common::BaseCallback< Common::Array<StorageFile> > *callback) = 0;
/** Calls the callback when finished. */ /** Calls the callback when finished. */
virtual void upload(Common::String path, Common::ReadStream* contents, OperationCallback callback) = 0; virtual void upload(Common::String path, Common::ReadStream* contents, Common::BaseCallback<bool> *callback) = 0;
/** Returns pointer to Common::ReadStream. */ /** Returns pointer to Common::ReadStream. */
virtual void download(Common::String path, DownloadCallback callback) = 0; virtual void download(Common::String path, Common::BaseCallback<Common::ReadStream> *callback) = 0;
/** Calls the callback when finished. */ /** Calls the callback when finished. */
virtual void remove(Common::String path, OperationCallback callback) = 0; virtual void remove(Common::String path, Common::BaseCallback<bool> *callback) = 0;
/** Calls the callback when finished. */ /** Calls the callback when finished. */
virtual void syncSaves(OperationCallback callback) = 0; virtual void syncSaves(Common::BaseCallback<bool> *callback) = 0;
/** Calls the callback when finished. */ /** Calls the callback when finished. */
virtual void createDirectory(Common::String path, OperationCallback callback) = 0; virtual void createDirectory(Common::String path, Common::BaseCallback<bool> *callback) = 0;
/** Calls the callback when finished. */ /** Calls the callback when finished. */
virtual void touch(Common::String path, OperationCallback callback) = 0; virtual void touch(Common::String path, Common::BaseCallback<bool> *callback) = 0;
/** Returns pointer to the ServiceInfo struct. */ /** Returns pointer to the StorageInfo struct. */
virtual void info(InfoCallback callback) = 0; virtual void info(Common::BaseCallback<StorageInfo> *callback) = 0;
/** Returns whether saves sync process is running. */ /** Returns whether saves sync process is running. */
virtual bool isSyncing() = 0; virtual bool isSyncing() = 0;

View file

@ -31,7 +31,7 @@
namespace Networking { namespace Networking {
CurlJsonRequest::CurlJsonRequest(Common::BaseCallback* cb, const char *url) : Request(cb), _stream(0), _headersList(0), _contentsStream(DisposeAfterUse::YES) { CurlJsonRequest::CurlJsonRequest(Common::BaseCallback<> *cb, const char *url): Request(cb), _stream(0), _headersList(0), _contentsStream(DisposeAfterUse::YES) {
_url = url; _url = url;
} }

View file

@ -25,10 +25,7 @@
#include "backends/networking/curl/request.h" #include "backends/networking/curl/request.h"
#include "common/memstream.h" #include "common/memstream.h"
#include "common/json.h"
namespace Common {
class BaseCallback;
}
struct curl_slist; struct curl_slist;
@ -47,7 +44,7 @@ class CurlJsonRequest : public Request {
char *getPreparedContents(); char *getPreparedContents();
public: public:
CurlJsonRequest(Common::BaseCallback *cb, const char *url); CurlJsonRequest(Common::BaseCallback<> *cb, const char *url);
virtual ~CurlJsonRequest(); virtual ~CurlJsonRequest();
virtual bool handle(); virtual bool handle();

View file

@ -22,30 +22,22 @@
#ifndef BACKENDS_NETWORKING_CURL_REQUEST_H #ifndef BACKENDS_NETWORKING_CURL_REQUEST_H
#define BACKENDS_NETWORKING_CURL_REQUEST_H #define BACKENDS_NETWORKING_CURL_REQUEST_H
#include <common/callback.h>
#include "common/callback.h"
namespace Networking { namespace Networking {
class Request { class Request {
protected: protected:
typedef void(*SimpleCallback)(Request* request, void *result);
/** /**
* Callback, which should be called before Request returns true in handle(). * Callback, which should be called before Request returns true in handle().
* That's the way Requests pass the result to the code which asked to create this request. * That's the way Requests pass the result to the code which asked to create this request.
*/ */
Common::BaseCallback* _callback; Common::BaseCallback<> *_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: public:
Request(Common::BaseCallback* cb): _callback(cb) {}; Request(Common::BaseCallback<> *cb): _callback(cb) {};
virtual ~Request() {}; virtual ~Request() {};
/** /**
@ -55,9 +47,6 @@ public:
*/ */
virtual bool handle() = 0; virtual bool handle() = 0;
void setPointer(void *ptr) { _pointer = ptr; }
void *pointer() const { return _pointer; }
}; };
} //end of namespace Cloud } //end of namespace Cloud

View file

@ -25,45 +25,116 @@
namespace Common { namespace Common {
class BaseCallback { /**
* BaseCallback<S> is a simple base class for object-oriented callbacks.
*
* Object-oriented callbacks are such callbacks that know exact instance
* which method must be called.
*
* For backwards compatibility purposes, there is a GlobalFunctionCallback,
* which is BaseCallback<void *>, so it can be used with global C-like
* functions too.
*
* <S> is the type, which is passed to operator() of this callback.
* This allows you to specify that you accept a callback, which wants
* to receive an <S> object.
*/
template<typename S = void *> class BaseCallback {
public: public:
BaseCallback() {} BaseCallback() {}
virtual ~BaseCallback() {} virtual ~BaseCallback() {}
virtual void operator()(void *ptr) = 0; virtual void operator()(S data) = 0;
}; };
class GlobalFunctionCallback: public BaseCallback { /**
* GlobalFunctionCallback is a simple wrapper for global C functions.
*
* If there is a method, which accepts BaseCallback<void *>, you can
* easily pass your C function by passing
* new GlobalFunctionCallback(yourFunction)
*/
class GlobalFunctionCallback: public BaseCallback<void *> {
typedef void(*GlobalFunction)(void *result); typedef void(*GlobalFunction)(void *result);
GlobalFunction _callback; GlobalFunction _callback;
public: public:
GlobalFunctionCallback(GlobalFunction cb): _callback(cb) {} GlobalFunctionCallback(GlobalFunction cb): _callback(cb) {}
virtual ~GlobalFunctionCallback() {} virtual ~GlobalFunctionCallback() {}
virtual void operator()(void *ptr) { virtual void operator()(void *data) {
if (_callback) _callback(ptr); if (_callback) _callback(data);
} }
}; };
template<class T> class Callback: public BaseCallback { /**
typedef void(T::*TMethod)(void *); * Callback<T, S> implements an object-oriented callback.
*
* <T> stands for a class which method you want to call.
* <S>, again, is the type of an object passed to operator().
*
* So, if you have void MyClass::myMethod(AnotherClass) method,
* the corresponding callback is Callback<MyClass, AnotherClass>.
* You create it similarly to this:
* new Callback<MyClass, AnotherClass>(
* pointerToMyClassObject,
* &MyClass::myMethod
* )
*/
template<class T, typename S = void *> class Callback: public BaseCallback<S> {
protected:
typedef void(T::*TMethod)(S);
T *_object; T *_object;
TMethod _method; TMethod _method;
public: public:
Callback(T *object, TMethod method): _object(object), _method(method) {} Callback(T *object, TMethod method): _object(object), _method(method) {}
virtual ~Callback() {} virtual ~Callback() {}
void operator()(void *ptr) { (_object->*_method)(ptr); } void operator()(S data) { (_object->*_method)(data); }
}; };
template<class T> class CallbackBridge: public BaseCallback { /**
typedef void(T::*TCallbackMethod)(BaseCallback *, void *); * CallbackBridge<T, OS, S> helps you to chain callbacks.
*
* CallbackBridge keeps a pointer to BaseCallback<OS>.
* When its operator() is called, it passes this pointer
* along with the actual data (of type <S>) to the method
* of <T> class.
*
* This is needed when you have to call a callback only
* when your own callback is called. So, your callback
* is "inner" and the other one is "outer".
*
* CallbackBridge implements the "inner" one and calls
* the method you wanted. It passes the "outer", so you
* can call it from your method. You can ignore it, but
* probably there is no point in using CallbackBridge then.
*
* So, if you receive a BaseCallback<SomeClass> callback
* and you want to call it from your MyClass::myMethod method,
* you should create CallbackBridge<MyClass, SomeClass, S>,
* where <S> is data type you want to receive in MyClass::myMethod.
*
* You create it similarly to this:
* new Callback<MyClass, SomeClass, AnotherClass>(
* pointerToMyClassObject,
* &MyClass::myMethod,
* outerCallback
* )
* where `outerCallback` is BaseCallback<SomeClass> and `myMethod` is:
* void MyClass::myMethod(BaseCallback<SomeClass> *, AnotherClass)
*/
template<class T, typename OS, typename S = void *> class CallbackBridge: public BaseCallback<S> {
typedef void(T::*TCallbackMethod)(BaseCallback<OS> *, S);
T *_object; T *_object;
TCallbackMethod _method; TCallbackMethod _method;
BaseCallback *_outerCallback; BaseCallback<OS> *_outerCallback;
public: public:
CallbackBridge(T *object, TCallbackMethod method, BaseCallback *outerCallback): CallbackBridge(T *object, TCallbackMethod method, BaseCallback<OS> *outerCallback):
_object(object), _method(method), _outerCallback(outerCallback) {} _object(object), _method(method), _outerCallback(outerCallback) {}
virtual ~CallbackBridge() {} virtual ~CallbackBridge() {}
void operator()(void *ptr) { (_object->*_method)(_outerCallback, ptr); } void operator()(S data) { (_object->*_method)(_outerCallback, data); }
}; };
} // End of namespace Common } // End of namespace Common

View file

@ -53,7 +53,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::OperationCallback callback = 0) = 0; virtual void syncSaves(BaseCallback<bool> *callback = 0) = 0;
}; };
} //end of namespace Common } //end of namespace Common