From 3ab854aedfb7f85270342056541342d7fa52eb41 Mon Sep 17 00:00:00 2001 From: remittor Date: Tue, 27 Jan 2026 13:55:35 +0300 Subject: [PATCH] luci: Restart service on press Save&Apply --- .../luci-static/resources/view/zapret2/env.js | 2 + .../resources/view/zapret2/service.js | 52 +++---- .../resources/view/zapret2/settings.js | 49 ++----- .../resources/view/zapret2/tools.js | 137 ++++++++++++++++-- 4 files changed, 162 insertions(+), 78 deletions(-) diff --git a/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/env.js b/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/env.js index cacdacb..4548f4a 100644 --- a/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/env.js +++ b/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/env.js @@ -48,5 +48,7 @@ return baseclass.extend({ dst_obj.packager.path = '/bin/opkg'; dst_obj.packager.args = [ 'list-installed', '*'+this.appName+'*' ]; } + dst_obj.skey_pkg_dict = this.appName + '-pkg-dict'; + dst_obj.skey_deffered_action = this.appName + '-deffered-action'; } }); diff --git a/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/service.js b/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/service.js index a57c9b3..6453a5e 100644 --- a/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/service.js +++ b/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/service.js @@ -62,7 +62,9 @@ return view.extend({ }); }, - setAppStatus: function(status_array, elems = { }, force_app_status = 0) { + setAppStatus: function(status_array, elems = { }, force_app_status = 0) + { + tools.execDefferedAction(); let cfg = uci.get(tools.appName, 'config'); if (!status_array || cfg == null || typeof(cfg) !== 'object') { let elem_status = elems.status || document.getElementById("status"); @@ -73,7 +75,7 @@ return view.extend({ } let svc_boot = status_array[0] ? true : false; let svc_en = status_array[1]; // stdout: empty or error text - let svc_info = status_array[2]; // stdout: JSON as text + let svc_info = status_array[2]; // dict for services let proc_list = status_array[3]; // stdout: multiline text let pkg_dict = status_array[4]; // stdout: installed packages let stratlist = status_array[5]; // array of strat names @@ -140,45 +142,31 @@ return view.extend({ let btn = document.getElementById(button); this.disableButtons(true, btn); poll.stop(); - let errmsg = null; try { - let exec_cmd = null; - let exec_arg = [ ]; if (action == 'start' || action == 'restart') { - if (tools.checkUnsavedChanges()) { - ui.changes.apply(true); - await new Promise(resolve => setTimeout(resolve, 100)); - } - exec_cmd = tools.syncCfgPath; - errmsg = _('Unable to run sync_config.sh script.'); - } - if (action == 'reset') { - exec_cmd = tools.defaultCfgPath; - exec_arg = args; // (reset_ipset)(sync) ==> restore all configs + sync config - errmsg = _('Unable to run restore-def-cfg.sh script.'); - action = null; - } - if (exec_cmd) { - let res = await fs.exec(exec_cmd, exec_arg); - if (res.code != 0) { - throw Error('res.code = ' + res.code); + 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(); } - errmsg = null; - await tools.handleServiceAction(tools.appName, action); } catch(e) { - let msg = errmsg ? errmsg : _('Unable to run service action') + ' "' + action + '".'; - ui.addNotification(null, E('p', msg + ' Error: ' + e.message)); + //ui.addNotification(null, E('p', 'Error: ' + e.message)); } finally { - if (!poll.active()) { - poll.start(); - } - if (btn && btn_dis) { - setTimeout(() => { btn.disabled = true; }, 0); - } + setTimeout(() => { + if (btn && btn_dis) { + btn.disabled = true; + } + if (!poll.active()) { + poll.start(); + } + }, 0); } }, diff --git a/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/settings.js b/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/settings.js index 8982173..08b7353 100644 --- a/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/settings.js +++ b/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/settings.js @@ -13,43 +13,18 @@ document.head.appendChild(E('link', { })); return view.extend({ - parsers: { }, - - appStatusCode: null, - - depends: function(elem, key, array, empty=true) { - if (empty && array.length === 0) { - elem.depends(key, '_dummy'); - } else { - array.forEach(e => elem.depends(key, e)); - } - }, - - validateIpPort: function(section, value) { - return (/^$|^([0-9]{1,3}\.){3}[0-9]{1,3}(#[\d]{2,5})?$/.test(value)) ? true : _('Expecting:') - + ` ${_('One of the following:')}\n - ${_('valid IP address')}\n - ${_('valid address#port')}\n`; - }, - - validateUrl: function(section, value) { - return (/^$|^https?:\/\/[\w.-]+(:[0-9]{2,5})?[\w\/~.&?+=-]*$/.test(value)) ? true : _('Expecting:') - + ` ${_('valid URL')}\n`; - }, + svc_info: null, load: function() { - return Promise.all([ - { code: -1}, // L.resolveDefault(fs.exec(tools.execPath, [ 'raw-status' ]), 1), - null, // L.resolveDefault(fs.list(tools.parsersDir), null), - uci.load(tools.appName), - ]).catch(e => { - ui.addNotification(null, E('p', _('Unable to read the contents') + ': %s '.format(e.message) )); - }); + return tools.baseLoad(); }, render: function(data) { if (!data) { return; } - this.appStatusCode = data[0].code; + this.svc_info = data.svc_info; + tools.execDefferedAction(this.svc_info); let m, s, o, tabname; @@ -480,12 +455,18 @@ return view.extend({ return map_promise; }, - handleSaveApply: function(ev, mode) { + handleSaveApply: function(ev, mode) + { return this.handleSave(ev).then(() => { - ui.changes.apply(mode == '0'); - //if (this.appStatusCode != 1 && this.appStatusCode != 2) { - // window.setTimeout(() => fs.exec(tools.execPath, [ 'restart' ]), 3000); - //} + let apply_exec = tools.checkUnsavedChanges(); + if (apply_exec) { + ui.changes.apply(mode == '0'); + tools.setDefferedAction('restart', this.svc_info); + } else { + if (this.svc_info?.dmn.inited) { + tools.serviceActionEx('restart'); + } + } }); }, }); diff --git a/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/tools.js b/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/tools.js index 77ea168..526fa09 100644 --- a/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/tools.js +++ b/luci-app-zapret2/htdocs/luci-static/resources/view/zapret2/tools.js @@ -103,11 +103,10 @@ return baseclass.extend({ getPackageDict: function() { - let ses_var_name = this.appName+'_pkgdict'; let exec_cmd = this.packager.path; let exec_arg = this.packager.args; return fs.exec(exec_cmd, exec_arg).then(res => { - let pdict_json = sessionStorage.getItem(ses_var_name); + let pdict_json = localStorage.getItem(this.skey_pkg_dict); if (res.code != 0) { console.log(this.appName + ': Unable to enumerate installed packages. code = ' + res.code); if (pdict_json != null) { @@ -117,7 +116,7 @@ return baseclass.extend({ } let pdict = this.decode_pkg_list(res.stdout); if (pdict != pdict_json) { - sessionStorage.setItem(ses_var_name, JSON.stringify(pdict)); // renew cache + localStorage.setItem(this.skey_pkg_dict, JSON.stringify(pdict)); // renew cache } return pdict; }).catch(e => { @@ -138,7 +137,9 @@ return baseclass.extend({ }); }, - handleServiceAction: function(name, action) { + handleServiceAction: function(name, action, throwed = false) + { + console.log('handleServiceAction: '+name+' '+action); return this.callInitAction(name, action).then(success => { if (!success) { throw _('Command failed'); @@ -146,8 +147,114 @@ return baseclass.extend({ return true; }).catch(e => { ui.addNotification(null, E('p', _('Service action failed "%s %s": %s').format(name, action, e))); + if (throwed) { + throw e; + } }); }, + + serviceActionEx: async function(action, args = [ ], throwed = false) + { + let errmsg = null; + try { + let exec_cmd = null; + let exec_arg = [ ]; + if (action == 'start' || action == 'restart') { + exec_cmd = this.syncCfgPath; + errmsg = _('Unable to run sync_config.sh script.'); + } + if (action == 'reset') { + exec_cmd = this.defaultCfgPath; + exec_arg = args; // (reset_ipset)(sync) ==> restore all configs + sync config + errmsg = _('Unable to run restore-def-cfg.sh script.'); + action = null; + } + if (exec_cmd) { + let res = await fs.exec(exec_cmd, exec_arg); + if (res.code != 0) { + throw Error('res.code = ' + res.code); + } + } + errmsg = null; + await this.handleServiceAction(this.appName, action, throwed); + } catch(e) { + if (throwed) { + throw e; + } else { + let msg = errmsg ? errmsg : _('Unable to run service action') + ' "' + action + '".'; + ui.addNotification(null, E('p', msg + ' Error: ' + e.message)); + } + } + }, + + baseLoad: function(callback, cbarg) + { + return Promise.all([ + this.getSvcInfo(), // svc_info + uci.load(this.appName), + ]) + .then( ([svcInfo, uci_data]) => { + let svc_info = this.decodeSvcInfo(svcInfo); + let ret = { svc_info, uci_data }; + if (typeof callback === 'function') { + const res = callback(cbarg, ret); + if (res && typeof res.then === 'function') { + return res.then(() => ret); + } + return ret; + } + return ret; + }) + .catch(e => { + ui.addNotification(null, E('p', _('Unable to read the contents') + ' (baseLoad): %s '.format(e.message) )); + return null; + }); + }, + + decodeSvcInfo: function(svc_info, svc_autorun = true, proc_list = [ ]) + { + if (svc_info?.autorun !== undefined && svc_info?.dmn !== undefined) { + return svc_info; + } + if (svc_info != null && typeof(svc_info) == 'object') { + return this.decode_svc_info(svc_autorun, svc_info, proc_list); + } + return null; + }, + + setDefferedAction: function(action, svcInfo = null, forced = false) + { + let svc_info = this.decodeSvcInfo(svcInfo); + if (action == 'start' && svc_info?.dmn.inited) { + action = 'restart'; + } + if (action == 'start') { + if (!forced && svc_info?.dmn.inited) { + action = null; + } + } + if (action == 'restart') { + if (!forced && !svc_info?.dmn.inited) { + action = null; + } + } + if (action && localStorage.getItem(this.skey_deffered_action) == null) { + localStorage.setItem(this.skey_deffered_action, action); + console.log('setDefferedAction: '+this.skey_deffered_action+' = '+action); + } + }, + + execDefferedAction: function(svcInfo = null) + { + let svc_info = this.decodeSvcInfo(svcInfo); + //console.log('execDefferedAction: svc_info = '+JSON.stringify(svc_info)); + let action = localStorage.getItem(this.skey_deffered_action); + if (action) { + localStorage.removeItem(this.skey_deffered_action); + console.log('execDefferedAction: '+action); + this.serviceActionEx(action); + } + }, checkUnsavedChanges: function() { @@ -235,7 +342,8 @@ return baseclass.extend({ return plist; }, - decode_svc_info: function(svc_autorun, svc_info, proc_list, cfg) { + decode_svc_info: function(svc_autorun, svc_info, proc_list, cfg = null) + { let result = { "autorun": svc_autorun, "dmn": { @@ -246,13 +354,18 @@ return baseclass.extend({ }, "status": this.statusDict.error, }; - if (proc_list.code != 0) { - return -2; - } - let plist = this.get_pid_list(proc_list.stdout); - - if (plist.length < 4) { - return -3; + let plist = proc_list; + if (proc_list?.code !== undefined) { + if (proc_list.code != 0) { + return -2; + } + plist = this.get_pid_list(proc_list.stdout); + if (plist.length < 4) { + return -3; + } + } + if (svc_info == null) { + return null; } if (typeof(svc_info) !== 'object') { return -4;