|
|
@@ -0,0 +1,330 @@ |
|
|
|
/* |
|
|
|
The MIT License (MIT) |
|
|
|
|
|
|
|
Copyright (C) 2017 Vsevolod Stakhov <vsevolod@highsecure.ru> |
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
|
|
of this software and associated documentation files (the "Software"), to deal |
|
|
|
in the Software without restriction, including without limitation the rights |
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
|
|
copies of the Software, and to permit persons to whom the Software is |
|
|
|
furnished to do so, subject to the following conditions: |
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in |
|
|
|
all copies or substantial portions of the Software. |
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
|
|
THE SOFTWARE. |
|
|
|
*/ |
|
|
|
|
|
|
|
define(['jquery', 'd3pie', 'humanize'], |
|
|
|
function($, d3pie, Humanize) { |
|
|
|
// @ ms to date |
|
|
|
function msToTime(seconds) { |
|
|
|
years = seconds / 31536000 >> 0; // 3600*24*365 |
|
|
|
months = seconds % 31536000 / 2628000 >> 0; //3600*24*365/12 |
|
|
|
days = seconds % 31536000 % 2628000 / 86400 >> 0; //24*3600 |
|
|
|
hours = seconds % 31536000 % 2628000 % 86400 / 3600 >> 0; |
|
|
|
minutes = seconds % 31536000 % 2628000 % 86400 % 3600 / 60 >> 0; |
|
|
|
if (years > 0) { |
|
|
|
if (months > 0) { |
|
|
|
out = years + 'yr ' + months + 'mth'; |
|
|
|
} else { |
|
|
|
out = years + 'yr ' + days + 'd'; |
|
|
|
} |
|
|
|
} else if (months > 0) { |
|
|
|
out = months + 'mth ' + days + 'd'; |
|
|
|
} else if (days > 0) { |
|
|
|
out = days + 'd ' + hours + 'hr'; |
|
|
|
} else if (hours > 0) { |
|
|
|
out = hours + 'hr ' + minutes + 'min'; |
|
|
|
} else { |
|
|
|
out = minutes + 'min'; |
|
|
|
} |
|
|
|
return out; |
|
|
|
} |
|
|
|
|
|
|
|
function displayStatWidgets(checked_server) { |
|
|
|
var widgets = $('#statWidgets'); |
|
|
|
$(widgets).empty().hide(); |
|
|
|
|
|
|
|
var servers = JSON.parse(sessionStorage.getItem('Credentials')); |
|
|
|
var data = {}; |
|
|
|
|
|
|
|
if (servers && servers[checked_server]) { |
|
|
|
data = servers[checked_server].data; |
|
|
|
} |
|
|
|
var stat_w = []; |
|
|
|
|
|
|
|
$.each(data, function (i, item) { |
|
|
|
var widget = ''; |
|
|
|
if (i == 'auth') {} |
|
|
|
else if (i == 'error') {} |
|
|
|
else if (i == 'version') { |
|
|
|
widget = '<div class="left"><strong>' + item + '</strong>' + |
|
|
|
i + '</div>'; |
|
|
|
$(widget).appendTo(widgets); |
|
|
|
} else if (i == 'uptime') { |
|
|
|
widget = '<div class="right"><strong>' + msToTime(item) + |
|
|
|
'</strong>' + i + '</div>'; |
|
|
|
$(widget).appendTo(widgets); |
|
|
|
} else { |
|
|
|
widget = '<li class="stat-box"><div class="widget"><strong>' + |
|
|
|
Humanize.compactInteger(item) + '</strong>' + i + '</div></li>'; |
|
|
|
if (i == 'scanned') { |
|
|
|
stat_w[0] = widget; |
|
|
|
} else if (i == 'clean') { |
|
|
|
stat_w[1] = widget; |
|
|
|
} else if (i == 'greylist') { |
|
|
|
stat_w[2] = widget; |
|
|
|
} else if (i == 'probable') { |
|
|
|
stat_w[3] = widget; |
|
|
|
} else if (i == 'reject') { |
|
|
|
stat_w[4] = widget; |
|
|
|
} else if (i == 'learned') { |
|
|
|
stat_w[5] = widget; |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
$.each(stat_w, function (i, item) { |
|
|
|
$(item).appendTo(widgets); |
|
|
|
}); |
|
|
|
$('#statWidgets .left,#statWidgets .right').wrapAll('<li class="stat-box pull-right"><div class="widget"></div></li>'); |
|
|
|
$('#statWidgets').find('li.pull-right').appendTo('#statWidgets'); |
|
|
|
|
|
|
|
$("#clusterTable tbody").empty(); |
|
|
|
$.each(servers, function (key, val) { |
|
|
|
var glyph_status; |
|
|
|
if (val.status) { |
|
|
|
glyph_status = "glyphicon glyphicon-ok-circle"; |
|
|
|
} |
|
|
|
else { |
|
|
|
glyph_status = "glyphicon glyphicon-remove-circle"; |
|
|
|
} |
|
|
|
if (!('config_id' in val.data)) { |
|
|
|
val.data.config_id = ""; |
|
|
|
} |
|
|
|
if (checked_server == key) { |
|
|
|
$('#clusterTable tbody').append('<tr>' + |
|
|
|
'<td class="col1" title="Radio"><input type="radio" class="form-control radio" name="clusterName" value="' + key + '" checked></td>' + |
|
|
|
'<td class="col2" title="SNAme">' + key + '</td>' + |
|
|
|
'<td class="col3" title="SHost">' + val.host + '</td>' + |
|
|
|
'<td class="col4" title="SStatus"><span class="icon"><i class="' + glyph_status + '"></i></span></td>' + |
|
|
|
'<td class="col5" title="SId">' + val.data.config_id.substring(0, 8) + '</td></tr>'); |
|
|
|
} else { |
|
|
|
if (val.status) { |
|
|
|
$('#clusterTable tbody').append('<tr>' + |
|
|
|
'<td class="col1" title="Radio"><input type="radio" class="form-control radio" name="clusterName" value="' + key + '"></td>' + |
|
|
|
'<td class="col2" title="SNAme">' + key + '</td>' + |
|
|
|
'<td class="col3" title="SHost">' + val.host + '</td>' + |
|
|
|
'<td class="col4" title="SStatus"><span class="icon"><i class="' + glyph_status + '"></i></span></td>' + |
|
|
|
'<td class="col5" title="SId">' + val.data.config_id.substring(0, 8) + '</td></tr>'); |
|
|
|
} |
|
|
|
else { |
|
|
|
$('#clusterTable tbody').append('<tr>' + |
|
|
|
'<td class="col1" title="Radio"><input type="radio" class="form-control radio disabled" disabled="disabled" name="clusterName" value="' + key + '"></td>' + |
|
|
|
'<td class="col2" title="SNAme">' + key + '</td>' + |
|
|
|
'<td class="col3" title="SHost">' + val.host + '</td>' + |
|
|
|
'<td class="col4" title="SStatus"><span class="icon"><i class="' + glyph_status + '"></i></span></td>' + |
|
|
|
'<td class="col5" title="SId">???</td></tr>'); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
}); |
|
|
|
$(widgets).show(); |
|
|
|
} |
|
|
|
|
|
|
|
function getChart(pie, checked_server) { |
|
|
|
var creds = JSON.parse(sessionStorage.getItem('Credentials')); |
|
|
|
if (creds && creds[checked_server]) { |
|
|
|
var data = creds[checked_server].data; |
|
|
|
var new_data = [ { |
|
|
|
"color" : "#66CC00", |
|
|
|
"label" : "Clean", |
|
|
|
"data" : data.clean, |
|
|
|
"value" : data.clean |
|
|
|
}, { |
|
|
|
"color" : "#BF8040", |
|
|
|
"label" : "Temporary rejected", |
|
|
|
"data" : data.soft_reject, |
|
|
|
"value" : data.soft_reject |
|
|
|
}, { |
|
|
|
"color" : "#FFAD00", |
|
|
|
"label" : "Probable spam", |
|
|
|
"data" : data.probable, |
|
|
|
"value" : data.probable |
|
|
|
}, { |
|
|
|
"color" : "#436EEE", |
|
|
|
"label" : "Greylisted", |
|
|
|
"data" : data.greylist, |
|
|
|
"value" : data.greylist |
|
|
|
}, { |
|
|
|
"color" : "#FF0000", |
|
|
|
"label" : "Rejected", |
|
|
|
"data" : data.reject, |
|
|
|
"value" : data.reject |
|
|
|
} ]; |
|
|
|
return drawPie(pie, "chart", new_data); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function drawPie(obj, id, data, conf) { |
|
|
|
if (obj) { |
|
|
|
obj.updateProp("data.content", |
|
|
|
data.filter(function (elt) { |
|
|
|
return elt.value > 0; |
|
|
|
}) |
|
|
|
); |
|
|
|
} else { |
|
|
|
obj = new d3pie(id, |
|
|
|
$.extend({}, { |
|
|
|
"header": { |
|
|
|
"title": { |
|
|
|
"text": "Rspamd filter stats", |
|
|
|
"fontSize": 24, |
|
|
|
"font": "open sans" |
|
|
|
}, |
|
|
|
"subtitle": { |
|
|
|
"color": "#999999", |
|
|
|
"fontSize": 12, |
|
|
|
"font": "open sans" |
|
|
|
}, |
|
|
|
"titleSubtitlePadding": 9 |
|
|
|
}, |
|
|
|
"footer": { |
|
|
|
"color": "#999999", |
|
|
|
"fontSize": 10, |
|
|
|
"font": "open sans", |
|
|
|
"location": "bottom-left" |
|
|
|
}, |
|
|
|
"size": { |
|
|
|
"canvasWidth": 600, |
|
|
|
"canvasHeight": 400, |
|
|
|
"pieInnerRadius": "20%", |
|
|
|
"pieOuterRadius": "85%" |
|
|
|
}, |
|
|
|
"data": { |
|
|
|
//"sortOrder": "value-desc", |
|
|
|
"content": data.filter(function (elt) { |
|
|
|
return elt.value > 0; |
|
|
|
}) |
|
|
|
}, |
|
|
|
"labels": { |
|
|
|
"outer": { |
|
|
|
"hideWhenLessThanPercentage": 1, |
|
|
|
"pieDistance": 30 |
|
|
|
}, |
|
|
|
"inner": { |
|
|
|
"hideWhenLessThanPercentage": 4 |
|
|
|
}, |
|
|
|
"mainLabel": { |
|
|
|
"fontSize": 14 |
|
|
|
}, |
|
|
|
"percentage": { |
|
|
|
"color": "#eeeeee", |
|
|
|
"fontSize": 14, |
|
|
|
"decimalPlaces": 0 |
|
|
|
}, |
|
|
|
"lines": { |
|
|
|
"enabled": true |
|
|
|
}, |
|
|
|
"truncation": { |
|
|
|
"enabled": true |
|
|
|
} |
|
|
|
}, |
|
|
|
"tooltips": { |
|
|
|
"enabled": true, |
|
|
|
"type": "placeholder", |
|
|
|
"string": "{label}: {value}, {percentage}%" |
|
|
|
}, |
|
|
|
"effects": { |
|
|
|
"pullOutSegmentOnClick": { |
|
|
|
"effect": "back", |
|
|
|
"speed": 400, |
|
|
|
"size": 8 |
|
|
|
}, |
|
|
|
"load": { |
|
|
|
"effect": "none" |
|
|
|
} |
|
|
|
}, |
|
|
|
"misc": { |
|
|
|
"gradient": { |
|
|
|
"enabled": true, |
|
|
|
"percentage": 100 |
|
|
|
} |
|
|
|
} |
|
|
|
}, conf)); |
|
|
|
} |
|
|
|
return obj; |
|
|
|
} |
|
|
|
|
|
|
|
// Public API |
|
|
|
var interface = { |
|
|
|
statWidgets: function(rspamd, pie, checked_server) { |
|
|
|
rspamd.queryNeighbours("/auth", function(neighbours_status) { |
|
|
|
var neighbours_sum = { |
|
|
|
version: neighbours_status[0].data.version, |
|
|
|
auth: "ok", |
|
|
|
uptime: 0, |
|
|
|
clean: 0, |
|
|
|
probable: 0, |
|
|
|
greylist: 0, |
|
|
|
reject: 0, |
|
|
|
soft_reject: 0, |
|
|
|
scanned: 0, |
|
|
|
learned: 0, |
|
|
|
read_only: neighbours_status[0].data.read_only, |
|
|
|
config_id: "" |
|
|
|
}; |
|
|
|
var status_count = 0; |
|
|
|
for(var e in neighbours_status) { |
|
|
|
if(neighbours_status[e].status === true) { |
|
|
|
// Remove alert status |
|
|
|
localStorage.removeItem(e + '_alerted'); |
|
|
|
neighbours_sum.clean += neighbours_status[e].data.clean; |
|
|
|
neighbours_sum.probable += neighbours_status[e].data.probable; |
|
|
|
neighbours_sum.greylist += neighbours_status[e].data.greylist; |
|
|
|
neighbours_sum.reject += neighbours_status[e].data.reject; |
|
|
|
neighbours_sum.soft_reject += neighbours_status[e].data.soft_reject; |
|
|
|
neighbours_sum.scanned += neighbours_status[e].data.scanned; |
|
|
|
neighbours_sum.learned += neighbours_status[e].data.learned; |
|
|
|
neighbours_sum.uptime += neighbours_status[e].data.uptime; |
|
|
|
status_count++; |
|
|
|
} |
|
|
|
} |
|
|
|
neighbours_sum.uptime = Math.floor(neighbours_sum.uptime / status_count); |
|
|
|
var to_Credentials = {}; |
|
|
|
to_Credentials["All SERVERS"] = { name: "All SERVERS", |
|
|
|
url: "", |
|
|
|
host: "", |
|
|
|
checked: true, |
|
|
|
data: neighbours_sum, |
|
|
|
status: true |
|
|
|
}; |
|
|
|
neighbours_status.forEach(function (elmt) { |
|
|
|
to_Credentials[elmt.name] = elmt; |
|
|
|
}); |
|
|
|
sessionStorage.setItem("Credentials", JSON.stringify(to_Credentials)); |
|
|
|
displayStatWidgets(checked_server); |
|
|
|
pie.chart = getChart(pie.chart, checked_server); |
|
|
|
}, |
|
|
|
function (serv, jqXHR, textStatus, errorThrown) { |
|
|
|
var alert_status = serv.name + '_alerted'; |
|
|
|
|
|
|
|
if (!(alert_status in sessionStorage)) { |
|
|
|
sessionStorage.setItem(alert_status, true); |
|
|
|
rspamd.alertMessage('alert-error', 'Cannot receive stats data from: ' + |
|
|
|
serv.name + ', error: ' + errorThrown); |
|
|
|
} |
|
|
|
}); |
|
|
|
}, |
|
|
|
}; |
|
|
|
|
|
|
|
return interface; |
|
|
|
} |
|
|
|
); |