Prepare bindings version 2
[src/app-framework-binder.git] / src / afb-monitor.c
1 /*
2  * Copyright (C) 2016, 2017 "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 #define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO
20
21 #include <string.h>
22
23 #include <json-c/json.h>
24 #include <afb/afb-binding.h>
25
26 #include "afb-api.h"
27 #include "afb-apiset.h"
28 #include "afb-api-so-v2.h"
29 #include "afb-ditf.h"
30 #include "afb-xreq.h"
31 #include "verbose.h"
32
33 #include "monitor-api.inc"
34
35 extern struct afb_apiset *main_apiset;
36
37 int afb_monitor_init()
38 {
39         static int v;
40         return afb_api_so_v2_add_binding(&_afb_binding_v2_, NULL, main_apiset, &v);
41 }
42
43 /******************************************************************************
44 **** Monitoring verbosity
45 ******************************************************************************/
46
47 static const char _debug_[] = "debug";
48 static const char _info_[] = "info";
49 static const char _notice_[] = "notice";
50 static const char _warning_[] = "warning";
51 static const char _error_[] = "error";
52
53 /**
54  * Translate verbosity indication to an integer value.
55  * @param v the verbosity indication
56  * @return the verbosity level (0, 1, 2 or 3) or -1 in case of error
57  */
58 static int decode_verbosity(struct json_object *v)
59 {
60         const char *s;
61         int level = -1;
62         if (json_object_is_type(v, json_type_int)) {
63                 level = json_object_get_int(v);
64                 level = level < 0 ? 0 : level > 3 ? 3 : level;
65         } else if (json_object_is_type(v, json_type_string)) {
66                 s = json_object_get_string(v);
67                 switch(*s&~' ') {
68                 case 'D':
69                         if (!strcasecmp(s, _debug_))
70                                 level = 3;
71                         break;
72                 case 'I':
73                         if (!strcasecmp(s, _info_))
74                                 level = 2;
75                         break;
76                 case 'N':
77                         if (!strcasecmp(s, _notice_))
78                                 level = 1;
79                         break;
80                 case 'W':
81                         if (!strcasecmp(s, _warning_))
82                                 level = 1;
83                         break;
84                 case 'E':
85                         if (!strcasecmp(s, _error_))
86                                 level = 0;
87                         break;
88                 }
89         }
90         return level;
91 }
92
93 /**
94  * callback for setting verbosity on all apis
95  * @param set the apiset
96  * @param the name of the api to set
97  * @param closure the verbosity to set as an integer casted to a pointer
98  */
99 static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, void *closure)
100 {
101         afb_apiset_set_verbosity(set, name, (int)(intptr_t)closure);
102 }
103
104 /**
105  * set the verbosity 'level' of the api of 'name'
106  * @param name the api name or "*" for any api or NULL or "" for global verbosity
107  * @param level the verbosity level to set
108  */
109 static void set_verbosity_to(const char *name, int level)
110 {
111         if (!name || !name[0])
112                 verbosity = level;
113         else if (name[0] == '*' && !name[1])
114                 afb_apiset_enum(main_apiset, set_verbosity_to_all_cb, (void*)(intptr_t)level);
115         else
116                 afb_apiset_set_verbosity(main_apiset, name, level);
117 }
118
119 /**
120  * Set verbosities accordling to specification in 'spec'
121  * @param spec specification of the verbosity to set
122  */
123 static void set_verbosity(struct json_object *spec)
124 {
125         int l;
126         struct json_object_iterator it, end;
127
128         if (json_object_is_type(spec, json_type_object)) {
129                 it = json_object_iter_begin(spec);
130                 end = json_object_iter_end(spec);
131                 while (!json_object_iter_equal(&it, &end)) {
132                         l = decode_verbosity(json_object_iter_peek_value(&it));
133                         if (l >= 0)
134                                 set_verbosity_to(json_object_iter_peek_name(&it), l);
135                         json_object_iter_next(&it);
136                 }
137         } else {
138                 l = decode_verbosity(spec);
139                 if (l >= 0) {
140                         set_verbosity_to("", l);
141                         set_verbosity_to("*", l);
142                 }
143         }
144 }
145
146 /**
147  * Translate verbosity level to a protocol indication.
148  * @param level the verbosity 
149  * @return the encoded verbosity
150  */
151 static struct json_object *encode_verbosity(int level)
152 {
153         switch(level) {
154         case 0: return json_object_new_string(_error_);
155         case 1: return json_object_new_string(_notice_);
156         case 2: return json_object_new_string(_info_);
157         case 3: return json_object_new_string(_debug_);
158         default: return json_object_new_int(level);
159         }
160 }
161
162 /**
163  * callback for getting verbosity of all apis
164  * @param set the apiset
165  * @param the name of the api to set
166  * @param closure the json object to build
167  */
168 static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, void *closure)
169 {
170         struct json_object *resu = closure;
171         int l = afb_apiset_get_verbosity(set, name);
172         if (l >= 0)
173                 json_object_object_add(resu, name, encode_verbosity(l));
174 }
175
176 /**
177  * get in resu the verbosity of the api of 'name'
178  * @param resu the json object to build
179  * @param name the api name or "*" for any api or NULL or "" for global verbosity
180  */
181 static void get_verbosity_of(struct json_object *resu, const char *name)
182 {
183         int l;
184         if (!name || !name[0])
185                 json_object_object_add(resu, "", encode_verbosity(verbosity));
186         else if (name[0] == '*' && !name[1])
187                 afb_apiset_enum(main_apiset, get_verbosity_of_all_cb, resu);
188         else {
189                 l = afb_apiset_get_verbosity(main_apiset, name);
190                 if (l >= 0)
191                         json_object_object_add(resu, name, encode_verbosity(l));
192         }
193 }
194
195 /**
196  * get verbosities accordling to specification in 'spec'
197  * @param resu the json object to build
198  * @param spec specification of the verbosity to set
199  */
200 static void get_verbosity(struct json_object *resu, struct json_object *spec)
201 {
202         int i, n;
203         struct json_object_iterator it, end;
204
205         if (json_object_is_type(spec, json_type_object)) {
206                 it = json_object_iter_begin(spec);
207                 end = json_object_iter_end(spec);
208                 while (!json_object_iter_equal(&it, &end)) {
209                         get_verbosity_of(resu, json_object_iter_peek_name(&it));
210                         json_object_iter_next(&it);
211                 }
212         } else if (json_object_is_type(spec, json_type_array)) {
213                 n = json_object_array_length(spec);
214                 for (i = 0 ; i < n ; i++)
215                         get_verbosity_of(resu, json_object_get_string(json_object_array_get_idx(spec, i)));
216         } else if (json_object_get_boolean(spec)) {
217                 get_verbosity_of(resu, "");
218                 get_verbosity_of(resu, "*");
219         }
220 }
221
222 /******************************************************************************
223 **** Monitoring apis
224 ******************************************************************************/
225
226 /**
227  * get apis accordling to specification in 'spec'
228  * @param resu the json object to build
229  * @param spec specification of the verbosity to set
230  */
231 static void get_one_api(struct json_object *resu, const char *name, struct json_object *spec)
232 {
233         struct json_object *o;
234         struct afb_api api;
235         int rc;
236
237         rc = afb_apiset_lookup(main_apiset, name, &api);
238         if (!rc) {
239                 o = api.itf->describe ? api.itf->describe(api.closure) : NULL;
240                 json_object_object_add(resu, name, o);
241         }
242 }
243
244 /**
245  * callback for getting verbosity of all apis
246  * @param set the apiset
247  * @param the name of the api to set
248  * @param closure the json object to build
249  */
250 static void get_apis_of_all_cb(struct afb_apiset *set, const char *name, void *closure)
251 {
252         struct json_object *resu = closure;
253         get_one_api(resu, name, NULL);
254 }
255
256 /**
257  * get apis accordling to specification in 'spec'
258  * @param resu the json object to build
259  * @param spec specification of the verbosity to set
260  */
261 static void get_apis(struct json_object *resu, struct json_object *spec)
262 {
263         int i, n;
264         struct json_object_iterator it, end;
265
266         if (json_object_is_type(spec, json_type_object)) {
267                 it = json_object_iter_begin(spec);
268                 end = json_object_iter_end(spec);
269                 while (!json_object_iter_equal(&it, &end)) {
270                         get_one_api(resu, json_object_iter_peek_name(&it), json_object_iter_peek_value(&it));
271                         json_object_iter_next(&it);
272                 }
273         } else if (json_object_is_type(spec, json_type_array)) {
274                 n = json_object_array_length(spec);
275                 for (i = 0 ; i < n ; i++)
276                         get_one_api(resu, json_object_get_string(json_object_array_get_idx(spec, i)), NULL);
277         } else if (json_object_get_boolean(spec)) {
278                 afb_apiset_enum(main_apiset, get_apis_of_all_cb, resu);
279         }
280 }
281
282 /******************************************************************************
283 **** Implementation monitoring verbs
284 ******************************************************************************/
285
286 static const char _verbosity_[] = "verbosity";
287 static const char _apis_[] = "apis";
288
289 static void f_get(struct afb_req req)
290 {
291         struct json_object *o, *v, *r, *x;
292
293         r = json_object_new_object();
294         o = afb_req_json(req);
295
296         if (json_object_object_get_ex(o, _verbosity_, &v)) {
297                 x = json_object_new_object();
298                 json_object_object_add(r, _verbosity_, x);
299                 get_verbosity(x, v);
300         }
301
302         if (json_object_object_get_ex(o, _apis_, &v)) {
303                 x = json_object_new_object();
304                 json_object_object_add(r, _apis_, x);
305                 get_apis(x, v);
306         }
307
308         afb_req_success(req, json_object_get(r), NULL);
309         json_object_put(r);
310 }
311
312 static void f_set(struct afb_req req)
313 {
314         struct json_object *o, *v;
315
316         o = afb_req_json(req);
317         if (json_object_object_get_ex(o, _verbosity_, &v)) {
318                 set_verbosity(v);
319         }
320
321         afb_req_success(req, NULL, NULL);
322 }
323
324 #if 0
325 static void f_hook(struct afb_xreq *xreq)
326 {
327         struct json_object *o, *v;
328
329         o = afb_xreq_json(xreq);
330         if (json_object_object_get_ex(o, _verbosity_, &v)) {
331                 set_verbosity(v);
332         }
333
334         if (!xreq->replied)
335                 afb_xreq_success(xreq, NULL, NULL);
336 }
337 #endif
338