mirror of
https://github.com/remittor/zapret-openwrt.git
synced 2025-12-17 13:08:27 +03:00
245 lines
8.9 KiB
JavaScript
245 lines
8.9 KiB
JavaScript
'use strict';
|
|
'require baseclass';
|
|
'require fs';
|
|
'require poll';
|
|
'require uci';
|
|
'require ui';
|
|
'require view';
|
|
'require view.zapret.tools as tools';
|
|
|
|
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';
|
|
|
|
const fn_update_pkg_sh = '/opt/zapret/update-pkg.sh';
|
|
|
|
return baseclass.extend({
|
|
releasesUrlPrefix : 'https://raw.githubusercontent.com/remittor/zapret-openwrt/gh-pages/releases/',
|
|
|
|
appendLog: function(msg, end = '\n') {
|
|
this.logArea.value += msg + end;
|
|
this.logArea.scrollTop = this.logArea.scrollHeight;
|
|
},
|
|
|
|
setBtnMode: function(enable) {
|
|
this.btn_cancel.disabled = enable ? false : true;
|
|
this.btn_action.disabled = (enable == 2) ? false : true;
|
|
},
|
|
|
|
setStage: function(stage, btn_flag = true) {
|
|
if (stage == 0) {
|
|
this.btn_action.textContent = _('Check for updates');
|
|
} else
|
|
if (stage == 1) {
|
|
this.btn_action.textContent = _('Update packages');
|
|
} else {
|
|
this.btn_action.textContent = _('');
|
|
}
|
|
if (stage > 1 && typeof(this.btn_action) == 'object') {
|
|
this.setBtnMode(1);
|
|
}
|
|
this.stage = stage;
|
|
},
|
|
|
|
checkUpdates: function() {
|
|
this.setStage(0);
|
|
this.setBtnMode(0);
|
|
this.pkg_url = null;
|
|
this.appendLog(_('Checking for updates...'));
|
|
let opt_list = [ '-c' ]; // check for updates
|
|
if (document.getElementById('cfg_exclude_prereleases').checked == false) {
|
|
opt_list.push('-p'); // include prereleases ZIP-files
|
|
}
|
|
let forced_reinstall = document.getElementById('cfg_forced_reinstall').checked;
|
|
let rpc_opt = { timeout: 20*1000 }
|
|
//rpc_opt.uid = 0; // run under root
|
|
let res = fs.exec(fn_update_pkg_sh, opt_list, null, rpc_opt).then(res => {
|
|
let log = res.stdout.trim();
|
|
this.appendLog(log);
|
|
let code = log.match(/^RESULT:\s*\(([^)]+)\)\s+.+$/m);
|
|
let pkg_url = log.match(/^ZAP_PKG_URL\s*=\s*(.+)$/m);
|
|
if (res.code == 0 && code && pkg_url) {
|
|
this.pkg_url = pkg_url[1];
|
|
code = code[1];
|
|
if (code == 'E' && !forced_reinstall) {
|
|
this.setStage(999);
|
|
return 0;
|
|
}
|
|
this.setStage(1);
|
|
this.setBtnMode(2); // enable all buttons
|
|
} else {
|
|
if (res.code != 0) {
|
|
this.appendLog('ERROR: Check for updates failed with error ' + res.code);
|
|
}
|
|
this.setStage(999);
|
|
}
|
|
return res.code;
|
|
}).catch(e => {
|
|
this.appendLog('ERROR: ' + _('Updates checking failed'));
|
|
this.appendLog('ERROR: ' + e);
|
|
this.setStage(999);
|
|
return 1;
|
|
}).finally(() => {
|
|
this.appendLog('=========================================================');
|
|
});
|
|
},
|
|
|
|
installUpdates: async function() {
|
|
this.setStage(1);
|
|
this.setBtnMode(0);
|
|
if (!this.pkg_url || this.pkg_url.length < 10) {
|
|
this.appendLog('ERROR: pkg_url = null');
|
|
this.setStage(999);
|
|
return 1;
|
|
}
|
|
this.appendLog(_('Install updates...'));
|
|
let opt_list = [ '-u', this.pkg_url ]; // update packages
|
|
if (document.getElementById('cfg_forced_reinstall').checked == true) {
|
|
opt_list.push('-f'); // forced reinstall if same version
|
|
}
|
|
let rpc_opt = { timeout: 5*1000 }
|
|
//rpc_opt.uid = 0; // run under root
|
|
const logFile = '/tmp/zapret_pkg_install.log';
|
|
const pidFile = '/tmp/zapret_pkg_install.pid';
|
|
try {
|
|
await fs.exec('/bin/busybox', [ 'rm', '-f', '/tmp/zapret_pkg_install.*' ], null, rpc_opt);
|
|
this.appendLog('Install log cleared.');
|
|
} catch (e) {
|
|
this.appendLog('ERROR: Failed to clear log file');
|
|
this.setStage(999);
|
|
return 1;
|
|
}
|
|
//console.log(`Start ${fn_update_pkg_sh}...`);
|
|
try {
|
|
let opt = [ logFile, pidFile, fn_update_pkg_sh ];
|
|
//opt.push('-t'); // only for testing
|
|
opt.push(...opt_list);
|
|
await fs.exec('/opt/zapret/script-exec.sh', opt, null, rpc_opt);
|
|
this.appendLog('Process started...');
|
|
} catch (e) {
|
|
this.appendLog('ERROR: Failed to start process: ' + e.message);
|
|
this.setStage(999);
|
|
return 1;
|
|
}
|
|
let lastLen = 0;
|
|
let pid = 0;
|
|
//console.log('setInterval...');
|
|
let timer = setInterval(async () => {
|
|
try {
|
|
if (pid == 0) {
|
|
try {
|
|
let pid_data = await fs.exec('/bin/cat', [ pidFile ], null, rpc_opt);
|
|
pid = parseInt(pid_data.stdout.trim(), 10);
|
|
} catch (e) {
|
|
//return; // goto next timer iteration
|
|
}
|
|
}
|
|
let alive = null;
|
|
if (pid > 0) {
|
|
try {
|
|
await fs.stat(`/proc/${pid}`, [ ], null, { timeout: 4*1000 });
|
|
alive = true;
|
|
} catch (e) {
|
|
// file "/proc/${pid}" not founded ==> sh process terminated
|
|
alive = false;
|
|
}
|
|
}
|
|
let res = await fs.exec('/bin/cat', [ logFile ], null, rpc_opt);
|
|
if (res.stdout.length > lastLen) {
|
|
let log = res.stdout.slice(lastLen);
|
|
log = log.replace(/^ \* resolve_conffiles.*(?:\r?\n|$)/gm, '');
|
|
this.appendLog(log, '');
|
|
lastLen = res.stdout.length;
|
|
}
|
|
if (pid > 0 && !alive) {
|
|
clearInterval(timer);
|
|
this.appendLog('\nProcess finished.');
|
|
let log = res.stdout;
|
|
let code = log.match(/^RESULT:\s*\(([^)]+)\)\s+.+$/m);
|
|
if (code && code[1] == '+') {
|
|
this.setStage(999);
|
|
this.btn_action.textContent = _('OK');
|
|
this.btn_action.disabled = false;
|
|
this.btn_cancel.disabled = true;
|
|
return 0;
|
|
}
|
|
this.appendLog('ERROR: Install updates failed!');
|
|
this.setStage(999);
|
|
}
|
|
} catch (e) {
|
|
clearInterval(timer);
|
|
this.appendLog('ERROR: reading log: ' + e.message);
|
|
this.setStage(999);
|
|
}
|
|
}, 500);
|
|
},
|
|
|
|
openUpdateDialog: function(pkg_arch) {
|
|
this.stage = 0;
|
|
this.pkg_arch = pkg_arch;
|
|
this.pkg_url = null;
|
|
|
|
let exclude_prereleases = E('label', [
|
|
E('input', { type: 'checkbox', id: 'cfg_exclude_prereleases', checked: true }),
|
|
' ', _('Exclude PreReleases')
|
|
]);
|
|
|
|
let forced_reinstall = E('label', [
|
|
E('input', { type: 'checkbox', id: 'cfg_forced_reinstall'}),
|
|
' ', _('Forced reinstall packages')
|
|
]);
|
|
|
|
this.logArea = E('textarea', {
|
|
'readonly': true,
|
|
'style': 'width:100%; height:400px; font-family: monospace;'
|
|
});
|
|
|
|
this.btn_cancel = E('button', {
|
|
'id': 'btn_cancel',
|
|
'name': 'btn_cancel',
|
|
'class': btn_style_warning,
|
|
}, _('Cancel'));
|
|
this.btn_cancel.onclick = ui.hideModal;
|
|
|
|
this.btn_action = E('button', {
|
|
'id': 'btn_action',
|
|
'name': 'btn_action',
|
|
'class': btn_style_action,
|
|
}, 'BUTTON_ACTION');
|
|
this.btn_action.onclick = ui.createHandlerFn(this, () => {
|
|
if (this.stage == 0) {
|
|
return this.checkUpdates();
|
|
}
|
|
if (this.stage == 1) {
|
|
return this.installUpdates();
|
|
}
|
|
return ui.hideModal();
|
|
});
|
|
|
|
this.setStage(0);
|
|
this.setBtnMode(2);
|
|
|
|
ui.showModal(_('Package update'), [
|
|
E('div', { 'class': 'cbi-section' }, [
|
|
E('div', {}, [
|
|
E('p', {'class': 'cbi-title-field'}, [ 'CPU architecture: ' + pkg_arch ]),
|
|
]),
|
|
exclude_prereleases,
|
|
E('br'), E('br'),
|
|
forced_reinstall,
|
|
E('br'), E('br'),
|
|
E('hr'),
|
|
this.logArea,
|
|
]),
|
|
E('div', { 'class': 'right' }, [
|
|
this.btn_cancel,
|
|
' ',
|
|
this.btn_action,
|
|
])
|
|
]);
|
|
}
|
|
});
|