+/*
+ * Copyright (C) 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
var afb;
var ws;
var apis_node;
var all_node;
+var styles;
+
/* flags */
var show_perms = false;
var show_monitor_events = false;
function untrace_all() {
do_call("monitor/trace", {drop: true});
- for_all_nodes(null, ".trace-item input[type=radio]", function(n){n.checked = n.value == "no";});
}
-function disconnect() {
- untrace_all();
- apis = {};
- apis_node.innerHTML = "";
- root_node.className = "off";
+function disconnect(status) {
+ class_toggle(root_node, { on: "off" }, "off");
connected_node.innerHTML = "Connection Closed";
- connected_node.className = "ok";
- ws && ws.close();
- afb = null;
+ connected_node.className = status;
+ if (ws) {
+ untrace_all();
+ ws.onclose = ws.onabort = null;
+ ws.close();
+ }
ws = null;
+ if (afb)
+ at("param-token").value = afb.context.token;
+ afb = null;
}
-function connect(args) {
- drop_all_trace_events();
- drop_all_logmsgs();
- ws && ws.close();
- afb = new AFB(args);
- ws = new afb.ws(onopen, onabort);
+function on_disconnect() {
+ disconnect("ok");
}
-function on_connect(evt) {
- connect({
+function connect() {
+ ws && ws.close();
+ afb = new AFB({
host: at("param-host").value + ":" + at("param-port").value,
token: at("param-token").value
});
+ ws = new afb.ws(onopen, onabort);
+}
+
+function on_connect(evt) {
+ connect();
+}
+
+function next_style(evt) {
+ styles.next();
}
function init() {
+ styles = makecss();
+ at("style").onclick = next_style;
+
/* prepare the DOM templates */
t_api = at("t-api").content.firstElementChild;
t_verb = at("t-verb").content.firstElementChild;
for_all_nodes(root_node, ".opclo ~ :not(.closedoff)", function(n){n.onclick = on_toggle_opclo});
for_all_nodes(root_node, ".verbosity select", function(n){n.onchange = set_verbosity});
for_all_nodes(root_node, ".trace-item input", function(n){n.onchange = on_trace_change});
- at("disconnect").onclick = disconnect;
+ at("disconnect").onclick = on_disconnect;
at("connect").onclick = on_connect;
at("droptracevts").onclick = drop_all_trace_events;
at("dropmsgs").onclick = drop_all_logmsgs;
at("autoscroll").onclick = toggle_autoscroll;
start_autoscroll(true);
at("addsep").onclick = add_separator;
+ at("experts").onclick = toggle_experts;
+
+ at("param-host").value = document.location.hostname;
+ at("param-port").value = document.location.port;
+ var args = new URLSearchParams(document.location.search.substring(1));
+ at("param-token").value = args.get("x-afb-token") || args.get("token") || "HELLO";
+
+ document.onbeforeunload = on_disconnect;
connect();
}
}
function onopen() {
- root_node.className = "on";
+ class_toggle(root_node, { off: "on" }, "on");
connected_node.innerHTML = "Connected " + ws.url;
connected_node.className = "ok";
ws.onevent("*", gotevent);
ws.onclose = onabort;
+ untrace_all();
+ for_all_nodes(all_node, ".trace-box", update_trace_box);
do_call("monitor/get", {apis:true,verbosity:true}, on_got_apis, on_error_apis);
}
+
function onabort() {
- root_node.className = "off";
- connected_node.innerHTML = "Connection Closed";
- connected_node.className = "error";
+ disconnect("error");
}
function start_autoscroll(val) {
trace_events_node.append(x);
if (autoscroll)
x.scrollIntoView();
+ if (msgs) {
+ x = document.importNode(t_separator, true);
+ logmsgs_node.append(x);
+ if (autoscroll)
+ x.scrollIntoView();
+ }
}
function start_logmsgs(val) {
/* show all apis */
function on_got_apis(obj) {
inhibit = true;
+ var saved_apis = apis;
+ apis = {};
+ apis_node.innerHTML = "";
_.each(obj.response.apis, function(api_desc, api_name){
if (api_name == "monitor") return;
- var api = apis[api_name];
+ var api = saved_apis[api_name];
if (!api) {
+ /* create the node */
api = {
node: document.importNode(t_api, true),
verbs: {},
api.node.API = api;
api.node.dataset.api = api_name;
api.vnode = get(".verbs", api.node);
- apis[api_name] = api;
get(".name", api.node).textContent = api_name;
- get(".desc", api.node).textContent = api_desc.info.description || "";
+ var s = get(".verbosity select", api.node);
+ s.API = api;
+ s.onchange = set_verbosity;
for_all_nodes(api.node, ".opclo", function(n){n.onclick = on_toggle_opclo});
for_all_nodes(api.node, ".opclo ~ :not(.closedoff)", function(n){n.onclick = on_toggle_opclo});
for_all_nodes(api.node, ".trace-item input", function(n){n.onchange = on_trace_change});
- apis_node.append(api.node);
+ } else {
+ /* reactivate the expected traces */
+ for_all_nodes(api.node, ".trace-box", update_trace_box);
+ }
+ apis[api_name] = api;
+ if (api_desc == null) {
+ get(".desc", api.node).textContent = "?? unrecoverable ??";
+ } else {
+ get(".desc", api.node).textContent = api_desc.info.description || "";
_.each(api_desc.paths, function(verb_desc, path_name){
var verb_name = path_name.substring(1);
var verb = api.verbs[verb_name];
api.vnode.append(verb.node);
}
});
- var s = get(".verbosity select", api.node);
- s.API = api;
- s.onchange = set_verbosity;
}
+ apis_node.append(api.node);
});
inhibit = false;
on_got_verbosities(obj);
toggle_opened_closed(evt.target.parentElement);
}
-function on_trace_change(evt) {
- var obj = evt.target;
- var tra = obj.parentElement;
- while (tra && !tra.dataset.trace)
- tra = tra.parentElement;
- var api = tra;
+function toggle_experts(evt) {
+ toggle_opened_closed(evt.target);
+}
+
+function update_trace_box(node) {
+ set_trace_box(node, false);
+}
+
+function set_trace_box(node, clear) {
+ var api = node;
while (api && !api.dataset.api)
api = api.parentElement;
- var tag = api.dataset.api + "/" + tra.dataset.trace;
- if (tra) {
- var drop = false;
- for_all_nodes(tra, "input", function(n){
- if (n.checked) {
- n.checked = false;
- if (n != obj && n.value != "no")
- drop = true;
- }
- });
- if (drop)
- do_call("monitor/trace", {drop: {tag: tag}});
- obj.checked = true;
- if (obj.value != "no") {
- var spec = {tag: tag, name: "trace"};
- spec[tra.dataset.trace] = obj.value;
- if (api.dataset.api != "*")
- spec.api = api.dataset.api;
- do_call("monitor/trace", {add: spec});
- }
+ var tag = api.dataset.api + "/" + node.dataset.trace;
+ var value = false;
+ for_all_nodes(node, "input", function(n){ if (n.checked) value = n.value; });
+ if (clear)
+ do_call("monitor/trace", {drop: {tag: tag}});
+ if (value != "no") {
+ var spec = {tag: tag, name: "trace"};
+ spec[node.dataset.trace] = value;
+ if (api.dataset.api != "*")
+ spec.api = api.dataset.api;
+ do_call("monitor/trace", {add: spec});
}
}
+function on_trace_change(evt) {
+ var obj = evt.target;
+ var box = obj.parentElement;
+ while (box && !box.dataset.trace)
+ box = box.parentElement;
+ for_all_nodes(box, "input", function(n){n.checked = false;});
+ obj.checked = true;
+ set_trace_box(box, true);
+}
+
function makecontent(node, deep, val) {
if (--deep > 0) {
if (_.isObject(val)) {
return;
}
}
- node.innerHTML = obj2html(val);
+ node.innerHTML = '<pre>' + obj2html(val) + '</pre>';
}
function makearritem(tbl, deep, val) {
function gottraceevent(obj) {
var data = obj.data;
- var type = _.find(["request", "service", "daemon", "event"],function(x){return x in data;});
+ var type = data.type;
var desc = data[type];
if (!show_monitor_events) {
if (type == "event" ? desc.name.startsWith("monitor/") : desc.api == "monitor")
x.className = x.className + " " + type;
get(".time", x).textContent = data.time;
get(".tag", x).textContent = ({
- request: function(r) { return r.api + "/" + r.verb + " [" + r.index + "] " + r.action; },
+ request: function(r,d) { return r.api + "/" + r.verb + " [" + r.index + "] " + r.action + (r.action == 'reply' ? ' '+d.data.error : ''); },
service: function(r) { return r.api + "@" + r.action; },
daemon: function(r) { return r.api + ":" + r.action; },
event: function(r) { return r.name + "!" + r.action; },
- })[type](desc);
+ global: function(r) { return "$" + r.action; },
+ })[type](desc,data);
var tab = makeobj(desc, 4);
if ("data" in data)
makeobjitem(tab, 2, "data", data.data);
x.scrollIntoView();
}
-function toggle_opened_closed(node, defval) {
+function class_toggle(node, assoc, defval) {
var matched = false;
var cs = node.className.split(" ").map(
function(x){
- if (!matched) {
- switch(x) {
- case "closed": matched = true; return "opened";
- case "opened": matched = true; return "closed";
- }
+ if (!matched && (x in assoc)) {
+ matched = true;
+ return assoc[x];
}
- return x;
+ return x == defval ? "" : x;
}).join(" ");
- if (!matched)
- cs = cs + " " + (defval || "closed");
+ if (!matched && defval)
+ cs = cs + " " + defval;
node.className = cs;
}
+function toggle_opened_closed(node, defval) {
+ class_toggle(node, { closed: "opened", opened: "closed" }, defval);
+}
+
function on_toggle_traceevent(evt) {
if (getSelection() != "") return;
var node = evt.target;
cls = 'key';
} else {
cls = 'string';
+ match = match.replace(/\\n/g, "\\n<br>");
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
});
}
+function makecss()
+{
+ var i, l, a, links, x;
+
+ x = { idx: 0, byidx: [], byname: {}, names: [] };
+ links = document.getElementsByTagName("link");
+ for (i = 0 ; i < links.length ; i++) {
+ l = links[i];
+ if (l.title && l.rel.indexOf( "stylesheet" ) != -1) {
+ if (!(l.title in x.byname)) {
+ x.byname[l.title] = x.byidx.length;
+ x.names.push(l.title);
+ x.byidx.push([]);
+ }
+ x.byidx[x.byname[l.title]].push(l);
+ }
+ }
+
+ x.set = function(id) {
+ if (id in x.byname)
+ id = x.byname[id];
+ if (id in x.byidx) {
+ var i, j, a, b;
+ x.idx = id;
+ a = x.byidx;
+ for (i = 0 ; i < a.length ; i++) {
+ b = a[i];
+ for (j = 0 ; j < b.length ; j++)
+ b[j].disabled = i != id;
+ }
+ }
+ };
+
+ x.next = function() {
+ x.set((x.idx + 1) % x.byidx.length);
+ };
+
+ x.set(0);
+ return x;
+}
+