aprsc/src/web/aprsc.js

1109 lines
26 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
var options = {};
var range_selected;
function top_status(c, s)
{
if (!c) {
$('#status').hide('fast');
return;
}
$('#status').hide().html('<div class="' + c + '">' + s + '</div>').show('fast');
}
function isUndefined(v)
{
var undef;
return v === undef;
}
function cancel_events(e)
{
if (!e)
if (window.event) e = window.event;
else
return;
if (e.cancelBubble != null) e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
if (e.preventDefault) e.preventDefault();
if (window.event) e.returnValue = false;
if (e.cancel != null) e.cancel = true;
}
function parse_options(s)
{
options = {};
var a = s.split(' ');
for (var i = 0; i < a.length; i++) {
var p = a[i].split('=');
var c = p[0].toLowerCase();
options[c] = p[1];
}
if (options['showemail'] == 1)
key_translate['email'] = 'Admin email';
}
function server_status_host(s)
{
var h = s['addr_rem'];
var p = h.lastIndexOf(':');
if (h.lastIndexOf(']') > p || p == -1)
return h + ':14501';
return h.substr(0, p) + ':14501';
}
function addr_loc_port(s)
{
return s.substr(s.lastIndexOf(':') + 1);
}
function username_link(s)
{
return '<a href="http://aprs.fi/?call=' + s + '" target="_blank">' + htmlent(s) + "</a>";
}
function conv_verified(c, k)
{
if (c['verified'] == 3)
return '<span class="link" onclick="return cert_popup(event, ' + c['fd'] + ');">Cert</span>';
if (c['verified'])
return 'Yes';
return '<span class="red">No</span>';
}
function port_conn_rates(c, k)
{
var ckey = 'l_' + c['proto'] + c['addr'] + ':' + k;
var c = calc_rate(ckey + ':c', c['connects'], 1);
if (!isUndefined(c[1]) && c[1] !== '')
return c[1];
return '';
}
function client_bytes_rates(c, k)
{
var ckey;
if (isUndefined(c['addr_rem']))
ckey = 'l_' + c['proto'] + c['addr'] + ':' + k;
else
ckey = c['addr_rem'] + ':' + k;
var tx = calc_rate(ckey + ':tx', c['bytes_tx'], 1);
var rx = calc_rate(ckey + ':rx', c['bytes_rx'], 1);
if (!isUndefined(tx[1]) && tx[1] !== '')
return tx[1] + ' / ' + rx[1];
return '';
}
function client_pkts_rx(c, k)
{
//if (isUndefined(c['pkts_ign']))
// return c['pkts_rx'];
var s = c['pkts_rx'] + '/' + c['pkts_dup'] + '/' + c['pkts_ign'];
if (c['pkts_ign'] > 0 || c['pkts_dup'] > 0)
return '<span class="'
+ ((c['pkts_ign'] / c['pkts_rx'] > 0.1) ? 'rxerr_red' : 'rxerr')
+ '" onclick="return rx_err_popup(event, ' + c['fd'] + ');">' + s + '</span>';
return s;
}
function htmlent(s)
{
if (isUndefined(s))
return '';
return $('<div/>').text(s).html();
}
function lz(i)
{
if (i < 10)
return '0' + i;
return i;
}
function timestr(i)
{
var D = new Date(i*1000);
return D.getUTCFullYear() + '-' + lz(D.getUTCMonth()+1) + '-' + lz(D.getUTCDate())
+ ' ' + lz(D.getUTCHours()) + ':' + lz(D.getUTCMinutes()) + ':' + lz(D.getUTCSeconds())
+ 'z';
}
function dur_str(i)
{
var t;
var s = '';
var c = 0;
if (i > 86400) {
t = Math.floor(i/86400);
i -= t*86400;
s += t + 'd';
c++;
}
if (i > 3600) {
t = Math.floor(i / 3600);
i -= t*3600;
s += t + 'h';
c++;
}
if (c > 1)
return s;
if (i > 60) {
t = Math.floor(i / 60);
i -= t*60;
s += t + 'm';
c++;
}
if (c)
return s;
return i.toFixed(0) + 's';
}
function conv_none(s)
{
return s;
}
var listeners_table, uplinks_table, peers_table, clients_table, memory_table,
dupecheck_table, dupecheck_more_table, totals_table;
var alarm_strings = {
'no_uplink': "Server does not have any uplink connections.",
'packet_drop_hang': "Server has dropped packets due to forward time leaps or hangs caused by resource starvation.",
'packet_drop_future': "Server has dropped packets due to backward time leaps."
};
var rx_err_strings = {
"unknown": 'Unknown error',
"no_colon": 'No colon (":") in packet',
"no_dst": 'No ">" in packet to mark beginning of destination callsign',
"no_path": 'No path found between source callsign and ":"',
"inv_srccall": 'Invalid source callsign',
"no_body": 'No packet body/data after ":"',
"inv_dstcall": 'Invalid destination callsign',
"disallow_unverified": 'Packet from unverified local client',
"disallow_unverified_path": 'Packet from unverified client (TCPXX)',
"path_nogate": 'Packet with NOGATE/RFONLY in path',
"party_3rd_ip": '3rd-party packet gated TCPIP>RF>TCPIP',
"party_3rd_inv": 'Invalid 3rd-party packet header',
"general_query": 'General query',
"aprsc_oom_pbuf": 'aprsc out of packet buffers',
"aprsc_class_fail": 'aprsc failed to classify packet',
"aprsc_q_bug": 'aprsc Q construct processing failed',
"q_drop": 'Q construct algorithm dropped packet',
"short_packet": 'Packet too short',
"long_packet": 'Packet too long',
"inv_path_call": 'Invalid callsign in path',
"q_qax": 'qAX: Packet from unverified remote client',
"q_qaz": 'qAZ construct',
"q_path_mycall": 'My ServerID in Q path',
"q_path_call_twice": 'Same callsign twice in the Q path',
"q_path_login_not_last": 'Local client login found but not last in Q path',
"q_path_call_is_local": 'Callsign in Q path is a local verified client',
"q_path_call_inv": 'Invalid callsign in Q path',
"q_qau_path_call_srccall": 'qAU callsign in path equals srccall',
"q_newq_buffer_small": 'New Q construct too big',
"q_nonval_multi_q_calls": 'Multiple callsigns in Q path from unverified client',
"q_i_no_viacall": 'I path has no viacall',
"inerr_empty": 'Empty packet',
"disallow_srcall": 'Disallowed source callsign (N0CALL or such)',
"disallow_dx": 'DX beacon packet'
};
var key_translate = {
// server block
'server_id': 'Server ID',
'admin': 'Server admin',
'software': 'Server software',
'software_build_features': 'Software features',
'os': 'Operating system',
'time_started': 'Server started',
'uptime': 'Uptime',
// dupecheck block
'dupes_dropped': 'Duplicate packets dropped',
'uniques_out': 'Unique packets seen',
// dupecheck_more (variations) block
'exact': 'Exact duplicates',
'space_trim': 'Dupes with spaces trimmed from end',
'8bit_strip': 'Dupes with 8-bit bytes stripped out',
'8bit_clear': 'Dupes with 8th bit set to 0',
'8bit_spaced': 'Dupes with 8-bit bytes replaced with spaces',
'low_strip': 'Dupes with low bytes stripped out',
'low_spaced': 'Dupes with low bytes replaced with spaces',
'del_strip': 'Dupes with DEL bytes stripped out',
'del_spaced': 'Dupes with DEL bytes replaced with spaces',
// totals block
'clients': 'Clients',
'connects': 'Connects',
'tcp_pkts_tx': 'Packets Tx TCP',
'tcp_pkts_rx': 'Packets Rx TCP',
'tcp_bytes_tx': 'Bytes Tx TCP',
'tcp_bytes_rx': 'Bytes Rx TCP',
'udp_pkts_tx': 'Packets Tx UDP',
'udp_pkts_rx': 'Packets Rx UDP',
'udp_bytes_tx': 'Bytes Tx UDP',
'udp_bytes_rx': 'Bytes Rx UDP',
'sctp_pkts_tx': 'Packets Tx SCTP',
'sctp_pkts_rx': 'Packets Rx SCTP',
'sctp_bytes_tx': 'Bytes Tx SCTP',
'sctp_bytes_rx': 'Bytes Rx SCTP'
};
var key_tooltips = {
// dupecheck block
'dupes_dropped': 'Duplicate APRS-IS packets dropped in the dupecheck thread (per-client counts not available for performance reasons)',
'uniques_out': 'Unique packets passed by the dupecheck thread',
// totals block
'clients': 'Number of clients allocated currently (including Uplinks, Peers and pseudoclients for UDP listener sockets)',
'connects': 'Number of accepted TCP connections since startup',
'tcp_pkts_tx': 'APRS-IS packets transmitted over a TCP connection',
'tcp_pkts_rx': 'APRS-IS packets received over a TCP connection',
'tcp_bytes_tx': 'APRS-IS data transmitted over a TCP connection',
'tcp_bytes_rx': 'APRS-IS data received over a TCP connection',
'udp_pkts_tx': 'APRS-IS packets transmitted over UDP',
'udp_pkts_rx': 'APRS-IS packets received over UDP',
'udp_bytes_tx': 'APRS-IS data transmitted over UDP',
'udp_bytes_rx': 'APRS-IS data received over UDP',
'sctp_pkts_tx': 'APRS-IS packets transmitted over SCTP',
'sctp_pkts_rx': 'APRS-IS packets received over SCTP',
'sctp_bytes_tx': 'APRS-IS data transmitted over SCTP',
'sctp_bytes_rx': 'APRS-IS data received over SCTP'
};
var val_convert_c = {
'bytes_rates': client_bytes_rates,
'pkts_rx': client_pkts_rx,
'connects_rates': port_conn_rates,
'verified': conv_verified
};
var val_convert = {
'time_started': timestr,
'uptime': dur_str,
't_connect': timestr,
'since_connect': dur_str,
'since_last_read': dur_str,
'addr_rem_shown': conv_none,
'username': username_link,
'addr_loc': addr_loc_port
};
var listener_cols = {
'proto': 'Proto',
'addr': 'Address',
'name': 'Name',
'clients': 'Clients',
'clients_peak': 'Peak',
'clients_max': 'Max',
'connects': 'Connects',
'connects_rates': 'Conn/s',
'pkts_tx': 'Packets Tx',
'pkts_rx': 'Packets Rx',
'bytes_tx': 'Bytes Tx',
'bytes_rx': 'Bytes Rx',
'bytes_rates': 'Tx/Rx bytes/s'
};
var uplink_cols = {
'username': 'Server ID',
'addr_rem_shown': 'Address',
'mode': 'Mode',
't_connect': 'Connected',
'since_connect': 'Up',
'since_last_read': 'Last in',
'show_app_name': 'Software',
'pkts_tx': 'Packets Tx',
'pkts_rx': 'Packets Rx',
'bytes_tx': 'Bytes Tx',
'bytes_rx': 'Bytes Rx',
'bytes_rates': 'Tx/Rx bytes/s',
'obuf_q': 'OutQ'
};
var peer_cols = {
'username': 'Server ID',
'addr_rem_shown': 'Address',
'since_last_read': 'Last in',
'pkts_tx': 'Packets Tx',
'pkts_rx': 'Packets Rx',
'bytes_tx': 'Bytes Tx',
'bytes_rx': 'Bytes Rx',
'bytes_rates': 'Tx/Rx bytes/s',
'obuf_q': 'OutQ'
};
var client_cols = {
'addr_loc': 'Port',
'username': 'Callsign',
'addr_rem_shown': 'Address',
'verified': 'Verified',
'since_connect': 'Up',
'since_last_read': 'Last in',
'show_app_name': 'Software',
'pkts_tx': 'Packets Tx',
'pkts_rx': 'Packets Rx',
'bytes_tx': 'Bytes Tx',
'bytes_rx': 'Bytes Rx',
'bytes_rates': 'Tx/Rx bytes/s',
'obuf_q': 'OutQ',
'heard_count': 'MsgRcpts',
'filter': 'Filter'
};
/* applications which typically have a port 14501 status port - can be linked */
var linkable = {
'aprsc': 1,
'aprsd': 1,
'javAPRSSrvr': 1
};
/* clients per fd, to support onclick actions within client/uplink/peer tables */
var fd_clients = {};
var rx_err_codes = []; /* an array of rx err field codes */
/* tooltip action for rx errors counters */
function event_click_coordinates(e)
{
var posx = 0;
var posy = 0;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
} else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}/* else {
alert("event_click_coordinates failed!");
}*/
return [ posx, posy ];
}
var ttip_inside_element;
function ttip(e, elem, fd)
{
var co = event_click_coordinates(e);
// make note of element we're in
ttip_inside_element = elem;
//jsjam-keep: event_attach
//$(elem).on('mouseout', ttip_hide);
setTimeout(function() { ttip_show_maybe(elem, function() { return "contents"; }, co); }, 300);
}
function rx_err_contents(fd)
{
if (isUndefined(fd_clients[fd]))
return 'No client on fd ' + fd;
var er = fd_clients[fd]['rx_errs'];
if (isUndefined(er))
return 'No rx errors for client on fd ' + fd;
var s = '<b>Receive drops: ' + fd_clients[fd]['pkts_dup'] + ' dupes, ' + fd_clients[fd]['pkts_ign'] + ' errors in ' + fd_clients[fd]['pkts_rx'] + '</b><br />';
for (var i = 0; i < rx_err_codes.length; i++) {
if (er[i] < 1)
continue;
s += ((rx_err_strings[rx_err_codes[i]]) ? rx_err_strings[rx_err_codes[i]] : rx_err_codes[i])
+ ': ' + er[i] + '<br />';
}
return s;
}
function rx_err_popup(e, fd)
{
cancel_events(e);
if (isUndefined(fd_clients[fd]))
return;
var co = event_click_coordinates(e);
ttip_show(function() { return rx_err_contents(fd); }, co);
return false;
}
function cert_contents(fd)
{
if (isUndefined(fd_clients[fd]))
return 'No client on fd ' + fd;
var subj = fd_clients[fd]['cert_subject'];
var iss = fd_clients[fd]['cert_issuer'];
if (isUndefined(subj) && isUndefined(iss))
return 'Client on fd ' + fd + ' has no certificate';
var s = '';
if (!isUndefined(subj))
s += '<b>Subject:</b><br />' + htmlent(subj) + '<br />';
if (!isUndefined(iss))
s += '<b>Issuer:</b><br />' + htmlent(iss) + '<br />';
return s;
}
function cert_popup(e, fd)
{
cancel_events(e);
if (isUndefined(fd_clients[fd]))
return;
var co = event_click_coordinates(e);
ttip_show(function() { return cert_contents(fd); }, co);
return false;
}
function ttip_show_maybe(elem, cb, co)
{
if (ttip_inside_element == elem)
ttip_show(cb, co);
}
function ttip_show(cb, co)
{
var element = $('#ttip');
element.hide();
var ttip_size = 300;
if (co[0] > ttip_size + 40)
co[0] -= ttip_size + 40; // position on left of event
else
co[0] += 40; // position on right of event
element.html("<span>" + cb() + "</span>");
element.css({ 'left': co[0] + 'px', 'top': co[1] + 'px'}).show('fast');
}
function ttip_hide()
{
$('#ttip').hide('fast');
ttip_inside_element = null;
}
/* render a clients array (also peers, uplinks, and listeners) */
function render_clients(element, d, cols)
{
var s = '<table><tr>';
for (var k in cols) {
s += '<th>' + htmlent(cols[k]) + '</th>';
}
s += '</tr>';
for (var ci in d) {
s += '<tr>';
var c = d[ci];
if (isUndefined(c['fd']) || c['fd'] < 0)
c['fd'] = Math.random() * -1000000;
fd_clients[c['fd']] = c;
c['addr_rem_shown'] = c['addr_rem'];
if (c['udp_downstream']) {
if (c['mode'] == 'peer')
c['addr_rem_shown'] += ' UDP';
else
c['addr_rem_shown'] += ' +UDP';
}
if (linkable[c['app_name']] || c['mode'] == 'peer')
c['addr_rem_shown'] = '<a href="http://' + server_status_host(c) + '/">' + htmlent(c['addr_rem_shown']) + '</a>';
if (c['app_name'] && c['app_version'])
c['show_app_name'] = c['app_name'] + ' ' + c['app_version'];
else
c['show_app_name'] = c['app_name'];
for (var k in cols) {
s += '<td>';
if (val_convert_c[k])
s += val_convert_c[k](c, k);
else if (val_convert[k])
s += val_convert[k](c[k]);
else
s += htmlent(c[k]);
s += '</td>';
}
s += '</tr>';
}
s += '</table>';
element.html(s);
return;
}
var graph_selected = '';
function render_block(graph_tree, element, d)
{
var s = '<table>';
for (var k in d) {
if (!key_translate[k])
continue;
var o;
if (typeof(d[k]) == 'object') {
for (var i in d[k])
d[k][i] = htmlent(d[k][i]);
o = '<td class="ar">' + d[k].join('</td><td class="ar">') + '</td>';
} else {
if (val_convert[k])
o = val_convert[k](d[k]);
else
o = htmlent(d[k]);
o = '<td class="ar">' + o + '</td>';
}
if (graph_tree) {
var id = graph_tree + '.' + k;
var cl = (graph_selected == id) ? 'grtd grtd_sel' : 'grtd';
s += '<tr><td class="' + cl + '" id="' + id.replace('.', '_') + '" onclick="gr_switch(\'' + id + '\')">' + htmlent(key_translate[k]) + '</td>' + o + '</tr>';
} else {
s += '<tr><td>' + htmlent(key_translate[k]) + '</td>' + o + '</tr>';
}
}
s += '</table>';
element.html(s);
return;
}
var mem_rows = {
'pbuf_small': 'Small pbufs',
'pbuf_medium': 'Medium pbufs',
'pbuf_large': 'Large pbufs',
'historydb': 'Position history',
'dupecheck': 'Dupecheck DB',
'client': 'Clients',
'client_heard': 'Client MsgRcpts',
'client_courtesy': 'Client CourtesySrcs',
'filter': 'Filter entries',
'filter_wx': 'Filter WX stations',
'filter_entrycall': 'Filter entrycalls'
};
var mem_cols = {
'': 'Type',
'_cell_size_aligned': 'Cell size',
'_cells_used': 'Cells used',
'_cells_free': 'Cells free',
'_used_bytes': 'Bytes used',
'_allocated_bytes': 'Bytes allocated',
'_blocks': 'Blocks allocated'
};
function render_memory(element, d)
{
var s = '<tr>';
for (var k in mem_cols) {
s += '<th>' + htmlent(mem_cols[k]) + '</th>';
}
s += '</tr>';
for (var t in mem_rows) {
if (isUndefined(d[t + '_cells_used']))
continue;
s += '<tr>';
for (var k in mem_cols) {
if (k == '')
s += '<td>' + htmlent(mem_rows[t]) + '</td>';
else {
var rk = t + k;
if (k == '_blocks' && !isUndefined(d[rk]))
d[rk] += '/' + d[t + '_blocks_max'];
s += '<td>' + htmlent(d[rk]) + '</th>';
}
}
s += '</tr>';
}
$(element).html(s);
}
var tick_now;
var rate_cache = {};
function calc_rate(key, value, no_s)
{
var rate = '';
if (rate_cache[key]) {
// can calculate current rate
var t_dif = tick_now - rate_cache[key][0];
var val_dif = value - rate_cache[key][1];
rate = val_dif / t_dif;
var prefix = '';
if (rate < 0) {
rate *= -1;
prefix = '-';
}
if (rate >= 10)
rate = rate.toFixed(0);
else if (rate >= 1)
rate = rate.toFixed(1);
else if (rate > 0)
rate = rate.toFixed(2);
else if (rate == 0)
rate = '0';
else
rate = rate.toFixed(2);
if (!no_s)
rate += '/s';
rate = prefix + rate;
}
rate_cache[key] = [tick_now, value];
return [ value, rate ];
}
var totals_keys = [
'clients', 'connects',
'tcp_bytes_tx', 'tcp_bytes_rx', 'tcp_pkts_tx', 'tcp_pkts_rx',
'udp_bytes_tx', 'udp_bytes_rx', 'udp_pkts_tx', 'udp_pkts_rx',
'sctp_bytes_tx', 'sctp_bytes_rx', 'sctp_pkts_tx', 'sctp_pkts_rx'
];
var alarms_visible = 0;
function render_alarms(alarms)
{
var s = '';
for (var i = 0; i < alarms.length; i++) {
a = alarms[i];
//console.log("alarm " + i + ": " + a['err']);
if (a['set'] != 1)
continue;
s += '<div class="msg_e">'
+ ((alarm_strings[a['err']]) ? alarm_strings[a['err']] : a['err'])
+ ' See server log for details.</div>';
}
if (s == "") {
if (alarms_visible) {
alarms_visible = 0;
alarm_div.hide('slow', function() { alarm_div.empty(); });
return;
}
return;
}
alarm_div.html(s);
if (!alarms_visible) {
alarm_div.show('fast');
alarms_visible = 1;
}
}
var options_s;
function render(d)
{
if (d['status_options'] != options_s) {
options_s = d['status_options'];
parse_options(options_s);
}
if (d['server'] && d['server']['tick_now']) {
var s = d['server'];
if (s['server_id']) {
document.title = htmlent(s['server_id']) + ' aprsc status';
$('#serverid').html(htmlent(s['server_id']));
}
if (s['time_now'])
$('#upt').html(' at ' + timestr(s['time_now']));
if ((!isUndefined(s['software'])) && !isUndefined(s['software_version']))
s['software'] = s['software'] + ' ' + s['software_version'];
render_block(0, server_table, s);
} else {
return;
}
tick_now = d['server']['tick_now'];
rx_err_codes = d['rx_errs'];
if (d['alarms']) {
render_alarms(d['alarms']);
} else {
if (alarms_visible) {
alarms_visible = 0;
alarm_div.hide('slow', function() { alarm_div.empty(); });
}
}
if (d['dupecheck']) {
var u = d['dupecheck'];
u['dupes_dropped'] = calc_rate('dupecheck.dupes_dropped', u['dupes_dropped']);
u['uniques_out'] = calc_rate('dupecheck.uniques_out', u['uniques_out']);
render_block('dupecheck', dupecheck_table, u);
if (u['variations'])
render_block(0, dupecheck_more_table, u['variations']);
}
if (d['totals']) {
var u = d['totals'];
for (var i in totals_keys) {
if (u[totals_keys[i]] !== undefined)
u[totals_keys[i]] = calc_rate('totals.' + totals_keys[i], u[totals_keys[i]]);
}
render_block('totals', totals_table, u);
}
fd_clients = {};
if (d['listeners'])
render_clients(listeners_table, d['listeners'], listener_cols);
if (d['uplinks'] && d['uplinks'].length > 0) {
render_clients(uplinks_table, d['uplinks'], uplink_cols);
$('#uplinks_d').show();
} else {
$('#uplinks_d').hide();
}
if (d['peers'] && d['peers'].length > 0) {
render_clients(peers_table, d['peers'], peer_cols);
$('#peers_d').show();
} else {
$('#peers_d').hide();
}
if (d['clients'])
render_clients(clients_table, d['clients'], client_cols);
if (d['memory'])
render_memory(memory_table, d['memory']);
}
var next_req_timer;
function schedule_update()
{
if (next_req_timer)
clearTimeout(next_req_timer);
next_req_timer = setTimeout(update_status, 10000);
}
var current_status;
function update_success(data)
{
if (next_req_timer) {
clearTimeout(next_req_timer);
next_req_timer = 0;
}
top_status();
/* If this is the first successful status download, motd needs to be
* updated too.
*/
if (!current_status) {
current_status = data;
motd_check();
} else {
current_status = data;
}
render(data);
schedule_update();
}
function update_status()
{
if (next_req_timer) {
clearTimeout(next_req_timer);
next_req_timer = 0;
}
$.ajax({
url: '/status.json',
dataType: 'json',
cache: false,
timeout: 5000,
error: function(jqXHR, stat, errorThrown) {
var msg = '';
if (stat == 'timeout')
msg = 'Status download timed out. Network or server down?';
else if (stat == 'error')
msg = 'Status download failed with an error. Network or server down?';
else
msg = 'Status download failed (' + stat + ').';
if (errorThrown)
msg += '<br />HTTP error: ' + htmlent(errorThrown);
top_status('msg_e', msg);
schedule_update();
},
success: update_success
});
}
var graph_opt;
var graph_data;
function graph_fill(cdata, opts)
{
var vals = cdata['values'];
var vl = vals.length;
if (opts['div']) {
var div = opts['div'];
for (var i = 0; i < vl; i++)
vals[i][1] = vals[i][1] / div;
}
for (var i = 0; i < vl; i++)
vals[i][0] = vals[i][0] * 1000;
graph_data = [ { label: opts['label'], data: vals } ];
var _x_opt = {
mode: 'time'
};
var _y_opt = {
min: 0
};
graph_opt = {
grid: { hoverable: true, autoHighlight: false, minBorderMargin: 20 },
legend: { position: 'nw' },
colors: [ '#0000ff' ],
xaxis: _x_opt,
yaxis: _y_opt,
selection: { mode: "x" }
};
$.plot($('#graph'), graph_data, graph_opt);
}
var zoomed_in = false;
function graphZoom(zoom_in)
{
if (range_selected && zoom_in) {
zoomed_in = true;
graph_opt.xaxis.min = range_selected.from;
graph_opt.xaxis.max = range_selected.to;
} else {
zoomed_in = false;
graph_opt.xaxis.min = null;
graph_opt.xaxis.max = null;
}
update_buttons();
var p = $.plot($('#graph'), graph_data, graph_opt);
if (range_selected)
p.setSelection({ xaxis: { from: range_selected.from, to: range_selected.to }});
}
function update_buttons()
{
if (zoomed_in)
$('#g_zoom_out').show();
else
$('#g_zoom_out').hide();
}
var graphs = {
'totals.clients': { 'label': 'Clients allocated' },
'totals.connects': { 'label': 'Incoming connections/min' },
'totals.tcp_bytes_rx': { 'label': 'Bytes/s Rx, TCP', 'div' : 60 },
'totals.tcp_bytes_tx': { 'label': 'Bytes/s Tx, TCP', 'div' : 60 },
'totals.udp_bytes_rx': { 'label': 'Bytes/s Rx, UDP', 'div' : 60 },
'totals.udp_bytes_tx': { 'label': 'Bytes/s Tx, UDP', 'div' : 60 },
'totals.sctp_bytes_rx': { 'label': 'Bytes/s Rx, SCTP', 'div' : 60 },
'totals.sctp_bytes_tx': { 'label': 'Bytes/s Tx, SCTP', 'div' : 60 },
'totals.tcp_pkts_rx': { 'label': 'APRS-IS packets/s Rx, TCP', 'div' : 60 },
'totals.tcp_pkts_tx': { 'label': 'APRS-IS packets/s Tx, TCP', 'div' : 60 },
'totals.udp_pkts_rx': { 'label': 'APRS-IS packets/s Rx, UDP', 'div' : 60 },
'totals.udp_pkts_tx': { 'label': 'APRS-IS packets/s Tx, UDP', 'div' : 60 },
'totals.sctp_pkts_rx': { 'label': 'APRS-IS packets/s Rx, SCTP', 'div' : 60 },
'totals.sctp_pkts_tx': { 'label': 'APRS-IS packets/s Tx, SCTP', 'div' : 60 },
'dupecheck.dupes_dropped': { 'label': 'Duplicate packets dropped/s', 'div' : 60 },
'dupecheck.uniques_out': { 'label': 'Unique packets/s', 'div' : 60 }
};
var graph_timer;
function schedule_graph(t)
{
if (graph_timer)
clearTimeout(graph_timer);
graph_timer = setTimeout(load_graph, t);
}
function load_graph_success(data)
{
top_status();
var d = graphs[this.k];
graph_fill(data, d);
schedule_graph(60000);
$('#graph').trigger('plotunselected');
zoomed_in = false;
update_buttons();
}
function load_graph_error(jqXHR, stat, errorThrown)
{
var msg = 'Graph data download failed (' + stat + '). Server or network down?';
if (errorThrown)
msg += '<br />HTTP error: ' + htmlent(errorThrown);
top_status('msg_e', msg);
schedule_graph(60000);
}
function load_graph()
{
var k = graph_selected;
if (graph_timer) {
clearTimeout(graph_timer);
graph_timer = 0;
}
$('.grtd').removeClass('grtd_sel');
$('#' + k.replace('.', '_')).addClass('grtd_sel');
$.ajax({
url: '/counterdata?' + k,
dataType: 'json',
timeout: 5000,
context: { 'k': k },
success: load_graph_success,
error: load_graph_error
});
}
function gr_switch(id)
{
graph_selected = id;
range_selected = false;
zoomed_in = false;
$('#graph').trigger('plotunselected');
update_buttons();
load_graph();
}
var motd_last;
function motd_hide()
{
$('#motd').hide('slow');
motd_last = '';
}
function motd_success(data)
{
if (data) {
/* don't refill and re-animate if it doesn't change. */
if (data == motd_last)
return;
motd_last = data;
$('#motd').html(data);
$('#motd').show('fast');
} else {
motd_hide();
}
}
function motd_check()
{
if (current_status && current_status['motd']) {
$.ajax({
url: current_status['motd'],
dataType: 'html',
timeout: 30000,
success: motd_success,
error: motd_hide
});
} else {
motd_hide();
}
setTimeout(motd_check, 61000);
}
function toggle(id)
{
$('#' + id + '_show').toggle(100);
$('#' + id + '_hide').toggle(100);
$('#' + id).toggle(200);
}
function init()
{
listeners_table = $('#listeners');
uplinks_table = $('#uplinks');
peers_table = $('#peers');
clients_table = $('#clients');
memory_table = $('#memory');
dupecheck_table = $('#dupecheck');
dupecheck_more_table = $('#dupecheck_more');
totals_table = $('#totals');
server_table = $('#server');
alarm_div = $('#alarms');
update_status();
gr_switch('totals.tcp_bytes_rx');
$('#graph').bind('plotselected', function(event,ranges) {
var to = parseInt(ranges.xaxis.to.toFixed(0));
var from = parseInt(ranges.xaxis.from.toFixed(0));
range_selected = {
'from': from,
'to': to
};
$('#g_zoom_in').removeAttr('disabled');
schedule_graph(60000); /* delay next update */
});
$('#graph').bind('plotunselected', function(event,ranges) {
range_selected = undefined;
$('#g_zoom_in').attr("disabled", "disabled");
});
}
//-->