--- /dev/null
+/*
+ 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;
+}
+);
\ No newline at end of file