Files
zapret-openwrt/luci-app-zapret/htdocs/luci-static/resources/view/zapret/service.js
2026-01-28 09:27:34 +03:00

436 lines
17 KiB
JavaScript

'use strict';
'require fs';
'require poll';
'require uci';
'require ui';
'require view';
'require view.zapret.tools as tools';
'require view.zapret.diagnost as diagnost';
'require view.zapret.updater as updater';
const btn_style_neutral = 'btn';
const btn_style_action = 'btn cbi-button-action';
const btn_style_positive = 'btn cbi-button-save important';
const btn_style_negative = 'btn cbi-button-reset important';
const btn_style_warning = 'btn cbi-button-negative';
const btn_style_success = 'btn cbi-button-success important';
return view.extend({
POLL: new tools.POLLER( { } ),
get_svc_buttons: function(elems = { }) {
return {
"enable" : elems.btn_enable || document.getElementById('btn_enable'),
"disable" : elems.btn_disable || document.getElementById('btn_disable'),
"start" : elems.btn_start || document.getElementById('btn_start'),
"restart" : elems.btn_restart || document.getElementById('btn_restart'),
"stop" : elems.btn_stop || document.getElementById('btn_stop'),
"reset" : elems.btn_reset || document.getElementById('btn_reset'),
"diag" : elems.btn_diag || document.getElementById('btn_diag'),
"update" : elems.btn_update || document.getElementById('btn_update'),
};
},
disableButtons: function(flag, button, elems = { }) {
let error_code = 0;
if (Number.isInteger(button) && button < 0) {
error_code = button;
}
let btn = this.get_svc_buttons(elems);
btn.enable.disabled = flag;
btn.disable.disabled = flag;
btn.start.disabled = flag;
btn.restart.disabled = flag;
btn.stop.disabled = flag;
btn.reset.disabled = (error_code == 0) ? flag : false;
btn.update.disabled = (error_code == 0) ? flag : false;
},
getAppStatus: function()
{
return tools.promiseAllDict({
svc_boot : tools.getInitState(tools.appName),
svc_en : fs.exec(tools.execPath, [ 'enabled' ]),
svc_info : tools.getSvcInfo(),
proc_list : fs.exec('/bin/busybox', [ 'ps' ]),
pkg_dict : tools.getPackageDict(),
strat_list : tools.getStratList(),
sys_info : fs.exec('/bin/cat', [ '/etc/openwrt_release' ]),
uci_data : uci.load(tools.appName),
}).catch(e => {
ui.addNotification(null, E('p', _('Unable to execute or read contents')
+ ': %s [ %s | %s | %s ]'.format(
e.message, tools.execPath, 'tools.getInitState', 'uci.'+tools.appName
)));
});
},
setAppStatus: function(data, elems = { }, force_app_status = 0)
{
tools.execDefferedAction();
let cfg = uci.get(tools.appName, 'config');
if (!data || cfg == null || typeof(cfg) !== 'object') {
let elem_status = elems.status || document.getElementById("status");
elem_status.innerHTML = tools.makeStatusString(null, '', '');
ui.addNotification(null, E('p', _('Unable to read the contents') + ': setAppStatus()'));
this.disableButtons(true, -1, elems);
return;
}
let svc_boot = data.svc_boot ? true : false;
this.nfqws_strat_list = data.strat_list;
this.pkg_arch = tools.getConfigPar(data.sys_info.stdout, 'DISTRIB_ARCH', 'unknown');
//console.log('svc_en: ' + data.svc_en.code + ' poll.running = ' + this.POLL.running);
let svc_en = (data.svc_en.code == 0) ? true : false;
if (typeof(data.svc_info) !== 'object') {
ui.addNotification(null, E('p', _('Unable to read the service info') + ': setAppStatus()'));
this.disableButtons(true, -1, elems);
return;
}
if (data.proc_list.code != 0) {
ui.addNotification(null, E('p', _('Unable to read process list') + ': setAppStatus()'));
this.disableButtons(true, -1, elems);
return;
}
if (!data.pkg_dict) {
ui.addNotification(null, E('p', _('Unable to enumerate installed packages') + ': getPackageDict()'));
this.disableButtons(true, -1, elems);
return;
}
let svcinfo;
if (force_app_status) {
svcinfo = force_app_status;
} else {
svcinfo = tools.decode_svc_info(svc_en, data.svc_info, data.proc_list, cfg);
}
let btn = this.get_svc_buttons(elems);
btn.reset.disabled = false;
btn.update.disabled = false;
if (Number.isInteger(svcinfo)) {
ui.addNotification(null, E('p', _('Error')
+ ' %s: return code = %s'.format('decode_svc_info', svcinfo + ' ')));
this.disableButtons(true, -1, elems);
} else {
btn.enable.disabled = (svc_en) ? true : false;
btn.disable.disabled = (svc_en) ? false : true;
if (!svcinfo.dmn.inited) {
btn.start.disabled = false;
btn.restart.disabled = true;
btn.stop.disabled = true;
} else {
btn.start.disabled = true;
btn.restart.disabled = false;
btn.stop.disabled = false;
}
}
let elem_status = elems.status || document.getElementById("status");
elem_status.innerHTML = tools.makeStatusString(svcinfo, this.pkg_arch, '');
this.POLL.running = false;
},
serviceActionEx: async function(action, button, args = [ ], hide_modal = false)
{
let btn = document.getElementById(button);
if (btn?.create_args) {
args = btn.create_args();
console.log('serviceActionEx: btn.args = '+JSON.stringify(args));
}
if (action == 'reset') {
hide_modal = true;
}
await this.POLL.stopAndWait();
this.disableButtons(true, btn);
//console.log('serviceActionEx: poll.running = '+this.POLL.running);
try {
if (action == 'start' || action == 'restart') {
let apply_exec = tools.checkUnsavedChanges();
if (apply_exec) {
ui.changes.apply(true); // apply_rollback
await new Promise(resolve => setTimeout(resolve, 1000));
tools.setDefferedAction(action, null, true);
return;
}
}
await tools.serviceActionEx(action, args, false);
if (hide_modal) {
ui.hideModal();
}
} catch(e) {
//ui.addNotification(null, E('p', 'Error: ' + e.message));
}
},
serviceActionExCallback: function(btn, result, error)
{
//console.log('serviceActionExCallback: poll.active = '+this.POLL.active);
this.POLL.start(150);
},
createServiceHandlerFn: function(action, btn_name)
{
let opt = { keepDisabled: true, callback: this.serviceActionExCallback };
return tools.createHandlerFnEx(this, 'serviceActionEx', opt, action, btn_name);
},
statusPoll: function()
{
this.getAppStatus().then(
L.bind(this.setAppStatus, this)
);
},
dialogResetCfg: function(ev)
{
if (tools.checkUnsavedChanges()) {
ui.addNotification(null, E('p', _('You have unapplied changes')));
return;
}
ev.target.blur();
let reset_base = E('label', [
E('input', { type: 'checkbox', id: 'cfg_reset_base', checked: true }),
' ', _('Restore all base settings')
]);
let reset_ipset = E('label', [
E('input', { type: 'checkbox', id: 'cfg_reset_ipset', checked: true }),
' ', _('Restore ipset configs')
]);
let set_autohostlist = E('label', [
E('input', { type: 'checkbox', id: 'cfg_autohostlist', checked: true }),
' ', _('Set AutoHostList mode')
]);
let erase_autohostlist = E('label', [
E('input', { type: 'checkbox', id: 'cfg_erase_autohostlist' }),
' ', _('Erase AutoHostList (ipset)')
]);
let enable_custom_d = E('label', [
E('input', { type: 'checkbox', id: 'cfg_enable_custom_d' }),
' ', _('Enable use custom.d scripts')
]);
let strat_list = [ ];
strat_list.push( E('option', { value: 'strat__skip__' }, [ 'not change' ] ) );
for (let id = 0; id < this.nfqws_strat_list.length; id++) {
let strat = '' + this.nfqws_strat_list[id];
strat_list.push( E('option', { value: 'strat_' + id }, [ strat ] ) );
}
let label_nfqws = (tools.appName == 'zapret2') ? _('NFQWS2_OPT strategy: ') : _('NFQWS_OPT strategy: ');
let nfqws_strat = E('label', [
label_nfqws,
E('select', { id: 'cfg_nfqws_strat' }, strat_list)
]);
let cancel_button = E('button', {
'class': btn_style_neutral,
'click': ui.hideModal,
}, _('Cancel'));
let resetcfg_btn = E('button', {
'id': 'resetcfg_btn',
'name': 'resetcfg_btn',
'class': btn_style_action,
}, _('Reset settings'));
resetcfg_btn.create_args = () => {
let opt_flags = '';
if (document.getElementById('cfg_reset_base').checked == false) {
opt_flags += '(skip_base)';
};
if (document.getElementById('cfg_reset_ipset').checked) {
opt_flags += '(reset_ipset)';
};
if (document.getElementById('cfg_autohostlist').checked) {
opt_flags += '(set_mode_autohostlist)';
};
if (document.getElementById('cfg_erase_autohostlist').checked) {
opt_flags += '(erase_autohostlist)';
};
if (document.getElementById('cfg_enable_custom_d').checked) {
opt_flags += '(enable_custom_d)';
};
let sel_strat = document.getElementById('cfg_nfqws_strat');
let opt_strat = sel_strat.options[sel_strat.selectedIndex].text;
if (opt_strat == 'not change') {
opt_strat = '-';
}
opt_flags += '(sync)';
return [ opt_flags, opt_strat ];
};
resetcfg_btn.onclick = this.createServiceHandlerFn('reset', 'resetcfg_btn');
ui.showModal(_('Reset settings to default'), [
E('div', { 'class': 'cbi-section' }, [
reset_base,
E('br'), E('br'),
reset_ipset,
E('br'), E('br'),
set_autohostlist,
E('br'), E('br'),
erase_autohostlist,
E('br'), E('br'),
enable_custom_d,
E('br'), E('br'),
nfqws_strat,
E('br'), E('br')
]),
E('div', { 'class': 'right' }, [
cancel_button,
' ',
resetcfg_btn,
])
]);
},
load: function()
{
return tools.baseLoad(this, (data) => {
//console.log('SYS FEATURES: '+JSON.stringify(data.sys_feat));
tools.load_feat_env();
return this.getAppStatus();
});
},
render: function(data)
{
if (!data) {
return;
}
let cfg = uci.get(tools.appName, 'config');
let pkgdict = data.pkg_dict;
if (pkgdict == null) {
ui.addNotification(null, E('p', _('Unable to enumerate installed packages') + ': render()'));
return;
}
let status_string = E('div', {
'id' : 'status',
'name' : 'status',
'class': 'cbi-section-node',
});
let layout = E('div', { 'class': 'cbi-section-node' });
function layout_append(title, descr, elems) {
descr = (descr) ? E('div', { 'class': 'cbi-value-description' }, descr) : '';
let elist = elems;
let elem_list = [ ];
for (let i = 0; i < elist.length; i++) {
elem_list.push(elist[i]);
elem_list.push(' ');
}
let vlist = [ E('div', {}, elem_list ) ];
for (let i = 0; i < elist.length; i++) {
let input = E('input', {
'id' : elist[i].id + '_hidden',
'type': 'hidden',
});
vlist.push(input);
}
let elem_name = (elist.length == 1) ? elist[0].id + '_hidden' : null;
layout.append(
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'for': elem_name }, title),
E('div', { 'class': 'cbi-value-field' }, vlist),
])
);
}
let create_btn = function(name, _class, locname) {
return E('button', {
'id' : name,
'name' : name,
'class': _class,
}, locname);
};
let btn_enable = create_btn('btn_enable', btn_style_success, _('Enable'));
btn_enable.onclick = this.createServiceHandlerFn('enable', 'btn_enable');
let btn_disable = create_btn('btn_disable', btn_style_warning, _('Disable'));
btn_disable.onclick = this.createServiceHandlerFn('disable', 'btn_disable');
layout_append(_('Service autorun control'), null, [ btn_enable, btn_disable ] );
let btn_start = create_btn('btn_start', btn_style_action, _('Start'));
btn_start.onclick = this.createServiceHandlerFn('start', 'btn_start');
let btn_restart = create_btn('btn_restart', btn_style_action, _('Restart'));
btn_restart.onclick = this.createServiceHandlerFn('restart', 'btn_restart');
let btn_stop = create_btn('btn_stop', btn_style_warning, _('Stop'));
btn_stop.onclick = this.createServiceHandlerFn('stop', 'btn_stop');
layout_append(_('Service daemons control'), null, [ btn_start, btn_restart, btn_stop ] );
let btn_reset = create_btn('btn_reset', btn_style_action, _('Reset settings'));
btn_reset.onclick = L.bind(this.dialogResetCfg, this);
layout_append(_('Reset settings to default'), null, [ btn_reset ] );
let btn_diag = create_btn('btn_diag', btn_style_action, _('Diagnostics'));
btn_diag.onclick = ui.createHandlerFn(this, () => { diagnost.openDiagnostDialog(this.pkg_arch) });
layout_append('Diagnostic tools', null, [ btn_diag ] );
let btn_update = create_btn('btn_update', btn_style_action, _('Update'));
btn_update.onclick = ui.createHandlerFn(this, () => { updater.openUpdateDialog(this.pkg_arch) });
layout_append(_('Update package'), null, [ btn_update ] );
let elems = {
"status": status_string,
"btn_enable": btn_enable,
"btn_disable": btn_disable,
"btn_start": btn_start,
"btn_restart": btn_restart,
"btn_stop": btn_stop,
"btn_reset": btn_reset,
"btn_diag": btn_diag,
"btn_update": btn_update,
};
this.setAppStatus(data, elems);
this.POLL.mode = 1;
this.POLL.init( L.bind(this.statusPoll, this), 2000 ); // interval 2 sec
this.POLL.start(500); // first step after 500 ms
let page_title = tools.AppName;
page_title += ' &nbsp ';
if (pkgdict[tools.appName] === undefined || pkgdict[tools.appName] == '') {
page_title += 'unknown version';
} else {
page_title += 'v' + pkgdict[tools.appName];
page_title = page_title.replace(/-r1$/, '');
}
let aux1 = E('em');
let aux2 = E('em');
if (pkgdict[tools.appName] != pkgdict['luci-app-'+tools.appName]) {
let errtxt = 'LuCI APP v' + pkgdict['luci-app-'+tools.appName] + ' [ incorrect version! ]';
aux1 = E('div', { 'class': 'label-status error' }, errtxt);
aux2 = E('div', { }, '&nbsp');
}
let url1 = 'https://github.com/bol-van/'+tools.appName;
let url2 = 'https://github.com/remittor/zapret-openwrt';
return E([
E('h2', { 'class': 'fade-in' }, page_title),
aux1,
aux2,
E('div', { 'class': 'cbi-section-descr fade-in' },
E('a', { 'href': url1, 'target': '_blank' }, url1),
),
E('div', { 'class': 'cbi-section-descr fade-in' },
E('a', { 'href': url2, 'target': '_blank' }, url2),
),
E('div', { 'class': 'cbi-section fade-in' }, [
status_string,
]),
E('div', { 'class': 'cbi-section fade-in' },
layout
),
]);
},
handleSave : null,
handleSaveApply: null,
handleReset : null,
});