luci-app: New log.

ruantiblock: Minor fixes.
This commit is contained in:
gSpot
2021-03-11 18:24:24 +03:00
parent a5fc9016be
commit b187ab5384
25 changed files with 736 additions and 244 deletions
+3 -3
View File
@@ -9,9 +9,9 @@ LUA_MODULE=1
LUCI_APP=1 LUCI_APP=1
OWRT_VERSION="19.07" OWRT_VERSION="19.07"
RUAB_VERSION="0.9.0-1" RUAB_VERSION="0.9.0-2"
RUAB_MOD_LUA_VERSION="0.9.0-1" RUAB_MOD_LUA_VERSION="0.9.0-2"
RUAB_LUCI_APP_VERSION="0.9.0-2" RUAB_LUCI_APP_VERSION="0.9.0-3"
BASE_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master" BASE_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master"
PKG_DIR="/tmp" PKG_DIR="/tmp"
+1 -1
View File
@@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_VERSION:=0.9.0 PKG_VERSION:=0.9.0
PKG_RELEASE:=2 PKG_RELEASE:=3
LUCI_TITLE:=LuCI support for ruantiblock LUCI_TITLE:=LuCI support for ruantiblock
LUCI_DEPENDS:=+ruantiblock +luci-mod-admin-full LUCI_DEPENDS:=+ruantiblock +luci-mod-admin-full
LUCI_PKGARCH:=all LUCI_PKGARCH:=all
@@ -0,0 +1,502 @@
'use strict';
'require ui';
return L.Class.extend({
view: L.view.extend({
viewName: null,
title: null,
logFacilities: [
'kern',
'user',
'mail',
'daemon',
'auth',
'syslog',
'lpr',
'news',
],
logLevels: {
'emerg': E('span', { 'class': 'zonebadge log-emerg' }, E('strong', _('Emergency'))),
'alert': E('span', { 'class': 'zonebadge log-alert' }, E('strong', _('Alert'))),
'crit': E('span', { 'class': 'zonebadge log-crit' }, E('strong', _('Critical'))),
'err': E('span', { 'class': 'zonebadge log-err' }, E('strong', _('Error'))),
'warn': E('span', { 'class': 'zonebadge log-warn' }, E('strong', _('Warning'))),
'notice': E('span', { 'class': 'zonebadge log-notice' }, E('strong', _('Notice'))),
'info': E('span', { 'class': 'zonebadge log-info' }, E('strong', _('Info'))),
'debug': E('span', { 'class': 'zonebadge log-debug' }, E('strong', _('Debug'))),
},
tailValue: 25,
logSortingValue: 'asc',
logLevelsStat: {},
logLevelsDropdown: null,
totalLogLines: 0,
htmlEntities: function(str) {
return String(str).replace(
/&/g, '&').replace(
/</g, '&#60;').replace(
/>/g, '&#62;').replace(
/"/g, '&#34;');
},
/**
*
* @param {number} tail
* @returns {string}
* Returns the raw content of the log
*
*/
getLogData: function(tail) {
throw new Error('getLogData needs to be reloaded in subclass');
},
/**
*
* @param {string} logdata
* @param {number} tail
* @returns {Array<number, string|null, string|null, string|null, string|null>}
* Returns an array of values: [ #, Timestamp, Level, Facility, Message ]
*
*/
parseLogData: function(logdata, tail) {
throw new Error('parseLogData needs to be reloaded in subclass');
},
makeLogArea: function(logdataArray) {
let lines = `<div class="tr"><div class="td center log-entry-empty">${_('No entries available...')}</div></div>`;
let logTable = E('div', { 'id': 'logTable', 'class': 'table' });
for(let level of Object.keys(this.logLevels)) {
this.logLevelsStat[level] = 0;
};
if(logdataArray.length > 0) {
lines = [];
logdataArray.forEach((e, i) => {
this.logLevelsStat[e[2]] = (this.logLevelsStat[e[2]] != undefined) ?
this.logLevelsStat[e[2]] + 1 : 1;
lines.push(
`<div class="tr log-${e[2] || 'empty'}"><div class="td left" data-title="#">${e[0]}</div>` +
((e[1]) ? `<div class="td left" data-title="${_('Timestamp')}">${e[1]}</div>` : '') +
((e[2]) ? `<div class="td left" data-title="${_('Level')}">${e[2]}</div>` : '') +
((e[3]) ? `<div class="td left" data-title="${_('Facility')}">${e[3]}</div>` : '') +
((e[4]) ? `<div class="td left" data-title="${_('Message')}">${e[4]}</div>` : '') +
`</div>`
);
});
lines = lines.join('');
logTable.append(
E('div', { 'class': 'tr table-titles' }, [
E('div', { 'class': 'th left log-entry-number' }, '#'),
(logdataArray[0][1]) ? E('div', { 'class': 'th left log-entry-time' }, _('Timestamp')) : '',
(logdataArray[0][2]) ? E('div', { 'class': 'th left log-entry-log-level' }, _('Level')) : '',
(logdataArray[0][3]) ? E('div', { 'class': 'th left log-entry-facility' }, _('Facility')) : '',
(logdataArray[0][4]) ? E('div', { 'class': 'th left log-entry-message' }, _('Message')) : '',
])
);
};
try {
logTable.insertAdjacentHTML('beforeend', lines);
} catch(err) {
if(err.name === 'SyntaxError') {
ui.addNotification(null,
E('p', {}, _('HTML/XML error') + ': ' + err.message), 'error');
};
throw err;
};
let levelsStatString = '';
if((Object.values(this.logLevelsStat).reduce((s,c) => s + c, 0)) > 0) {
Object.entries(this.logLevelsStat).forEach(e => {
if(e[1] > 0) {
levelsStatString += `<span class="log-entries-count-level log-${e[0]}" title="${e[0]}">${e[1]}</span>`;
};
});
};
return E([
E('div', { 'class': 'log-entries-count' },
`${_('Entries')}: ${logdataArray.length} / ${this.totalLogLines}${levelsStatString}`
),
logTable
]);
},
setLevelFilter: function(cArr) {
let logLevelsKeys = Object.keys(this.logLevels);
if(logLevelsKeys.length > 0) {
let selectedLevels = this.logLevelsDropdown.getValue();
if(logLevelsKeys.length === selectedLevels.length) {
return cArr;
};
return cArr.filter(s => selectedLevels.length === 0 || selectedLevels.includes(s[2]));
};
return cArr;
},
setRegexpFilter: function(cArr) {
let fPattern = document.getElementById('logFilter').value;
if(!fPattern) {
return cArr;
};
let fArr = [];
try {
let regExp = new RegExp(`(${fPattern})`, 'giu');
cArr.forEach((e, i) => {
if(regExp.test(e[4])) {
e[4] = e[4].replace(regExp, '<span class="log-highlight-item">$1</span>');
fArr.push(e);
};
});
} catch(err) {
if(err.name === 'SyntaxError') {
ui.addNotification(null,
E('p', {}, _('Invalid regular expression') + ': ' + err.message));
return cArr;
} else {
throw err;
};
};
return fArr;
},
downloadLog: function() {
let formElems = Array.from(document.forms.logForm.elements);
formElems.forEach(e => e.disabled = true);
return this.getLogData(0).then(logdata => {
logdata = logdata || '';
let link = E('a', {
'download': this.viewName + '.txt',
'href': URL.createObjectURL(
new Blob([ logdata ], { type: 'text/plain' })),
});
link.click();
URL.revokeObjectURL(link.href);
}).catch(() => {
ui.addNotification(null,
E('p', {}, _('Download error') + ': ' + err.message));
}).finally(() => {
formElems.forEach(e => e.disabled = false);
});
},
load: function() {
// Restoring settings from localStorage
let tailValueLocal = localStorage.getItem(`luci-app-${this.viewName}-tailValue`);
if(tailValueLocal) {
this.tailValue = Number(tailValueLocal);
};
let logSortingLocal = localStorage.getItem(`luci-app-${this.viewName}-logSorting`);
if(logSortingLocal) {
this.logSortingValue = logSortingLocal;
};
return this.getLogData(this.tailValue);
},
render: function(logdata) {
document.head.append(E('style', {'type': 'text/css'},
`
.log-entry-empty {
}
.log-entry-number {
min-width: 4em !important;
}
.log-entry-time {
min-width: 14em !important;
}
.log-entry-log-level {
max-width: 5em !important;
}
.log-entry-facility{
max-width: 7em !important;
}
.log-entry-message {
min-width: 25em !important;
}
.log-empty {
}
.log-emerg {
background-color: #a93734 !important;
color: #fff;
}
.log-alert {
background-color: #ff7968 !important;
color: #fff;
}
.log-crit {
background-color: #fcc3bf !important;
}
.log-err {
background-color: #ffe9e8 !important;
}
.log-warn {
background-color: #fff7e2 !important;
}
.log-notice {
background-color: #e3ffec !important;
}
.log-info {
}
.log-debug {
background-color: #ebf6ff !important;
}
.log-highlight-item {
background-color: #ffef00;
}
.log-entries-count {
margin: 0 0 5px 5px;
font-weight: bold;
opacity: 0.6;
}
.log-entries-count-level {
display: inline-block !important;
margin: 0 0 0 5px;
padding: 0 4px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
border: 1px solid #ccc;
font-weight: normal;
}
`
));
let logWrapper = E('div', {
'id': 'logWrapper',
'style': 'width:100%; min-height:20em; padding: 0 0 0 45px; font-size:0.9em !important'
}, this.makeLogArea(this.parseLogData(logdata, this.tailValue)));
let tailInput = E('input', {
'id': 'tailInput',
'name': 'tailInput',
'type': 'text',
'form': 'logForm',
'class': 'cbi-input-text',
'style': 'width:4em !important; min-width:4em !important',
'maxlength': 5,
});
tailInput.value = (this.tailValue === 0) ? null : this.tailValue;
ui.addValidator(tailInput, 'uinteger', true);
let tailReset = E('input', {
'type': 'button',
'form': 'logForm',
'class': 'cbi-button btn cbi-button-reset',
'value': 'Χ',
'click': ev => {
tailInput.value = null;
logFormSubmitBtn.click();
ev.target.blur();
},
'style': 'max-width:4em !important',
});
let logLevelsDropdownElem = '';
let logLevelsKeys = Object.keys(this.logLevels);
if(logLevelsKeys.length > 0) {
this.logLevelsDropdown = new ui.Dropdown(
null,
this.logLevels,
{
id: 'logLevelsDropdown',
sort: logLevelsKeys,
multiple: true,
select_placeholder: _('All'),
display_items: 3,
dropdown_items: -1,
}
);
logLevelsDropdownElem = E(
'div', { 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
'for': 'logLevelsDropdown',
}, _('Logging levels')),
E('div', { 'class': 'cbi-value-field' },
this.logLevelsDropdown.render()
),
]
);
};
let logFilter = E('input', {
'id': 'logFilter',
'name': 'logFilter',
'type': 'text',
'form': 'logForm',
'class': 'cbi-input-text',
'placeholder': _('Type an expression...'),
});
let logFormSubmitBtn = E('input', {
'type': 'submit',
'form': 'logForm',
'class': 'cbi-button btn cbi-button-action',
'value': _('Apply'),
'click': ev => ev.target.blur(),
'style': 'margin-right: 1em',
});
let logSorting = E('select', {
'id': 'logSorting',
'form': 'logForm',
'class': "cbi-input-select",
}, [
E('option', { 'value': 'asc' }, _('ascending')),
E('option', { 'value': 'desc' }, _('descending')),
]);
logSorting.value = this.logSortingValue;
let logDownloadBtn = E('button', {
'class': 'cbi-button btn',
'click': ui.createHandlerFn(this, this.downloadLog),
}, _('Download log'));
return E([
E('h2', { 'id': 'logTitle', 'class': 'fade-in' }, this.title),
E('div', { 'class': 'cbi-section-descr fade-in' }),
E('div', { 'class': 'cbi-section fade-in' },
E('div', { 'class': 'cbi-section-node' }, [
E('div', { 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
'for': 'tailInput',
}, _('Last entries')),
E('div', { 'class': 'cbi-value-field' }, [
tailInput,
tailReset,
]),
]),
logLevelsDropdownElem,
E('div', { 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
'for': 'logFilter',
}, _('Message filter')),
E('div', { 'class': 'cbi-value-field' }, logFilter),
]),
E('div', { 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
'for': 'logSorting',
}, _('Sorting entries')),
E('div', { 'class': 'cbi-value-field' }, logSorting,),
]),
E('div', { 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
'for': 'logFilter',
}),
E('div', { 'class': 'cbi-value-field' }, [
logFormSubmitBtn,
E('form', {
'id': 'logForm',
'name': 'logForm',
'style': 'display:inline-block',
'submit': ui.createHandlerFn(this, function(ev) {
ev.preventDefault();
let formElems = Array.from(document.forms.logForm.elements);
formElems.forEach(e => e.disabled = true);
logDownloadBtn.disabled = true;
// Saving settings to localStorage
if(this.tailValue != tailInput.value) {
this.tailValue = (/^[0-9]+$/.test(tailInput.value)) ? tailInput.value : 0;
localStorage.setItem(
`luci-app-${this.viewName}-tailValue`, String(this.tailValue));
};
if(this.logSortingValue != logSorting.value) {
this.logSortingValue = logSorting.value;
localStorage.setItem(
`luci-app-${this.viewName}-logSorting`, this.logSortingValue);
};
let tail = (tailInput.value && tailInput.value > 0) ? tailInput.value : 0
return this.getLogData(tail).then(logdata => {
logdata = logdata || '';
let loglines = this.makeLogArea(
this.setRegexpFilter(
this.setLevelFilter(
this.parseLogData(logdata, tail)
)
)
);
logWrapper.innerHTML = '';
logWrapper.append(loglines);
}).finally(() => {
formElems.forEach(e => e.disabled = false);
logDownloadBtn.disabled = false;
});
}),
}, E('span', {}, '&#160;')),
]),
]),
])
),
E('div', { 'class': 'cbi-section fade-in' },
E('div', { 'class': 'cbi-section-node' },
E('div', { 'class': 'cbi-value' }, [
E('div', { 'style': 'position:fixed; z-index:1 !important' }, [
E('button', {
'class': 'btn',
'style': 'position:relative; display:block; margin:0 !important; left:1px; top:1px',
'click': ev => {
document.getElementById('logTitle').scrollIntoView(true);
ev.target.blur();
},
}, '&#8593;'),
E('button', {
'class': 'btn',
'style': 'position:relative; display:block; margin:0 !important; margin-top:1px !important; left:1px; top:1px',
'click': ev => {
logWrapper.scrollIntoView(false);
ev.target.blur();
},
}, '&#8595;'),
]),
logWrapper,
])
)
),
E('div', { 'class': 'cbi-section fade-in' },
E('div', { 'class': 'cbi-section-node' },
E('div', { 'class': 'cbi-value' },
E('div', { 'style': 'width:100%; text-align:right !important' }, [
E('hr'),
logDownloadBtn,
])
)
)
),
]);
},
handleSaveApply: null,
handleSave: null,
handleReset: null,
}),
})
@@ -1,18 +1,14 @@
'use strict';
'require fs'; 'require fs';
'require ui'; 'require ui';
'require view.ruantiblock.baselog as baselog';
'require view.ruantiblock.tools as tools'; 'require view.ruantiblock.tools as tools';
let log_regexp = new RegExp(`^.*(user\\.notice ${tools.app_name}).*$`, 'gm'); return baselog.view.extend({
viewName: 'ruantiblock-log',
return L.view.extend({ title: _('Ruantiblock') + ' - ' + _('Log'),
tail_default: 25,
parse_log_data: function(logdata) { getLogData: function(tail) {
return logdata.trim().match(log_regexp);
},
load: function() {
return Promise.all([ return Promise.all([
L.resolveDefault(fs.stat('/sbin/logread'), null), L.resolveDefault(fs.stat('/sbin/logread'), null),
L.resolveDefault(fs.stat('/usr/sbin/logread'), null), L.resolveDefault(fs.stat('/usr/sbin/logread'), null),
@@ -20,9 +16,9 @@ return L.view.extend({
let logger = (stat[0]) ? stat[0].path : (stat[1]) ? stat[1].path : null; let logger = (stat[0]) ? stat[0].path : (stat[1]) ? stat[1].path : null;
if(logger) { if(logger) {
return fs.exec_direct(logger, [ '-e', tools.app_name ]).catch(e => { return fs.exec_direct(logger, [ '-e', '^' + tools.app_name ]).catch(err => {
ui.addNotification(null, E('p', _('Unable to execute or read contents') ui.addNotification(null, E('p', _('Unable to execute or read contents')
+ ': %s<br />[ %s ]'.format(e.message, logger) + ': %s<br />[ %s ]'.format(err.message, logger)
)); ));
return ''; return '';
}); });
@@ -30,166 +26,36 @@ return L.view.extend({
}); });
}, },
render: function(logdata) { parseLogData: function(logdata, tail) {
let nav_btns_top = '1px'; if(!logdata) {
let loglines = this.parse_log_data(logdata); return [];
};
let log_textarea = E('textarea', { let strings = logdata.trim().split(/\n/);
'id': 'syslog',
'class': 'cbi-input-textarea',
'style': 'width:100% !important; resize:horizontal; padding: 0 0 0 45px; font-size:12px',
'readonly': 'readonly',
'wrap': 'off',
'rows': this.tail_default,
'spellcheck': 'false',
}, [ loglines.slice(-this.tail_default).join('\n') ]);
let tail_value = E('input', { if(tail && tail > 0 && strings) {
'id': 'tail_value', strings = strings.slice(-tail);
'name': 'tail_value', };
'type': 'text',
'form': 'log_form',
'class': 'cbi-input-text',
'style': 'width:4em !important; min-width:4em !important; margin-bottom:0.3em !important',
'maxlength': 5,
});
tail_value.value = this.tail_default;
ui.addValidator(tail_value, 'uinteger', true);
let log_filter = E('input', { this.totalLogLines = strings.length;
'id': 'log_filter',
'name': 'log_filter', let entriesArray = strings.map((e, i) => {
'type': 'text', let strArray = e.split(/\s+/);
'form': 'log_form', let logLevel = strArray[5].split('.');
'class': 'cbi-input-text',
'style': 'min-width:16em !important; margin-right:1em !important; margin-bottom:0.3em !important', return [
'placeholder': _('Message filter'), i + 1, // # (Number)
'data-tooltip': _('Filter messages with a regexp'), strArray.slice(0, 5).join(' '), // Timestamp (String)
logLevel[1], // Level (String)
logLevel[0], // Facility (String)
this.htmlEntities(strArray.slice(6).join(' ')), // Message (String)
];
}); });
let log_form_submit_btn = E('input', { if(this.logSortingValue === 'desc') {
'type': 'submit', entriesArray.reverse();
'form': 'log_form', };
'class': 'cbi-button btn cbi-button-action',
'style': 'margin-right:1em !important; margin-bottom:0.3em !important;',
'value': _('Apply'),
'click': ev => ev.target.blur(),
});
function set_log_tail(c_arr) { return entriesArray;
let tail_num_val = tail_value.value;
if(tail_num_val && tail_num_val > 0 && c_arr) {
return c_arr.slice(-tail_num_val);
};
return c_arr;
}
function set_log_filter(c_arr) {
let f_pattern = log_filter.value;
if(!f_pattern) {
return c_arr;
};
let f_arr = [];
try {
f_arr = c_arr.filter(s => new RegExp(f_pattern.toLowerCase()).test(s.toLowerCase()));
} catch(err) {
if(err.name === 'SyntaxError') {
ui.addNotification(null,
E('p', {}, _('Wrong regular expression') + ': ' + err.message));
return c_arr;
} else {
throw err;
};
};
if(f_arr.length === 0) {
f_arr.push(_('No matches...'));
};
return f_arr;
}
return E([
E('h2', { 'id': 'log_title', 'class': 'fade-in' }, _('Ruantiblock') + ' - ' + _('Log')),
E('div', { 'class': 'cbi-section-descr fade-in' }),
E('div', { 'class': 'cbi-section fade-in' },
E('div', { 'class': 'cbi-section-node' },
E('div', { 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
'for': 'tailValue',
'style': 'margin-bottom:0.3em !important',
}, _('Show only the last messages')),
E('div', { 'class': 'cbi-value-field' }, [
tail_value,
E('input', {
'type': 'button',
'form': 'log_form',
'class': 'cbi-button btn cbi-button-reset',
'value': 'Χ',
'click': ev => {
tail_value.value = null;
log_form_submit_btn.click();
ev.target.blur();
}, },
'style': 'margin-right:1em !important; margin-bottom:0.3em !important; max-width:4em !important',
}),
log_filter,
log_form_submit_btn,
E('form', {
'id': 'log_form',
'name': 'log_form',
'style': 'display:inline-block; margin-bottom:0.3em !important',
'submit': ui.createHandlerFn(this, function(ev) {
ev.preventDefault();
let form_elems = Array.from(document.forms.log_form.elements);
form_elems.forEach(e => e.disabled = true);
return this.load().then(logdata => {
let loglines = set_log_filter(set_log_tail(
this.parse_log_data(logdata)));
log_textarea.rows = (loglines.length < this.tail_default) ?
this.tail_default : loglines.length;
log_textarea.value = loglines.join('\n');
}).finally(() => {
form_elems.forEach(e => e.disabled = false);
}); });
}),
}, E('span', {}, '&#160;')),
]),
])
)
),
E('div', { 'class': 'cbi-section fade-in' },
E('div', { 'class': 'cbi-section-node' },
E('div', { 'class': 'cbi-value' }, [
E('div', { 'style': 'position:fixed' }, [
E('button', {
'class': 'btn',
'style': 'position:relative; display:block; margin:0 !important; left:1px; top:'
+ nav_btns_top,
'click': ev => {
document.getElementById('log_title').scrollIntoView(true);
ev.target.blur();
},
}, '&#8593;'),
E('button', {
'class': 'btn',
'style': 'position:relative; display:block; margin:0 !important; margin-top:1px !important; left:1px; top:'
+ nav_btns_top,
'click': ev => {
log_textarea.scrollIntoView(false);
ev.target.blur();
},
}, '&#8595;'),
]),
log_textarea,
])
)
),
]);
},
handleSaveApply: null,
handleSave: null,
handleReset: null,
});
+74 -12
View File
@@ -117,9 +117,6 @@ msgstr "Исключение IP адресов из блэклиста по ша
msgid "Expecting:" msgid "Expecting:"
msgstr "Ожидается:" msgstr "Ожидается:"
msgid "Filter messages with a regexp"
msgstr "Фильтровать сообщения с помощью регулярного выражения"
msgid "FQDN configuration" msgid "FQDN configuration"
msgstr "Конфигурация FQDN" msgstr "Конфигурация FQDN"
@@ -171,9 +168,6 @@ msgstr "Основные настройки"
msgid "Match-set" msgid "Match-set"
msgstr "Правило" msgstr "Правило"
msgid "Message filter"
msgstr "Фильтр сообщений"
msgid "Minute" msgid "Minute"
msgstr "Минута" msgstr "Минута"
@@ -189,9 +183,6 @@ msgstr "Нет изменений для сохранения."
msgid "No data" msgid "No data"
msgstr "Нет данных" msgstr "Нет данных"
msgid "No matches..."
msgstr "Нет совпадений..."
msgid "No Shedule" msgid "No Shedule"
msgstr "Нет расписания" msgstr "Нет расписания"
@@ -262,9 +253,6 @@ msgstr "Установить"
msgid "Settings" msgid "Settings"
msgstr "Настройки" msgstr "Настройки"
msgid "Show only the last messages"
msgstr "Показать только последние сообщения"
msgid "Shutdown" msgid "Shutdown"
msgstr "Выключение" msgstr "Выключение"
@@ -371,3 +359,77 @@ msgstr "верный IP-адрес"
msgid "valid address#port" msgid "valid address#port"
msgstr "верный IP-адрес#порт" msgstr "верный IP-адрес#порт"
msgid "Alert"
msgstr "Тревога"
msgid "All"
msgstr "Все"
msgid "Critical"
msgstr "Критическая ситуация"
msgid "Debug"
msgstr "Отладка"
msgid "Download log"
msgstr "Скачать лог"
msgid "Emergency"
msgstr "Чрезвычайная ситуация"
msgid "Entries"
msgstr "Записи"
msgid "Facility"
msgstr "Категория"
msgid "Info"
msgstr "Информация"
msgid "Invalid regular expression"
msgstr "Неправильное регулярное выражение"
msgid "Last entries"
msgstr "Последние записи"
msgid "Level"
msgstr "Уровень"
msgid "Logging levels"
msgstr "Уровни логирования"
msgid "Message"
msgstr "Сообщение"
msgid "Message filter"
msgstr "Фильтр сообщений"
msgid "No entries available..."
msgstr "Нет доступных записей..."
msgid "Notice"
msgstr "Сообщение"
msgid "Sorting entries"
msgstr "Сортировка записей"
msgid "Timestamp"
msgstr "Время"
msgid "Type an expression..."
msgstr "Введите выражение..."
msgid "Unable to load log data:"
msgstr "Невозможно загрузить данные лога:"
msgid "Warning"
msgstr "Внимание"
msgid "ascending"
msgstr "по возрастанию"
msgid "descending"
msgstr "по убыванию"
@@ -104,9 +104,6 @@ msgstr ""
msgid "Expecting:" msgid "Expecting:"
msgstr "" msgstr ""
msgid "Filter messages with a regexp"
msgstr ""
msgid "FQDN configuration" msgid "FQDN configuration"
msgstr "" msgstr ""
@@ -158,9 +155,6 @@ msgstr ""
msgid "Match-set" msgid "Match-set"
msgstr "" msgstr ""
msgid "Message filter"
msgstr ""
msgid "Minute" msgid "Minute"
msgstr "" msgstr ""
@@ -176,9 +170,6 @@ msgstr ""
msgid "No data" msgid "No data"
msgstr "" msgstr ""
msgid "No matches..."
msgstr ""
msgid "No Shedule" msgid "No Shedule"
msgstr "" msgstr ""
@@ -237,9 +228,6 @@ msgstr ""
msgid "Settings" msgid "Settings"
msgstr "" msgstr ""
msgid "Show only the last messages"
msgstr ""
msgid "Shutdown" msgid "Shutdown"
msgstr "" msgstr ""
@@ -341,3 +329,77 @@ msgstr ""
msgid "valid address#port" msgid "valid address#port"
msgstr "" msgstr ""
msgid "Alert"
msgstr ""
msgid "All"
msgstr ""
msgid "Critical"
msgstr ""
msgid "Debug"
msgstr ""
msgid "Download log"
msgstr ""
msgid "Emergency"
msgstr ""
msgid "Entries"
msgstr ""
msgid "Facility"
msgstr ""
msgid "Info"
msgstr ""
msgid "Invalid regular expression"
msgstr ""
msgid "Last entries"
msgstr ""
msgid "Level"
msgstr ""
msgid "Logging levels"
msgstr ""
msgid "Message"
msgstr ""
msgid "Message filter"
msgstr ""
msgid "No entries available..."
msgstr ""
msgid "Notice"
msgstr ""
msgid "Sorting entries"
msgstr ""
msgid "Timestamp"
msgstr ""
msgid "Type an expression..."
msgstr ""
msgid "Unable to load log data:"
msgstr ""
msgid "Warning"
msgstr ""
msgid "ascending"
msgstr ""
msgid "descending"
msgstr ""
@@ -18,8 +18,8 @@
"/etc/init.d/cron enabled": [ "exec" ], "/etc/init.d/cron enabled": [ "exec" ],
"/etc/init.d/cron enable": [ "exec" ], "/etc/init.d/cron enable": [ "exec" ],
"/etc/init.d/cron restart": [ "exec" ], "/etc/init.d/cron restart": [ "exec" ],
"/sbin/logread -e ruantiblock": [ "exec" ], "/sbin/logread -e ^ruantiblock": [ "exec" ],
"/usr/sbin/logread -e ruantiblock": [ "exec" ] "/usr/sbin/logread -e ^ruantiblock": [ "exec" ]
}, },
"uci": [ "network", "ruantiblock" ] "uci": [ "network", "ruantiblock" ]
}, },
-15
View File
@@ -1,15 +0,0 @@
#
# (с) 2020 gSpot (https://github.com/gSpotx2f/ruantiblock_openwrt)
#
include $(TOPDIR)/rules.mk
PKG_VERSION:=0.9.0
PKG_RELEASE:=2
LUCI_TITLE:=Translation for luci-app-ruantiblock - Русский (Russian)
LUCI_DEPENDS:=+luci-app-ruantiblock
LUCI_PKGARCH:=all
include ../../luci.mk
# call BuildPackage - OpenWrt buildroot signature
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=ruantiblock-mod-lua PKG_NAME:=ruantiblock-mod-lua
PKG_VERSION:=0.9.0 PKG_VERSION:=0.9.0
PKG_RELEASE:=1 PKG_RELEASE:=2
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt> PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt>
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
@@ -317,8 +317,8 @@ function BlackListParser:fill_domain_tables(val)
end end
function BlackListParser:sink() function BlackListParser:sink()
-- Must be reload in the subclass -- Needs to be reloaded in subclass
error("Method BlackListParser:sink() must be reload in the subclass!") error("Method BlackListParser:sink() needs to be reloaded in subclass!")
end end
function BlackListParser:optimize_ip_table() function BlackListParser:optimize_ip_table()
+1 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=ruantiblock-mod-py PKG_NAME:=ruantiblock-mod-py
PKG_VERSION:=0.9.0 PKG_VERSION:=0.9.0
PKG_RELEASE:=1 PKG_RELEASE:=2
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt> PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt>
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
@@ -294,9 +294,7 @@ class BlackListParser(Config):
raise FieldValueError() raise FieldValueError()
def parser_func(self): def parser_func(self):
""" """Needs to be reloaded in subclass"""
Must be reload in the subclass
"""
raise NotImplementedError() raise NotImplementedError()
def _check_sld_masks(self, sld): def _check_sld_masks(self, sld):
+1 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=ruantiblock PKG_NAME:=ruantiblock
PKG_VERSION:=0.9.0 PKG_VERSION:=0.9.0
PKG_RELEASE:=1 PKG_RELEASE:=2
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt> PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt>
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+30 -13
View File
@@ -17,6 +17,7 @@ CONFIG_DIR="/etc/${NAME}"
CONFIG_FILE="${CONFIG_DIR}/${NAME}.conf" CONFIG_FILE="${CONFIG_DIR}/${NAME}.conf"
export DATA_DIR="${CONFIG_DIR}/var" export DATA_DIR="${CONFIG_DIR}/var"
export EXEC_DIR="/usr/bin" export EXEC_DIR="/usr/bin"
### Команда для перезапуска dnsmasq ### Команда для перезапуска dnsmasq
export DNSMASQ_RESTART_CMD="/etc/init.d/dnsmasq restart" export DNSMASQ_RESTART_CMD="/etc/init.d/dnsmasq restart"
### Директория для html-страницы статуса (не используется в OpenWrt) ### Директория для html-страницы статуса (не используется в OpenWrt)
@@ -123,12 +124,14 @@ export AF_ENCODING=""
############################ Configuration ############################# ############################ Configuration #############################
### External config
[ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE" [ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE"
CONFIG_SCRIPT="${CONFIG_DIR}/scripts/config_script" CONFIG_SCRIPT="${CONFIG_DIR}/scripts/config_script"
START_SCRIPT="${CONFIG_DIR}/scripts/start_script" START_SCRIPT="${CONFIG_DIR}/scripts/start_script"
STOP_SCRIPT="${CONFIG_DIR}/scripts/stop_script" STOP_SCRIPT="${CONFIG_DIR}/scripts/stop_script"
### Config script
[ -f "$CONFIG_SCRIPT" ] && . "$CONFIG_SCRIPT" [ -f "$CONFIG_SCRIPT" ] && . "$CONFIG_SCRIPT"
AWK_CMD="awk" AWK_CMD="awk"
@@ -208,7 +211,15 @@ EOF
} }
MakeLogRecord() { MakeLogRecord() {
[ $USE_LOGGER = "1" ] && $LOGGER_CMD $LOGGER_PARAMS $1 local _log_level
if [ $USE_LOGGER = "1" ]; then
if [ -z "$2" ]; then
_log_level="info"
else
_log_level="$2"
fi
$LOGGER_CMD $LOGGER_PARAMS -p "user.${_log_level}" "$1"
fi
} }
DnsmasqRestart() { DnsmasqRestart() {
@@ -250,7 +261,7 @@ TotalProxyOn() {
IptTotalProxyAdd IptTotalProxyAdd
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo " ${IPSET_TOTAL_PROXY} enabled" echo " ${IPSET_TOTAL_PROXY} enabled"
MakeLogRecord "${IPSET_TOTAL_PROXY} enabled" MakeLogRecord "${IPSET_TOTAL_PROXY} enabled" "notice"
fi fi
MakeToken MakeToken
fi fi
@@ -263,7 +274,7 @@ TotalProxyOff() {
echo " ${IPSET_TOTAL_PROXY} is already disabled" >&2 echo " ${IPSET_TOTAL_PROXY} is already disabled" >&2
else else
echo " ${IPSET_TOTAL_PROXY} disabled" echo " ${IPSET_TOTAL_PROXY} disabled"
MakeLogRecord "${IPSET_TOTAL_PROXY} disabled" MakeLogRecord "${IPSET_TOTAL_PROXY} disabled" "notice"
fi fi
MakeToken MakeToken
fi fi
@@ -291,6 +302,7 @@ DelIptRules() {
SetNetConfig() { SetNetConfig() {
local _set local _set
### Создание списков ipset. Проверка на наличие списка с таким же именем, если нет, то создается новый
for _set in "$IPSET_TOTAL_PROXY" "$IPSET_CIDR_TMP" "$IPSET_CIDR" for _set in "$IPSET_TOTAL_PROXY" "$IPSET_CIDR_TMP" "$IPSET_CIDR"
do do
IsIpsetExists "$_set" || $IPSET_CMD create "$_set" hash:net maxelem $IPSET_MAXELEM IsIpsetExists "$_set" || $IPSET_CMD create "$_set" hash:net maxelem $IPSET_MAXELEM
@@ -311,6 +323,7 @@ DropNetConfig() {
FillIpsets() { FillIpsets() {
local _set local _set
### Заполнение списков ipset $IPSET_IP и $IPSET_CIDR. Сначала restore загружает во временные списки, а затем swap из временных добавляет в основные
if [ -f "$IP_DATA_FILE" ]; then if [ -f "$IP_DATA_FILE" ]; then
echo " Filling ipsets..." echo " Filling ipsets..."
FlushIpSets "$IPSET_IP_TMP" "$IPSET_CIDR_TMP" FlushIpSets "$IPSET_IP_TMP" "$IPSET_CIDR_TMP"
@@ -321,7 +334,7 @@ FillIpsets() {
FlushIpSets "$IPSET_IP_TMP" "$IPSET_CIDR_TMP" FlushIpSets "$IPSET_IP_TMP" "$IPSET_CIDR_TMP"
else else
echo " Error! Ipset wasn't updated" >&2 echo " Error! Ipset wasn't updated" >&2
MakeLogRecord "Error! Ipset wasn't updated" MakeLogRecord "Error! Ipset wasn't updated" "err"
fi fi
fi fi
} }
@@ -353,6 +366,7 @@ CheckStatus() {
PreStartCheck() { PreStartCheck() {
[ -d "$DATA_DIR" ] || mkdir -p "$DATA_DIR" [ -d "$DATA_DIR" ] || mkdir -p "$DATA_DIR"
[ "$HTML_INFO" = "1" -a ! -d "$HTML_DIR" ] && mkdir -p "$HTML_DIR" [ "$HTML_INFO" = "1" -a ! -d "$HTML_DIR" ] && mkdir -p "$HTML_DIR"
### Костыль для старта dnsmasq
[ -e "$DNSMASQ_DATA_FILE" ] || printf "\n" > "$DNSMASQ_DATA_FILE" [ -e "$DNSMASQ_DATA_FILE" ] || printf "\n" > "$DNSMASQ_DATA_FILE"
} }
@@ -404,8 +418,9 @@ GetDataFiles() {
$BLLIST_MODULE $BLLIST_MODULE
_return_code=$? _return_code=$?
[ $_return_code -eq 0 ] && break [ $_return_code -eq 0 ] && break
### STDOUT
echo " Module run attempt ${_attempt}: failed [${BLLIST_MODULE}]" echo " Module run attempt ${_attempt}: failed [${BLLIST_MODULE}]"
MakeLogRecord "Module run attempt ${_attempt}: failed [${BLLIST_MODULE}]" MakeLogRecord "Module run attempt ${_attempt}: failed [${BLLIST_MODULE}]" "err"
_attempt=`expr $_attempt + 1` _attempt=`expr $_attempt + 1`
[ $_attempt -gt $MODULE_RUN_ATTEMPTS ] && break [ $_attempt -gt $MODULE_RUN_ATTEMPTS ] && break
sleep $MODULE_RUN_TIMEOUT sleep $MODULE_RUN_TIMEOUT
@@ -416,8 +431,9 @@ GetDataFiles() {
printf "Received entries: %s\n", (NF < 3) ? "No data" : "IP: "$1", CIDR: "$2", FQDN: "$3; printf "Received entries: %s\n", (NF < 3) ? "No data" : "IP: "$1", CIDR: "$2", FQDN: "$3;
exit; exit;
}' "$UPDATE_STATUS_FILE"` }' "$UPDATE_STATUS_FILE"`
### STDOUT
echo " ${_update_string}" echo " ${_update_string}"
MakeLogRecord "${_update_string}" MakeLogRecord "${_update_string}" "info"
printf " `date +%d.%m.%Y-%H:%M`\n" >> "$UPDATE_STATUS_FILE" printf " `date +%d.%m.%Y-%H:%M`\n" >> "$UPDATE_STATUS_FILE"
fi fi
else else
@@ -429,6 +445,7 @@ GetDataFiles() {
if [ "$PROXY_MODE" = "2" ]; then if [ "$PROXY_MODE" = "2" ]; then
printf "\n" >> "$DNSMASQ_DATA_FILE" printf "\n" >> "$DNSMASQ_DATA_FILE"
else else
### Запись для .onion в $DNSMASQ_DATA_FILE
printf "server=/onion/%s\nipset=/onion/%s\n" "${ONION_DNS_ADDR}" "${IPSET_ONION}" >> "$DNSMASQ_DATA_FILE" printf "server=/onion/%s\nipset=/onion/%s\n" "${ONION_DNS_ADDR}" "${IPSET_ONION}" >> "$DNSMASQ_DATA_FILE"
fi fi
rm -f "$UPDATE_PID_FILE" rm -f "$UPDATE_PID_FILE"
@@ -450,11 +467,11 @@ Update() {
MakeToken MakeToken
if [ -e "$UPDATE_PID_FILE" ] && [ "$1" != "force-update" ]; then if [ -e "$UPDATE_PID_FILE" ] && [ "$1" != "force-update" ]; then
echo " ${NAME} ${1} - Error! Another instance of update is already running" >&2 echo " ${NAME} ${1} - Error! Another instance of update is already running" >&2
MakeLogRecord "${1} - Error! Another instance of update is already running" MakeLogRecord "${1} - Error! Another instance of update is already running" "err"
_return_code=2 _return_code=2
else else
echo " ${NAME} ${1}..." echo " ${NAME} ${1}..."
MakeLogRecord "${1}..." MakeLogRecord "${1}..." "notice"
if [ "$IPSET_CLEAR_SETS" = "1" ]; then if [ "$IPSET_CLEAR_SETS" = "1" ]; then
FlushIpSets "$IPSET_IP" "$IPSET_CIDR" "$IPSET_DNSMASQ" FlushIpSets "$IPSET_IP" "$IPSET_CIDR" "$IPSET_DNSMASQ"
fi fi
@@ -462,16 +479,16 @@ Update() {
case $? in case $? in
0) 0)
echo " Blacklist updated" echo " Blacklist updated"
MakeLogRecord "Blacklist updated" MakeLogRecord "Blacklist updated" "info"
;; ;;
2) 2)
echo " Error! Blacklist update error" >&2 echo " Error! Blacklist update error" >&2
MakeLogRecord "Error! Blacklist update error" MakeLogRecord "Error! Blacklist update error" "err"
_return_code=1 _return_code=1
;; ;;
*) *)
echo " Module error! [${BLLIST_MODULE}]" >&2 echo " Module error! [${BLLIST_MODULE}]" >&2
MakeLogRecord "Module error! [${BLLIST_MODULE}]" MakeLogRecord "Module error! [${BLLIST_MODULE}]" "err"
_return_code=1 _return_code=1
;; ;;
esac esac
@@ -498,7 +515,7 @@ Start() {
_return_code=1 _return_code=1
else else
echo " ${NAME} ${1}..." echo " ${NAME} ${1}..."
MakeLogRecord "${1}..." MakeLogRecord "${1}..." "notice"
DropNetConfig &> /dev/null DropNetConfig &> /dev/null
SetNetConfig SetNetConfig
PreStartCheck PreStartCheck
@@ -517,7 +534,7 @@ Stop() {
if CheckStatus; then if CheckStatus; then
MakeToken MakeToken
echo " ${NAME} ${1}..." echo " ${NAME} ${1}..."
MakeLogRecord "${1}..." MakeLogRecord "${1}..." "notice"
DropNetConfig &> /dev/null DropNetConfig &> /dev/null
_return_code=$? _return_code=$?
### Stop script ### Stop script