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),
61 const struct afb_auth *auth,
64 struct afb_api_dyn_verb *v, **vv;
66 vv = realloc(dynapi->verbs, (1 + dynapi->count) * sizeof *vv);
71 v = malloc(sizeof *v + strlen(verb) + (info ? 1 + strlen(info) : 0));
75 v->callback = callback;
79 v->info = 1 + stpcpy(v->verb, verb);
81 strcpy((char*)v->info, info);
85 dynapi->verbs[dynapi->count++] = v;
92 int afb_api_dyn_sub_verb(
93 struct afb_api_dyn *dynapi,
96 struct afb_api_dyn_verb *v;
99 /* look first in dyna mic verbs */
100 for (i = 0 ; i < dynapi->count ; i++) {
101 v = dynapi->verbs[i];
102 if (!strcasecmp(v->verb, verb)) {
103 if (i != --dynapi->count)
104 dynapi->verbs[i] = dynapi->verbs[dynapi->count];
114 static void call_cb(void *closure, struct afb_xreq *xreq)
116 struct afb_api_dyn *dynapi = closure;
117 struct afb_api_dyn_verb **verbs;
118 const struct afb_verb_v2 *verbsv2;
123 xreq->request.dynapi = (void*)dynapi->export; /* hack: this avoids to export afb_export structure */
125 /* look first in dyna mic verbs */
126 verbs = dynapi->verbs;
129 if (!strcasecmp(verbs[--i]->verb, name)) {
130 afb_xreq_call_verb_vdyn(xreq, verbs[i]);
135 verbsv2 = dynapi->verbsv2;
137 while (verbsv2->verb) {
138 if (strcasecmp(verbsv2->verb, name))
141 afb_xreq_call_verb_v2(xreq, verbsv2);
147 afb_xreq_fail_unknown_verb(xreq);
150 static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset)
152 struct afb_api_dyn *dynapi = closure;
153 return afb_export_start(dynapi->export, share_session, onneed, apiset);
156 static void update_hooks_cb(void *closure)
158 struct afb_api_dyn *dynapi = closure;
159 afb_export_update_hook(dynapi->export);
162 static int get_verbosity_cb(void *closure)
164 struct afb_api_dyn *dynapi = closure;
165 return afb_export_verbosity_get(dynapi->export);
168 static void set_verbosity_cb(void *closure, int level)
170 struct afb_api_dyn *dynapi = closure;
171 afb_export_verbosity_set(dynapi->export, level);
174 static struct json_object *make_description_openAPIv3(struct afb_api_dyn *dynapi)
177 struct afb_api_dyn_verb **iter, **end, *verb;
178 struct json_object *r, *f, *a, *i, *p, *g;
180 r = json_object_new_object();
181 json_object_object_add(r, "openapi", json_object_new_string("3.0.0"));
183 i = json_object_new_object();
184 json_object_object_add(r, "info", i);
185 json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(dynapi->export)));
186 json_object_object_add(i, "version", json_object_new_string("0.0.0"));
187 json_object_object_add(i, "description", json_object_new_string(dynapi->info));
189 p = json_object_new_object();
190 json_object_object_add(r, "paths", p);
191 iter = dynapi->verbs;
192 end = iter + dynapi->count;
193 while (iter != end) {
196 strncpy(buffer + 1, verb->verb, sizeof buffer - 1);
197 buffer[sizeof buffer - 1] = 0;
198 f = json_object_new_object();
199 json_object_object_add(p, buffer, f);
200 g = json_object_new_object();
201 json_object_object_add(f, "get", g);
203 a = afb_auth_json_v2(verb->auth, verb->session);
205 json_object_object_add(g, "x-permissions", a);
207 a = json_object_new_object();
208 json_object_object_add(g, "responses", a);
209 f = json_object_new_object();
210 json_object_object_add(a, "200", f);
211 json_object_object_add(f, "description", json_object_new_string(verb->info?:verb->verb));
216 static struct json_object *describe_cb(void *closure)
218 struct afb_api_dyn *dynapi = closure;
219 struct json_object *r = make_description_openAPIv3(dynapi);
223 static struct afb_api_itf dyn_api_itf = {
225 .service_start = service_start_cb,
226 .update_hooks = update_hooks_cb,
227 .get_verbosity = get_verbosity_cb,
228 .set_verbosity = set_verbosity_cb,
229 .describe = describe_cb
232 int afb_api_dyn_add(struct afb_apiset *apiset, const char *name, const char *info, int (*preinit)(void*, struct afb_dynapi*), void *closure)
235 struct afb_api_dyn *dynapi;
236 struct afb_api afb_api;
237 struct afb_export *export;
239 INFO("Starting creation of dynamic API %s", name);
241 /* allocates the description */
243 dynapi = calloc(1, sizeof *dynapi + strlen(info));
244 export = afb_export_create_vdyn(apiset, name, dynapi);
245 if (!dynapi || !export) {
246 ERROR("out of memory");
249 strcpy(dynapi->info, info);
250 dynapi->export = export;
252 /* preinit the api */
253 rc = afb_export_preinit_vdyn(export, preinit, closure);
255 ERROR("dynamic api %s preinit function failed, ABORTING it!",
256 afb_export_apiname(dynapi->export));
260 /* records the binding */
261 afb_api.closure = dynapi;
262 afb_api.itf = &dyn_api_itf;
263 afb_api.group = NULL;
264 if (afb_apiset_add(apiset, afb_export_apiname(dynapi->export), afb_api) < 0) {
265 ERROR("dynamic api %s can't be registered to set %s, ABORTING it!",
266 afb_export_apiname(dynapi->export),
267 afb_apiset_name(apiset));
270 INFO("binding %s added to set %s", afb_export_apiname(dynapi->export), afb_apiset_name(apiset));
274 afb_export_destroy(export);