From bdff72f45e1d02f596595f6229d5bccf7c0827c2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Wed, 2 Aug 2017 19:14:09 +0200 Subject: [PATCH] subcall_req: introduce afb_req_subcall_req MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- bindings/samples/HelloWorld.c | 22 ++++++++++++ docs/afb-binding-references.md | 31 ++++++++++++++++ include/afb/afb-req-common.h | 33 +++++++++++++++++ src/afb-hook.c | 24 ++++++++++++- src/afb-hook.h | 19 ++++++---- src/afb-xreq.c | 82 +++++++++++++++++++++++++++++++++++++----- 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, @@ -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, 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,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) { 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) -- 2.16.6