17 var autoscroll = false;
21 var trace_events_node;
27 var show_perms = false;
28 var show_monitor_events = false;
30 _.templateSettings = { interpolate: /\{\{(.+?)\}\}/g };
32 function untrace_all() {
33 do_call("monitor/trace", {drop: true});
34 for_all_nodes(null, ".trace-item input[type=radio]", function(n){n.checked = n.value == "no";});
37 function disconnect() {
40 apis_node.innerHTML = "";
41 root_node.className = "off";
42 connected_node.innerHTML = "Connection Closed";
43 connected_node.className = "ok";
49 function connect(args) {
50 drop_all_trace_events();
54 ws = new afb.ws(onopen, onabort);
57 function on_connect(evt) {
59 host: at("param-host").value + ":" + at("param-port").value,
60 token: at("param-token").value
65 /* prepare the DOM templates */
66 t_api = at("t-api").content.firstElementChild;
67 t_verb = at("t-verb").content.firstElementChild;
68 t_logmsg = at("t-logmsg").content.firstElementChild;
69 t_traceevent = at("t-traceevent").content.firstElementChild;
70 t_verbosity = at("t-verbosity").content.firstElementChild;
71 t_trace = at("t-trace").content.firstElementChild;
72 t_separator = at("t-separator").content.firstElementChild;
74 root_node = at("root");
75 connected_node = at("connected");
76 trace_events_node = at("trace-events");
77 logmsgs_node = at("logmsgs");
78 apis_node = at("apis");
81 plug(t_api, ".verbosity", t_verbosity);
82 plug(t_api, ".trace", t_trace);
83 plug(all_node, ".trace", t_trace);
84 plug(all_node, ".verbosity", t_verbosity);
85 plug(at("common"), ".verbosity", t_verbosity);
86 for_all_nodes(root_node, ".opclo", function(n){n.onclick = on_toggle_opclo});
87 for_all_nodes(root_node, ".opclo ~ :not(.closedoff)", function(n){n.onclick = on_toggle_opclo});
88 for_all_nodes(root_node, ".verbosity select", function(n){n.onchange = set_verbosity});
89 for_all_nodes(root_node, ".trace-item input", function(n){n.onchange = on_trace_change});
90 at("disconnect").onclick = disconnect;
91 at("connect").onclick = on_connect;
92 at("droptracevts").onclick = drop_all_trace_events;
93 at("dropmsgs").onclick = drop_all_logmsgs;
94 at("stopmsgs").onclick = toggle_logmsgs;
96 trace_events_node.onclick = on_toggle_traceevent;
97 at("autoscroll").onclick = toggle_autoscroll;
98 start_autoscroll(true);
99 at("addsep").onclick = add_separator;
104 function for_all_nodes(root, sel, fun) {
105 (root ? root : document).querySelectorAll(sel).forEach(fun);
108 function get(sel,x) {
111 var r = x.querySelector(sel);
114 function at(id) { return document.getElementById(id); }
116 function plug(target, sel, node) {
117 var x = get(sel, target);
118 var n = target.ownerDocument.importNode(node, true);
119 x.parentNode.insertBefore(n, x);
120 x.parentNode.removeChild(x);
124 root_node.className = "on";
125 connected_node.innerHTML = "Connected " + ws.url;
126 connected_node.className = "ok";
127 ws.onevent("*", gotevent);
128 ws.onclose = onabort;
129 do_call("monitor/get", {apis:true,verbosity:true}, on_got_apis, on_error_apis);
132 root_node.className = "off";
133 connected_node.innerHTML = "Connection Closed";
134 connected_node.className = "error";
137 function start_autoscroll(val) {
138 at("autoscroll").textContent = (autoscroll = val) ? "Stop scroll" : "Start scroll";
141 function toggle_autoscroll() {
142 start_autoscroll(!autoscroll);
145 function add_separator() {
146 var x = document.importNode(t_separator, true);
147 trace_events_node.append(x);
152 function start_logmsgs(val) {
153 at("stopmsgs").textContent = (msgs = val) ? "Stop logs" : "Get logs";
156 function toggle_logmsgs() {
157 start_logmsgs(!msgs);
160 function drop_all_logmsgs() {
161 logmsgs_node.innerHTML = "";
164 function drop_all_trace_events() {
165 trace_events_node.innerHTML = "";
168 function add_logmsg(tag, content, add) {
170 var x = document.importNode(t_logmsg, true);
171 get(".tag", x).textContent = tag;
172 get(".content", x).textContent = content;
173 get(".close", x).onclick = function(evt){x.remove();};
175 x.className = x.className + " " + add;
176 logmsgs_node.append(x);
181 function add_error(tag, obj) {
182 add_logmsg(tag, JSON.stringify(obj, null, 1), "error");
185 function on_error_apis(obj) {
186 add_error("can't get apis", obj);
189 function do_call(api_verb, request, onsuccess, onerror) {
190 var call = api_verb + "(" + JSON.stringify(request, null, 1) + ")";
191 add_logmsg("send request", call, "call");
192 ws.call(api_verb, request).then(
194 add_logmsg("receive success", call + " -> " + JSON.stringify(obj, null, 1), "retok");
199 add_logmsg("receive error", call + " -> ", JSON.stringify(obj, null, 1), "reterr");
205 /* show all verbosities */
206 function on_got_verbosities(obj) {
208 _.each(obj.response.verbosity, function(verbosity, api_name){
209 if (api_name == "monitor") return;
210 var node = api_name ? apis[api_name].node : at("common");
212 get(".verbosity option[value='"+verbosity+"']", node).selected = true;
217 function set_verbosity(evt) {
220 var obj = evt.target;
221 var req = {verbosity:{}};
222 var name = obj.API ? obj.API.name : obj === get(".select", all_node) ? "*" : "";
224 req.verbosity[name] = obj.value;
226 req.verbosity = obj.value;
229 do_call("monitor/set", req);
230 do_call("monitor/get", {verbosity:true}, on_got_verbosities);
234 function on_got_apis(obj) {
236 _.each(obj.response.apis, function(api_desc, api_name){
237 if (api_name == "monitor") return;
238 var api = apis[api_name];
241 node: document.importNode(t_api, true),
246 api.node.dataset.api = api_name;
247 api.vnode = get(".verbs", api.node);
248 apis[api_name] = api;
249 get(".name", api.node).textContent = api_name;
250 get(".desc", api.node).textContent = api_desc.info.description || "";
251 for_all_nodes(api.node, ".opclo", function(n){n.onclick = on_toggle_opclo});
252 for_all_nodes(api.node, ".opclo ~ :not(.closedoff)", function(n){n.onclick = on_toggle_opclo});
253 for_all_nodes(api.node, ".trace-item input", function(n){n.onchange = on_trace_change});
254 apis_node.append(api.node);
255 _.each(api_desc.paths, function(verb_desc, path_name){
256 var verb_name = path_name.substring(1);
257 var verb = api.verbs[verb_name];
260 node: document.importNode(t_verb, true),
264 verb.node.VERB = verb;
265 verb.node.dataset.verb = verb_name;
266 api.verbs[verb_name] = verb;
267 get(".name", verb.node).textContent = verb_name;
268 var g = verb_desc.get ||{};
269 var r = g["responses"] || {};
270 var t = r["200"] || {};
271 var d = t.description || "";
272 get(".desc", verb.node).textContent = d;
274 var p = g["x-permissions"] || "";
275 get(".perm", verb.node).textContent = p ? JSON.stringify(p, null, 1) : "";
277 api.vnode.append(verb.node);
280 var s = get(".verbosity select", api.node);
282 s.onchange = set_verbosity;
286 on_got_verbosities(obj);
289 function on_toggle_opclo(evt) {
290 toggle_opened_closed(evt.target.parentElement);
293 function on_trace_change(evt) {
294 var obj = evt.target;
295 var tra = obj.parentElement;
296 while (tra && !tra.dataset.trace)
297 tra = tra.parentElement;
299 while (api && !api.dataset.api)
300 api = api.parentElement;
301 var tag = api.dataset.api + "/" + tra.dataset.trace;
304 for_all_nodes(tra, "input", function(n){
307 if (n != obj && n.value != "no")
312 do_call("monitor/trace", {drop: {tag: tag}});
314 if (obj.value != "no") {
315 var spec = {tag: tag, name: "trace"};
316 spec[tra.dataset.trace] = obj.value;
317 if (api.dataset.api != "*")
318 spec.api = api.dataset.api;
319 do_call("monitor/trace", {add: spec});
324 function makecontent(node, deep, val) {
326 if (_.isObject(val)) {
327 node.append(makeobj(val, deep));
330 if (_.isArray(val)) {
331 node.append(makearr(val, deep));
335 node.innerHTML = obj2html(val);
338 function makearritem(tbl, deep, val) {
339 var tr = document.createElement("tr");
340 var td = document.createElement("td");
343 makecontent(td, deep, val);
346 function makearr(arr, deep) {
347 var node = document.createElement("table");
348 node.className = "array";
349 _.each(arr, function(v) { makearritem(node, deep, v);});
353 function makeobjitem(tbl, deep, key, val) {
354 var tr = document.createElement("tr");
355 var td1 = document.createElement("td");
356 var td2 = document.createElement("td");
359 td1.textContent = key;
362 makecontent(td2, deep, val);
365 function makeobj(obj, deep, ekey, eobj) {
366 var node = document.createElement("table");
367 node.className = "object";
368 _.each(_.keys(obj).sort(), function(k) { makeobjitem(node, deep, k, obj[k]);});
370 makeobjitem(node, deep, ekey, eobj);
374 function gotevent(obj) {
375 if (obj.event != "monitor/trace")
376 add_logmsg("unexpected event!", JSON.stringify(obj, null, 1), "event");
378 add_logmsg("trace event", JSON.stringify(obj, null, 1), "trace");
383 function gottraceevent(obj) {
385 var type = _.find(["request", "service", "daemon", "event"],function(x){return x in data;});
386 var desc = data[type];
387 if (!show_monitor_events) {
388 if (type == "event" ? desc.name.startsWith("monitor/") : desc.api == "monitor")
391 var x = document.importNode(t_traceevent, true);
392 x.dataset.event = obj;
393 get(".close", x).onclick = function(evt){x.remove();};
394 x.className = x.className + " " + type;
395 get(".time", x).textContent = data.time;
396 get(".tag", x).textContent = ({
397 request: function(r) { return r.api + "/" + r.verb + " [" + r.index + "] " + r.action; },
398 service: function(r) { return r.api + "@" + r.action; },
399 daemon: function(r) { return r.api + ":" + r.action; },
400 event: function(r) { return r.name + "!" + r.action; },
402 var tab = makeobj(desc, 4);
404 makeobjitem(tab, 2, "data", data.data);
405 get(".content", x).append(tab);
406 trace_events_node.append(x);
411 function toggle_opened_closed(node, defval) {
413 var cs = node.className.split(" ").map(
417 case "closed": matched = true; return "opened";
418 case "opened": matched = true; return "closed";
424 cs = cs + " " + (defval || "closed");
428 function on_toggle_traceevent(evt) {
429 if (getSelection() != "") return;
430 var node = evt.target;
431 while(node && node.parentElement != trace_events_node)
432 node = node.parentElement;
433 node && toggle_opened_closed(node);
436 function obj2html(json) {
437 json = JSON.stringify(json, undefined, 2);
438 json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
440 /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
443 if (/^"/.test(match)) {
444 if (/:$/.test(match)) {
449 } else if (/true|false/.test(match)) {
451 } else if (/null/.test(match)) {
454 return '<span class="json ' + cls + '">' + match + '</span>';