mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-07-27 18:41:15 +08:00
367 lines
12 KiB
JavaScript
367 lines
12 KiB
JavaScript
'use strict';
|
||
'require view';
|
||
'require poll';
|
||
'require fs';
|
||
'require uci';
|
||
'require ui';
|
||
'require dom';
|
||
'require rpc';
|
||
'require form';
|
||
|
||
const mntpkgs = '/mnt/packagesync';
|
||
const mntreg = RegExp(/\/mnt\/packagesync/);
|
||
const conf = 'packagesync';
|
||
const release = 'release';
|
||
const instance = 'sync';
|
||
|
||
const callServiceList = rpc.declare({
|
||
object: 'service',
|
||
method: 'list',
|
||
params: ['name'],
|
||
expect: { '': {} }
|
||
});
|
||
|
||
function getServiceStatus() {
|
||
return L.resolveDefault(callServiceList(conf), {})
|
||
.then((res) => {
|
||
let isrunning = false;
|
||
try {
|
||
isrunning = res[conf]['instances'][instance]['running'];
|
||
} catch (e) { }
|
||
return isrunning;
|
||
});
|
||
}
|
||
|
||
return view.extend({
|
||
// handleSaveApply: null,
|
||
// handleSave: null,
|
||
// handleReset: null,
|
||
|
||
load() {
|
||
return Promise.all([
|
||
L.resolveDefault(fs.read('/var/packagesync/releaseslist'), null),
|
||
L.resolveDefault(fs.read('/var/packagesync/targetslist'), null),
|
||
L.resolveDefault(fs.read('/var/packagesync/pkgarchslist'), null),
|
||
L.resolveDefault(fs.stat('/var/run/packagesync.pid'), {}),
|
||
L.resolveDefault(fs.exec('/etc/init.d/packagesync', ['checkln']), {}),
|
||
L.resolveDefault(fs.exec('/bin/df', ['-hT']), {}),
|
||
getServiceStatus(),
|
||
uci.load('packagesync')
|
||
]);
|
||
},
|
||
|
||
poll_status(nodes, stat) {
|
||
const isRunning = stat[0];
|
||
let view = nodes.querySelector('#sync_status');
|
||
|
||
if (isRunning) {
|
||
view.innerHTML = "<span style=\"color:green;font-weight:bold\">" + _("SYNC IN PROGRESS") + "</span>";
|
||
} else {
|
||
view.innerHTML = "<span style=\"color:red;font-weight:bold\">" + _("SYNC NOT IN PROGRESS") + "</span>";
|
||
}
|
||
return;
|
||
},
|
||
|
||
render(res) {
|
||
const releaseslist = res[0] ? res[0].trim().split("\n") : [];
|
||
const targetslist = res[1] ? res[1].trim().split("\n") : [];
|
||
const pkgarchslist = res[2] ? res[2].trim().split("\n") : [];
|
||
const locked = res[3].path;
|
||
const usedname = res[4].stdout ? res[4].stdout.trim().split("\n") : [];
|
||
const storages = res[5].stdout ? res[5].stdout.trim().split("\n") : [];
|
||
const isRunning = res[6];
|
||
|
||
let storage = [];
|
||
if (storages.length) {
|
||
for (let i = 1; i < storages.length; i++) {
|
||
if (storages[i].match(mntreg)) {
|
||
storage = storages[i].trim().split(/\s+/, 7);
|
||
break;
|
||
}
|
||
}
|
||
};
|
||
|
||
let m, s, o;
|
||
|
||
m = new form.Map('packagesync');
|
||
|
||
s = m.section(form.NamedSection, 'config', 'packagesync', _('Local software source'),
|
||
_('packagesync used to build a local mirror feeds source on the router<br/>\
|
||
To use packagesync, you need to prepare a storage device with a size of at least <b>16G</b> and connect it to the router<br/>\
|
||
then open <a href="%s"><b>Mount Points</b></a>, find the connected device and set its mount point to <b>%s</b>, check <b>Enabled</b> and click <b>Save&Apple</b>')
|
||
.format(L.url('admin', 'system', 'mounts'), mntpkgs));
|
||
s.anonymous = true;
|
||
|
||
o = s.option(form.DummyValue, '_status', _('Running Status'));
|
||
o.rawhtml = true;
|
||
|
||
if (isRunning) {
|
||
o.cfgvalue = function(s) {
|
||
return E('div', { class: 'cbi-section' }, [
|
||
E('div', { id: 'sync_status' }, [
|
||
E('span', { 'style': 'color:green;font-weight:bold' }, [ _("SYNC IN PROGRESS") ])
|
||
])
|
||
]);
|
||
}
|
||
} else {
|
||
o.cfgvalue = function(s) {
|
||
return E('div', { class: 'cbi-section' }, [
|
||
E('div', { id: 'sync_status' }, [
|
||
E('span', { 'style': 'color:red;font-weight:bold' }, [ _("SYNC NOT IN PROGRESS") ])
|
||
])
|
||
]);
|
||
}
|
||
};
|
||
|
||
o = s.option(form.Value, 'home_url', _('Home URL'),
|
||
_('Open <a href="/%s" target="_blank">URL</a>').format(uci.get('packagesync', '@packagesync[0]', 'home_url')));
|
||
o.placeholder = 'packagesync';
|
||
o.rmempty = false;
|
||
o.validate = function(section, value) {
|
||
if (usedname.length)
|
||
for (let i = 0; i < usedname.length; i++)
|
||
if (usedname[i] == value)
|
||
return _('The Name %h is already used').format(value);
|
||
|
||
return true;
|
||
};
|
||
o.write = function(section, value) {
|
||
uci.set('packagesync', section, 'home_url', value);
|
||
fs.exec('/etc/init.d/packagesync', ['symln', value]);
|
||
};
|
||
|
||
o = s.option(form.Button, '_exec_now', _('Execute'));
|
||
o.inputtitle = _('Execute');
|
||
o.inputstyle = 'apply';
|
||
if ((! storage.length) || locked)
|
||
o.readonly = true;
|
||
o.onclick = function() {
|
||
window.setTimeout(() => {
|
||
window.location = window.location.href.split('#')[0];
|
||
}, L.env.apply_display * 500);
|
||
|
||
return fs.exec('/etc/init.d/packagesync', ['start'])
|
||
.catch((e) => { ui.addNotification(null, E('p', e.message), 'error') });
|
||
};
|
||
|
||
o = s.option(form.Value, 'download_url', _('Download URL'));
|
||
o.placeholder = 'https://downloads.openwrt.org';
|
||
o.rmempty = false;
|
||
|
||
o = s.option(form.Value, 'rsync_url', _('Rsync URL'),
|
||
_('<a href="%s" target="_blank">%s</a>')
|
||
.format('https://openwrt.org/mirrors', _('Available Mirrors')));
|
||
o.placeholder = 'rsync://rsync.openwrt.org/downloads';
|
||
o.rmempty = false;
|
||
|
||
o = s.option(form.ListValue, 'bwlimit', _('Bandwidth Limit'));
|
||
o.value('0', _('Unlimited'));
|
||
o.value('100', _('100 KB/s'));
|
||
o.value('200', _('200 KB/s'));
|
||
o.value('300', _('300 KB/s'));
|
||
o.value('500', _('500 KB/s'));
|
||
o.value('800', _('800 KB/s'));
|
||
o.value('1000', _('1 MB/s'));
|
||
o.value('2000', _('2 MB/s'));
|
||
o.value('3000', _('3 MB/s'));
|
||
o.value('5000', _('5 MB/s'));
|
||
o.value('8000', _('8 MB/s'));
|
||
o.value('10000', _('10 MB/s'));
|
||
o.value('20000', _('20 MB/s'));
|
||
o.value('30000', _('30 MB/s'));
|
||
o.value('50000', _('50 MB/s'));
|
||
o.value('80000', _('80 MB/s'));
|
||
o.value('100000', _('100 MB/s'));
|
||
o.default = '8000';
|
||
o.rmempty = false;
|
||
|
||
o = s.option(form.Flag, 'auto_exec', _('Auto Exec'));
|
||
o.default = o.enabled;
|
||
o.rmempty = false;
|
||
o.write = function(section, value) {
|
||
uci.set('packagesync', section, 'auto_exec', value);
|
||
if (value == 1) {
|
||
fs.exec('/etc/init.d/packagesync', ['setcron', uci.get('packagesync', '@packagesync[0]', 'cron_expression')]);
|
||
} else {
|
||
fs.exec('/etc/init.d/packagesync', ['setcron']);
|
||
}
|
||
};
|
||
|
||
o = s.option(form.Value, 'cron_expression', _('Cron expression'),
|
||
_('The default value is 0:00 every day'));
|
||
o.default = '0 0 * * *';
|
||
o.placeholder = '0 0 * * *';
|
||
o.rmempty = false;
|
||
o.retain = true;
|
||
o.depends('auto_exec', '1');
|
||
o.write = function(section, value) {
|
||
uci.set('packagesync', section, 'cron_expression', value);
|
||
fs.exec('/etc/init.d/packagesync', ['setcron', value]);
|
||
};
|
||
o.remove = function(section, value) {
|
||
//uci.unset('packagesync', section, 'cron_expression');
|
||
fs.exec('/etc/init.d/packagesync', ['setcron']);
|
||
};
|
||
|
||
o = s.option(form.Flag, 'proxy_enabled', _('Enable proxy'));
|
||
o.rmempty = false;
|
||
|
||
o = s.option(form.ListValue, 'proxy_protocol', _('Proxy Protocol'));
|
||
o.value('http', 'HTTP');
|
||
o.value('https', 'HTTPS');
|
||
o.value('socks5', 'SOCKS5');
|
||
o.value('socks5h', 'SOCKS5H');
|
||
o.default = 'socks5';
|
||
o.rmempty = false;
|
||
o.retain = true;
|
||
o.depends('proxy_enabled', '1');
|
||
|
||
o = s.option(form.Value, 'proxy_server', _('Proxy Server'));
|
||
o.datatype = "ipaddrport(1)";
|
||
o.placeholder = '192.168.1.10:1080';
|
||
o.rmempty = false;
|
||
o.retain = true;
|
||
o.depends('proxy_enabled', '1');
|
||
|
||
o = s.option(form.Button, '_list_invalid', _('List removable versions'));
|
||
o.inputtitle = _('List');
|
||
o.inputstyle = 'apply';
|
||
if (! storage.length)
|
||
o.readonly = true;
|
||
o.onclick = function(ev, section_id) {
|
||
let precontent = document.getElementById('cleanup-output');
|
||
|
||
return fs.exec('/etc/init.d/packagesync', ['cleanup'])
|
||
.then((res) => { dom.content(precontent, [ res.stdout.trim().length ? res.stdout.trim() : _('no objects need to remove.'), res.stderr ? res.stderr : '' ]) })
|
||
.catch((err) => { ui.addNotification(null, E('p', err.message), 'error') });
|
||
};
|
||
|
||
o = s.option(form.DummyValue, '_removable_versions', ' ');
|
||
o.rawhtml = true;
|
||
o.cfgvalue = function(section_id) {
|
||
return E('pre', { 'id': 'cleanup-output' }, []);
|
||
};
|
||
|
||
s = m.section(form.GridSection, '_storage');
|
||
|
||
s.render = L.bind(function(view, section_id) {
|
||
let table = E('table', { 'class': 'table cbi-section-table', 'id': 'storage_device' }, [
|
||
E('tr', { 'class': 'tr table-titles' }, [
|
||
E('th', { 'class': 'th' }, _('Filesystem')),
|
||
E('th', { 'class': 'th' }, _('Type')),
|
||
E('th', { 'class': 'th' }, _('Size')),
|
||
E('th', { 'class': 'th' }, _('Used')),
|
||
E('th', { 'class': 'th' }, _('Available')),
|
||
E('th', { 'class': 'th' }, _('Used') + ' %'),
|
||
E('th', { 'class': 'th' }, _('Mount point')),
|
||
E('th', { 'class': 'th cbi-section-actions' }, '')
|
||
])
|
||
]);
|
||
let rows = [];
|
||
if (storage.length) {
|
||
storage[5] = E('div', { 'class': 'cbi-progressbar', 'title': storage[5], 'style': 'min-width:8em !important' }, E('div', { 'style': 'width:' + storage[5] }))
|
||
//storage[5] = E('div', { 'class': 'cbi-progressbar', 'title': storage[3] + ' / ' + storage[2] + ' (' + storage[5] + ')', 'style': 'min-width:8em !important' }, [
|
||
// E('div', { 'style': 'width:' + storage[5] })
|
||
//]);
|
||
rows.push(storage);
|
||
};
|
||
|
||
cbi_update_table(table, rows, E('em', _('<span style=\'color:red;font-weight:bold\'>Device not exist or mount point in the wrong location<span/>')));
|
||
return E('div', { 'class': 'cbi-section cbi-tblsection' }, [
|
||
E('h3', _('Storage Device')), table ]);
|
||
}, o, this);
|
||
|
||
s = m.section(form.GridSection, 'release', _('Mirror Releases'));
|
||
s.sortable = true;
|
||
s.anonymous = true;
|
||
s.addremove = true;
|
||
|
||
o = s.option(form.Value, 'name', _('Nick name'));
|
||
o.datatype = 'uciname';
|
||
o.rmempty = false;
|
||
o.validate = function(section_id, value) {
|
||
let ss = uci.sections(conf, release);
|
||
for (let i = 0; i < ss.length; i++) {
|
||
let sid = ss[i]['.name'];
|
||
if (sid == section_id)
|
||
continue;
|
||
if (value == uci.get(conf, sid, 'name'))
|
||
return _('The Nick name is already used');
|
||
};
|
||
|
||
return true;
|
||
};
|
||
|
||
o = s.option(form.Flag, 'enabled', _('Enable'));
|
||
o.default = o.enabled;
|
||
o.editable = true;
|
||
o.rmempty = false;
|
||
|
||
o = s.option(form.Button, '_getinfo', _('Get Option Info'));
|
||
o.modalonly = true;
|
||
o.write = function() {};
|
||
o.onclick = function() {
|
||
return fs.exec_direct('/etc/init.d/packagesync', ['getinfo'])
|
||
.then((res) => { return window.location.reload() })
|
||
.catch((e) => { ui.addNotification(null, E('p', e.message), 'error') });
|
||
};
|
||
|
||
o = s.option(form.Value, 'version', _('Version'));
|
||
o.rmempty = false;
|
||
|
||
if (releaseslist.length) {
|
||
for (let i = 0; i < releaseslist.length; i++)
|
||
o.value(releaseslist[i]);
|
||
};
|
||
|
||
o = s.option(form.Value, 'target', _('Target'));
|
||
o.placeholder = 'x86/64';
|
||
o.rmempty = false;
|
||
|
||
if (targetslist.length) {
|
||
for (let i = 0; i < targetslist.length; i++)
|
||
o.value(targetslist[i]);
|
||
};
|
||
|
||
o = s.option(form.Flag, 'extra', _('Supplementary Files'));
|
||
o.default = o.disabled;
|
||
o.rmempty = false;
|
||
o.modalonly = true;
|
||
|
||
o = s.option(form.Value, 'pkgarch', _('Arch'));
|
||
o.rmempty = false;
|
||
|
||
if (pkgarchslist.length) {
|
||
for (let i = 0; i < pkgarchslist.length; i++)
|
||
o.value(pkgarchslist[i]);
|
||
};
|
||
|
||
o = s.option(form.Value, 'model', _('Product model'));
|
||
o.rmempty = true;
|
||
|
||
o = s.option(form.DummyValue, 'return', _('Last exec result'));
|
||
o.readonly = true;
|
||
|
||
o = s.option(form.DummyValue, '_return_log', _('Last Error log'));
|
||
o.editable = true;
|
||
o.readonly = true;
|
||
//o.rawhtml = true;
|
||
//o.modalonly = true;
|
||
o.cfgvalue = function(section_id) {
|
||
let href = uci.get('packagesync', '@packagesync[0]', 'home_url');
|
||
let result = uci.get('packagesync', section_id, 'name');
|
||
return E('span', { 'style': 'font-weight:bold' }, [ E('a', { 'href': '/' + href + '/results/' + result + '.log', 'target': '_blank' }, _('Click to view')) ]);
|
||
};
|
||
|
||
return m.render()
|
||
.then(L.bind(function(m, nodes) {
|
||
poll.add(L.bind(function() {
|
||
return Promise.all([
|
||
getServiceStatus()
|
||
]).then(L.bind(this.poll_status, this, nodes));
|
||
}, this), 3);
|
||
return nodes;
|
||
}, this, m));
|
||
}
|
||
});
|