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
OWRT_VERSION="19.07"
RUAB_VERSION="0.9.0-1"
RUAB_MOD_LUA_VERSION="0.9.0-1"
RUAB_LUCI_APP_VERSION="0.9.0-2"
RUAB_VERSION="0.9.0-2"
RUAB_MOD_LUA_VERSION="0.9.0-2"
RUAB_LUCI_APP_VERSION="0.9.0-3"
BASE_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_openwrt/master"
PKG_DIR="/tmp"
+1 -1
View File
@@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=0.9.0
PKG_RELEASE:=2
PKG_RELEASE:=3
LUCI_TITLE:=LuCI support for ruantiblock
LUCI_DEPENDS:=+ruantiblock +luci-mod-admin-full
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,195 +1,61 @@
'use strict';
'require fs';
'require ui';
'require view.ruantiblock.baselog as baselog';
'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({
tail_default: 25,
title: _('Ruantiblock') + ' - ' + _('Log'),
parse_log_data: function(logdata) {
return logdata.trim().match(log_regexp);
},
getLogData: function(tail) {
return Promise.all([
L.resolveDefault(fs.stat('/sbin/logread'), null),
L.resolveDefault(fs.stat('/usr/sbin/logread'), null),
]).then(stat => {
let logger = (stat[0]) ? stat[0].path : (stat[1]) ? stat[1].path : null;
load: function() {
return Promise.all([
L.resolveDefault(fs.stat('/sbin/logread'), null),
L.resolveDefault(fs.stat('/usr/sbin/logread'), null),
]).then(stat => {
let logger = (stat[0]) ? stat[0].path : (stat[1]) ? stat[1].path : null;
if(logger) {
return fs.exec_direct(logger, [ '-e', tools.app_name ]).catch(e => {
ui.addNotification(null, E('p', _('Unable to execute or read contents')
+ ': %s<br />[ %s ]'.format(e.message, logger)
if(logger) {
return fs.exec_direct(logger, [ '-e', '^' + tools.app_name ]).catch(err => {
ui.addNotification(null, E('p', _('Unable to execute or read contents')
+ ': %s<br />[ %s ]'.format(err.message, logger)
));
return '';
});
};
});
},
return '';
});
};
});
},
render: function(logdata) {
let nav_btns_top = '1px';
let loglines = this.parse_log_data(logdata);
parseLogData: function(logdata, tail) {
if(!logdata) {
return [];
};
let log_textarea = E('textarea', {
'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 strings = logdata.trim().split(/\n/);
let tail_value = E('input', {
'id': 'tail_value',
'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);
if(tail && tail > 0 && strings) {
strings = strings.slice(-tail);
};
let log_filter = E('input', {
'id': 'log_filter',
'name': 'log_filter',
'type': 'text',
'form': 'log_form',
'class': 'cbi-input-text',
'style': 'min-width:16em !important; margin-right:1em !important; margin-bottom:0.3em !important',
'placeholder': _('Message filter'),
'data-tooltip': _('Filter messages with a regexp'),
});
this.totalLogLines = strings.length;
let log_form_submit_btn = E('input', {
'type': 'submit',
'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(),
});
let entriesArray = strings.map((e, i) => {
let strArray = e.split(/\s+/);
let logLevel = strArray[5].split('.');
function set_log_tail(c_arr) {
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;
}
return [
i + 1, // # (Number)
strArray.slice(0, 5).join(' '), // Timestamp (String)
logLevel[1], // Level (String)
logLevel[0], // Facility (String)
this.htmlEntities(strArray.slice(6).join(' ')), // Message (String)
];
});
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;
}
if(this.logSortingValue === 'desc') {
entriesArray.reverse();
};
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,
return entriesArray;
},
});
+74 -12
View File
@@ -117,9 +117,6 @@ msgstr "Исключение IP адресов из блэклиста по ша
msgid "Expecting:"
msgstr "Ожидается:"
msgid "Filter messages with a regexp"
msgstr "Фильтровать сообщения с помощью регулярного выражения"
msgid "FQDN configuration"
msgstr "Конфигурация FQDN"
@@ -171,9 +168,6 @@ msgstr "Основные настройки"
msgid "Match-set"
msgstr "Правило"
msgid "Message filter"
msgstr "Фильтр сообщений"
msgid "Minute"
msgstr "Минута"
@@ -189,9 +183,6 @@ msgstr "Нет изменений для сохранения."
msgid "No data"
msgstr "Нет данных"
msgid "No matches..."
msgstr "Нет совпадений..."
msgid "No Shedule"
msgstr "Нет расписания"
@@ -262,9 +253,6 @@ msgstr "Установить"
msgid "Settings"
msgstr "Настройки"
msgid "Show only the last messages"
msgstr "Показать только последние сообщения"
msgid "Shutdown"
msgstr "Выключение"
@@ -371,3 +359,77 @@ msgstr "верный IP-адрес"
msgid "valid address#port"
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:"
msgstr ""
msgid "Filter messages with a regexp"
msgstr ""
msgid "FQDN configuration"
msgstr ""
@@ -158,9 +155,6 @@ msgstr ""
msgid "Match-set"
msgstr ""
msgid "Message filter"
msgstr ""
msgid "Minute"
msgstr ""
@@ -176,9 +170,6 @@ msgstr ""
msgid "No data"
msgstr ""
msgid "No matches..."
msgstr ""
msgid "No Shedule"
msgstr ""
@@ -237,9 +228,6 @@ msgstr ""
msgid "Settings"
msgstr ""
msgid "Show only the last messages"
msgstr ""
msgid "Shutdown"
msgstr ""
@@ -341,3 +329,77 @@ msgstr ""
msgid "valid address#port"
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 enable": [ "exec" ],
"/etc/init.d/cron restart": [ "exec" ],
"/sbin/logread -e ruantiblock": [ "exec" ],
"/usr/sbin/logread -e ruantiblock": [ "exec" ]
"/sbin/logread -e ^ruantiblock": [ "exec" ],
"/usr/sbin/logread -e ^ruantiblock": [ "exec" ]
},
"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_VERSION:=0.9.0
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt>
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
@@ -317,8 +317,8 @@ function BlackListParser:fill_domain_tables(val)
end
function BlackListParser:sink()
-- Must be reload in the subclass
error("Method BlackListParser:sink() must be reload in the subclass!")
-- Needs to be reloaded in subclass
error("Method BlackListParser:sink() needs to be reloaded in subclass!")
end
function BlackListParser:optimize_ip_table()
+1 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=ruantiblock-mod-py
PKG_VERSION:=0.9.0
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt>
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
@@ -294,9 +294,7 @@ class BlackListParser(Config):
raise FieldValueError()
def parser_func(self):
"""
Must be reload in the subclass
"""
"""Needs to be reloaded in subclass"""
raise NotImplementedError()
def _check_sld_masks(self, sld):
+1 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=ruantiblock
PKG_VERSION:=0.9.0
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt>
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"
export DATA_DIR="${CONFIG_DIR}/var"
export EXEC_DIR="/usr/bin"
### Команда для перезапуска dnsmasq
export DNSMASQ_RESTART_CMD="/etc/init.d/dnsmasq restart"
### Директория для html-страницы статуса (не используется в OpenWrt)
@@ -123,12 +124,14 @@ export AF_ENCODING=""
############################ Configuration #############################
### External config
[ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE"
CONFIG_SCRIPT="${CONFIG_DIR}/scripts/config_script"
START_SCRIPT="${CONFIG_DIR}/scripts/start_script"
STOP_SCRIPT="${CONFIG_DIR}/scripts/stop_script"
### Config script
[ -f "$CONFIG_SCRIPT" ] && . "$CONFIG_SCRIPT"
AWK_CMD="awk"
@@ -208,7 +211,15 @@ EOF
}
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() {
@@ -250,7 +261,7 @@ TotalProxyOn() {
IptTotalProxyAdd
if [ $? -eq 0 ]; then
echo " ${IPSET_TOTAL_PROXY} enabled"
MakeLogRecord "${IPSET_TOTAL_PROXY} enabled"
MakeLogRecord "${IPSET_TOTAL_PROXY} enabled" "notice"
fi
MakeToken
fi
@@ -263,7 +274,7 @@ TotalProxyOff() {
echo " ${IPSET_TOTAL_PROXY} is already disabled" >&2
else
echo " ${IPSET_TOTAL_PROXY} disabled"
MakeLogRecord "${IPSET_TOTAL_PROXY} disabled"
MakeLogRecord "${IPSET_TOTAL_PROXY} disabled" "notice"
fi
MakeToken
fi
@@ -291,6 +302,7 @@ DelIptRules() {
SetNetConfig() {
local _set
### Создание списков ipset. Проверка на наличие списка с таким же именем, если нет, то создается новый
for _set in "$IPSET_TOTAL_PROXY" "$IPSET_CIDR_TMP" "$IPSET_CIDR"
do
IsIpsetExists "$_set" || $IPSET_CMD create "$_set" hash:net maxelem $IPSET_MAXELEM
@@ -311,6 +323,7 @@ DropNetConfig() {
FillIpsets() {
local _set
### Заполнение списков ipset $IPSET_IP и $IPSET_CIDR. Сначала restore загружает во временные списки, а затем swap из временных добавляет в основные
if [ -f "$IP_DATA_FILE" ]; then
echo " Filling ipsets..."
FlushIpSets "$IPSET_IP_TMP" "$IPSET_CIDR_TMP"
@@ -321,7 +334,7 @@ FillIpsets() {
FlushIpSets "$IPSET_IP_TMP" "$IPSET_CIDR_TMP"
else
echo " Error! Ipset wasn't updated" >&2
MakeLogRecord "Error! Ipset wasn't updated"
MakeLogRecord "Error! Ipset wasn't updated" "err"
fi
fi
}
@@ -353,6 +366,7 @@ CheckStatus() {
PreStartCheck() {
[ -d "$DATA_DIR" ] || mkdir -p "$DATA_DIR"
[ "$HTML_INFO" = "1" -a ! -d "$HTML_DIR" ] && mkdir -p "$HTML_DIR"
### Костыль для старта dnsmasq
[ -e "$DNSMASQ_DATA_FILE" ] || printf "\n" > "$DNSMASQ_DATA_FILE"
}
@@ -404,8 +418,9 @@ GetDataFiles() {
$BLLIST_MODULE
_return_code=$?
[ $_return_code -eq 0 ] && break
### STDOUT
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 -gt $MODULE_RUN_ATTEMPTS ] && break
sleep $MODULE_RUN_TIMEOUT
@@ -416,8 +431,9 @@ GetDataFiles() {
printf "Received entries: %s\n", (NF < 3) ? "No data" : "IP: "$1", CIDR: "$2", FQDN: "$3;
exit;
}' "$UPDATE_STATUS_FILE"`
### STDOUT
echo " ${_update_string}"
MakeLogRecord "${_update_string}"
MakeLogRecord "${_update_string}" "info"
printf " `date +%d.%m.%Y-%H:%M`\n" >> "$UPDATE_STATUS_FILE"
fi
else
@@ -429,6 +445,7 @@ GetDataFiles() {
if [ "$PROXY_MODE" = "2" ]; then
printf "\n" >> "$DNSMASQ_DATA_FILE"
else
### Запись для .onion в $DNSMASQ_DATA_FILE
printf "server=/onion/%s\nipset=/onion/%s\n" "${ONION_DNS_ADDR}" "${IPSET_ONION}" >> "$DNSMASQ_DATA_FILE"
fi
rm -f "$UPDATE_PID_FILE"
@@ -450,11 +467,11 @@ Update() {
MakeToken
if [ -e "$UPDATE_PID_FILE" ] && [ "$1" != "force-update" ]; then
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
else
echo " ${NAME} ${1}..."
MakeLogRecord "${1}..."
MakeLogRecord "${1}..." "notice"
if [ "$IPSET_CLEAR_SETS" = "1" ]; then
FlushIpSets "$IPSET_IP" "$IPSET_CIDR" "$IPSET_DNSMASQ"
fi
@@ -462,16 +479,16 @@ Update() {
case $? in
0)
echo " Blacklist updated"
MakeLogRecord "Blacklist updated"
MakeLogRecord "Blacklist updated" "info"
;;
2)
echo " Error! Blacklist update error" >&2
MakeLogRecord "Error! Blacklist update error"
MakeLogRecord "Error! Blacklist update error" "err"
_return_code=1
;;
*)
echo " Module error! [${BLLIST_MODULE}]" >&2
MakeLogRecord "Module error! [${BLLIST_MODULE}]"
MakeLogRecord "Module error! [${BLLIST_MODULE}]" "err"
_return_code=1
;;
esac
@@ -498,7 +515,7 @@ Start() {
_return_code=1
else
echo " ${NAME} ${1}..."
MakeLogRecord "${1}..."
MakeLogRecord "${1}..." "notice"
DropNetConfig &> /dev/null
SetNetConfig
PreStartCheck
@@ -517,7 +534,7 @@ Stop() {
if CheckStatus; then
MakeToken
echo " ${NAME} ${1}..."
MakeLogRecord "${1}..."
MakeLogRecord "${1}..." "notice"
DropNetConfig &> /dev/null
_return_code=$?
### Stop script