summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2017-08-02 19:14:09 +0200
committerJosé Bollo <jose.bollo@iot.bzh>2017-08-03 11:47:27 +0200
commitbdff72f45e1d02f596595f6229d5bccf7c0827c2 (patch)
tree9a4eb13b2d784df41e7e46cbcc2fab6fab9977c7
parentd0c20134a2c9ecb53045b63cb1e0d6e2aa2b26d2 (diff)
subcall_req: introduce afb_req_subcall_req
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>
-rw-r--r--bindings/samples/HelloWorld.c22
-rw-r--r--docs/afb-binding-references.md31
-rw-r--r--include/afb/afb-req-common.h33
-rw-r--r--src/afb-hook.c24
-rw-r--r--src/afb-hook.h19
-rw-r--r--src/afb-xreq.c82
6 files changed, 195 insertions, 16 deletions
diff --git a/bindings/samples/HelloWorld.c b/bindings/samples/HelloWorld.c
index 731ea530..002c4721 100644
--- a/bindings/samples/HelloWorld.c
+++ b/bindings/samples/HelloWorld.c
@@ -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 },
diff --git a/docs/afb-binding-references.md b/docs/afb-binding-references.md
index 97ed14a7..d0a9a6d0 100644
--- a/docs/afb-binding-references.md
+++ b/docs/afb-binding-references.md
@@ -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,
@@ -598,6 +602,29 @@ void afb_req_subcall(
/*
* 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'.
* This call is synchronous, it waits untill completion of the request.
* It returns 0 on success or a negative value on error answer.
* The object pointed by 'result' is filled and must be released by the caller
@@ -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,
diff --git a/include/afb/afb-req-common.h b/include/afb/afb-req-common.h
index 9fce668f..d6d02583 100644
--- a/include/afb/afb-req-common.h
+++ b/include/afb/afb-req-common.h
@@ -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,6 +345,10 @@ 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)
{
@@ -352,6 +358,29 @@ static inline void afb_req_subcall(struct afb_req req, const char *api, const ch
/*
* 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'.
* This call is synchronous, it waits untill completion of the request.
* It returns 0 on success or a negative value on error answer.
* The object pointed by 'result' is filled and must be released by the caller
@@ -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)
{
diff --git a/src/afb-hook.c b/src/afb-hook.c
index 2f101bf5..05b04aec 100644
--- a/src/afb-hook.c
+++ b/src/afb-hook.c
@@ -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
*****************************************************************************/
diff --git a/src/afb-hook.h b/src/afb-hook.h
index df119056..1cf73488 100644
--- a/src/afb-hook.h
+++ b/src/afb-hook.h
@@ -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)
diff --git a/src/afb-xreq.c b/src/afb-xreq.c
index ec3a8fe2..c70e0006 100644
--- a/src/afb-xreq.c
+++ b/src/afb-xreq.c
@@ -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)