binding-wrap: Rework of context handling 09/21009/4
authorJose Bollo <jose.bollo@iot.bzh>
Fri, 12 Apr 2019 09:18:46 +0000 (11:18 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Tue, 23 Apr 2019 09:22:09 +0000 (11:22 +0200)
The C++ wrapper for handling contexts has
to be improved. This is a proposition of
improvement.

Change-Id: I7df36383f427d109356bdf4df573cba4b6e6ec05
Signed-off-by: Jose Bollo <jose.bollo@iot.bzh>
bindings/tutorials/tuto-3.cpp
include/afb/c++/binding-wrap.hpp

index 8ad69ef..a257999 100644 (file)
@@ -1,3 +1,5 @@
+#include <string>
+
 #include <string.h>
 #include <json-c/json.h>
 
@@ -6,10 +8,20 @@
 
 afb::event event_login, event_logout;
 
+class session
+{
+private:
+       std::string user_;
+public:
+       session(const char *user) : user_(user) {}
+       ~session() {}
+       operator const char *() const { return user_.c_str(); }
+};
+
 void login(afb::req req)
 {
        json_object *args, *user, *passwd;
-       char *usr;
+       const char *usr;
 
        args = req.json();
        if (!json_object_object_get_ex(args, "user", &user)
@@ -23,10 +35,10 @@ void login(afb::req req)
                AFB_REQ_ERROR(req, "login, unauthorized: %s", json_object_get_string(args));
                req.fail("unauthorized");
        } else {
-               usr = strdup(json_object_get_string(user));
+               usr = json_object_get_string(user);
                AFB_REQ_NOTICE(req, "login user: %s", usr);
+               req.context<session>().set(new session(usr));
                req.session_set_LOA(1);
-//             req.context(1, nullptr, free, usr);
                req.success();
                event_login.push(json_object_new_string(usr));
        }
@@ -35,19 +47,17 @@ void login(afb::req req)
 void action(afb::req req)
 {
        json_object *args, *val;
-       char *usr;
+       session &usr = req.context<session>();
 
        args = req.json();
-//     usr = (char*)req.context_get();
-usr = nullptr;
-       AFB_REQ_NOTICE(req, "action for user %s: %s", usr, json_object_get_string(args));
+       AFB_REQ_NOTICE(req, "action for user %s: %s", (const char*)usr, json_object_get_string(args));
        if (json_object_object_get_ex(args, "subscribe", &val)) {
                if (json_object_get_boolean(val)) {
-                       AFB_REQ_NOTICE(req, "user %s subscribes to events", usr);
+                       AFB_REQ_NOTICE(req, "user %s subscribes to events", (const char*)usr);
                        req.subscribe(event_login);
                        req.subscribe(event_logout);
                } else {
-                       AFB_REQ_NOTICE(req, "user %s unsubscribes to events", usr);
+                       AFB_REQ_NOTICE(req, "user %s unsubscribes to events", (const char*)usr);
                        req.unsubscribe(event_login);
                        req.unsubscribe(event_logout);
                }
@@ -57,22 +67,16 @@ usr = nullptr;
 
 void logout(afb::req req)
 {
-       char *usr;
+       session &usr = req.context<session>();
 
-//     usr = (char*)req.context_get();
-usr = nullptr;
-       AFB_REQ_NOTICE(req, "login user %s out", usr);
-       event_logout.push(json_object_new_string(usr));
+       AFB_REQ_NOTICE(req, "login user %s out", (const char*)usr);
+       event_logout.push(json_object_new_string((const char*)usr));
        req.session_set_LOA(0);
-//     req.context_clear();
+       req.context<session>().clear();
        req.success();
 }
 
-int init(
-#if AFB_BINDING_VERSION >= 3
-       afb_api_t api
-#endif
-)
+int init(afb_api_t api)
 {
        AFB_NOTICE("init");
        event_login = afb_daemon_make_event("login");
@@ -92,4 +96,3 @@ const afb_verb_t verbs[] = {
 
 const afb_binding_t afbBindingExport = afb::binding("tuto-3", verbs, "third tutorial: C++", init);
 
-
index a23e553..6af3f84 100644 (file)
@@ -258,8 +258,6 @@ public:
        void failf(const char *error, const char *info, ...) const;
        void failv(const char *error, const char *info, va_list args) const;
 
-       template < class T > T *context() const;
-
        void addref() const;
 
        void unref() const;
@@ -294,6 +292,54 @@ public:
        int get_uid() const;
 
        json_object *get_client_info() const;
+
+       template < class T = void >
+       class contextclass {
+
+               friend class req;
+               afb_req_t req_;
+               contextclass(afb_req_t r) : req_(r) {}
+
+       public:
+               inline operator T *() const { return get(); }
+               inline operator T &() const { return *get(); }
+               inline T* get() const {
+                       return reinterpret_cast<T*>(
+                               afb_req_context(req_, 0,
+                                       nullptr,
+                                       nullptr,
+                                       nullptr));
+               }
+
+               inline void set(T *value, void (*destroyer)(T*) = [](T*t){delete t;}) const {
+                       afb_req_context(req_, 1,
+                               nullptr,
+                               reinterpret_cast<void(*)(void*)>(destroyer),
+                               reinterpret_cast<void*>(value));
+               }
+
+               inline void unset() { set(nullptr); }
+               inline void clear() { set(nullptr); }
+
+               inline T *lazy(T *(*allocator)() = []()->T*{return new T();}, void (*destroyer)(T*) = [](T*t){delete t;}) const {
+                       return reinterpret_cast<T*>(
+                               afb_req_context(req_, 0,
+                                       [allocator](void*)->T*{return allocator();},
+                                       reinterpret_cast<void(*)(void*)>(destroyer),
+                                       nullptr));
+               }
+
+               template <class I>
+               inline T *lazy(I *i, T *(*allocator)(I*) = [](I*i)->T*{return new T(i);}, void (*destroyer)(T*) = [](T*t){delete t;}) const {
+                       return reinterpret_cast<T*>(
+                               afb_req_context(req_, 0,
+                                       [allocator](void*i)->T*{return allocator(reinterpret_cast<I*>(i));},
+                                       reinterpret_cast<void(*)(void*)>(destroyer),
+                                       reinterpret_cast<void*>(i)));
+               }
+       };
+
+       template < class T > contextclass<T> context() const { return contextclass<T>(req_); }
 };
 
 /*************************************************************************/
@@ -476,16 +522,6 @@ inline void req::failf(const char *error, const char *info, ...) const
        va_end(args);
 }
 
-template < class T >
-inline T *req::context() const
-{
-       T* (*creater)(void*) = [](){return new T();};
-       void (*freer)(T*) = [](T*t){delete t;};
-       return reinterpret_cast<T*>(afb_req_context(req_, 0,
-                       reinterpret_cast<void *(*)(void*)>(creater),
-                       reinterpret_cast<void (*)(void*)>(freer), nullptr));
-}
-
 inline void req::addref() const { afb_req_addref(req_); }
 
 inline void req::unref() const { afb_req_unref(req_); }