/*
- * Copyright (C) 2016, 2017 "IoT.bzh"
+ * Copyright (C) 2016-2019 "IoT.bzh"
* Author José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
*/
#define _GNU_SOURCE
-#define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO
#include <string.h>
#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-ditf.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
int level = -1;
if (!wrap_json_unpack(v, "i", &level)) {
- level = level < 0 ? 0 : level > 3 ? 3 : 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 = 3;
+ level = _VERBOSITY_(Log_Level_Debug);
break;
case 'I':
if (!strcasecmp(s, _info_))
- level = 2;
+ level = _VERBOSITY_(Log_Level_Info);
break;
case 'N':
if (!strcasecmp(s, _notice_))
- level = 1;
+ level = _VERBOSITY_(Log_Level_Notice);
break;
case 'W':
if (!strcasecmp(s, _warning_))
- level = 1;
+ level = _VERBOSITY_(Log_Level_Warning);
break;
case 'E':
if (!strcasecmp(s, _error_))
- level = 0;
+ level = _VERBOSITY_(Log_Level_Error);
break;
}
}
* @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);
}
/**
*/
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, 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);
}
/**
/**
* Translate verbosity level to a protocol indication.
- * @param level the verbosity
+ * @param level the verbosity
* @return the encoded verbosity
*/
static struct json_object *encode_verbosity(int level)
{
- switch(level) {
- case 0: return json_object_new_string(_error_);
- case 1: return json_object_new_string(_notice_);
- case 2: return json_object_new_string(_info_);
- case 3: 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);
}
}
* @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)));
}
/**
*/
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, 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)));
}
}
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)) {
}
/******************************************************************************
-**** 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 afb_api api;
- int rc;
+ struct namelist *previous, *next;
+
+ previous = NULL;
+ while(head) {
+ next = head->next;
+ head->next = previous;
+ previous = head;
+ head = next;
+ }
+ return previous;
+}
- rc = afb_apiset_lookup(main_apiset, name, &api);
- if (!rc) {
- o = api.itf->describe ? api.itf->describe(api.closure) : NULL;
- 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, 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 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);
+ }
+}
-static void f_get(struct afb_req req)
+/******************************************************************************
+**** 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;
afb_req_success(req, NULL, NULL);
}
-#if 0
-static void f_hook(struct afb_xreq *xreq)
+#if WITH_AFB_TRACE
+static void *context_create(void *closure)
{
- struct json_object *o, *v;
+ return afb_trace_create(_afb_binding_monitor.api, NULL);
+}
- o = afb_xreq_json(xreq);
- if (json_object_object_get_ex(o, _verbosity_, &v)) {
- set_verbosity(v);
- }
+static void context_destroy(void *pointer)
+{
+ struct afb_trace *trace = pointer;
+ afb_trace_unref(trace);
+}
- if (!xreq->replied)
- afb_xreq_success(xreq, NULL, NULL);
+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, 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);
+ if (rc)
+ goto end;
+ }
+ if (drop) {
+ rc = afb_trace_drop(req, drop, trace);
+ if (rc)
+ goto end;
+ }
+ afb_req_success(req, NULL, NULL);
+end:
+ 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);
+}
+