subcall_req: introduce afb_req_subcall_req
authorJosé Bollo <jose.bollo@iot.bzh>
Wed, 2 Aug 2017 17:14:09 +0000 (19:14 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Thu, 3 Aug 2017 09:47:27 +0000 (11:47 +0200)
The function 'afb_req_subcall_req' can be used to make asynchronous
subcalls. It improves the function 'afb_req_subcall' by automatically
keeping the request opened for the callback and by passing it, the
request, as an extra argument of the callback.

Change-Id: I2dc79c01fc25c7a65b9c8cc9e001a5b85fba99df
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
bindings/samples/HelloWorld.c
docs/afb-binding-references.md
include/afb/afb-req-common.h
src/afb-hook.c
src/afb-hook.h
src/afb-xreq.c

index 731ea53..002c472 100644 (file)
@@ -192,6 +192,27 @@ static void subcall (afb_req request)
                afb_req_subcall(request, api, verb, object, subcallcb, afb_req_store(request));
 }
 
+static void subcallreqcb (void *prequest, int status, json_object *object, afb_req request)
+{
+       if (status < 0)
+               afb_req_fail(request, "failed", json_object_to_json_string(object));
+       else
+               afb_req_success(request, json_object_get(object), NULL);
+}
+
+static void subcallreq (afb_req request)
+{
+       const char *api = afb_req_value(request, "api");
+       const char *verb = afb_req_value(request, "verb");
+       const char *args = afb_req_value(request, "args");
+       json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
+
+       if (object == NULL)
+               afb_req_fail(request, "failed", "bad arguments");
+       else
+               afb_req_subcall_req(request, api, verb, object, subcallreqcb, NULL);
+}
+
 static void subcallsync (afb_req request)
 {
        int rc;
@@ -418,6 +439,7 @@ static const afb_verb_v2 verbs[]= {
   { .verb="pingJson",    .callback=pingJson },
   { .verb="pingevent",   .callback=pingEvent },
   { .verb="subcall",     .callback=subcall },
+  { .verb="subcallreq",  .callback=subcallreq },
   { .verb="subcallsync", .callback=subcallsync },
   { .verb="eventadd",    .callback=eventadd },
   { .verb="eventdel",    .callback=eventdel },
index 97ed14a..d0a9a6d 100644 (file)
@@ -586,6 +586,10 @@ client (with its permissions).
  * For convenience, the function calls 'json_object_put' for 'args'.
  * Thus, in the case where 'args' should remain available after
  * the function returns, the function 'json_object_get' shall be used.
+ *
+ * See also:
+ *  - 'afb_req_subcall_req' that is convenient to keep request alive automatically.
+ *  - 'afb_req_subcall_sync' the synchronous version
  */
 void afb_req_subcall(
                 struct afb_req req,
@@ -595,6 +599,29 @@ void afb_req_subcall(
                 void (*callback)(void *closure, int status, struct json_object *result),
                 void *closure);
 
+/*
+ * Makes a call to the method of name 'api' / 'verb' with the object 'args'.
+ * This call is made in the context of the request 'req'.
+ * On completion, the function 'callback' is invoked with the
+ * original request 'req', the 'closure' given at call and two
+ * other parameters: 'iserror' and 'result'.
+ * 'status' is 0 on success or negative when on an error reply.
+ * 'result' is the json object of the reply, you must not call json_object_put
+ * on the result.
+ *
+ * For convenience, the function calls 'json_object_put' for 'args'.
+ * Thus, in the case where 'args' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * See also:
+ *  - 'afb_req_subcall' that doesn't keep request alive automatically.
+ *  - 'afb_req_subcall_sync' the synchronous version
+ */
+static inline void afb_req_subcall_req(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req req), void *closure)
+{
+       req.itf->subcall_req(req.closure, api, verb, args, callback, closure);
+}
+
 /*
  * Makes a call to the method of name 'api' / 'verb' with the object 'args'.
  * This call is made in the context of the request 'req'.
@@ -606,6 +633,10 @@ void afb_req_subcall(
  * For convenience, the function calls 'json_object_put' for 'args'.
  * Thus, in the case where 'args' should remain available after
  * the function returns, the function 'json_object_get' shall be used.
+ *
+ * See also:
+ *  - 'afb_req_subcall_req' that is convenient to keep request alive automatically.
+ *  - 'afb_req_subcall' that doesn't keep request alive automatically.
  */
 int afb_req_subcall_sync(
                 struct afb_req req,
index 9fce668..d6d0258 100644 (file)
@@ -23,6 +23,7 @@
 
 struct json_object;
 struct afb_stored_req;
+struct afb_req;
 
 /*
  * Describes an argument (or parameter) of a request
@@ -72,6 +73,7 @@ struct afb_req_itf
 
        void (*vverbose)(void *closure, int level, const char *file, int line, const char * func, const char *fmt, va_list args);
        struct afb_stored_req *(*store)(void *closure);
+       void (*subcall_req)(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure);
 };
 
 /*
@@ -343,12 +345,39 @@ static inline int afb_req_unsubscribe(struct afb_req req, struct afb_event event
  * For convenience, the function calls 'json_object_put' for 'args'.
  * Thus, in the case where 'args' should remain available after
  * the function returns, the function 'json_object_get' shall be used.
+ *
+ * See also:
+ *  - 'afb_req_subcall_req' that is convenient to keep request alive automatically.
+ *  - 'afb_req_subcall_sync' the synchronous version
  */
 static inline void afb_req_subcall(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result), void *closure)
 {
        req.itf->subcall(req.closure, api, verb, args, callback, closure);
 }
 
+/*
+ * Makes a call to the method of name 'api' / 'verb' with the object 'args'.
+ * This call is made in the context of the request 'req'.
+ * On completion, the function 'callback' is invoked with the
+ * original request 'req', the 'closure' given at call and two
+ * other parameters: 'iserror' and 'result'.
+ * 'status' is 0 on success or negative when on an error reply.
+ * 'result' is the json object of the reply, you must not call json_object_put
+ * on the result.
+ *
+ * For convenience, the function calls 'json_object_put' for 'args'.
+ * Thus, in the case where 'args' should remain available after
+ * the function returns, the function 'json_object_get' shall be used.
+ *
+ * See also:
+ *  - 'afb_req_subcall' that doesn't keep request alive automatically.
+ *  - 'afb_req_subcall_sync' the synchronous version
+ */
+static inline void afb_req_subcall_req(struct afb_req req, const char *api, const char *verb, struct json_object *args, void (*callback)(void *closure, int iserror, struct json_object *result, struct afb_req req), void *closure)
+{
+       req.itf->subcall_req(req.closure, api, verb, args, callback, closure);
+}
+
 /*
  * Makes a call to the method of name 'api' / 'verb' with the object 'args'.
  * This call is made in the context of the request 'req'.
@@ -360,6 +389,10 @@ static inline void afb_req_subcall(struct afb_req req, const char *api, const ch
  * For convenience, the function calls 'json_object_put' for 'args'.
  * Thus, in the case where 'args' should remain available after
  * the function returns, the function 'json_object_get' shall be used.
+ *
+ * See also:
+ *  - 'afb_req_subcall_req' that is convenient to keep request alive automatically.
+ *  - 'afb_req_subcall' that doesn't keep request alive automatically.
  */
 static inline int afb_req_subcall_sync(struct afb_req req, const char *api, const char *verb, struct json_object *args, struct json_object **result)
 {
index 2f101bf..05b04ae 100644 (file)
@@ -281,6 +281,16 @@ static void hook_xreq_unstore_default_cb(void * closure, const struct afb_xreq *
        _hook_xreq_(xreq, "unstore()");
 }
 
+static void hook_xreq_subcall_req_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
+{
+       _hook_xreq_(xreq, "subcall_req(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
+}
+
+static void hook_xreq_subcall_req_result_default_cb(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result)
+{
+       _hook_xreq_(xreq, "    ...subcall_req... -> %d: %s", status, json_object_to_json_string(result));
+}
+
 static struct afb_hook_xreq_itf hook_xreq_default_itf = {
        .hook_xreq_begin = hook_xreq_begin_default_cb,
        .hook_xreq_end = hook_xreq_end_default_cb,
@@ -302,7 +312,9 @@ static struct afb_hook_xreq_itf hook_xreq_default_itf = {
        .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_default_cb,
        .hook_xreq_vverbose = hook_xreq_vverbose_default_cb,
        .hook_xreq_store = hook_xreq_store_default_cb,
-       .hook_xreq_unstore = hook_xreq_unstore_default_cb
+       .hook_xreq_unstore = hook_xreq_unstore_default_cb,
+       .hook_xreq_subcall_req = hook_xreq_subcall_req_default_cb,
+       .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result_default_cb
 };
 
 /******************************************************************************
@@ -438,6 +450,16 @@ void afb_hook_xreq_unstore(const struct afb_xreq *xreq)
        _HOOK_XREQ_(unstore, xreq);
 }
 
+void afb_hook_xreq_subcall_req(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
+{
+       _HOOK_XREQ_(subcall_req, xreq, api, verb, args);
+}
+
+void afb_hook_xreq_subcall_req_result(const struct afb_xreq *xreq, int status, struct json_object *result)
+{
+       _HOOK_XREQ_(subcall_req_result, xreq, status, result);
+}
+
 /******************************************************************************
  * section: hooking xreqs
  *****************************************************************************/
index df11905..1cf7348 100644 (file)
@@ -53,12 +53,14 @@ struct afb_hook_xreq;
 #define afb_hook_flag_req_subscribe            0x001000
 #define afb_hook_flag_req_unsubscribe          0x002000
 #define afb_hook_flag_req_subcall              0x004000
-#define afb_hook_flag_req_subcall_result       0x010800
-#define afb_hook_flag_req_subcallsync          0x020000
-#define afb_hook_flag_req_subcallsync_result   0x040000
-#define afb_hook_flag_req_vverbose             0x080000
-#define afb_hook_flag_req_store                        0x100000
-#define afb_hook_flag_req_unstore              0x200000
+#define afb_hook_flag_req_subcall_result       0x008000
+#define afb_hook_flag_req_subcallsync          0x010000
+#define afb_hook_flag_req_subcallsync_result   0x020000
+#define afb_hook_flag_req_vverbose             0x040000
+#define afb_hook_flag_req_store                        0x080000
+#define afb_hook_flag_req_unstore              0x100000
+#define afb_hook_flag_req_subcall_req          0x200000
+#define afb_hook_flag_req_subcall_req_result   0x400000
 
 /* common flags */
 #define afb_hook_flags_req_life                (afb_hook_flag_req_begin|afb_hook_flag_req_end)
@@ -67,6 +69,7 @@ struct afb_hook_xreq;
 #define afb_hook_flags_req_session     (afb_hook_flag_req_session_close|afb_hook_flag_req_session_set_LOA)
 #define afb_hook_flags_req_event       (afb_hook_flag_req_subscribe|afb_hook_flag_req_unsubscribe)
 #define afb_hook_flags_req_subcalls    (afb_hook_flag_req_subcall|afb_hook_flag_req_subcall_result\
+                                       |afb_hook_flag_req_subcall_req|afb_hook_flag_req_subcall_req_result\
                                        |afb_hook_flag_req_subcallsync|afb_hook_flag_req_subcallsync_result)
 
 /* extra flags */
@@ -104,6 +107,8 @@ struct afb_hook_xreq_itf {
        void (*hook_xreq_vverbose)(void * closure, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args);
        void (*hook_xreq_store)(void * closure, const struct afb_xreq *xreq, struct afb_stored_req *sreq);
        void (*hook_xreq_unstore)(void * closure, const struct afb_xreq *xreq);
+       void (*hook_xreq_subcall_req)(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args);
+       void (*hook_xreq_subcall_req_result)(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result);
 };
 
 extern void afb_hook_init_xreq(struct afb_xreq *xreq);
@@ -134,6 +139,8 @@ extern int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int sta
 extern void afb_hook_xreq_vverbose(const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args);
 extern void afb_hook_xreq_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq);
 extern void afb_hook_xreq_unstore(const struct afb_xreq *xreq);
+extern void afb_hook_xreq_subcall_req(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args);
+extern void afb_hook_xreq_subcall_req_result(const struct afb_xreq *xreq, int status, struct json_object *result);
 
 /*********************************************************
 * section hooking ditf (daemon interface)
index ec3a8fe..c70e000 100644 (file)
@@ -57,6 +57,16 @@ static inline void xreq_unref(struct afb_xreq *xreq)
 
 /******************************************************************************/
 
+extern const struct afb_req_itf xreq_itf;
+extern const struct afb_req_itf xreq_hooked_itf;
+
+static inline struct afb_req to_req(struct afb_xreq *xreq)
+{
+       return (struct afb_req){ .itf = xreq->hookflags ? &xreq_hooked_itf : &xreq_itf, .closure = xreq };
+}
+
+/******************************************************************************/
+
 struct subcall
 {
        struct afb_xreq xreq;
@@ -70,8 +80,11 @@ struct subcall
                        int status;
                };
                struct {
+                       union {
                                void (*callback)(void*, int, struct json_object*);
-                               void *closure;
+                               void (*callback2)(void*, int, struct json_object*, struct afb_req);
+                       };
+                       void *closure;
                } hooked;
        };
 };
@@ -363,6 +376,32 @@ static void xreq_subcall_cb(void *closure, const char *api, const char *verb, st
        }
 }
 
+static void xreq_subcall_req_reply_cb(void *closure, int status, struct json_object *result)
+{
+       struct subcall *subcall = closure;
+       subcall->hooked.callback2(subcall->hooked.closure, status, result, to_req(subcall->caller));
+}
+
+static void xreq_subcall_req_cb(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure)
+{
+       struct afb_xreq *xreq = closure;
+       struct subcall *subcall;
+
+       subcall = subcall_alloc(xreq, api, verb, args);
+       if (subcall == NULL) {
+               if (callback)
+                       callback(cb_closure, 1, afb_msg_json_internal_error(), to_req(xreq));
+               json_object_put(args);
+       } else {
+               subcall->callback = xreq_subcall_req_reply_cb;
+               subcall->closure = subcall;
+               subcall->hooked.callback2 = callback;
+               subcall->hooked.closure = cb_closure;
+               subcall_process(subcall);
+       }
+}
+
+
 static int xreq_subcallsync_cb(void *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result)
 {
        int rc;
@@ -506,7 +545,7 @@ static int xreq_hooked_unsubscribe_cb(void *closure, struct afb_event event)
 static void xreq_hooked_subcall_reply_cb(void *closure, int status, struct json_object *result)
 {
        struct subcall *subcall = closure;
-       
+
        afb_hook_xreq_subcall_result(subcall->caller, status, result);
        subcall->hooked.callback(subcall->hooked.closure, status, result);
 }
@@ -531,6 +570,34 @@ static void xreq_hooked_subcall_cb(void *closure, const char *api, const char *v
        }
 }
 
+static void xreq_hooked_subcall_req_reply_cb(void *closure, int status, struct json_object *result)
+{
+       struct subcall *subcall = closure;
+
+       afb_hook_xreq_subcall_req_result(subcall->caller, status, result);
+       subcall->hooked.callback2(subcall->hooked.closure, status, result, to_req(subcall->caller));
+}
+
+static void xreq_hooked_subcall_req_cb(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure)
+{
+       struct afb_xreq *xreq = closure;
+       struct subcall *subcall;
+
+       afb_hook_xreq_subcall_req(xreq, api, verb, args);
+       subcall = subcall_alloc(xreq, api, verb, args);
+       if (subcall == NULL) {
+               if (callback)
+                       callback(cb_closure, 1, afb_msg_json_internal_error(), to_req(xreq));
+               json_object_put(args);
+       } else {
+               subcall->callback = xreq_hooked_subcall_req_reply_cb;
+               subcall->closure = subcall;
+               subcall->hooked.callback2 = callback;
+               subcall->hooked.closure = cb_closure;
+               subcall_process(subcall);
+       }
+}
+
 static int xreq_hooked_subcallsync_cb(void *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result)
 {
        int r;
@@ -578,7 +645,8 @@ const struct afb_req_itf xreq_itf = {
        .subcall = xreq_subcall_cb,
        .subcallsync = xreq_subcallsync_cb,
        .vverbose = xreq_vverbose_cb,
-       .store = xreq_store_cb
+       .store = xreq_store_cb,
+       .subcall_req = xreq_subcall_req_cb
 };
 
 const struct afb_req_itf xreq_hooked_itf = {
@@ -599,14 +667,10 @@ const struct afb_req_itf xreq_hooked_itf = {
        .subcall = xreq_hooked_subcall_cb,
        .subcallsync = xreq_hooked_subcallsync_cb,
        .vverbose = xreq_hooked_vverbose_cb,
-       .store = xreq_hooked_store_cb
+       .store = xreq_hooked_store_cb,
+       .subcall_req = xreq_hooked_subcall_req_cb
 };
 
-static inline struct afb_req to_req(struct afb_xreq *xreq)
-{
-       return (struct afb_req){ .itf = xreq->hookflags ? &xreq_hooked_itf : &xreq_itf, .closure = xreq };
-}
-
 /******************************************************************************/
 
 struct afb_req afb_xreq_unstore(struct afb_stored_req *sreq)