diff --git a/luci-app-zapret/htdocs/luci-static/resources/view/zapret/dmnlog.js b/luci-app-zapret/htdocs/luci-static/resources/view/zapret/dmnlog.js new file mode 100644 index 0000000..5df0659 --- /dev/null +++ b/luci-app-zapret/htdocs/luci-static/resources/view/zapret/dmnlog.js @@ -0,0 +1,155 @@ +'use strict'; +'require view'; +'require fs'; +'require form'; +'require poll'; +'require uci'; +'require ui'; +'require view.zapret.tools as tools'; + +return view.extend({ + retrieveLog: async function() { + return Promise.all([ + L.resolveDefault(fs.stat('/bin/cat'), null), + fs.exec('/usr/bin/find', [ '/tmp', '-maxdepth', '1', '-type', 'f', '-name', 'zapret+*.log' ]), + ]).then(function(status_array) { + var filereader = status_array[0] ? status_array[0].path : null; + var log_data = status_array[1]; // stdout: multiline text + if (log_data.code != 0) { + ui.addNotification(null, E('p', _('Unable to get log files') + '(code = ' + log_data.code + ') : retrieveLog()')); + return null; + } + var log_list = log_data.stdout.trim().split('\n'); + if (log_list.length <= 0) { + ui.addNotification(null, E('p', _('Unable to get log files') + '(not found) : retrieveLog()')); + return null; + } + var tasks = [ ]; + var logdata = [ ]; + for (let i = 0; i < log_list.length; i++) { + let logfn = log_list[i].trim(); + if (logfn.startsWith('/tmp/')) { + //console.log('LOG: ' + logfn); + logdata.push( { filename: logfn, data: null, rows: 0 } ); + tasks.push( fs.exec_direct(filereader, [ logfn ] ) ); + } + } + return Promise.all(tasks).then(function(log_array) { + for (let i = 0; i < log_array.length; i++) { + if (log_array[i]) { + logdata[i].data = log_array[i]; + logdata[i].rows = tools.getLineCount(log_array[i]) + 1; + } + } + return logdata; + }).catch(function(e) { + ui.addNotification(null, E('p', _('Unable to execute or read contents') + + ': %s [ %s | %s | %s | %s ]'.format( + e.message, tools.execPath, 'retrieveLogData', 'uci.zapret' + ))); + return null; + }); + }).catch(function(e) { + ui.addNotification(null, E('p', _('Unable to execute or read contents') + + ': %s [ %s | %s | %s | %s ]'.format( + e.message, tools.execPath, 'retrieveLog', 'uci.zapret' + ))); + return null; + }); + }, + + pollLog: async function() { + const elem0 = document.getElementById('dmnlog_0'); + if (elem0) { + const logdata = await this.retrieveLog(); + for (let log_num = 0; log_num < logdata.length; log_num++) { + let elem = document.getElementById('dmnlog_' + log_num); + if (elem) { + if (logdata[log_num].data) { + elem.value = logdata[log_num].data; + elem.rows = logdata[log_num].rows; + } else { + elem.value = ''; + elem.rows = 0; + } + } + } + //console.log('POLL: updated ' + logdata.length); + } + }, + + load: async function() { + poll.add(this.pollLog.bind(this)); + return await this.retrieveLog(); + }, + + render: function(logdata) { + if (!logdata) { + return; + } + var h2 = E('div', {'class' : 'cbi-title-section'}, [ + E('h2', {'class': 'cbi-title-field'}, [ _('Zapret') + ' - ' + _('Log Viewer') ]), + ]); + + var tabs = E('div', {}, E('div')); + + for (let log_num = 0; log_num < logdata.length; log_num++) { + //console.log('REN: ' + logdata[log_num].filename + ' : ' + logdata[log_num].data.length); + var logfn = logdata[log_num].filename; + let filename = logfn.replace(/.*\//, ''); + let fname = filename.split('.')[0]; + fname = fname.replace(/^(zapret\+)/, ''); + let fn = fname.split('+'); + + let tabNameText = fname.replace(/\+/g, ' '); + let tabname = 'tablog_' + log_num; + + var scrollDownButton = null; + var scrollUpButton = null; + + scrollDownButton = E('button', { + 'id': 'scrollDownButton_' + log_num, + 'class': 'cbi-button cbi-button-neutral' + }, _('Scroll to tail', 'scroll to bottom (the tail) of the log file') + ); + scrollDownButton.addEventListener('click', function() { + scrollUpButton.focus(); + }); + + scrollUpButton = E('button', { + 'id' : 'scrollUpButton_' + log_num, + 'class': 'cbi-button cbi-button-neutral' + }, _('Scroll to head', 'scroll to top (the head) of the log file') + ); + scrollUpButton.addEventListener('click', function() { + scrollDownButton.focus(); + }); + + let log_text = (logdata[log_num].data) ? logdata[log_num].data : ''; + + let tab = E('div', { 'data-tab': tabname, 'data-tab-title': tabNameText }, [ + E('div', { 'id': 'content_dmnlog_' + log_num }, [ + E('div', {'style': 'padding-bottom: 20px'}, [ scrollDownButton ]), + E('textarea', { + 'id': 'dmnlog_' + log_num, + 'style': 'font-size:12px', + 'readonly': 'readonly', + 'wrap': 'off', + 'rows': logdata[log_num].rows, + }, [ log_text ]), + E('div', {'style': 'padding-bottom: 20px'}, [ scrollUpButton ]), + ]), + ]); + + tabs.firstElementChild.appendChild(tab); + } + ui.tabs.initTabGroup(tabs.firstElementChild.childNodes); + //this.pollFn = L.bind(this.handleScanRefresh, this); + //poll.add(this.pollFn); + return E('div', { }, [ h2, tabs ]); + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/luci-app-zapret/htdocs/luci-static/resources/view/zapret/tools.js b/luci-app-zapret/htdocs/luci-static/resources/view/zapret/tools.js index e9927ff..aacf511 100644 --- a/luci-app-zapret/htdocs/luci-static/resources/view/zapret/tools.js +++ b/luci-app-zapret/htdocs/luci-static/resources/view/zapret/tools.js @@ -308,6 +308,17 @@ return baseclass.extend({ `; return out; }, + + getLineCount: function(mstr) { + let count = 0; + let c = '\n'.charAt(0); + for (let i = 0; i < mstr.length; ++i) { + if (c === mstr.charAt(i)) { + ++count; + } + } + return count; + }, fileEditDialog: baseclass.extend({ __init__: function(file, title, desc, aux = null, rows = 10, callback, file_exists = false) { diff --git a/luci-app-zapret/root/usr/share/luci/menu.d/luci-app-zapret.json b/luci-app-zapret/root/usr/share/luci/menu.d/luci-app-zapret.json index 8fc21f4..cea1cf2 100644 --- a/luci-app-zapret/root/usr/share/luci/menu.d/luci-app-zapret.json +++ b/luci-app-zapret/root/usr/share/luci/menu.d/luci-app-zapret.json @@ -33,5 +33,14 @@ "type": "view", "path": "zapret/settings" } + }, + + "admin/services/zapret/dmnlog": { + "title": "Log Viewer", + "order": 30, + "action": { + "type": "view", + "path": "zapret/dmnlog" + } } } diff --git a/luci-app-zapret/root/usr/share/rpcd/acl.d/luci-app-zapret.json b/luci-app-zapret/root/usr/share/rpcd/acl.d/luci-app-zapret.json index 7243e57..2607454 100644 --- a/luci-app-zapret/root/usr/share/rpcd/acl.d/luci-app-zapret.json +++ b/luci-app-zapret/root/usr/share/rpcd/acl.d/luci-app-zapret.json @@ -7,11 +7,14 @@ "/opt/zapret/config": [ "read" ], "/opt/zapret/ipset/*": [ "read" ], "/etc/crontabs/root": [ "read" ], + "/tmp/zapret*": [ "read" ], "/etc/init.d/zapret*": [ "exec" ], "/bin/ps*": [ "exec" ], + "/bin/cat*": [ "exec" ], "/bin/busybox*": [ "exec" ], "/bin/opkg*": [ "exec" ], "/usr/bin/apk*": [ "exec" ], + "/usr/bin/find*": [ "exec" ], "/opt/zapret/restore-def-cfg.sh*": [ "exec" ], "/opt/zapret/sync_config.sh*": [ "exec" ] },