X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-api-dyn.c;fp=src%2Fafb-api-dyn.c;h=880221095d3d04bfb81d1800df50608c27e25854;hb=59cd34b59853f6a47e756d7ab5bc0329f40a471c;hp=0000000000000000000000000000000000000000;hpb=325e6a7f034c80562096d60ab01f2e4532eea98c;p=src%2Fapp-framework-binder.git diff --git a/src/afb-api-dyn.c b/src/afb-api-dyn.c new file mode 100644 index 00000000..88022109 --- /dev/null +++ b/src/afb-api-dyn.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2016, 2017 "IoT.bzh" + * Author José Bollo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include + +#define AFB_BINDING_VERSION 0 +#include + +#include "afb-api.h" +#include "afb-api-dyn.h" +#include "afb-apiset.h" +#include "afb-auth.h" +#include "afb-export.h" +#include "afb-xreq.h" +#include "verbose.h" + +/* + * Description of a binding + */ +struct afb_api_dyn { + int count; + struct afb_api_dyn_verb **verbs; + const struct afb_verb_v2 *verbsv2; + struct afb_export *export; + char info[1]; +}; + +void afb_api_dyn_set_verbs_v2( + struct afb_api_dyn *dynapi, + const struct afb_verb_v2 *verbs) +{ + dynapi->verbsv2 = verbs; +} + +int afb_api_dyn_add_verb( + struct afb_api_dyn *dynapi, + const char *verb, + const char *info, + void (*callback)(struct afb_request *request), + const struct afb_auth *auth, + uint32_t session) +{ + struct afb_api_dyn_verb *v, **vv; + + vv = realloc(dynapi->verbs, (1 + dynapi->count) * sizeof *vv); + if (!vv) + goto oom; + dynapi->verbs = vv; + + v = malloc(sizeof *v + strlen(verb) + (info ? 1 + strlen(info) : 0)); + if (!v) + goto oom; + + v->callback = callback; + v->auth = auth; + v->session = session; + + v->info = 1 + stpcpy(v->verb, verb); + if (info) + strcpy((char*)v->info, info); + else + v->info = NULL; + + dynapi->verbs[dynapi->count++] = v; + return 0; +oom: + errno = ENOMEM; + return -1; +} + +int afb_api_dyn_sub_verb( + struct afb_api_dyn *dynapi, + const char *verb) +{ + struct afb_api_dyn_verb *v; + int i; + + /* look first in dyna mic verbs */ + for (i = 0 ; i < dynapi->count ; i++) { + v = dynapi->verbs[i]; + if (!strcasecmp(v->verb, verb)) { + if (i != --dynapi->count) + dynapi->verbs[i] = dynapi->verbs[dynapi->count]; + free(v); + return 0; + } + } + + errno = ENOENT; + return -1; +} + +static void call_cb(void *closure, struct afb_xreq *xreq) +{ + struct afb_api_dyn *dynapi = closure; + struct afb_api_dyn_verb **verbs; + const struct afb_verb_v2 *verbsv2; + int i; + const char *name; + + name = xreq->verb; + xreq->request.dynapi = (void*)dynapi->export; /* hack: this avoids to export afb_export structure */ + + /* look first in dyna mic verbs */ + verbs = dynapi->verbs; + i = dynapi->count; + while (i) { + if (!strcasecmp(verbs[--i]->verb, name)) { + afb_xreq_call_verb_vdyn(xreq, verbs[i]); + return; + } + } + + verbsv2 = dynapi->verbsv2; + if (verbsv2) { + while (verbsv2->verb) { + if (strcasecmp(verbsv2->verb, name)) + verbsv2++; + else { + afb_xreq_call_verb_v2(xreq, verbsv2); + return; + } + } + } + + afb_xreq_fail_unknown_verb(xreq); +} + +static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset) +{ + struct afb_api_dyn *dynapi = closure; + return afb_export_start(dynapi->export, share_session, onneed, apiset); +} + +static void update_hooks_cb(void *closure) +{ + struct afb_api_dyn *dynapi = closure; + afb_export_update_hook(dynapi->export); +} + +static int get_verbosity_cb(void *closure) +{ + struct afb_api_dyn *dynapi = closure; + return afb_export_verbosity_get(dynapi->export); +} + +static void set_verbosity_cb(void *closure, int level) +{ + struct afb_api_dyn *dynapi = closure; + afb_export_verbosity_set(dynapi->export, level); +} + +static struct json_object *make_description_openAPIv3(struct afb_api_dyn *dynapi) +{ + char buffer[256]; + struct afb_api_dyn_verb **iter, **end, *verb; + struct json_object *r, *f, *a, *i, *p, *g; + + r = json_object_new_object(); + json_object_object_add(r, "openapi", json_object_new_string("3.0.0")); + + i = json_object_new_object(); + json_object_object_add(r, "info", i); + json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(dynapi->export))); + json_object_object_add(i, "version", json_object_new_string("0.0.0")); + json_object_object_add(i, "description", json_object_new_string(dynapi->info)); + + p = json_object_new_object(); + json_object_object_add(r, "paths", p); + iter = dynapi->verbs; + end = iter + dynapi->count; + while (iter != end) { + verb = *iter++; + buffer[0] = '/'; + strncpy(buffer + 1, verb->verb, sizeof buffer - 1); + buffer[sizeof buffer - 1] = 0; + f = json_object_new_object(); + json_object_object_add(p, buffer, f); + g = json_object_new_object(); + json_object_object_add(f, "get", g); + + a = afb_auth_json_v2(verb->auth, verb->session); + if (a) + json_object_object_add(g, "x-permissions", a); + + a = json_object_new_object(); + json_object_object_add(g, "responses", a); + f = json_object_new_object(); + json_object_object_add(a, "200", f); + json_object_object_add(f, "description", json_object_new_string(verb->info?:verb->verb)); + } + return r; +} + +static struct json_object *describe_cb(void *closure) +{ + struct afb_api_dyn *dynapi = closure; + struct json_object *r = make_description_openAPIv3(dynapi); + return r; +} + +static struct afb_api_itf dyn_api_itf = { + .call = call_cb, + .service_start = service_start_cb, + .update_hooks = update_hooks_cb, + .get_verbosity = get_verbosity_cb, + .set_verbosity = set_verbosity_cb, + .describe = describe_cb +}; + +int afb_api_dyn_add(struct afb_apiset *apiset, const char *name, const char *info, int (*preinit)(void*, struct afb_dynapi*), void *closure) +{ + int rc; + struct afb_api_dyn *dynapi; + struct afb_api afb_api; + struct afb_export *export; + + INFO("Starting creation of dynamic API %s", name); + + /* allocates the description */ + info = info ?: ""; + dynapi = calloc(1, sizeof *dynapi + strlen(info)); + export = afb_export_create_vdyn(apiset, name, dynapi); + if (!dynapi || !export) { + ERROR("out of memory"); + goto error; + } + strcpy(dynapi->info, info); + dynapi->export = export; + + /* preinit the api */ + rc = afb_export_preinit_vdyn(export, preinit, closure); + if (rc < 0) { + ERROR("dynamic api %s preinit function failed, ABORTING it!", + afb_export_apiname(dynapi->export)); + goto error; + } + + /* records the binding */ + afb_api.closure = dynapi; + afb_api.itf = &dyn_api_itf; + afb_api.group = NULL; + if (afb_apiset_add(apiset, afb_export_apiname(dynapi->export), afb_api) < 0) { + ERROR("dynamic api %s can't be registered to set %s, ABORTING it!", + afb_export_apiname(dynapi->export), + afb_apiset_name(apiset)); + goto error; + } + INFO("binding %s added to set %s", afb_export_apiname(dynapi->export), afb_apiset_name(apiset)); + return 1; + +error: + afb_export_destroy(export); + free(dynapi); + + return -1; +} +