From b55f3cd48507105e85894be89557787eccfbe22f Mon Sep 17 00:00:00 2001 From: Jose Bollo Date: Mon, 4 Nov 2019 17:57:23 +0100 Subject: [PATCH] afb-stub-ws: Enforce asynchronous describe Because remote apis describe themselves asynchronousely, it is better to have asynchronous describe api. Bug-AGL: SPEC-2968 Change-Id: I52b4dab697f229ad01ea2b73d6b8dee22d507912 Signed-off-by: Jose Bollo --- src/afb-api.h | 2 +- src/afb-apiset.c | 26 +++++--- src/afb-apiset.h | 2 +- src/afb-export.c | 4 +- src/afb-monitor.c | 178 ++++++++++++++++++++++++++++++++++++++++-------------- src/afb-stub-ws.c | 80 ++++-------------------- 6 files changed, 164 insertions(+), 128 deletions(-) diff --git a/src/afb-api.h b/src/afb-api.h index d55970c9..1f2a4a98 100644 --- a/src/afb-api.h +++ b/src/afb-api.h @@ -30,7 +30,7 @@ struct afb_api_itf #endif int (*get_logmask)(void *closure); void (*set_logmask)(void *closure, int level); - struct json_object *(*describe)(void *closure); + void (*describe)(void *closure, void (*describecb)(void *, struct json_object *), void *clocb); void (*unref)(void *closure); }; diff --git a/src/afb-apiset.c b/src/afb-apiset.c index 0a8b3390..9fddd46c 100644 --- a/src/afb-apiset.c +++ b/src/afb-apiset.c @@ -28,6 +28,7 @@ #include "afb-apiset.h" #include "afb-context.h" #include "afb-xreq.h" +#include "jobs.h" #define INCR 8 /* CAUTION: must be a power of 2 */ @@ -941,20 +942,25 @@ int afb_apiset_get_logmask(struct afb_apiset *set, const char *name) return i->api.itf->get_logmask(i->api.closure); } -/** - * Get the description of the API of 'name' - * @param set the api set - * @param name the api whose description is required - * @return the description or NULL - */ -struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name) +void afb_apiset_describe(struct afb_apiset *set, const char *name, void (*describecb)(void *, struct json_object *), void *closure) { const struct api_desc *i; - - i = name ? searchrec(set, name) : NULL; - return i && i->api.itf->describe ? i->api.itf->describe(i->api.closure) : NULL; + struct json_object *r; + + r = NULL; + if (name) { + i = searchrec(set, name); + if (i) { + if (i->api.itf->describe) { + i->api.itf->describe(i->api.closure, describecb, closure); + return; + } + } + } + describecb(closure, r); } + struct get_names { union { struct { diff --git a/src/afb-apiset.h b/src/afb-apiset.h index d1f968b7..f21277a5 100644 --- a/src/afb-apiset.h +++ b/src/afb-apiset.h @@ -60,7 +60,7 @@ extern void afb_apiset_update_hooks(struct afb_apiset *set, const char *name); extern void afb_apiset_set_logmask(struct afb_apiset *set, const char *name, int mask); extern int afb_apiset_get_logmask(struct afb_apiset *set, const char *name); -extern struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name); +extern void afb_apiset_describe(struct afb_apiset *set, const char *name, void (*describecb)(void *, struct json_object *), void *closure); extern const char **afb_apiset_get_names(struct afb_apiset *set, int rec, int type); extern void afb_apiset_enum( diff --git a/src/afb-export.c b/src/afb-export.c index a9643f54..f96f8f81 100644 --- a/src/afb-export.c +++ b/src/afb-export.c @@ -1823,7 +1823,7 @@ static void api_call_cb(void *closure, struct afb_xreq *xreq) } } -static struct json_object *api_describe_cb(void *closure) +static void api_describe_cb(void *closure, void (*describecb)(void *, struct json_object *), void *clocb) { struct afb_export *export = closure; struct json_object *result; @@ -1846,7 +1846,7 @@ static struct json_object *api_describe_cb(void *closure) result = NULL; break; } - return result; + describecb(clocb, result); } static int api_service_start_cb(void *closure) diff --git a/src/afb-monitor.c b/src/afb-monitor.c index e32c85ac..a53f75a3 100644 --- a/src/afb-monitor.c +++ b/src/afb-monitor.c @@ -36,6 +36,17 @@ #include "monitor-api.inc" + +static const char _verbosity_[] = "verbosity"; +static const char _apis_[] = "apis"; + +static const char _debug_[] = "debug"; +static const char _info_[] = "info"; +static const char _notice_[] = "notice"; +static const char _warning_[] = "warning"; +static const char _error_[] = "error"; + + static struct afb_apiset *target_set; int afb_monitor_init(struct afb_apiset *declare_set, struct afb_apiset *call_set) @@ -48,12 +59,6 @@ int afb_monitor_init(struct afb_apiset *declare_set, struct afb_apiset *call_set **** Monitoring verbosity ******************************************************************************/ -static const char _debug_[] = "debug"; -static const char _info_[] = "info"; -static const char _notice_[] = "notice"; -static const char _warning_[] = "warning"; -static const char _error_[] = "error"; - /** * Translate verbosity indication to an integer value. * @param v the verbosity indication @@ -231,72 +236,141 @@ static struct json_object *get_verbosity(struct json_object *spec) } /****************************************************************************** -**** Monitoring apis +**** Manage namelist of api names ******************************************************************************/ -/** - * get apis accordling to specification in 'spec' - * @param resu the json object to build - * @param spec specification of the verbosity to set - */ -static void get_one_api(struct json_object *resu, const char *name, struct json_object *spec) +struct namelist { + struct namelist *next; + json_object *data; + char name[]; +}; + +static struct namelist *reverse_namelist(struct namelist *head) { - struct json_object *o; + struct namelist *previous, *next; + + previous = NULL; + while(head) { + next = head->next; + head->next = previous; + previous = head; + head = next; + } + return previous; +} - o = afb_apiset_describe(target_set, name); - if (o || afb_apiset_lookup(target_set, name, 1)) - json_object_object_add(resu, name, o); +static void add_one_name_to_namelist(struct namelist **head, const char *name, struct json_object *data) +{ + size_t length = strlen(name) + 1; + struct namelist *item = malloc(length + sizeof *item); + if (!item) + ERROR("out of memory"); + else { + item->next = *head; + item->data = data; + memcpy(item->name, name, length); + *head = item; + } } -/** - * callback for getting verbosity of all apis - * @param set the apiset - * @param the name of the api to set - * @param closure the json object to build - */ -static void get_apis_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias) +static void get_apis_namelist_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias) { - struct json_object *resu = closure; - get_one_api(resu, name, NULL); + struct namelist **head = closure; + add_one_name_to_namelist(head, name, NULL); } /** - * get apis accordling to specification in 'spec' - * @param resu the json object to build - * @param spec specification of the verbosity to set + * get apis names as a list accordling to specification in 'spec' + * @param spec specification of the apis to get */ -static struct json_object *get_apis(struct json_object *spec) +static struct namelist *get_apis_namelist(struct json_object *spec) { int i, n; - struct json_object *resu; struct json_object_iterator it, end; + struct namelist *head; - resu = json_object_new_object(); + head = NULL; if (json_object_is_type(spec, json_type_object)) { it = json_object_iter_begin(spec); end = json_object_iter_end(spec); while (!json_object_iter_equal(&it, &end)) { - get_one_api(resu, json_object_iter_peek_name(&it), json_object_iter_peek_value(&it)); + add_one_name_to_namelist(&head, + json_object_iter_peek_name(&it), + json_object_iter_peek_value(&it)); json_object_iter_next(&it); } } else if (json_object_is_type(spec, json_type_array)) { n = (int)json_object_array_length(spec); for (i = 0 ; i < n ; i++) - get_one_api(resu, json_object_get_string(json_object_array_get_idx(spec, i)), NULL); + add_one_name_to_namelist(&head, + json_object_get_string( + json_object_array_get_idx(spec, i)), + NULL); } else if (json_object_is_type(spec, json_type_string)) { - get_one_api(resu, json_object_get_string(spec), NULL); + add_one_name_to_namelist(&head, json_object_get_string(spec), NULL); } else if (json_object_get_boolean(spec)) { - afb_apiset_enum(target_set, 1, get_apis_of_all_cb, resu); + afb_apiset_enum(target_set, 1, get_apis_namelist_of_all_cb, &head); } - return resu; + return reverse_namelist(head); } /****************************************************************************** -**** Implementation monitoring verbs +**** Monitoring apis ******************************************************************************/ -static const char _verbosity_[] = "verbosity"; -static const char _apis_[] = "apis"; +struct desc_apis { + struct namelist *names; + struct json_object *resu; + struct json_object *apis; + afb_req_t req; +}; + +static void describe_first_api(struct desc_apis *desc); + +static void on_api_description(void *closure, struct json_object *apidesc) +{ + struct desc_apis *desc = closure; + struct namelist *head = desc->names; + + if (apidesc || afb_apiset_lookup(target_set, head->name, 1)) + json_object_object_add(desc->apis, head->name, apidesc); + desc->names = head->next; + free(head); + describe_first_api(desc); +} + +static void describe_first_api(struct desc_apis *desc) +{ + struct namelist *head = desc->names; + if (head) + afb_apiset_describe(target_set, head->name, on_api_description, desc); + else { + afb_req_success(desc->req, desc->resu, NULL); + afb_req_unref(desc->req); + free(desc); + } +} + +static void describe_apis(afb_req_t req, struct json_object *resu, struct json_object *spec) +{ + struct desc_apis *desc; + + desc = malloc(sizeof *desc); + if (!desc) + afb_req_fail(req, "out-of-memory", NULL); + else { + desc->req = afb_req_addref(req); + desc->resu = resu; + desc->apis = json_object_new_object(); + json_object_object_add(desc->resu, _apis_, desc->apis); + desc->names = get_apis_namelist(spec); + describe_first_api(desc); + } +} + +/****************************************************************************** +**** Implementation monitoring verbs +******************************************************************************/ static void f_get(afb_req_t req) { @@ -305,13 +379,23 @@ static void f_get(afb_req_t req) struct json_object *verbosity = NULL; wrap_json_unpack(afb_req_json(req), "{s?:o,s?:o}", _verbosity_, &verbosity, _apis_, &apis); - if (verbosity) - verbosity = get_verbosity(verbosity); - if (apis) - apis = get_apis(apis); - - wrap_json_pack(&r, "{s:o*,s:o*}", _verbosity_, verbosity, _apis_, apis); - afb_req_success(req, r, NULL); + if (!verbosity && !apis) + afb_req_success(req, NULL, NULL); + else { + r = json_object_new_object(); + if (!r) + afb_req_fail(req, "out-of-memory", NULL); + else { + if (verbosity) { + verbosity = get_verbosity(verbosity); + json_object_object_add(r, _verbosity_, verbosity); + } + if (!apis) + afb_req_success(req, r, NULL); + else + describe_apis(req, r, apis); + } + } } static void f_set(afb_req_t req) diff --git a/src/afb-stub-ws.c b/src/afb-stub-ws.c index 2a48745b..9bd8ed63 100644 --- a/src/afb-stub-ws.c +++ b/src/afb-stub-ws.c @@ -70,16 +70,6 @@ struct client_event int refcount; /**< a reference count */ }; -/** - * structure for recording describe requests on the client side - */ -struct client_describe -{ - struct afb_stub_ws *stubws; /**< the stub */ - struct jobloop *jobloop; /**< the jobloop to leave */ - struct json_object *result; /**< result */ -}; - /** * structure for jobs of describing */ @@ -280,38 +270,17 @@ static void client_api_call_cb(void * closure, struct afb_xreq *xreq) } } -static void client_on_description_cb(void *closure, struct json_object *data) -{ - struct client_describe *desc = closure; - - desc->result = data; - jobs_leave(desc->jobloop); -} - -static void client_send_describe_cb(int signum, void *closure, struct jobloop *jobloop) -{ - struct client_describe *desc = closure; - struct afb_proto_ws *proto; - - proto = client_get_proto(desc->stubws); - if (signum || proto == NULL) - jobs_leave(jobloop); - else { - desc->jobloop = jobloop; - afb_proto_ws_client_describe(proto, client_on_description_cb, desc); - } -} - /* get the description */ -static struct json_object *client_api_describe_cb(void * closure) +static void client_api_describe_cb(void * closure, void (*describecb)(void *, struct json_object *), void *clocb) { - struct client_describe desc; + struct afb_stub_ws *stubws = closure; + struct afb_proto_ws *proto; - /* synchronous job: send the request and wait its result */ - desc.stubws = closure; - desc.result = NULL; - jobs_enter(NULL, 0, client_send_describe_cb, &desc); - return desc.result; + proto = client_get_proto(stubws); + if (proto) + afb_proto_ws_client_describe(proto, describecb, clocb); + else + describecb(clocb, NULL); } /******************* server part: manage events **********************************/ @@ -546,42 +515,19 @@ out_of_memory: afb_proto_ws_call_unref(call); } -static void server_describe_cb(int signum, void *closure) +static void server_on_description_cb(void *closure, struct json_object *description) { - struct json_object *obj; - struct server_describe *desc = closure; - - /* get the description if possible */ - obj = !signum ? afb_apiset_describe(desc->stubws->apiset, desc->stubws->apiname) : NULL; - - /* send it */ - afb_proto_ws_describe_put(desc->describe, obj); - json_object_put(obj); - afb_stub_ws_unref(desc->stubws); + struct afb_proto_ws_describe *describe = closure; + afb_proto_ws_describe_put(describe, description); + json_object_put(description); } -static void server_describe_job(int signum, void *closure) -{ - server_describe_cb(signum, closure); - free(closure); -} static void server_on_describe_cb(void *closure, struct afb_proto_ws_describe *describe) { - struct server_describe *desc, sdesc; struct afb_stub_ws *stubws = closure; - /* allocate (if possible) and init */ - desc = malloc(sizeof *desc); - if (desc == NULL) - desc = &sdesc; - desc->stubws = stubws; - desc->describe = describe; - afb_stub_ws_addref(stubws); - - /* process */ - if (desc == &sdesc || jobs_queue(NULL, 0, server_describe_job, desc) < 0) - jobs_call(NULL, 0, server_describe_cb, desc); + afb_apiset_describe(stubws->apiset, stubws->apiname, server_on_description_cb, describe); } /*****************************************************/ -- 2.16.6