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