2 * Copyright (C) 2016, 2017 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
25 #include <json-c/json.h>
27 #define AFB_BINDING_VERSION 0
28 #include <afb/afb-binding.h>
31 #include "afb-api-dyn.h"
32 #include "afb-apiset.h"
34 #include "afb-export.h"
39 * Description of a binding
43 struct afb_api_dyn_verb **verbs;
44 const struct afb_verb_v2 *verbsv2;
45 struct afb_export *export;
49 void afb_api_dyn_set_verbs_v2(
50 struct afb_api_dyn *dynapi,
51 const struct afb_verb_v2 *verbs)
53 dynapi->verbsv2 = verbs;
56 int afb_api_dyn_add_verb(
57 struct afb_api_dyn *dynapi,
60 void (*callback)(struct afb_request *request),
62 const struct afb_auth *auth,
65 struct afb_api_dyn_verb *v, **vv;
67 afb_api_dyn_sub_verb(dynapi, verb);
69 vv = realloc(dynapi->verbs, (1 + dynapi->count) * sizeof *vv);
74 v = malloc(sizeof *v + strlen(verb) + (info ? 1 + strlen(info) : 0));
78 v->callback = callback;
83 v->info = 1 + stpcpy(v->verb, verb);
85 strcpy((char*)v->info, info);
89 dynapi->verbs[dynapi->count++] = v;
96 int afb_api_dyn_sub_verb(
97 struct afb_api_dyn *dynapi,
100 struct afb_api_dyn_verb *v;
103 /* look first in dyna mic verbs */
104 for (i = 0 ; i < dynapi->count ; i++) {
105 v = dynapi->verbs[i];
106 if (!strcasecmp(v->verb, verb)) {
107 if (i != --dynapi->count)
108 dynapi->verbs[i] = dynapi->verbs[dynapi->count];
118 static void call_cb(void *closure, struct afb_xreq *xreq)
120 struct afb_api_dyn *dynapi = closure;
121 struct afb_api_dyn_verb **verbs, *v;
122 const struct afb_verb_v2 *verbsv2;
126 name = xreq->request.verb;
127 xreq->request.dynapi = (void*)dynapi->export; /* hack: this avoids to export afb_export structure */
129 /* look first in dyna mic verbs */
130 verbs = dynapi->verbs;
134 if (!strcasecmp(v->verb, name)) {
135 xreq->request.vcbdata = v->vcbdata;
136 afb_xreq_call_verb_vdyn(xreq, verbs[i]);
141 verbsv2 = dynapi->verbsv2;
143 while (verbsv2->verb) {
144 if (strcasecmp(verbsv2->verb, name))
147 afb_xreq_call_verb_v2(xreq, verbsv2);
153 afb_xreq_fail_unknown_verb(xreq);
156 static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset)
158 struct afb_api_dyn *dynapi = closure;
159 return afb_export_start(dynapi->export, share_session, onneed, apiset);
162 static void update_hooks_cb(void *closure)
164 struct afb_api_dyn *dynapi = closure;
165 afb_export_update_hook(dynapi->export);
168 static int get_verbosity_cb(void *closure)
170 struct afb_api_dyn *dynapi = closure;
171 return afb_export_verbosity_get(dynapi->export);
174 static void set_verbosity_cb(void *closure, int level)
176 struct afb_api_dyn *dynapi = closure;
177 afb_export_verbosity_set(dynapi->export, level);
180 static struct json_object *make_description_openAPIv3(struct afb_api_dyn *dynapi)
183 struct afb_api_dyn_verb **iter, **end, *verb;
184 struct json_object *r, *f, *a, *i, *p, *g;
186 r = json_object_new_object();
187 json_object_object_add(r, "openapi", json_object_new_string("3.0.0"));
189 i = json_object_new_object();
190 json_object_object_add(r, "info", i);
191 json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(dynapi->export)));
192 json_object_object_add(i, "version", json_object_new_string("0.0.0"));
193 json_object_object_add(i, "description", json_object_new_string(dynapi->info));
195 p = json_object_new_object();
196 json_object_object_add(r, "paths", p);
197 iter = dynapi->verbs;
198 end = iter + dynapi->count;
199 while (iter != end) {
202 strncpy(buffer + 1, verb->verb, sizeof buffer - 1);
203 buffer[sizeof buffer - 1] = 0;
204 f = json_object_new_object();
205 json_object_object_add(p, buffer, f);
206 g = json_object_new_object();
207 json_object_object_add(f, "get", g);
209 a = afb_auth_json_v2(verb->auth, verb->session);
211 json_object_object_add(g, "x-permissions", a);
213 a = json_object_new_object();
214 json_object_object_add(g, "responses", a);
215 f = json_object_new_object();
216 json_object_object_add(a, "200", f);
217 json_object_object_add(f, "description", json_object_new_string(verb->info?:verb->verb));
222 static struct json_object *describe_cb(void *closure)
224 struct afb_api_dyn *dynapi = closure;
225 struct json_object *r = make_description_openAPIv3(dynapi);
229 static struct afb_api_itf dyn_api_itf = {
231 .service_start = service_start_cb,
232 .update_hooks = update_hooks_cb,
233 .get_verbosity = get_verbosity_cb,
234 .set_verbosity = set_verbosity_cb,
235 .describe = describe_cb
238 int afb_api_dyn_add(struct afb_apiset *apiset, const char *name, const char *info, int noconcurrency, int (*preinit)(void*, struct afb_dynapi*), void *closure)
241 struct afb_api_dyn *dynapi;
242 struct afb_api afb_api;
243 struct afb_export *export;
245 INFO("Starting creation of dynamic API %s", name);
247 /* allocates the description */
249 dynapi = calloc(1, sizeof *dynapi + strlen(info));
250 export = afb_export_create_vdyn(apiset, name, dynapi);
251 if (!dynapi || !export) {
252 ERROR("out of memory");
255 strcpy(dynapi->info, info);
256 dynapi->export = export;
258 /* preinit the api */
259 rc = afb_export_preinit_vdyn(export, preinit, closure);
261 ERROR("dynamic api %s preinit function failed, ABORTING it!",
262 afb_export_apiname(dynapi->export));
266 /* records the binding */
267 afb_api.closure = dynapi;
268 afb_api.itf = &dyn_api_itf;
269 afb_api.group = noconcurrency ? dynapi : NULL;
270 if (afb_apiset_add(apiset, afb_export_apiname(dynapi->export), afb_api) < 0) {
271 ERROR("dynamic api %s can't be registered to set %s, ABORTING it!",
272 afb_export_apiname(dynapi->export),
273 afb_apiset_name(apiset));
276 INFO("binding %s added to set %s", afb_export_apiname(dynapi->export), afb_apiset_name(apiset));
280 afb_export_destroy(export);