api-v3: First draft
[src/app-framework-binder.git] / src / afb-api-v3.c
1 /*
2  * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
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
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <fnmatch.h>
25
26 #include <json-c/json.h>
27
28 #define AFB_BINDING_VERSION 0
29 #include <afb/afb-binding.h>
30
31 #include "afb-api.h"
32 #include "afb-api-v3.h"
33 #include "afb-apiset.h"
34 #include "afb-auth.h"
35 #include "afb-export.h"
36 #include "afb-xreq.h"
37 #include "verbose.h"
38
39 /*
40  * Description of a binding
41  */
42 struct afb_api_v3 {
43         int refcount;
44         int count;
45         struct afb_verb_v3 **verbs;
46         const struct afb_verb_v2 *verbsv2;
47         const struct afb_verb_v3 *verbsv3;
48         struct afb_export *export;
49         const char *info;
50 };
51
52 static const char nulchar = 0;
53
54 static int verb_name_compare(const struct afb_verb_v3 *verb, const char *name)
55 {
56         return verb->glob
57                 ? fnmatch(verb->verb, name, FNM_NOESCAPE|FNM_PATHNAME|FNM_CASEFOLD|FNM_PERIOD)
58                 : strcasecmp(verb->verb, name);
59 }
60
61 static struct afb_verb_v3 *search_dynamic_verb(struct afb_api_v3 *api, const char *name)
62 {
63         struct afb_verb_v3 **v, **e, *i;
64
65         v = api->verbs;
66         e = &v[api->count];
67         while (v != e) {
68                 i = *v;
69                 if (!verb_name_compare(i, name))
70                         return i;
71                 v++;
72         }
73         return 0;
74 }
75
76 void afb_api_v3_process_call(struct afb_api_v3 *api, struct afb_xreq *xreq)
77 {
78         const struct afb_verb_v3 *verbsv3;
79         const struct afb_verb_v2 *verbsv2;
80         const char *name;
81
82         name = xreq->request.called_verb;
83
84         /* look first in dynamic set */
85         verbsv3 = search_dynamic_verb(api, name);
86         if (!verbsv3) {
87                 /* look then in static set */
88                 verbsv3 = api->verbsv3;
89                 while (verbsv3) {
90                         if (!verbsv3->verb)
91                                 verbsv3 = 0;
92                         else if (!verb_name_compare(verbsv3, name))
93                                 break;
94                         else
95                                 verbsv3++;
96                 }
97         }
98         /* is it a v3 verb ? */
99         if (verbsv3) {
100                 /* yes */
101                 xreq->request.vcbdata = verbsv3->vcbdata;
102                 afb_xreq_call_verb_v3(xreq, verbsv3);
103                 return;
104         }
105
106         /* look in legacy set */
107         verbsv2 = api->verbsv2;
108         if (verbsv2) {
109                 while (verbsv2->verb) {
110                         if (strcasecmp(verbsv2->verb, name))
111                                 verbsv2++;
112                         else {
113                                 afb_xreq_call_verb_v2(xreq, verbsv2);
114                                 return;
115                         }
116                 }
117         }
118
119         afb_xreq_reply_unknown_verb(xreq);
120 }
121
122 struct json_object *afb_api_v3_make_description_openAPIv3(struct afb_api_v3 *api, const char *apiname)
123 {
124         char buffer[256];
125         struct afb_verb_v3 **iter, **end, *verb;
126         struct json_object *r, *f, *a, *i, *p, *g;
127
128         r = json_object_new_object();
129         json_object_object_add(r, "openapi", json_object_new_string("3.0.0"));
130
131         i = json_object_new_object();
132         json_object_object_add(r, "info", i);
133         json_object_object_add(i, "title", json_object_new_string(apiname));
134         json_object_object_add(i, "version", json_object_new_string("0.0.0"));
135         json_object_object_add(i, "description", json_object_new_string(api->info));
136
137         p = json_object_new_object();
138         json_object_object_add(r, "paths", p);
139         iter = api->verbs;
140         end = iter + api->count;
141         while (iter != end) {
142                 verb = *iter++;
143                 buffer[0] = '/';
144                 strncpy(buffer + 1, verb->verb, sizeof buffer - 1);
145                 buffer[sizeof buffer - 1] = 0;
146                 f = json_object_new_object();
147                 json_object_object_add(p, buffer, f);
148                 g = json_object_new_object();
149                 json_object_object_add(f, "get", g);
150
151                 a = afb_auth_json_v2(verb->auth, verb->session);
152                 if (a)
153                         json_object_object_add(g, "x-permissions", a);
154
155                 a = json_object_new_object();
156                 json_object_object_add(g, "responses", a);
157                 f = json_object_new_object();
158                 json_object_object_add(a, "200", f);
159                 json_object_object_add(f, "description", json_object_new_string(verb->info?:verb->verb));
160         }
161         return r;
162 }
163
164 struct afb_api_v3 *afb_api_v3_create(
165                 struct afb_apiset *declare_set,
166                 struct afb_apiset *call_set,
167                 const char *apiname,
168                 const char *info,
169                 int noconcurrency,
170                 int (*preinit)(void*, struct afb_api_x3 *),
171                 void *closure,
172                 int copy_info
173 )
174 {
175         struct afb_api_v3 *api;
176
177         /* allocates the description */
178         api = calloc(1, sizeof *api + (copy_info && info ? 1 + strlen(info) : 0));
179         if (!api)
180                 goto oom;
181         api->refcount = 1;
182         if (!info)
183                 api->info = &nulchar;
184         else if (copy_info)
185                 api->info = strcpy((char*)(api + 1), info);
186         else
187                 api->info = info;
188
189         api->export = afb_export_create_v3(declare_set, call_set, apiname, api);
190         if (!api->export)
191                 goto oom2;
192
193         if (afb_export_declare(api->export, noconcurrency) < 0)
194                 goto oom3;
195
196         if (preinit && afb_export_preinit_x3(api->export, preinit, closure) < 0)
197                 goto oom4;
198
199         return api;
200
201 oom4:
202         afb_export_undeclare(api->export);
203 oom3:
204         afb_export_unref(api->export);
205 oom2:
206         free(api);
207 oom:
208         ERROR("out of memory");
209         return NULL;
210 }
211
212 struct afb_api_v3 *afb_api_v3_addref(struct afb_api_v3 *api)
213 {
214         if (api)
215                 __atomic_add_fetch(&api->refcount, 1, __ATOMIC_RELAXED);
216         return api;
217 }
218
219 void afb_api_v3_unref(struct afb_api_v3 *api)
220 {
221         if (api && !__atomic_sub_fetch(&api->refcount, 1, __ATOMIC_RELAXED)) {
222                 afb_export_destroy(api->export);
223                 free(api);
224         }
225 }
226
227 struct afb_export *afb_api_v3_export(struct afb_api_v3 *api)
228 {
229         return api->export;
230 }
231
232 void afb_api_v3_set_verbs_v2(
233                 struct afb_api_v3 *api,
234                 const struct afb_verb_v2 *verbs)
235 {
236         api->verbsv2 = verbs;
237 }
238
239 void afb_api_v3_set_verbs_v3(
240                 struct afb_api_v3 *api,
241                 const struct afb_verb_v3 *verbs)
242 {
243         api->verbsv3 = verbs;
244 }
245
246 int afb_api_v3_add_verb(
247                 struct afb_api_v3 *api,
248                 const char *verb,
249                 const char *info,
250                 void (*callback)(struct afb_req_x2 *req),
251                 void *vcbdata,
252                 const struct afb_auth *auth,
253                 uint16_t session,
254                 int glob)
255 {
256         struct afb_verb_v3 *v, **vv;
257         char *txt;
258         int i;
259
260         for (i = 0 ; i < api->count ; i++) {
261                 v = api->verbs[i];
262                 if (glob == v->glob && !strcasecmp(verb, v->verb)) {
263                         /* refuse to redefine a dynamic verb */
264                         errno = EEXIST;
265                         return -1;
266                 }
267         }
268
269         vv = realloc(api->verbs, (1 + api->count) * sizeof *vv);
270         if (!vv)
271                 goto oom;
272         api->verbs = vv;
273
274         v = malloc(sizeof *v + (1 + strlen(verb)) + (info ? 1 + strlen(info) : 0));
275         if (!v)
276                 goto oom;
277
278         v->callback = callback;
279         v->vcbdata = vcbdata;
280         v->auth = auth;
281         v->session = session;
282         v->glob = !!glob;
283
284         txt = (char*)(v + 1);
285         v->verb = txt;
286         txt = stpcpy(txt, verb);
287         if (!info)
288                 v->info = NULL;
289         else {
290                 v->info = ++txt;
291                 strcpy(txt, info);
292         }
293
294         api->verbs[api->count++] = v;
295         return 0;
296 oom:
297         errno = ENOMEM;
298         return -1;
299 }
300
301 int afb_api_v3_del_verb(
302                 struct afb_api_v3 *api,
303                 const char *verb,
304                 void **vcbdata)
305 {
306         struct afb_verb_v3 **v, **e, *i;
307
308         v = api->verbs;
309         e = &v[api->count];
310         while (v != e) {
311                 i = *v++;
312                 if (!strcasecmp(i->verb, verb)) {
313                         api->count--;
314                         if (vcbdata)
315                                 *vcbdata = i->vcbdata;
316                         if (v != e)
317                                 *--v = *--e;
318                         free(i);
319                         return 0;
320                 }
321         }
322
323         errno = ENOENT;
324         return -1;
325 }
326
327 int afb_api_v3_set_binding_fields(const struct afb_binding_v3 *desc, struct afb_api_x3 *api)
328 {
329         int rc = 0;
330         if (desc->verbs)
331                 rc =  afb_api_x3_set_verbs_v3(api, desc->verbs);
332         if (!rc && desc->onevent)
333                 rc =  afb_api_x3_on_event(api, desc->onevent);
334         if (!rc && desc->init)
335                 rc =  afb_api_x3_on_init(api, desc->init);
336         if (!rc && desc->provide_class)
337                 rc =  afb_api_x3_provide_class(api, desc->provide_class);
338         if (!rc && desc->require_class)
339                 rc =  afb_api_x3_require_class(api, desc->require_class);
340         if (!rc && desc->require_api)
341                 rc =  afb_api_x3_require_api(api, desc->require_api, 1);
342         return rc;
343 }
344
345 static int init_binding(void *closure, struct afb_api_x3 *api)
346 {
347         const struct afb_binding_v3 *desc = closure;
348         int rc = afb_api_v3_set_binding_fields(desc, api);
349         if (!rc && desc->preinit)
350                 rc =  desc->preinit(api);
351         return rc;
352 }
353
354 struct afb_api_v3 *afb_api_v3_from_binding(const struct afb_binding_v3 *desc, struct afb_apiset *declare_set, struct afb_apiset * call_set)
355 {
356         return afb_api_v3_create(declare_set, call_set, desc->api, desc->info, desc->noconcurrency, init_binding, (void*)desc, 0);
357 }
358