From: José Bollo Date: Tue, 4 Apr 2017 12:52:40 +0000 (+0200) Subject: Add synchronous subcalls X-Git-Tag: dab_3.99.1~99 X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?p=src%2Fapp-framework-binder.git;a=commitdiff_plain;h=ede362db9ea82b85a531849c21582f1692bf0d4d Add synchronous subcalls Synchronous subcalls are more easy for writing simple applications with sequential logic. Change-Id: I76a0231a64a6db8270014cd2a64284e1b0fc16ec Signed-off-by: José Bollo --- diff --git a/bindings/samples/HelloWorld.c b/bindings/samples/HelloWorld.c index cb4a5a4a..585154e5 100644 --- a/bindings/samples/HelloWorld.c +++ b/bindings/samples/HelloWorld.c @@ -165,7 +165,7 @@ static void subcallcb (void *prequest, int iserror, json_object *object) if (iserror) afb_req_fail(request, "failed", json_object_to_json_string(object)); else - afb_req_success(request, object, NULL); + afb_req_success(request, json_object_get(object), NULL); afb_req_unref(request); } @@ -178,8 +178,32 @@ static void subcall (struct afb_req request) if (object == NULL) afb_req_fail(request, "failed", "bad arguments"); - else + else { afb_req_subcall(request, api, verb, object, subcallcb, afb_req_store(request)); + json_object_put(object); + } +} + +static void subcallsync (struct afb_req request) +{ + int rc; + 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 *result, *object = api && verb && args ? json_tokener_parse(args) : NULL; + + if (object == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else { + rc = afb_req_subcall_sync(request, api, verb, object, &result); + if (rc) { + afb_req_success(request, result, NULL); + } else { + afb_req_fail(request, "failed", json_object_to_json_string(result)); + json_object_put(result); + } + json_object_put(object); + } } static void eventadd (struct afb_req request) @@ -260,6 +284,7 @@ static const struct afb_verb_desc_v1 verbs[]= { {"pingJson" , AFB_SESSION_NONE, pingJson , "Return a JSON object"}, {"pingevent", AFB_SESSION_NONE, pingEvent , "Send an event"}, {"subcall", AFB_SESSION_NONE, subcall , "Call api/verb(args)"}, + {"subcallsync", AFB_SESSION_NONE, subcallsync , "Call api/verb(args)"}, {"eventadd", AFB_SESSION_NONE, eventadd , "adds the event of 'name' for the 'tag'"}, {"eventdel", AFB_SESSION_NONE, eventdel , "deletes the event of 'tag'"}, {"eventsub", AFB_SESSION_NONE, eventsub , "subscribes to the event of 'tag'"}, diff --git a/include/afb/afb-req-itf.h b/include/afb/afb-req-itf.h index 6b6c8b70..8f8dc8a9 100644 --- a/include/afb/afb-req-itf.h +++ b/include/afb/afb-req-itf.h @@ -72,6 +72,7 @@ struct afb_req_itf { int (*unsubscribe)(void *closure, struct afb_event event); void (*subcall)(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure); + int (*subcallsync)(void *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result); }; /* @@ -365,6 +366,19 @@ static inline void afb_req_subcall(struct afb_req req, const char *api, const ch 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'. + * This call is synchronous, it waits untill completion of the request. + * It returns 0 on an error answer and returns 1 when no error was detected. + * The object pointed by 'result' is filled and must be released by the caller + * after its use by calling 'json_object_put'. + */ +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) +{ + return req.itf->subcallsync(req.closure, api, verb, args, result); +} + /* internal use */ static inline const char *afb_req_raw(struct afb_req req, size_t *size) { diff --git a/src/afb-apis.c b/src/afb-apis.c index 2f61fe95..0e257883 100644 --- a/src/afb-apis.c +++ b/src/afb-apis.c @@ -231,38 +231,55 @@ int afb_apis_start_all_services(int share_session) return 0; } +/** + * Internal direct dispatch of the request 'xreq' + * @param xreq the request to dispatch + */ +static void do_call_direct(struct afb_xreq *xreq) +{ + const struct api_desc *a; + /* search the api */ + a = search(xreq->api); + if (!a) + afb_xreq_fail_f(xreq, "unknown-api", "api %s not found", xreq->api); + else { + xreq->context.api_key = a->api.closure; + a->api.call(a->api.closure, xreq); + } +} - - - +/** + * Asynchronous dispatch callback for the request 'xreq' + * @param signum 0 on normal flow or the signal number that interupted the normal flow + */ static void do_call_async(int signum, void *arg) { struct afb_xreq *xreq = arg; - const struct api_desc *a; if (signum != 0) afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum); else { - /* search the api */ - a = search(xreq->api); - if (!a) - afb_xreq_fail_f(xreq, "unknown-api", "api %s not found", xreq->api); - else { - xreq->context.api_key = a->api.closure; - a->api.call(a->api.closure, xreq); - } + do_call_direct(xreq); } afb_xreq_unref(xreq); } /** - * Dispatch the request 'req' with the 'context' to the - * method of 'api' and 'verb'. - * @param req the request to dispatch - * @param context the context of the request - * @param api the api of the verb - * @param verb the verb within the api + * Dispatch the request 'xreq' synchronously and directly. + * @param xreq the request to dispatch + */ +void afb_apis_call_direct(struct afb_xreq *xreq) +{ + /* init hooking the request */ + // TODO req = afb_hook_req_call(req, context, api, verb); + + do_call_direct(xreq); +} + +/** + * Dispatch the request 'xreq' asynchronously. + * @param xreq the request to dispatch */ void afb_apis_call(struct afb_xreq *xreq) { diff --git a/src/afb-apis.h b/src/afb-apis.h index e9834d0e..dd3e6b6d 100644 --- a/src/afb-apis.h +++ b/src/afb-apis.h @@ -38,5 +38,6 @@ extern int afb_apis_start_all_services(int share_session); extern int afb_apis_start_service(const char *name, int share_session, int onneed); extern void afb_apis_call(struct afb_xreq *xreq); +extern void afb_apis_call_direct(struct afb_xreq *xreq); diff --git a/src/afb-msg-json.c b/src/afb-msg-json.c index 7702eb63..b4ae51b4 100644 --- a/src/afb-msg-json.c +++ b/src/afb-msg-json.c @@ -107,4 +107,14 @@ struct afb_arg afb_msg_json_get_arg(struct json_object *object, const char *name return arg; } +struct json_object *afb_msg_json_internal_error() +{ + static struct json_object *obj; + + if (obj == NULL) + obj = afb_msg_json_reply_error("failed", "internal error", NULL, NULL); + + return obj; +} + diff --git a/src/afb-msg-json.h b/src/afb-msg-json.h index 9805d3b8..0434e209 100644 --- a/src/afb-msg-json.h +++ b/src/afb-msg-json.h @@ -29,3 +29,4 @@ extern struct json_object *afb_msg_json_event(const char *event, struct json_obj extern struct afb_arg afb_msg_json_get_arg(struct json_object *object, const char *name); +extern struct json_object *afb_msg_json_internal_error(); diff --git a/src/afb-subcall.c b/src/afb-subcall.c index 81361a08..bc5fc862 100644 --- a/src/afb-subcall.c +++ b/src/afb-subcall.c @@ -29,6 +29,7 @@ #include "afb-context.h" #include "afb-xreq.h" #include "verbose.h" +#include "jobs.h" struct subcall; @@ -36,6 +37,7 @@ static void subcall_destroy(void *closure); static void subcall_reply(void *closure, int iserror, struct json_object *obj); static int subcall_subscribe(void *closure, struct afb_event event); static int subcall_unsubscribe(void *closure, struct afb_event event); +static void subcall_sync_leave(struct subcall *subcall); const struct afb_xreq_query_itf afb_subcall_xreq_itf = { .reply = subcall_reply, @@ -50,6 +52,9 @@ struct subcall struct afb_xreq *caller; void (*callback)(void*, int, struct json_object*); void *closure; + struct jobloop *jobloop; + struct json_object *result; + int iserror; }; static void subcall_destroy(void *closure) @@ -65,8 +70,14 @@ static void subcall_reply(void *closure, int iserror, struct json_object *obj) { struct subcall *subcall = closure; - subcall->callback(subcall->closure, iserror, obj); - json_object_put(obj); + if (subcall->callback) { + subcall->callback(subcall->closure, iserror, obj); + json_object_put(obj); + } else { + subcall->result = obj; + subcall->iserror = iserror; + subcall_sync_leave(subcall); + } } static int subcall_subscribe(void *closure, struct afb_event event) @@ -83,16 +94,6 @@ static int subcall_unsubscribe(void *closure, struct afb_event event) return afb_xreq_unsubscribe(subcall->caller, event); } -void afb_subcall_internal_error(void (*callback)(void*, int, struct json_object*), void *closure) -{ - static struct json_object *obj; - - if (obj == NULL) - obj = afb_msg_json_reply_error("failed", "internal error", NULL, NULL); - - callback(closure, 1, obj); -} - static struct subcall *create_subcall(struct afb_xreq *caller, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure) { struct subcall *subcall; @@ -102,7 +103,6 @@ static struct subcall *create_subcall(struct afb_xreq *caller, const char *api, return NULL; } - afb_context_subinit(&subcall->xreq.context, &caller->context); subcall->xreq.refcount = 1; subcall->xreq.json = args; @@ -113,6 +113,8 @@ static struct subcall *create_subcall(struct afb_xreq *caller, const char *api, subcall->caller = caller; subcall->callback = callback; subcall->closure = closure; + afb_xreq_addref(caller); + json_object_get(args); return subcall; } @@ -129,13 +131,61 @@ void afb_subcall( subcall = create_subcall(caller, api, verb, args, callback, closure); if (subcall == NULL) { - afb_subcall_internal_error(callback, closure); + callback(closure, 1, afb_msg_json_internal_error()); return; } - afb_xreq_addref(caller); afb_apis_call(&subcall->xreq); afb_xreq_unref(&subcall->xreq); } +static void subcall_sync_leave(struct subcall *subcall) +{ + struct jobloop *jobloop = subcall->jobloop; + subcall->jobloop = NULL; + if (jobloop) + jobs_leave(jobloop); +} + +static void subcall_sync_cb(int signum, void *closure, struct jobloop *jobloop) +{ + struct subcall *subcall = closure; + + if (!signum) { + subcall->jobloop = jobloop; + afb_apis_call_direct(&subcall->xreq); + } else { + afb_xreq_fail_f(&subcall->xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum); + } + subcall_sync_leave(subcall); +} + +int afb_subcall_sync( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result +) +{ + int rc; + struct subcall *subcall; + + subcall = create_subcall(caller, api, verb, args, NULL, NULL); + if (subcall == NULL) { + *result = json_object_get(afb_msg_json_internal_error()); + return 0; + } + + rc = jobs_enter(NULL, 0, subcall_sync_cb, subcall); + if (rc < 0) { + subcall->result = json_object_get(afb_msg_json_internal_error()); + subcall->iserror = 1; + } + rc = !subcall->iserror; + *result = subcall->result; + afb_xreq_unref(&subcall->xreq); + return rc; +} + diff --git a/src/afb-subcall.h b/src/afb-subcall.h index 7d29e1a2..bf3d8cd1 100644 --- a/src/afb-subcall.h +++ b/src/afb-subcall.h @@ -28,7 +28,10 @@ extern void afb_subcall( void (*callback)(void*, int, struct json_object*), void *closure); -extern void afb_subcall_internal_error( - void (*callback)(void*, int, struct json_object*), - void *closure); +extern int afb_subcall_sync( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); diff --git a/src/afb-svc.c b/src/afb-svc.c index 93e85533..59e775cd 100644 --- a/src/afb-svc.c +++ b/src/afb-svc.c @@ -27,7 +27,7 @@ #include "afb-session.h" #include "afb-context.h" #include "afb-evt.h" -#include "afb-subcall.h" +#include "afb-msg-json.h" #include "afb-svc.h" #include "afb-xreq.h" #include "afb-apis.h" @@ -228,7 +228,8 @@ static void svc_call(void *closure, const char *api, const char *verb, struct js if (svcreq == NULL) { ERROR("out of memory"); json_object_put(args); - return afb_subcall_internal_error(callback, cbclosure); + callback(cbclosure, 1, afb_msg_json_internal_error()); + return; } /* initialises the request */ diff --git a/src/afb-xreq.c b/src/afb-xreq.c index c8fd94e9..15ebae05 100644 --- a/src/afb-xreq.c +++ b/src/afb-xreq.c @@ -62,6 +62,13 @@ static void xreq_subcall_cb( void (*callback)(void*, int, struct json_object*), void *cb_closure); +static int xreq_subcallsync_cb( + void *closure, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); + const struct afb_req_itf xreq_itf = { .json = xreq_json_cb, .get = xreq_get_cb, @@ -77,7 +84,8 @@ const struct afb_req_itf xreq_itf = { .session_set_LOA = xreq_session_set_LOA_cb, .subscribe = xreq_subscribe_cb, .unsubscribe = xreq_unsubscribe_cb, - .subcall = xreq_subcall_cb + .subcall = xreq_subcall_cb, + .subcallsync = xreq_subcallsync_cb }; static struct json_object *xreq_json_cb(void *closure) @@ -248,6 +256,17 @@ static void xreq_subcall_cb(void *closure, const char *api, const char *verb, st afb_subcall(xreq, api, verb, args, callback, cb_closure); } +static int xreq_subcallsync_cb(void *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result) +{ + struct afb_xreq *xreq = closure; +/* + if (xreq->queryitf->subcallsync) + xreq->queryitf->subcall(xreq->query, api, verb, args, callback, cb_closure); + else +*/ + return afb_subcall_sync(xreq, api, verb, args, result); +} + void afb_xreq_success_f(struct afb_xreq *xreq, struct json_object *obj, const char *info, ...) { char *message;