Update copyright dates
[src/app-framework-binder.git] / src / afb-monitor.c
index 4b1c038..40a6d3b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016, 2017 "IoT.bzh"
+ * Copyright (C) 2015-2020 "IoT.bzh"
  * Author José Bollo <jose.bollo@iot.bzh>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
 
 #include <json-c/json.h>
 
-#include <afb/afb-binding-v2.h>
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
 
 #include "afb-api.h"
 #include "afb-apiset.h"
-#include "afb-api-so-v2.h"
+#include "afb-api-v3.h"
 #include "afb-evt.h"
 #include "afb-xreq.h"
 #include "afb-trace.h"
+#include "afb-session.h"
+#include "afb-error-text.h"
 #include "verbose.h"
 #include "wrap-json.h"
 
 #include "monitor-api.inc"
 
-extern struct afb_apiset *main_apiset;
 
-static struct afb_binding_data_v2 datav2;
+static const char _verbosity_[] = "verbosity";
+static const char _apis_[] = "apis";
+
+static const char _debug_[] = "debug";
+static const char _info_[] = "info";
+static const char _notice_[] = "notice";
+static const char _warning_[] = "warning";
+static const char _error_[] = "error";
+
+
+static struct afb_apiset *target_set;
 
-int afb_monitor_init()
+int afb_monitor_init(struct afb_apiset *declare_set, struct afb_apiset *call_set)
 {
-       return afb_api_so_v2_add_binding(&_afb_binding_v2_monitor, NULL, main_apiset, &datav2);
+       target_set = call_set;
+       return -!afb_api_v3_from_binding(&_afb_binding_monitor, declare_set, call_set);
 }
 
 /******************************************************************************
 **** Monitoring verbosity
 ******************************************************************************/
 
-static const char _debug_[] = "debug";
-static const char _info_[] = "info";
-static const char _notice_[] = "notice";
-static const char _warning_[] = "warning";
-static const char _error_[] = "error";
-
 /**
  * Translate verbosity indication to an integer value.
  * @param v the verbosity indication
@@ -64,28 +71,28 @@ static int decode_verbosity(struct json_object *v)
        int level = -1;
 
        if (!wrap_json_unpack(v, "i", &level)) {
-               level = level < Verbosity_Level_Error ? Verbosity_Level_Error : level > Verbosity_Level_Debug ? Verbosity_Level_Debug : level;
+               level = level < _VERBOSITY_(Log_Level_Error) ? _VERBOSITY_(Log_Level_Error) : level > _VERBOSITY_(Log_Level_Debug) ? _VERBOSITY_(Log_Level_Debug) : level;
        } else if (!wrap_json_unpack(v, "s", &s)) {
                switch(*s&~' ') {
                case 'D':
                        if (!strcasecmp(s, _debug_))
-                               level = Verbosity_Level_Debug;
+                               level = _VERBOSITY_(Log_Level_Debug);
                        break;
                case 'I':
                        if (!strcasecmp(s, _info_))
-                               level = Verbosity_Level_Info;
+                               level = _VERBOSITY_(Log_Level_Info);
                        break;
                case 'N':
                        if (!strcasecmp(s, _notice_))
-                               level = Verbosity_Level_Notice;
+                               level = _VERBOSITY_(Log_Level_Notice);
                        break;
                case 'W':
                        if (!strcasecmp(s, _warning_))
-                               level = Verbosity_Level_Warning;
+                               level = _VERBOSITY_(Log_Level_Warning);
                        break;
                case 'E':
                        if (!strcasecmp(s, _error_))
-                               level = Verbosity_Level_Error;
+                               level = _VERBOSITY_(Log_Level_Error);
                        break;
                }
        }
@@ -98,9 +105,10 @@ static int decode_verbosity(struct json_object *v)
  * @param the name of the api to set
  * @param closure the verbosity to set as an integer casted to a pointer
  */
-static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, void *closure)
+static void set_verbosity_to_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias)
 {
-       afb_apiset_set_verbosity(set, name, (int)(intptr_t)closure);
+       if (!isalias)
+               afb_apiset_set_logmask(set, name, (int)(intptr_t)closure);
 }
 
 /**
@@ -110,12 +118,13 @@ static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, vo
  */
 static void set_verbosity_to(const char *name, int level)
 {
+       int mask = verbosity_to_mask(level);
        if (!name || !name[0])
-               verbosity = level;
+               verbosity_set(level);
        else if (name[0] == '*' && !name[1])
-               afb_apiset_enum(main_apiset, 1, set_verbosity_to_all_cb, (void*)(intptr_t)level);
+               afb_apiset_enum(target_set, 1, set_verbosity_to_all_cb, (void*)(intptr_t)mask);
        else
-               afb_apiset_set_verbosity(main_apiset, name, level);
+               afb_apiset_set_logmask(target_set, name, mask);
 }
 
 /**
@@ -152,12 +161,12 @@ static void set_verbosity(struct json_object *spec)
  */
 static struct json_object *encode_verbosity(int level)
 {
-       switch(level) {
-       case Verbosity_Level_Error:     return json_object_new_string(_error_);
-       case Verbosity_Level_Warning:   return json_object_new_string(_warning_);
-       case Verbosity_Level_Notice:    return json_object_new_string(_notice_);
-       case Verbosity_Level_Info:      return json_object_new_string(_info_);
-       case Verbosity_Level_Debug:     return json_object_new_string(_debug_);
+       switch(_DEVERBOSITY_(level)) {
+       case Log_Level_Error:   return json_object_new_string(_error_);
+       case Log_Level_Warning: return json_object_new_string(_warning_);
+       case Log_Level_Notice:  return json_object_new_string(_notice_);
+       case Log_Level_Info:    return json_object_new_string(_info_);
+       case Log_Level_Debug:   return json_object_new_string(_debug_);
        default: return json_object_new_int(level);
        }
 }
@@ -168,12 +177,12 @@ static struct json_object *encode_verbosity(int level)
  * @param the name of the api to set
  * @param closure the json object to build
  */
-static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, void *closure)
+static void get_verbosity_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias)
 {
        struct json_object *resu = closure;
-       int l = afb_apiset_get_verbosity(set, name);
-       if (l >= 0)
-               json_object_object_add(resu, name, encode_verbosity(l));
+       int m = afb_apiset_get_logmask(set, name);
+       if (m >= 0)
+               json_object_object_add(resu, name, encode_verbosity(verbosity_from_mask(m)));
 }
 
 /**
@@ -183,15 +192,15 @@ static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, vo
  */
 static void get_verbosity_of(struct json_object *resu, const char *name)
 {
-       int l;
+       int m;
        if (!name || !name[0])
-               json_object_object_add(resu, "", encode_verbosity(verbosity));
+               json_object_object_add(resu, "", encode_verbosity(verbosity_get()));
        else if (name[0] == '*' && !name[1])
-               afb_apiset_enum(main_apiset, 1, get_verbosity_of_all_cb, resu);
+               afb_apiset_enum(target_set, 1, get_verbosity_of_all_cb, resu);
        else {
-               l = afb_apiset_get_verbosity(main_apiset, name);
-               if (l >= 0)
-                       json_object_object_add(resu, name, encode_verbosity(l));
+               m = afb_apiset_get_logmask(target_set, name);
+               if (m >= 0)
+                       json_object_object_add(resu, name, encode_verbosity(verbosity_from_mask(m)));
        }
 }
 
@@ -215,7 +224,7 @@ static struct json_object *get_verbosity(struct json_object *spec)
                        json_object_iter_next(&it);
                }
        } else if (json_object_is_type(spec, json_type_array)) {
-               n = json_object_array_length(spec);
+               n = (int)json_object_array_length(spec);
                for (i = 0 ; i < n ; i++)
                        get_verbosity_of(resu, json_object_get_string(json_object_array_get_idx(spec, i)));
        } else if (json_object_is_type(spec, json_type_string)) {
@@ -228,90 +237,169 @@ static struct json_object *get_verbosity(struct json_object *spec)
 }
 
 /******************************************************************************
-**** Monitoring apis
+**** Manage namelist of api names
 ******************************************************************************/
 
-/**
- * get apis accordling to specification in 'spec'
- * @param resu the json object to build
- * @param spec specification of the verbosity to set
- */
-static void get_one_api(struct json_object *resu, const char *name, struct json_object *spec)
+struct namelist {
+       struct namelist *next;
+       json_object *data;
+       char name[];
+};
+
+static struct namelist *reverse_namelist(struct namelist *head)
 {
-       struct json_object *o;
+       struct namelist *previous, *next;
+
+       previous = NULL;
+       while(head) {
+               next = head->next;
+               head->next = previous;
+               previous = head;
+               head = next;
+       }
+       return previous;
+}
 
-       o = afb_apiset_describe(main_apiset, name);
-       if (o || afb_apiset_lookup(main_apiset, name, 1))
-               json_object_object_add(resu, name, o);
+static void add_one_name_to_namelist(struct namelist **head, const char *name, struct json_object *data)
+{
+       size_t length = strlen(name) + 1;
+       struct namelist *item = malloc(length + sizeof *item);
+       if (!item)
+               ERROR("out of memory");
+       else {
+               item->next = *head;
+               item->data = data;
+               memcpy(item->name, name, length);
+               *head = item;
+       }
 }
 
-/**
- * callback for getting verbosity of all apis
- * @param set the apiset
- * @param the name of the api to set
- * @param closure the json object to build
- */
-static void get_apis_of_all_cb(struct afb_apiset *set, const char *name, void *closure)
+static void get_apis_namelist_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias)
 {
-       struct json_object *resu = closure;
-       get_one_api(resu, name, NULL);
+       struct namelist **head = closure;
+       add_one_name_to_namelist(head, name, NULL);
 }
 
 /**
- * get apis accordling to specification in 'spec'
- * @param resu the json object to build
- * @param spec specification of the verbosity to set
+ * get apis names as a list accordling to specification in 'spec'
+ * @param spec specification of the apis to get
  */
-static struct json_object *get_apis(struct json_object *spec)
+static struct namelist *get_apis_namelist(struct json_object *spec)
 {
        int i, n;
-       struct json_object *resu;
        struct json_object_iterator it, end;
+       struct namelist *head;
 
-       resu = json_object_new_object();
+       head = NULL;
        if (json_object_is_type(spec, json_type_object)) {
                it = json_object_iter_begin(spec);
                end = json_object_iter_end(spec);
                while (!json_object_iter_equal(&it, &end)) {
-                       get_one_api(resu, json_object_iter_peek_name(&it), json_object_iter_peek_value(&it));
+                       add_one_name_to_namelist(&head,
+                                                json_object_iter_peek_name(&it),
+                                                json_object_iter_peek_value(&it));
                        json_object_iter_next(&it);
                }
        } else if (json_object_is_type(spec, json_type_array)) {
-               n = json_object_array_length(spec);
+               n = (int)json_object_array_length(spec);
                for (i = 0 ; i < n ; i++)
-                       get_one_api(resu, json_object_get_string(json_object_array_get_idx(spec, i)), NULL);
+                       add_one_name_to_namelist(&head,
+                                                json_object_get_string(
+                                                        json_object_array_get_idx(spec, i)),
+                                                NULL);
        } else if (json_object_is_type(spec, json_type_string)) {
-               get_one_api(resu, json_object_get_string(spec), NULL);
+               add_one_name_to_namelist(&head, json_object_get_string(spec), NULL);
        } else if (json_object_get_boolean(spec)) {
-               afb_apiset_enum(main_apiset, 1, get_apis_of_all_cb, resu);
+               afb_apiset_enum(target_set, 1, get_apis_namelist_of_all_cb, &head);
        }
-       return resu;
+       return reverse_namelist(head);
 }
 
 /******************************************************************************
-**** Implementation monitoring verbs
+**** Monitoring apis
 ******************************************************************************/
 
-static const char _verbosity_[] = "verbosity";
-static const char _apis_[] = "apis";
+struct desc_apis {
+       struct namelist *names;
+       struct json_object *resu;
+       struct json_object *apis;
+       afb_req_t req;
+};
+
+static void describe_first_api(struct desc_apis *desc);
+
+static void on_api_description(void *closure, struct json_object *apidesc)
+{
+       struct desc_apis *desc = closure;
+       struct namelist *head = desc->names;
+
+       if (apidesc || afb_apiset_lookup(target_set, head->name, 1))
+               json_object_object_add(desc->apis, head->name, apidesc);
+       desc->names = head->next;
+       free(head);
+       describe_first_api(desc);
+}
+
+static void describe_first_api(struct desc_apis *desc)
+{
+       struct namelist *head = desc->names;
+       if (head)
+               afb_apiset_describe(target_set, head->name, on_api_description, desc);
+       else {
+               afb_req_success(desc->req, desc->resu, NULL);
+               afb_req_unref(desc->req);
+               free(desc);
+       }
+}
 
-static void f_get(struct afb_req req)
+static void describe_apis(afb_req_t req, struct json_object *resu, struct json_object *spec)
+{
+       struct desc_apis *desc;
+
+       desc = malloc(sizeof *desc);
+       if (!desc)
+               afb_req_fail(req, "out-of-memory", NULL);
+       else {
+               desc->req = afb_req_addref(req);
+               desc->resu = resu;
+               desc->apis = json_object_new_object();
+               json_object_object_add(desc->resu, _apis_, desc->apis);
+               desc->names = get_apis_namelist(spec);
+               describe_first_api(desc);
+       }
+}
+
+/******************************************************************************
+**** Implementation monitoring verbs
+******************************************************************************/
+
+static void f_get(afb_req_t req)
 {
        struct json_object *r;
        struct json_object *apis = NULL;
        struct json_object *verbosity = NULL;
 
        wrap_json_unpack(afb_req_json(req), "{s?:o,s?:o}", _verbosity_, &verbosity, _apis_, &apis);
-       if (verbosity)
-               verbosity = get_verbosity(verbosity);
-       if (apis)
-               apis = get_apis(apis);
-
-       wrap_json_pack(&r, "{s:o*,s:o*}", _verbosity_, verbosity, _apis_, apis);
-       afb_req_success(req, r, NULL);
+       if (!verbosity && !apis)
+               afb_req_success(req, NULL, NULL);
+       else {
+               r = json_object_new_object();
+               if (!r)
+                       afb_req_fail(req, "out-of-memory", NULL);
+               else {
+                       if (verbosity) {
+                               verbosity = get_verbosity(verbosity);
+                               json_object_object_add(r, _verbosity_, verbosity);
+                       }
+                       if (!apis)
+                               afb_req_success(req, r, NULL);
+                       else
+                               describe_apis(req, r, apis);
+               }
+       }
 }
 
-static void f_set(struct afb_req req)
+static void f_set(afb_req_t req)
 {
        struct json_object *verbosity = NULL;
 
@@ -322,9 +410,10 @@ static void f_set(struct afb_req req)
        afb_req_success(req, NULL, NULL);
 }
 
-static void *context_create()
+#if WITH_AFB_TRACE
+static void *context_create(void *closure)
 {
-       return afb_trace_create(&datav2.daemon, NULL);
+       return afb_trace_create(_afb_binding_monitor.api, NULL);
 }
 
 static void context_destroy(void *pointer)
@@ -333,14 +422,14 @@ static void context_destroy(void *pointer)
        afb_trace_unref(trace);
 }
 
-static void f_trace(struct afb_req req)
+static void f_trace(afb_req_t req)
 {
        int rc;
        struct json_object *add = NULL;
        struct json_object *drop = NULL;
        struct afb_trace *trace;
 
-       trace = afb_req_context(req, context_create, context_destroy);
+       trace = afb_req_context(req, 0, context_create, context_destroy, NULL);
        wrap_json_unpack(afb_req_json(req), "{s?o s?o}", "add", &add, "drop", &drop);
        if (add) {
                rc = afb_trace_add(req, add, trace);
@@ -354,7 +443,33 @@ static void f_trace(struct afb_req req)
        }
        afb_req_success(req, NULL, NULL);
 end:
-       afb_apiset_update_hooks(main_apiset, NULL);
+       afb_apiset_update_hooks(target_set, NULL);
        afb_evt_update_hooks();
+       return;
+}
+#else
+static void f_trace(afb_req_t req)
+{
+       afb_req_reply(req, NULL, afb_error_text_not_available, NULL);
+}
+#endif
+
+static void f_session(afb_req_t req)
+{
+       struct json_object *r = NULL;
+       struct afb_xreq *xreq = xreq_from_req_x2(req);
+
+       /* check right to call it */
+       if (xreq->context.super) {
+               afb_req_fail(req, "invalid", "reserved to direct clients");
+               return;
+       }
+
+       /* make the result */
+       wrap_json_pack(&r, "{s:s,s:i,s:i}",
+                       "uuid", afb_session_uuid(xreq->context.session),
+                       "timeout", afb_session_timeout(xreq->context.session),
+                       "remain", afb_session_what_remains(xreq->context.session));
+       afb_req_success(req, r, NULL);
 }