diff options
author | 2017-09-22 15:17:31 +0200 | |
---|---|---|
committer | 2017-10-09 14:08:33 +0200 | |
commit | 59cd34b59853f6a47e756d7ab5bc0329f40a471c (patch) | |
tree | 8655c0191ac3e1bf5d11236909c2422dcd4cd801 /src | |
parent | 325e6a7f034c80562096d60ab01f2e4532eea98c (diff) |
Allow dynamic creation of APIs
Change-Id: I825bfa7969c98dd214457d9ff94e2948362286a9
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/afb-api-dyn.c | 279 | ||||
-rw-r--r-- | src/afb-api-dyn.h | 55 | ||||
-rw-r--r-- | src/afb-export.c | 485 | ||||
-rw-r--r-- | src/afb-export.h | 9 | ||||
-rw-r--r-- | src/afb-xreq.c | 10 | ||||
-rw-r--r-- | src/afb-xreq.h | 3 |
7 files changed, 809 insertions, 33 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 39b7fe1a..0e05f850 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,6 +32,7 @@ ADD_DEFINITIONS(-DINFER_EXTENSION) ADD_LIBRARY(afb-lib STATIC afb-api.c afb-api-dbus.c + afb-api-dyn.c afb-api-so.c afb-api-so-v1.c afb-api-so-v2.c 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 <jose.bollo@iot.bzh> + * + * 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 <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include <json-c/json.h> + +#define AFB_BINDING_VERSION 0 +#include <afb/afb-binding.h> + +#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; +} + diff --git a/src/afb-api-dyn.h b/src/afb-api-dyn.h new file mode 100644 index 00000000..ea184df1 --- /dev/null +++ b/src/afb-api-dyn.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016, 2017 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * 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. + */ + + +#pragma once + +struct afb_apiset; +struct afb_dynapi; +struct afb_auth; +struct afb_request; +struct afb_verb_v2; + +struct afb_api_dyn_verb +{ + void (*callback)(struct afb_request *request); + const struct afb_auth *auth; + const char *info; + int session; + char verb[1]; +}; + +struct afb_api_dyn; + +extern int afb_api_dyn_add(struct afb_apiset *apiset, const char *name, const char *info, int (*preinit)(void*, struct afb_dynapi*), void *closure); + +extern void afb_api_dyn_set_verbs_v2( + struct afb_api_dyn *dynapi, + const struct afb_verb_v2 *verbs); + +extern 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); + +extern int afb_api_dyn_sub_verb( + struct afb_api_dyn *dynapi, + const char *verb); + diff --git a/src/afb-export.c b/src/afb-export.c index bd5b61e0..5688cfee 100644 --- a/src/afb-export.c +++ b/src/afb-export.c @@ -23,11 +23,12 @@ #include <json-c/json.h> -#include <afb/afb-binding-v1.h> -#include <afb/afb-binding-v2.h> +#define AFB_BINDING_VERSION 0 +#include <afb/afb-binding.h> #include "afb-api.h" #include "afb-apiset.h" +#include "afb-api-dyn.h" #include "afb-common.h" #include "afb-cred.h" #include "afb-evt.h" @@ -39,17 +40,15 @@ #include "jobs.h" #include "verbose.h" - /************************************************************************* * internal types and structures ************************************************************************/ enum afb_api_version { - Api_Version_None = 0, + Api_Version_Dyn = 0, Api_Version_1 = 1, Api_Version_2 = 2, - Api_Version_3 = 3 }; enum afb_api_state @@ -61,6 +60,9 @@ enum afb_api_state struct afb_export { + /* keep it first */ + struct afb_dynapi dynapi; + /* name of the api */ char *apiname; @@ -74,6 +76,9 @@ struct afb_export int hookditf; int hooksvc; + /* dynamic api */ + struct afb_api_dyn *apidyn; + /* session for service */ struct afb_session *session; @@ -87,11 +92,13 @@ struct afb_export union { int (*v1)(struct afb_service); int (*v2)(); + int (*vdyn)(struct afb_dynapi *dynapi); } init; /* event handling */ union { void (*v12)(const char *event, struct json_object *object); + void (*vdyn)(struct afb_dynapi *dynapi, const char *event, struct json_object *object); } on_event; /* exported data */ @@ -101,6 +108,18 @@ struct afb_export } export; }; +/************************************************************************************************************/ + +static inline struct afb_dynapi *to_dynapi(struct afb_export *export) +{ + return (struct afb_dynapi*)export; +} + +static inline struct afb_export *from_dynapi(struct afb_dynapi *dynapi) +{ + return (struct afb_export*)dynapi; +} + /************************************************************************************************************* ************************************************************************************************************* ************************************************************************************************************* @@ -232,6 +251,17 @@ static int rename_api_cb(void *closure, const char *name) return 0; } +static int api_new_api_cb( + void *closure, + const char *api, + const char *info, + int (*preinit)(void*, struct afb_dynapi *), + void *preinit_closure) +{ + struct afb_export *export = closure; + return afb_api_dyn_add(export->apiset, api, info, preinit, preinit_closure); +} + /********************************************** * hooked flow **********************************************/ @@ -342,6 +372,16 @@ static int hooked_rename_api_cb(void *closure, const char *name) return afb_hook_ditf_rename_api(export, oldname, name, result); } +static int hooked_api_new_api_cb( + void *closure, + const char *api, + const char *info, + int (*preinit)(void*, struct afb_dynapi *), + void *preinit_closure) +{ + /* TODO */ + return api_new_api_cb(closure, api, info, preinit, preinit_closure); +} /********************************************** * vectors **********************************************/ @@ -358,7 +398,8 @@ static const struct afb_daemon_itf daemon_itf = { .queue_job = queue_job_cb, .unstore_req = unstore_req_cb, .require_api = require_api_cb, - .rename_api = rename_api_cb + .rename_api = rename_api_cb, + .new_api = api_new_api_cb, }; static const struct afb_daemon_itf hooked_daemon_itf = { @@ -374,10 +415,10 @@ static const struct afb_daemon_itf hooked_daemon_itf = { .queue_job = hooked_queue_job_cb, .unstore_req = hooked_unstore_req_cb, .require_api = hooked_require_api_cb, - .rename_api = hooked_rename_api_cb + .rename_api = hooked_rename_api_cb, + .new_api = hooked_api_new_api_cb, }; - /************************************************************************************************************* ************************************************************************************************************* ************************************************************************************************************* @@ -411,7 +452,10 @@ struct call_req struct afb_export *export; /* the args */ - void (*callback)(void*, int, struct json_object*); + union { + void (*callback)(void*, int, struct json_object*); + void (*callback_dynapi)(void*, int, struct json_object*, struct afb_dynapi*); + }; void *closure; /* sync */ @@ -433,7 +477,7 @@ static void callreq_destroy(struct afb_xreq *xreq) free(callreq); } -static void callreq_reply(struct afb_xreq *xreq, int status, json_object *obj) +static void callreq_reply_async(struct afb_xreq *xreq, int status, json_object *obj) { struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); if (callreq->callback) @@ -441,6 +485,14 @@ static void callreq_reply(struct afb_xreq *xreq, int status, json_object *obj) json_object_put(obj); } +static void callreq_reply_async_dynapi(struct afb_xreq *xreq, int status, json_object *obj) +{ + struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); + if (callreq->callback_dynapi) + callreq->callback_dynapi(callreq->closure, status, obj, to_dynapi(callreq->export)); + json_object_put(obj); +} + static void callreq_sync_leave(struct call_req *callreq) { struct jobloop *jobloop = callreq->jobloop; @@ -474,9 +526,15 @@ static void callreq_sync_enter(int signum, void *closure, struct jobloop *jobloo } /* interface for requests of services */ -const struct afb_xreq_query_itf afb_export_xreq_itf = { +const struct afb_xreq_query_itf afb_export_xreq_async_itf = { .unref = callreq_destroy, - .reply = callreq_reply + .reply = callreq_reply_async +}; + +/* interface for requests of services */ +const struct afb_xreq_query_itf afb_export_xreq_async_dynapi_itf = { + .unref = callreq_destroy, + .reply = callreq_reply_async_dynapi }; /* interface for requests of services */ @@ -488,7 +546,12 @@ const struct afb_xreq_query_itf afb_export_xreq_sync_itf = { /* * create an call_req */ -static struct call_req *callreq_create(struct afb_export *export, const char *api, const char *verb, struct json_object *args, const struct afb_xreq_query_itf *itf) +static struct call_req *callreq_create( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + const struct afb_xreq_query_itf *itf) { struct call_req *callreq; size_t lenapi, lenverb; @@ -519,14 +582,20 @@ static struct call_req *callreq_create(struct afb_export *export, const char *ap /* * Initiates a call for the service */ -static void svc_call(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cbclosure) +static void svc_call( + void *closure, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *cbclosure) { struct afb_export *export = closure; struct call_req *callreq; struct json_object *ierr; /* allocates the request */ - callreq = callreq_create(export, api, verb, args, &afb_export_xreq_itf); + callreq = callreq_create(export, api, verb, args, &afb_export_xreq_async_itf); if (callreq == NULL) { ERROR("out of memory"); json_object_put(args); @@ -546,8 +615,45 @@ static void svc_call(void *closure, const char *api, const char *verb, struct js afb_xreq_process(&callreq->xreq, export->apiset); } -static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args, - struct json_object **result) +static void svc_call_dynapi( + struct afb_dynapi *dynapi, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_dynapi*), + void *cbclosure) +{ + struct afb_export *export = from_dynapi(dynapi); + struct call_req *callreq; + struct json_object *ierr; + + /* allocates the request */ + callreq = callreq_create(export, api, verb, args, &afb_export_xreq_async_dynapi_itf); + if (callreq == NULL) { + ERROR("out of memory"); + json_object_put(args); + ierr = afb_msg_json_internal_error(); + if (callback) + callback(cbclosure, -1, ierr, to_dynapi(export)); + json_object_put(ierr); + return; + } + + /* initialises the request */ + callreq->jobloop = NULL; + callreq->callback_dynapi = callback; + callreq->closure = cbclosure; + + /* terminates and frees ressources if needed */ + afb_xreq_process(&callreq->xreq, export->apiset); +} + +static int svc_call_sync( + void *closure, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) { struct afb_export *export = closure; struct call_req *callreq; @@ -585,7 +691,10 @@ static int svc_call_sync(void *closure, const char *api, const char *verb, struc struct hooked_call { struct afb_export *export; - void (*callback)(void*, int, struct json_object*); + union { + void (*callback)(void*, int, struct json_object*); + void (*callback_dynapi)(void*, int, struct json_object*, struct afb_dynapi*); + }; void *cbclosure; }; @@ -597,7 +706,21 @@ static void svc_hooked_call_result(void *closure, int status, struct json_object free(hc); } -static void svc_hooked_call(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cbclosure) +static void svc_hooked_call_dynapi_result(void *closure, int status, struct json_object *result, struct afb_dynapi *dynapi) +{ + struct hooked_call *hc = closure; + afb_hook_svc_call_result(hc->export, status, result); + hc->callback_dynapi(hc->cbclosure, status, result, dynapi); + free(hc); +} + +static void svc_hooked_call( + void *closure, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *cbclosure) { struct afb_export *export = closure; struct hooked_call *hc; @@ -620,8 +743,41 @@ static void svc_hooked_call(void *closure, const char *api, const char *verb, st svc_call(closure, api, verb, args, callback, cbclosure); } -static int svc_hooked_call_sync(void *closure, const char *api, const char *verb, struct json_object *args, - struct json_object **result) +static void svc_hooked_call_dynapi( + struct afb_dynapi *dynapi, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_dynapi*), + void *cbclosure) +{ + struct afb_export *export = from_dynapi(dynapi); + struct hooked_call *hc; + + if (export->hooksvc & afb_hook_flag_svc_call) + afb_hook_svc_call(export, api, verb, args); + + if (export->hooksvc & afb_hook_flag_svc_call_result) { + hc = malloc(sizeof *hc); + if (!hc) + WARNING("allocation failed"); + else { + hc->export = export; + hc->callback_dynapi = callback; + hc->cbclosure = cbclosure; + callback = svc_hooked_call_dynapi_result; + cbclosure = hc; + } + } + svc_call_dynapi(dynapi, api, verb, args, callback, cbclosure); +} + +static int svc_hooked_call_sync( + void *closure, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) { struct afb_export *export = closure; struct json_object *resu; @@ -659,6 +815,195 @@ static const struct afb_service_itf hooked_service_itf = { ************************************************************************************************************* ************************************************************************************************************* ************************************************************************************************************* + F R O M D Y N A P I + ************************************************************************************************************* + ************************************************************************************************************* + ************************************************************************************************************* + *************************************************************************************************************/ + +static int api_set_verbs_v2_cb( + struct afb_dynapi *dynapi, + const struct afb_verb_v2 *verbs) +{ + struct afb_export *export = from_dynapi(dynapi); + + if (export->apidyn) { + afb_api_dyn_set_verbs_v2(export->apidyn, verbs); + return 0; + } + + errno = EPERM; + return -1; +} + +static int api_add_verb_cb( + struct afb_dynapi *dynapi, + const char *verb, + const char *info, + void (*callback)(struct afb_request *request), + const struct afb_auth *auth, + uint32_t session) +{ + struct afb_export *export = from_dynapi(dynapi); + + if (export->apidyn) + return afb_api_dyn_add_verb(export->apidyn, verb, info, callback, auth, session); + + errno = EPERM; + return -1; +} + +static int api_sub_verb_cb( + struct afb_dynapi *dynapi, + const char *verb) +{ + struct afb_export *export = from_dynapi(dynapi); + + if (export->apidyn) + return afb_api_dyn_sub_verb(export->apidyn, verb); + + errno = EPERM; + return -1; +} + +static int api_set_on_event_cb( + struct afb_dynapi *dynapi, + void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) +{ + struct afb_export *export = from_dynapi(dynapi); + return afb_export_handle_events_vdyn(export, onevent); +} + +static int api_set_on_init_cb( + struct afb_dynapi *dynapi, + int (*oninit)(struct afb_dynapi *dynapi)) +{ + struct afb_export *export = from_dynapi(dynapi); + + return afb_export_handle_init_vdyn(export, oninit); +} + +static void api_seal_cb( + struct afb_dynapi *dynapi) +{ + struct afb_export *export = from_dynapi(dynapi); + + export->apidyn = NULL; +} + +static int hooked_api_set_verbs_v2_cb( + struct afb_dynapi *dynapi, + const struct afb_verb_v2 *verbs) +{ + /* TODO */ + return api_set_verbs_v2_cb(dynapi, verbs); +} + +static int hooked_api_add_verb_cb( + struct afb_dynapi *dynapi, + const char *verb, + const char *info, + void (*callback)(struct afb_request *request), + const struct afb_auth *auth, + uint32_t session) +{ + /* TODO */ + return api_add_verb_cb(dynapi, verb, info, callback, auth, session); +} + +static int hooked_api_sub_verb_cb( + struct afb_dynapi *dynapi, + const char *verb) +{ + /* TODO */ + return api_sub_verb_cb(dynapi, verb); +} + +static int hooked_api_set_on_event_cb( + struct afb_dynapi *dynapi, + void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) +{ + /* TODO */ + return api_set_on_event_cb(dynapi, onevent); +} + +static int hooked_api_set_on_init_cb( + struct afb_dynapi *dynapi, + int (*oninit)(struct afb_dynapi *dynapi)) +{ + /* TODO */ + return api_set_on_init_cb(dynapi, oninit); +} + +static void hooked_api_seal_cb( + struct afb_dynapi *dynapi) +{ + /* TODO */ + api_seal_cb(dynapi); +} + +static const struct afb_dynapi_itf dynapi_itf = { + + .vverbose = (void*)vverbose_cb, + + .get_event_loop = afb_common_get_event_loop, + .get_user_bus = afb_common_get_user_bus, + .get_system_bus = afb_common_get_system_bus, + .rootdir_get_fd = afb_common_rootdir_get_fd, + .rootdir_open_locale = rootdir_open_locale_cb, + .queue_job = queue_job_cb, + + .require_api = require_api_cb, + .rename_api = rename_api_cb, + + .event_broadcast = event_broadcast_cb, + .eventid_make = eventid_make_cb, + + .call = svc_call_dynapi, + .call_sync = svc_call_sync, + + .api_new_api = api_new_api_cb, + .api_set_verbs_v2 = api_set_verbs_v2_cb, + .api_add_verb = api_add_verb_cb, + .api_sub_verb = api_sub_verb_cb, + .api_set_on_event = api_set_on_event_cb, + .api_set_on_init = api_set_on_init_cb, + .api_seal = api_seal_cb, +}; + +static const struct afb_dynapi_itf hooked_dynapi_itf = { + + .vverbose = hooked_vverbose_cb, + + .get_event_loop = hooked_get_event_loop, + .get_user_bus = hooked_get_user_bus, + .get_system_bus = hooked_get_system_bus, + .rootdir_get_fd = hooked_rootdir_get_fd, + .rootdir_open_locale = hooked_rootdir_open_locale_cb, + .queue_job = hooked_queue_job_cb, + + .require_api = hooked_require_api_cb, + .rename_api = hooked_rename_api_cb, + + .event_broadcast = hooked_event_broadcast_cb, + .eventid_make = hooked_eventid_make_cb, + + .call = svc_hooked_call_dynapi, + .call_sync = svc_hooked_call_sync, + + .api_new_api = hooked_api_new_api_cb, + .api_set_verbs_v2 = hooked_api_set_verbs_v2_cb, + .api_add_verb = hooked_api_add_verb_cb, + .api_sub_verb = hooked_api_sub_verb_cb, + .api_set_on_event = hooked_api_set_on_event_cb, + .api_set_on_init = hooked_api_set_on_init_cb, + .api_seal = hooked_api_seal_cb, +}; + +/************************************************************************************************************* + ************************************************************************************************************* + ************************************************************************************************************* + ************************************************************************************************************* F R O M S V C ************************************************************************************************************* ************************************************************************************************************* @@ -686,6 +1031,27 @@ static const struct afb_evt_itf evt_v12_itf = { .push = export_on_event_v12 }; +/* + * Propagates the event to the service + */ +static void export_on_event_vdyn(void *closure, const char *event, int eventid, struct json_object *object) +{ + struct afb_export *export = closure; + + if (export->hooksvc & afb_hook_flag_svc_on_event_before) + afb_hook_svc_on_event_before(export, event, eventid, object); + export->on_event.vdyn(to_dynapi(export), event, object); + if (export->hooksvc & afb_hook_flag_svc_on_event_after) + afb_hook_svc_on_event_after(export, event, eventid, object); + json_object_put(object); +} + +/* the interface for events */ +static const struct afb_evt_itf evt_vdyn_itf = { + .broadcast = export_on_event_vdyn, + .push = export_on_event_vdyn +}; + /************************************************************************************************************* ************************************************************************************************************* ************************************************************************************************************* @@ -738,9 +1104,9 @@ struct afb_export *afb_export_create_v1(struct afb_apiset *apiset, const char *a if (export) { export->init.v1 = init; export->on_event.v12 = onevent; - export->export.v1.verbosity = verbosity; export->export.v1.mode = AFB_MODE_LOCAL; export->export.v1.daemon.closure = export; + afb_export_verbosity_set(export, verbosity); afb_export_update_hook(export); } return export; @@ -753,9 +1119,20 @@ struct afb_export *afb_export_create_v2(struct afb_apiset *apiset, const char *a export->init.v2 = init; export->on_event.v12 = onevent; export->export.v2 = data; - data->verbosity = verbosity; data->daemon.closure = export; data->service.closure = export; + afb_export_verbosity_set(export, verbosity); + afb_export_update_hook(export); + } + return export; +} + +struct afb_export *afb_export_create_vdyn(struct afb_apiset *apiset, const char *apiname, struct afb_api_dyn *apidyn) +{ + struct afb_export *export = create(apiset, apiname, Api_Version_Dyn); + if (export) { + export->apidyn = apidyn; + afb_export_verbosity_set(export, verbosity); afb_export_update_hook(export); } return export; @@ -777,11 +1154,12 @@ void afb_export_update_hook(struct afb_export *export) { export->hookditf = afb_hook_flags_ditf(export->apiname); export->hooksvc = afb_hook_flags_svc(export->apiname); + export->dynapi.itf = export->hookditf|export->hooksvc ? &hooked_dynapi_itf : &dynapi_itf; + switch (export->version) { case Api_Version_1: export->export.v1.daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf; break; - default: case Api_Version_2: export->export.v2->daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf; export->export.v2->service.itf = export->hooksvc ? &hooked_service_itf : &service_itf; @@ -820,9 +1198,6 @@ struct afb_apiset *afb_export_get_apiset(struct afb_export *export) return export->apiset; } -/* - * Creates a new service - */ int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object)) { /* check version */ @@ -852,6 +1227,47 @@ int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(con return 0; } +int afb_export_handle_events_vdyn(struct afb_export *export, void (*on_event)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) +{ + /* check version */ + switch (export->version) { + case Api_Version_Dyn: break; + default: + ERROR("invalid version Dyn for API %s", export->apiname); + errno = EINVAL; + return -1; + } + + /* set the event handler */ + if (!on_event) { + if (export->listener) { + afb_evt_listener_unref(export->listener); + export->listener = NULL; + } + export->on_event.vdyn = on_event; + } else { + export->on_event.vdyn = on_event; + if (!export->listener) { + export->listener = afb_evt_listener_create(&evt_vdyn_itf, export); + if (export->listener == NULL) + return -1; + } + } + return 0; +} + +int afb_export_handle_init_vdyn(struct afb_export *export, int (*oninit)(struct afb_dynapi *dynapi)) +{ + if (export->state != Api_State_Pre_Init) { + ERROR("[API %s] Bad call to 'afb_dynapi_on_init', must be in PreInit", export->apiname); + errno = EINVAL; + return -1; + } + + export->init.vdyn = oninit; + return 0; +} + /* * Starts a new service (v1) */ @@ -860,17 +1276,19 @@ struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct return regfun(&export->export.v1); } +int afb_export_preinit_vdyn(struct afb_export *export, int (*preinit)(void*, struct afb_dynapi*), void *closure) +{ + return preinit(closure, to_dynapi(export)); +} + int afb_export_verbosity_get(const struct afb_export *export) { - switch (export->version) { - case Api_Version_1: return export->export.v1.verbosity; - case Api_Version_2: return export->export.v2->verbosity; - } - return verbosity; + return export->dynapi.verbosity; } void afb_export_verbosity_set(struct afb_export *export, int level) { + export->dynapi.verbosity = level; switch (export->version) { case Api_Version_1: export->export.v1.verbosity = level; break; case Api_Version_2: export->export.v2->verbosity = level; break; @@ -937,6 +1355,9 @@ int afb_export_start(struct afb_export *export, int share_session, int onneed, s case Api_Version_2: rc = export->init.v2 ? export->init.v2() : 0; break; + case Api_Version_Dyn: + rc = export->init.vdyn ? export->init.vdyn(to_dynapi(export)) : 0; + break; default: break; } diff --git a/src/afb-export.h b/src/afb-export.h index 9bd08204..ff9dc10e 100644 --- a/src/afb-export.h +++ b/src/afb-export.h @@ -17,15 +17,20 @@ #pragma once +struct json_object; + struct afb_export; struct afb_apiset; +struct afb_api_dyn; struct afb_service; struct afb_binding_data_v2; struct afb_binding_interface_v1; +struct afb_dynapi; extern struct afb_export *afb_export_create_v1(struct afb_apiset *apiset, const char *apiname, int (*init)(struct afb_service), void (*onevent)(const char*, struct json_object*)); extern struct afb_export *afb_export_create_v2(struct afb_apiset *apiset, const char *apiname, struct afb_binding_data_v2 *data, int (*init)(), void (*onevent)(const char*, struct json_object*)); +extern struct afb_export *afb_export_create_vdyn(struct afb_apiset *apiset, const char *apiname, struct afb_api_dyn *dynapi); extern void afb_export_destroy(struct afb_export *export); @@ -38,7 +43,11 @@ extern void afb_export_set_apiset(struct afb_export *export, struct afb_apiset * extern struct afb_apiset *afb_export_get_apiset(struct afb_export *export); extern struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*)); +extern int afb_export_preinit_vdyn(struct afb_export *export, int (*preinit)(void*, struct afb_dynapi*), void *closure); + extern int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object)); +extern int afb_export_handle_events_vdyn(struct afb_export *export, void (*on_event)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)); +extern int afb_export_handle_init_vdyn(struct afb_export *export, int (*oninit)(struct afb_dynapi *dynapi)); extern int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset); diff --git a/src/afb-xreq.c b/src/afb-xreq.c index 8bfb3639..cbed87f3 100644 --- a/src/afb-xreq.c +++ b/src/afb-xreq.c @@ -34,6 +34,7 @@ #include "afb-cred.h" #include "afb-hook.h" #include "afb-api.h" +#include "afb-api-dyn.h" #include "afb-apiset.h" #include "afb-auth.h" #include "jobs.h" @@ -1039,6 +1040,15 @@ void afb_xreq_call_verb_v2(struct afb_xreq *xreq, const struct afb_verb_v2 *verb verb->callback(to_req(xreq)); } +void afb_xreq_call_verb_vdyn(struct afb_xreq *xreq, const struct afb_api_dyn_verb *verb) +{ + if (!verb) + afb_xreq_fail_unknown_verb(xreq); + else + if (xreq_session_check_apply_v2(xreq, verb->session, verb->auth) >= 0) + verb->callback(to_request(xreq)); +} + void afb_xreq_init(struct afb_xreq *xreq, const struct afb_xreq_query_itf *queryitf) { memset(xreq, 0, sizeof *xreq); diff --git a/src/afb-xreq.h b/src/afb-xreq.h index d899a3d3..d78d88fb 100644 --- a/src/afb-xreq.h +++ b/src/afb-xreq.h @@ -25,6 +25,7 @@ struct afb_evt_listener; struct afb_xreq; struct afb_cred; struct afb_apiset; +struct afb_api_dyn_verb; struct afb_eventid; struct afb_verb_desc_v1; struct afb_verb_v2; @@ -148,4 +149,4 @@ extern void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset); extern void afb_xreq_call_verb_v1(struct afb_xreq *xreq, const struct afb_verb_desc_v1 *verb); extern void afb_xreq_call_verb_v2(struct afb_xreq *xreq, const struct afb_verb_v2 *verb); - +extern void afb_xreq_call_verb_vdyn(struct afb_xreq *xreq, const struct afb_api_dyn_verb *verb); |