afb-apiset: refactor access to apis
[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
25 #include <afb/afb-binding-v2.h>
26
27 #include "afb-api.h"
28 #include "afb-apiset.h"
29 #include "afb-api-so-v2.h"
30 #include "afb-ditf.h"
31 #include "afb-evt.h"
32 #include "afb-xreq.h"
33 #include "afb-trace.h"
34 #include "verbose.h"
35 #include "wrap-json.h"
36
37 #include "monitor-api.inc"
38
39 extern struct afb_apiset *main_apiset;
40
41 static struct afb_binding_data_v2 datav2;
42
43 int afb_monitor_init()
44 {
45         return afb_api_so_v2_add_binding(&_afb_binding_v2_monitor, NULL, main_apiset, &datav2);
46 }
47
48 /******************************************************************************
49 **** Monitoring verbosity
50 ******************************************************************************/
51
52 static const char _debug_[] = "debug";
53 static const char _info_[] = "info";
54 static const char _notice_[] = "notice";
55 static const char _warning_[] = "warning";
56 static const char _error_[] = "error";
57
58 /**
59  * Translate verbosity indication to an integer value.
60  * @param v the verbosity indication
61  * @return the verbosity level (0, 1, 2 or 3) or -1 in case of error
62  */
63 static int decode_verbosity(struct json_object *v)
64 {
65         const char *s;
66         int level = -1;
67
68         if (!wrap_json_unpack(v, "i", &level)) {
69                 level = level < Verbosity_Level_Error ? Verbosity_Level_Error : level > Verbosity_Level_Debug ? Verbosity_Level_Debug : level;
70         } else if (!wrap_json_unpack(v, "s", &s)) {
71                 switch(*s&~' ') {
72                 case 'D':
73                         if (!strcasecmp(s, _debug_))
74                                 level = Verbosity_Level_Debug;
75                         break;
76                 case 'I':
77                         if (!strcasecmp(s, _info_))
78                                 level = Verbosity_Level_Info;
79                         break;
80                 case 'N':
81                         if (!strcasecmp(s, _notice_))
82                                 level = Verbosity_Level_Notice;
83                         break;
84                 case 'W':
85                         if (!strcasecmp(s, _warning_))
86                                 level = Verbosity_Level_Warning;
87                         break;
88                 case 'E':
89                         if (!strcasecmp(s, _error_))
90                                 level = Verbosity_Level_Error;
91                         break;
92                 }
93         }
94         return level;
95 }
96
97 /**
98  * callback for setting verbosity on all apis
99  * @param set the apiset
100  * @param the name of the api to set
101  * @param closure the verbosity to set as an integer casted to a pointer
102  */
103 static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, void *closure)
104 {
105         afb_apiset_set_verbosity(set, name, (int)(intptr_t)closure);
106 }
107
108 /**
109  * set the verbosity 'level' of the api of 'name'
110  * @param name the api name or "*" for any api or NULL or "" for global verbosity
111  * @param level the verbosity level to set
112  */
113 static void set_verbosity_to(const char *name, int level)
114 {
115         if (!name || !name[0])
116                 verbosity = level;
117         else if (name[0] == '*' && !name[1])
118                 afb_apiset_enum(main_apiset, set_verbosity_to_all_cb, (void*)(intptr_t)level);
119         else
120                 afb_apiset_set_verbosity(main_apiset, name, level);
121 }
122
123 /**
124  * Set verbosities accordling to specification in 'spec'
125  * @param spec specification of the verbosity to set
126  */
127 static void set_verbosity(struct json_object *spec)
128 {
129         int l;
130         struct json_object_iterator it, end;
131
132         if (json_object_is_type(spec, json_type_object)) {
133                 it = json_object_iter_begin(spec);
134                 end = json_object_iter_end(spec);
135                 while (!json_object_iter_equal(&it, &end)) {
136                         l = decode_verbosity(json_object_iter_peek_value(&it));
137                         if (l >= 0)
138                                 set_verbosity_to(json_object_iter_peek_name(&it), l);
139                         json_object_iter_next(&it);
140                 }
141         } else {
142                 l = decode_verbosity(spec);
143                 if (l >= 0) {
144                         set_verbosity_to("", l);
145                         set_verbosity_to("*", l);
146                 }
147         }
148 }
149
150 /**
151  * Translate verbosity level to a protocol indication.
152  * @param level the verbosity 
153  * @return the encoded verbosity
154  */
155 static struct json_object *encode_verbosity(int level)
156 {
157         switch(level) {
158         case Verbosity_Level_Error:     return json_object_new_string(_error_);
159         case Verbosity_Level_Warning:   return json_object_new_string(_warning_);
160         case Verbosity_Level_Notice:    return json_object_new_string(_notice_);
161         case Verbosity_Level_Info:      return json_object_new_string(_info_);
162         case Verbosity_Level_Debug:     return json_object_new_string(_debug_);
163         default: return json_object_new_int(level);
164         }
165 }
166
167 /**
168  * callback for getting verbosity of all apis
169  * @param set the apiset
170  * @param the name of the api to set
171  * @param closure the json object to build
172  */
173 static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, void *closure)
174 {
175         struct json_object *resu = closure;
176         int l = afb_apiset_get_verbosity(set, name);
177         if (l >= 0)
178                 json_object_object_add(resu, name, encode_verbosity(l));
179 }
180
181 /**
182  * get in resu the verbosity of the api of 'name'
183  * @param resu the json object to build
184  * @param name the api name or "*" for any api or NULL or "" for global verbosity
185  */
186 static void get_verbosity_of(struct json_object *resu, const char *name)
187 {
188         int l;
189         if (!name || !name[0])
190                 json_object_object_add(resu, "", encode_verbosity(verbosity));
191         else if (name[0] == '*' && !name[1])
192                 afb_apiset_enum(main_apiset, get_verbosity_of_all_cb, resu);
193         else {
194                 l = afb_apiset_get_verbosity(main_apiset, name);
195                 if (l >= 0)
196                         json_object_object_add(resu, name, encode_verbosity(l));
197         }
198 }
199
200 /**
201  * get verbosities accordling to specification in 'spec'
202  * @param resu the json object to build
203  * @param spec specification of the verbosity to set
204  */
205 static struct json_object *get_verbosity(struct json_object *spec)
206 {
207         int i, n;
208         struct json_object *resu;
209         struct json_object_iterator it, end;
210
211         resu = json_object_new_object();
212         if (json_object_is_type(spec, json_type_object)) {
213                 it = json_object_iter_begin(spec);
214                 end = json_object_iter_end(spec);
215                 while (!json_object_iter_equal(&it, &end)) {
216                         get_verbosity_of(resu, json_object_iter_peek_name(&it));
217                         json_object_iter_next(&it);
218                 }
219         } else if (json_object_is_type(spec, json_type_array)) {
220                 n = json_object_array_length(spec);
221                 for (i = 0 ; i < n ; i++)
222                         get_verbosity_of(resu, json_object_get_string(json_object_array_get_idx(spec, i)));
223         } else if (json_object_is_type(spec, json_type_string)) {
224                 get_verbosity_of(resu, json_object_get_string(spec));
225         } else if (json_object_get_boolean(spec)) {
226                 get_verbosity_of(resu, "");
227                 get_verbosity_of(resu, "*");
228         }
229         return resu;
230 }
231
232 /******************************************************************************
233 **** Monitoring apis
234 ******************************************************************************/
235
236 /**
237  * get apis accordling to specification in 'spec'
238  * @param resu the json object to build
239  * @param spec specification of the verbosity to set
240  */
241 static void get_one_api(struct json_object *resu, const char *name, struct json_object *spec)
242 {
243         struct json_object *o;
244
245         o = afb_apiset_describe(main_apiset, name);
246         if (o || afb_apiset_has(main_apiset, name, 0))
247                 json_object_object_add(resu, name, o);
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 static void *context_create()
328 {
329         return afb_trace_create(&datav2.daemon, NULL);
330 }
331
332 static void context_destroy(void *pointer)
333 {
334         struct afb_trace *trace = pointer;
335         afb_trace_unref(trace);
336 }
337
338 static void f_trace(struct afb_req req)
339 {
340         int rc;
341         struct json_object *add = NULL;
342         struct json_object *drop = NULL;
343         struct afb_trace *trace;
344
345         trace = afb_req_context(req, context_create, context_destroy);
346         wrap_json_unpack(afb_req_json(req), "{s?o s?o}", "add", &add, "drop", &drop);
347         if (add) {
348                 rc = afb_trace_add(req, add, trace);
349                 if (rc)
350                         goto end;
351         }
352         if (drop) {
353                 rc = afb_trace_drop(req, drop, trace);
354                 if (rc)
355                         goto end;
356         }
357         afb_req_success(req, NULL, NULL);
358 end:
359         afb_apiset_update_hooks(main_apiset, NULL);
360         afb_evt_update_hooks();
361 }
362