mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-07-28 09:22:05 +08:00
2051 lines
59 KiB
JavaScript
2051 lines
59 KiB
JavaScript
'use strict';
|
|
'require baseclass';
|
|
'require form';
|
|
'require fs';
|
|
'require poll';
|
|
'require rpc';
|
|
'require uci';
|
|
'require ui';
|
|
'require view';
|
|
'require tools.widgets as widgets'
|
|
|
|
document.head.append(E('style', {'type': 'text/css'},
|
|
`
|
|
:root {
|
|
--app-id-font-color: #454545;
|
|
--app-id-font-shadow: #fff;
|
|
--app-id-connected-color: #6bdebb;
|
|
--app-id-disconnected-color: #f8aeba;
|
|
--app-id-undefined-color: #dfdfdf;
|
|
}
|
|
:root[data-darkmode="true"] {
|
|
--app-id-font-color: #f6f6f6;
|
|
--app-id-font-shadow: #4d4d4d;
|
|
--app-id-connected-color: #005F20;
|
|
--app-id-disconnected-color: #a93734;
|
|
--app-id-undefined-color: #4d4d4d;
|
|
}
|
|
.id-connected {
|
|
--on-color: var(--app-id-font-color);
|
|
background-color: var(--app-id-connected-color) !important;
|
|
border-color: var(--app-id-connected-color) !important;
|
|
color: var(--app-id-font-color) !important;
|
|
text-shadow: 0 1px 1px var(--app-id-font-shadow);
|
|
}
|
|
.id-disconnected {
|
|
--on-color: var(--app-id-font-color);
|
|
background-color: var(--app-id-disconnected-color) !important;
|
|
border-color: var(--app-id-disconnected-color) !important;
|
|
color: var(--app-id-font-color) !important;
|
|
text-shadow: 0 1px 1px var(--app-id-font-shadow);
|
|
}
|
|
.id-undefined {
|
|
--on-color: var(--app-id-font-color);
|
|
background-color: var(--app-id-undefined-color) !important;
|
|
border-color: var(--app-id-undefined-color) !important;
|
|
color: var(--app-id-font-color) !important;
|
|
text-shadow: 0 1px 1px var(--app-id-font-shadow);
|
|
}
|
|
.id-label-status {
|
|
display: inline-block;
|
|
word-wrap: break-word;
|
|
margin: 2px !important;
|
|
padding: 4px 8px;
|
|
border: 1px solid;
|
|
-webkit-border-radius: 4px;
|
|
-moz-border-radius: 4px;
|
|
border-radius: 4px;
|
|
font-weight: bold;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
}
|
|
`));
|
|
|
|
const btnStyleEnabled = 'btn cbi-button-save';
|
|
const btnStyleDisabled = 'btn cbi-button-reset';
|
|
const btnStyleApply = 'btn cbi-button-apply';
|
|
|
|
var Timefield = ui.Textfield.extend({
|
|
secToString(value) {
|
|
let string = '0';
|
|
if(/^\d+$/.test(value)) {
|
|
value = Number(value);
|
|
if(value >= 86400 && (value % 86400) == 0) {
|
|
string = String(value / 86400) + 'd';
|
|
}
|
|
else if(value >= 3600 && (value % 3600) == 0) {
|
|
string = String(value / 3600) + 'h';
|
|
}
|
|
else if(value >= 60 && (value % 60) == 0) {
|
|
string = String(value / 60) + 'm';
|
|
}
|
|
else {
|
|
string = String(value) + 's';
|
|
};
|
|
};
|
|
return string;
|
|
},
|
|
|
|
render() {
|
|
let frameEl = E('div', { 'id': this.options.id }),
|
|
inputEl = E('input', {
|
|
'id' : this.options.id ? 'widget.' + this.options.id : null,
|
|
'name' : this.options.name,
|
|
'type' : 'text',
|
|
'class' : 'cbi-input-text',
|
|
'readonly' : this.options.readonly ? '' : null,
|
|
'disabled' : this.options.disabled ? '' : null,
|
|
'maxlength' : this.options.maxlength,
|
|
'placeholder': this.options.placeholder,
|
|
'value' : this.secToString(this.value),
|
|
});
|
|
frameEl.appendChild(inputEl);
|
|
return this.bind(frameEl);
|
|
},
|
|
|
|
getValue() {
|
|
let rawValue = this.node.querySelector('input').value,
|
|
value = 0,
|
|
res = rawValue.match(/^(\d+)([dhms]?)$/);
|
|
if(res) {
|
|
if(res[2] == 'd') {
|
|
value = Number(res[1]) * 86400;
|
|
}
|
|
else if(res[2] == 'h') {
|
|
value = Number(res[1]) * 3600;
|
|
}
|
|
else if(res[2] == 'm') {
|
|
value = Number(res[1]) * 60;
|
|
}
|
|
else if(!res[2] || res[2] == 's') {
|
|
value = Number(res[1]);
|
|
}
|
|
else {
|
|
value = 0;
|
|
};
|
|
} else {
|
|
value = 0;
|
|
};
|
|
return String(value);
|
|
},
|
|
|
|
setValue(value) {
|
|
let inputEl = this.node.querySelector('input');
|
|
inputEl.value = this.secToString(value);
|
|
},
|
|
});
|
|
|
|
var TextfieldButton = ui.Textfield.extend({
|
|
render() {
|
|
let frameEl = E('div', { 'id': this.options.id }),
|
|
inputEl = E('input', {
|
|
'id' : this.options.id ? 'widget.' + this.options.id : null,
|
|
'name' : this.options.name,
|
|
'type' : 'text',
|
|
'class' : 'cbi-input-text',
|
|
'readonly' : this.options.readonly ? '' : null,
|
|
'disabled' : this.options.disabled ? '' : null,
|
|
'maxlength' : this.options.maxlength,
|
|
'placeholder': this.options.placeholder,
|
|
'value' : this.value,
|
|
});
|
|
frameEl.appendChild(E('div', { 'class': 'control-group' }, [
|
|
inputEl,
|
|
E('button', {
|
|
'class' : `cbi-button cbi-button-${this.options.btnstyle || 'neutral'}`,
|
|
'title' : this.options.btntitle,
|
|
'aria-label': this.options.btntitle,
|
|
'click' : this.options.onclick,
|
|
}, this.options.btntext,)
|
|
]));
|
|
return this.bind(frameEl);
|
|
},
|
|
});
|
|
|
|
return view.extend({
|
|
appName : 'internet-detector',
|
|
configDir : '/etc/internet-detector',
|
|
pollInterval : L.env.pollinterval,
|
|
appStatus : 'stoped',
|
|
initStatus : null,
|
|
inetStatus : null,
|
|
inetStatusArea : E('div', { 'class': 'cbi-value-field', 'id': 'inetStatusArea' }),
|
|
serviceStatusLabel : E('em', { 'id': 'serviceStatusLabel' }),
|
|
initButton : null,
|
|
currentAppMode : '0',
|
|
defaultHosts : [ '8.8.8.8', '1.1.1.1' ],
|
|
defaultURLs : [ 'https://www.google.com' ],
|
|
ledsPath : '/sys/class/leds',
|
|
ledsPerInstance : 3,
|
|
leds : [],
|
|
publicIPProviders : {
|
|
dns : [
|
|
{ name: 'opendns1', title: 'opendns1 (DNS)' },
|
|
{ name: 'opendns2', title: 'opendns2 (DNS)' },
|
|
{ name: 'opendns3', title: 'opendns3 (DNS)' },
|
|
{ name: 'opendns4', title: 'opendns4 (DNS)' },
|
|
{ name: 'google', title: 'google (DNS)' },
|
|
{ name: 'akamai', title: 'akamai (DNS)' },
|
|
],
|
|
http: [
|
|
{ name: 'akamai_http', title: 'akamai (HTTP)' },
|
|
{ name: 'amazonaws', title: 'amazonaws (HTTP)' },
|
|
{ name: 'wgetip', title: 'wgetip.com (HTTP)' },
|
|
{ name: 'ifconfig', title: 'ifconfig.me (HTTP)' },
|
|
{ name: 'ipecho', title: 'ipecho.net (HTTP)' },
|
|
{ name: 'canhazip', title: 'canhazip.com (HTTP)' },
|
|
{ name: 'icanhazip', title: 'icanhazip.com (HTTP)' },
|
|
],
|
|
},
|
|
mm : false,
|
|
mmInit : false,
|
|
email : false,
|
|
emailExec : false,
|
|
telegram : false,
|
|
curlExec : false,
|
|
modRegularScriptNextRun: {},
|
|
|
|
callInitStatus: rpc.declare({
|
|
object: 'luci',
|
|
method: 'getInitList',
|
|
params: [ 'name' ],
|
|
expect: { '': {} }
|
|
}),
|
|
|
|
callInitAction: rpc.declare({
|
|
object: 'luci',
|
|
method: 'setInitAction',
|
|
params: [ 'name', 'action' ],
|
|
expect: { result: false }
|
|
}),
|
|
|
|
getInitStatus() {
|
|
return this.callInitStatus(this.appName).then(res => {
|
|
if(res) {
|
|
return res[this.appName].enabled;
|
|
} else {
|
|
throw _('Command failed');
|
|
}
|
|
}).catch(e => {
|
|
ui.addNotification(null,
|
|
E('p', _('Failed to get %s init status: %s').format(this.appName, e)));
|
|
});
|
|
},
|
|
|
|
handleServiceAction(action) {
|
|
return this.callInitAction(this.appName, action).then(success => {
|
|
if(!success) {
|
|
throw _('Command failed');
|
|
};
|
|
return true;
|
|
}).catch(e => {
|
|
ui.addNotification(null,
|
|
E('p', _('Service action failed "%s %s": %s').format(this.appName, action, e)));
|
|
});
|
|
},
|
|
|
|
callInit: rpc.declare({
|
|
object: 'luci.internet-detector',
|
|
method: 'Init',
|
|
expect: { '': {} }
|
|
}),
|
|
|
|
getInit() {
|
|
return this.callInit().then(data => {
|
|
return data;
|
|
});
|
|
},
|
|
|
|
callUIPoll: rpc.declare({
|
|
object: 'luci.internet-detector',
|
|
method: 'UIPoll',
|
|
expect: { '': {} }
|
|
}),
|
|
|
|
getUIPoll() {
|
|
return this.callUIPoll().then(data => {
|
|
return data;
|
|
});
|
|
},
|
|
|
|
callStatus: rpc.declare({
|
|
object: 'luci.internet-detector',
|
|
method: 'Status',
|
|
expect: { '': {} }
|
|
}),
|
|
|
|
getStatus() {
|
|
return this.callStatus().then(data => {
|
|
return data;
|
|
});
|
|
},
|
|
|
|
callInetStatus: rpc.declare({
|
|
object: 'luci.internet-detector',
|
|
method: 'InetStatus',
|
|
expect: { '': {} }
|
|
}),
|
|
|
|
getInetStatus() {
|
|
return this.callInetStatus().then(data => {
|
|
return data;
|
|
});
|
|
},
|
|
|
|
callTgChatId: rpc.declare({
|
|
object: 'luci.internet-detector-mod-telegram',
|
|
method: 'GetTgChatId',
|
|
params: [ 'botToken', 'proxyType', 'proxyHost', 'proxyPort', 'proxyUser', 'proxyPasswd', 'iface' ],
|
|
expect: { '': {} }
|
|
}),
|
|
|
|
getTgChatId(botToken, proxyType, proxyHost, proxyPort, proxyUser, proxyPasswd, iface) {
|
|
return this.callTgChatId(
|
|
botToken, proxyType, proxyHost, proxyPort, proxyUser, proxyPasswd, iface).then(data => {
|
|
return data;
|
|
});
|
|
},
|
|
|
|
setInternetStatus() {
|
|
this.inetStatusArea.innerHTML = '';
|
|
|
|
if(!this.inetStatus || !this.inetStatus.instances || this.inetStatus.instances.length == 0) {
|
|
let label = E('span', { 'class': 'id-label-status id-undefined' }, _('Undefined'));
|
|
if((this.currentAppMode == '1' && this.appStatus != 'stoped') || this.currentAppMode == '2') {
|
|
label.classList.add('spinning');
|
|
};
|
|
this.inetStatusArea.append(label);
|
|
} else {
|
|
this.inetStatus.instances.sort((a, b) => a.num - b.num);
|
|
for(let i of this.inetStatus.instances) {
|
|
let status = _('Disconnected');
|
|
let className = 'id-label-status id-disconnected';
|
|
if(i.inet == 0) {
|
|
status = _('Connected');
|
|
className = 'id-label-status id-connected';
|
|
}
|
|
else if(i.inet == -1) {
|
|
status = _('Undefined');
|
|
className = 'id-label-status id-undefined spinning';
|
|
};
|
|
|
|
let publicIp = (i.mod_public_ip !== undefined) ?
|
|
' | %s: %s'.format(_('Public IP'), (i.mod_public_ip == '') ? _('Undefined') : _(i.mod_public_ip))
|
|
: '';
|
|
|
|
this.inetStatusArea.append(
|
|
E('span', { 'class': className }, '%s%s%s'.format(
|
|
i.instance + ': ', status, publicIp)
|
|
)
|
|
);
|
|
|
|
if(i.mod_regular_script) {
|
|
this.modRegularScriptNextRun[i.instance] = i.mod_regular_script;
|
|
let nextRunLabel = document.getElementById('id_next_run_' + i.instance);
|
|
if(nextRunLabel) {
|
|
if(this.appStatus == 'running') {
|
|
nextRunLabel.innerHTML = this.modRegularScriptNextRun[i.instance];
|
|
} else {
|
|
nextRunLabel.innerHTML = _('Not scheduled');
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
if(this.appStatus == 'running') {
|
|
this.serviceStatusLabel.textContent = _('Running');
|
|
} else {
|
|
this.serviceStatusLabel.textContent = _('Stopped');
|
|
};
|
|
},
|
|
|
|
servicePoll() {
|
|
return Promise.all([
|
|
this.getStatus(),
|
|
this.getInetStatus(),
|
|
]).then(stat => {
|
|
this.appStatus = stat[0].status;
|
|
this.inetStatus = stat[1];
|
|
this.setInternetStatus();
|
|
}).catch(e => {
|
|
this.appStatus = 'stoped';
|
|
this.inetStatus = {};
|
|
});
|
|
},
|
|
|
|
uiPoll() {
|
|
return this.getUIPoll().then(status => {
|
|
this.inetStatus = status;
|
|
this.setInternetStatus();
|
|
});
|
|
},
|
|
|
|
serviceRestart() {
|
|
return this.handleServiceAction('restart');
|
|
},
|
|
|
|
serviceRestartHandler() {
|
|
poll.stop();
|
|
return this.serviceRestart().then(() => {
|
|
window.setTimeout(() => this.servicePoll(), 1000);
|
|
poll.start();
|
|
});
|
|
},
|
|
|
|
getTgChatIdHandler(ev, instance) {
|
|
ev.preventDefault();
|
|
|
|
let botToken;
|
|
let botTokenInput = document.getElementById(
|
|
'widget.cbid.%s.%s.mod_telegram_api_token'.format(this.appName, instance));
|
|
if(botTokenInput) {
|
|
botToken = botTokenInput.value;
|
|
};
|
|
if(!botTokenInput || !botToken) {
|
|
alert(_('Bot API token is missing!'));
|
|
return;
|
|
};
|
|
let proxyType = '';
|
|
let proxyTypeInput = document.getElementById(
|
|
'widget.cbid.%s.%s.mod_telegram_proxy_type'.format(this.appName, instance));
|
|
if(proxyTypeInput) {
|
|
proxyType = proxyTypeInput.value;
|
|
};
|
|
let proxyHost = '';
|
|
let proxyHostInput = document.getElementById(
|
|
'widget.cbid.%s.%s.mod_telegram_proxy_host'.format(this.appName, instance));
|
|
if(proxyHostInput) {
|
|
proxyHost = proxyHostInput.value;
|
|
};
|
|
let proxyPort = '';
|
|
let proxyPortInput = document.getElementById(
|
|
'widget.cbid.%s.%s.mod_telegram_proxy_port'.format(this.appName, instance));
|
|
if(proxyPortInput) {
|
|
proxyPort = proxyPortInput.value;
|
|
};
|
|
let proxyUser = '';
|
|
let proxyUserInput = document.getElementById(
|
|
'widget.cbid.%s.%s.mod_telegram_proxy_user'.format(this.appName, instance));
|
|
if(proxyUserInput) {
|
|
proxyUser = proxyUserInput.value;
|
|
};
|
|
let proxyPasswd = '';
|
|
let proxyPasswdInput = document.getElementById(
|
|
'widget.cbid.%s.%s.mod_telegram_proxy_passwd'.format(this.appName, instance));
|
|
if(proxyPasswdInput) {
|
|
proxyPasswd = proxyPasswdInput.value;
|
|
};
|
|
let iface = '';
|
|
let ifaceInput = document.getElementById(
|
|
'cbid.%s.%s.mod_telegram_iface'.format(this.appName, instance));
|
|
if(ifaceInput) {
|
|
let li = ifaceInput.querySelector('li[selected]');
|
|
if(li) {
|
|
iface = li.dataset.value || '';
|
|
};
|
|
};
|
|
|
|
return this.getTgChatId(botToken, proxyType, proxyHost, proxyPort, proxyUser, proxyPasswd, iface).then(r => {
|
|
if(r.ok) {
|
|
if(r.chatId) {
|
|
let tgChatIdInput = document.getElementById(
|
|
'widget.cbid.%s.%s.mod_telegram_chat_id'.format(this.appName, instance));
|
|
if(tgChatIdInput) {
|
|
if(r.chatId.length == 0) {
|
|
alert(_('No messages available. Write something to the bot and try again.'));
|
|
} else {
|
|
tgChatIdInput.value = r.chatId[r.chatId.length - 1];
|
|
tgChatIdInput.focus();
|
|
tgChatIdInput.blur();
|
|
};
|
|
};
|
|
};
|
|
} else {
|
|
let errCode = r.errCode;
|
|
let errorString = `${_('Error')} ${errCode}.`;
|
|
if(errCode == 401 || errCode == 404) {
|
|
errorString += ` ${_('Incorrect bot token?')}`;
|
|
} else {
|
|
errorString += ` ${r.errDesc}.`;
|
|
}
|
|
alert(errorString);
|
|
};
|
|
}).catch(e => {
|
|
alert(e.message);
|
|
throw e;
|
|
});
|
|
},
|
|
|
|
validateUrl(section, value) {
|
|
return (/^$|^https?:\/\/([\w.-]+|\[[a-fA-F0-9:.]+\])(:[0-9]{2,5})?((\/|\?).*)?$/.test(value)) ?
|
|
true : _('Expecting:') + ` ${_('valid URL')}\n`;
|
|
},
|
|
|
|
CBITimeInput: form.Value.extend({
|
|
__name__ : 'CBI.TimeInput',
|
|
|
|
renderWidget(section_id, option_index, cfgvalue) {
|
|
let value = (cfgvalue != null) ? cfgvalue : this.default,
|
|
widget = new Timefield(value, {
|
|
id : this.cbid(section_id),
|
|
optional : this.optional || this.rmempty,
|
|
maxlength : 3,
|
|
placeholder: _('Type a time string'),
|
|
validate : L.bind(
|
|
function(section, value) {
|
|
return (/^$|^\d+[dhms]?$/.test(value)) ? true : _('Expecting:') +
|
|
` ${_('One of the following:')}\n - ${_('days')}: 1d\n - ${_('hours')}: 2h\n - ${_('minutes')}: 10m\n - ${_('seconds')}: 30s\n`;
|
|
},
|
|
this,
|
|
section_id
|
|
),
|
|
disabled : (this.readonly != null) ? this.readonly : this.map.readonly,
|
|
});
|
|
return widget.render();
|
|
},
|
|
}),
|
|
|
|
CBITextfieldButtonInput: form.Value.extend({
|
|
__name__ : 'CBI.TextfieldButtonInput',
|
|
|
|
renderWidget(section_id, option_index, cfgvalue) {
|
|
let value = (cfgvalue != null) ? cfgvalue : this.default,
|
|
widget = new TextfieldButton(value, {
|
|
id : this.cbid(section_id),
|
|
optional : this.optional || this.rmempty,
|
|
datatype : this.datatype,
|
|
placeholder: this.placeholder,
|
|
validate : L.bind(this.validate, this, section_id),
|
|
disabled : (this.readonly != null) ? this.readonly : this.map.readonly,
|
|
btntext : this.btntext,
|
|
btntitle : this.btntitle,
|
|
btnstyle : this.btnstyle,
|
|
onclick : this.onclick,
|
|
});
|
|
return widget.render();
|
|
},
|
|
}),
|
|
|
|
CBIBlockInetStatus: form.Value.extend({
|
|
__name__ : 'CBI.BlockInetStatus',
|
|
|
|
__init__(map, section, ctx) {
|
|
this.map = map;
|
|
this.section = section;
|
|
this.ctx = ctx;
|
|
this.optional = true;
|
|
this.rmempty = true;
|
|
},
|
|
|
|
renderWidget(section_id, option_index, cfgvalue) {
|
|
this.ctx.setInternetStatus();
|
|
|
|
return E([
|
|
E('label', { 'class': 'cbi-value-title', 'for': 'inetStatusArea' },
|
|
_('Internet status')
|
|
), this.ctx.inetStatusArea
|
|
])
|
|
},
|
|
}),
|
|
|
|
CBIBlockServiceStatus: form.Value.extend({
|
|
__name__ : 'CBI.BlockServiceStatus',
|
|
|
|
__init__(map, section, ctx) {
|
|
this.map = map;
|
|
this.section = section;
|
|
this.ctx = ctx;
|
|
this.optional = true;
|
|
this.rmempty = true;
|
|
},
|
|
|
|
renderWidget(section_id, option_index, cfgvalue) {
|
|
return E([
|
|
E('label', { 'class': 'cbi-value-title', 'for': 'serviceStatusLabel' },
|
|
_('Service')
|
|
),
|
|
E('div', { 'class': 'cbi-value-field' },
|
|
this.ctx.serviceStatusLabel
|
|
),
|
|
]);
|
|
},
|
|
}),
|
|
|
|
CBIBlockInitButton: form.Value.extend({
|
|
__name__ : 'CBI.BlockInitButton',
|
|
|
|
__init__(map, section, ctx) {
|
|
this.map = map;
|
|
this.section = section;
|
|
this.ctx = ctx;
|
|
this.optional = true;
|
|
this.rmempty = true;
|
|
},
|
|
|
|
renderWidget(section_id, option_index, cfgvalue) {
|
|
this.ctx.initButton = E('button', {
|
|
'class': (!this.ctx.initStatus) ? btnStyleDisabled : btnStyleEnabled,
|
|
'click': ui.createHandlerFn(this, () => {
|
|
return this.ctx.handleServiceAction(
|
|
(!this.ctx.initStatus) ? 'enable' : 'disable'
|
|
).then(success => {
|
|
if(!success) {
|
|
return;
|
|
};
|
|
if(!this.ctx.initStatus) {
|
|
this.ctx.initButton.textContent = _('Enabled');
|
|
this.ctx.initButton.className = btnStyleEnabled;
|
|
this.ctx.initStatus = true;
|
|
}
|
|
else {
|
|
this.ctx.initButton.textContent = _('Disabled');
|
|
this.ctx.initButton.className = btnStyleDisabled;
|
|
this.ctx.initStatus = false;
|
|
};
|
|
});
|
|
}),
|
|
}, (!this.ctx.initStatus) ? _('Disabled') : _('Enabled'));
|
|
|
|
return E( [
|
|
E('label', { 'class': 'cbi-value-title', 'for': 'initButton' },
|
|
_('Run service at startup')
|
|
),
|
|
E('div', { 'class': 'cbi-value-field' }, [
|
|
E('div', {}, this.ctx.initButton),
|
|
E('input', {
|
|
'id' : 'initButton',
|
|
'type': 'hidden',
|
|
}),
|
|
]),
|
|
]);
|
|
},
|
|
}),
|
|
|
|
CBIBlockFileEdit: form.Value.extend({
|
|
__name__ : 'CBI.BlockFileEdit',
|
|
|
|
__init__(map, section, ctx, id, file, title, description, callback) {
|
|
this.map = map;
|
|
this.section = section;
|
|
this.ctx = ctx;
|
|
this.id = id,
|
|
this.optional = true;
|
|
this.rmempty = true;
|
|
this.file = file;
|
|
this.title = title;
|
|
this.description = description;
|
|
this.callback = callback;
|
|
this.content = '';
|
|
},
|
|
|
|
cfgvalue(section_id, option) {
|
|
return this.content;
|
|
},
|
|
|
|
formvalue(section_id) {
|
|
let value = this.content;
|
|
let textarea = document.getElementById('widget.file_edit.content.' + this.id);
|
|
if(textarea) {
|
|
value = textarea.value.trim().replace(/\r\n/g, '\n') + '\n';
|
|
};
|
|
return value;
|
|
},
|
|
|
|
write(section_id, formvalue) {
|
|
return fs.write(this.file, formvalue).then(rc => {
|
|
ui.addNotification(null, E('p', _('Contents have been saved.')),
|
|
'info');
|
|
if(this.callback) {
|
|
return this.callback(rc);
|
|
};
|
|
}).catch(e => {
|
|
ui.addNotification(null, E('p', _('Unable to save the contents')
|
|
+ ': %s'.format(e.message)));
|
|
});
|
|
},
|
|
|
|
load() {
|
|
return L.resolveDefault(fs.read(this.file), '').then(c => {
|
|
this.content = c;
|
|
});
|
|
},
|
|
|
|
renderWidget(section_id, option_index, cfgvalue) {
|
|
return E('textarea', {
|
|
'id' : 'widget.file_edit.content.' + this.id,
|
|
'class' : 'cbi-input-textarea',
|
|
'style' : 'width:100% !important',
|
|
'rows' : 10,
|
|
'wrap' : 'off',
|
|
'spellcheck': 'false',
|
|
}, cfgvalue);
|
|
},
|
|
}),
|
|
|
|
load() {
|
|
return Promise.all([
|
|
this.getStatus(),
|
|
this.getInitStatus(),
|
|
L.resolveDefault(fs.list(this.ledsPath), []),
|
|
this.getInit(),
|
|
uci.load(this.appName),
|
|
]).catch(e => {
|
|
ui.addNotification(
|
|
null, E('p', _('An error has occurred') + ': %s'.format(e.message)));
|
|
});
|
|
},
|
|
|
|
render(data) {
|
|
if(!data) {
|
|
return;
|
|
};
|
|
this.appStatus = (data[0].code == 0) ? data[0].stdout.trim() : null;
|
|
this.initStatus = data[1];
|
|
this.leds = data[2];
|
|
if(data[3]) {
|
|
if(data[3].mm_mod) {
|
|
this.mm = true;
|
|
};
|
|
if(data[3].mm_init) {
|
|
this.mmInit = true;
|
|
};
|
|
if(data[3].email_mod) {
|
|
this.email = true;
|
|
};
|
|
if(data[3].email_exec) {
|
|
this.emailExec = true;
|
|
};
|
|
if(data[3].telegram) {
|
|
this.telegram = true;
|
|
};
|
|
if(data[3].curl_exec) {
|
|
this.curlExec = true;
|
|
};
|
|
};
|
|
this.currentAppMode = uci.get(this.appName, 'config', 'mode');
|
|
|
|
let s, o, ss;
|
|
let m = new form.Map(this.appName,
|
|
_('Internet Detector'),
|
|
_('Checking Internet availability.'));
|
|
|
|
|
|
/* Status widget */
|
|
|
|
s = m.section(form.NamedSection, 'config', 'main');
|
|
o = s.option(this.CBIBlockInetStatus, this);
|
|
|
|
|
|
s = m.section(form.NamedSection, 'config', 'main');
|
|
|
|
|
|
/* Service widget */
|
|
|
|
if(this.currentAppMode == '1') {
|
|
o = s.option(this.CBIBlockServiceStatus, this);
|
|
|
|
// restart button
|
|
o = s.option(form.Button,
|
|
'_restart_btn', _('Restart service')
|
|
);
|
|
o.onclick = () => this.serviceRestartHandler();
|
|
o.inputtitle = _('Restart');
|
|
o.inputstyle = btnStyleApply;
|
|
|
|
// init button
|
|
o = s.option(this.CBIBlockInitButton, this);
|
|
};
|
|
|
|
|
|
/* Main settings */
|
|
|
|
// mode
|
|
let mode = s.option(form.ListValue, 'mode',
|
|
_('Internet detector mode'));
|
|
mode.value('0', _('Disabled'));
|
|
mode.value('1', _('Service'));
|
|
mode.value('2', _('Web UI only (UI detector)'));
|
|
mode.description = '%s<br />%s<br />%s'.format(
|
|
_('Disabled: detector is completely off.'),
|
|
_('Service: detector always runs as a system service.'),
|
|
_('Web UI only: detector works only when the Web UI is open (UI detector).')
|
|
);
|
|
mode.default = '0';
|
|
|
|
|
|
/* Instances configuration */
|
|
|
|
if(this.currentAppMode != '2') {
|
|
|
|
// logging_level
|
|
o = s.option(form.ListValue, 'logging_level',
|
|
_('Logging'),
|
|
_('Log event level.')
|
|
);
|
|
o.value(-1, _('Disabled'));
|
|
o.value(3, _('Error'));
|
|
o.value(4, _('Warning'));
|
|
o.value(5, _('Notice'));
|
|
o.value(6, _('Info'));
|
|
o.value(7, _('Debug'));
|
|
o.rmempty = false;
|
|
o.default = '6';
|
|
};
|
|
|
|
s = m.section(form.GridSection, 'instance');
|
|
|
|
s.title = _('Instances');
|
|
s.addremove = true;
|
|
s.sortable = true;
|
|
s.nodescriptions = true;
|
|
s.addbtntitle = _('Add instance');
|
|
|
|
s.tab('main', _('Main settings'));
|
|
|
|
function makeIntervalOptions(list) {
|
|
list.value(2, '2 ' + _('sec'));
|
|
list.value(5, '5 ' + _('sec'));
|
|
list.value(10, '10 ' + _('sec'));
|
|
list.value(15, '15 ' + _('sec'));
|
|
list.value(20, '20 ' + _('sec'));
|
|
list.value(25, '25 ' + _('sec'));
|
|
list.value(30, '30 ' + _('sec'));
|
|
list.value(60, '1 ' + _('min'));
|
|
list.value(120, '2 ' + _('min'));
|
|
list.value(300, '5 ' + _('min'));
|
|
list.value(600, '10 ' + _('min'));
|
|
}
|
|
|
|
function makeTimerDelayOptions(list) {
|
|
list.value(25, '25 ' + _('msec'));
|
|
list.value(50, '50 ' + _('msec'));
|
|
list.value(100, '100 ' + _('msec'));
|
|
list.value(250, '250 ' + _('msec'));
|
|
list.value(500, '500 ' + _('msec'));
|
|
list.value(750, '750 ' + _('msec'));
|
|
list.value(1000, '1 ' + _('sec'));
|
|
list.value(1500, '1.5 ' + _('sec'));
|
|
list.value(2000, '2 ' + _('sec'));
|
|
}
|
|
|
|
// description
|
|
o = s.taboption('main', form.Value, 'description',
|
|
_("Description"));
|
|
o.datatype = 'maxlength(30)';
|
|
o.modalonly = null;
|
|
|
|
// hosts
|
|
o = s.taboption('main', form.DynamicList,
|
|
'hosts', _('Hosts'),
|
|
_('Hosts for checking Internet availability. Hosts are polled (in list order) until at least one responds.')
|
|
);
|
|
o.datatype = 'or(host,hostport,ipaddrport(1))';
|
|
o.default = this.defaultHosts;
|
|
o.depends({ check_type: '0' });
|
|
o.depends({ check_type: '1' });
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
if(this.curlExec) {
|
|
|
|
// urls
|
|
o = s.taboption('main', form.DynamicList,
|
|
'urls', _('URLs'),
|
|
_('URLs for checking Internet availability. URLs are polled (in list order) until at least one returns HTTP status code 200.')
|
|
);
|
|
o.validate = this.validateUrl;
|
|
o.default = this.defaultURLs;
|
|
o.rmempty = false;
|
|
o.depends({ check_type: '2' });
|
|
o.modalonly = true;
|
|
};
|
|
|
|
// check_type
|
|
o = s.taboption('main', form.ListValue,
|
|
'check_type', _('Check type'),
|
|
_('Host availability check type.') + '<br />' +
|
|
((this.curlExec) ? '' :
|
|
_('To support URL checking, you need to install curl.'))
|
|
);
|
|
o.value(1, _('ICMP-echo request (ping)'));
|
|
o.value(0, _('TCP port connection'));
|
|
if(this.curlExec) {
|
|
o.value(2, _('URL test (HTTP)'));
|
|
};
|
|
o.default = '0';
|
|
o.modalonly = true;
|
|
|
|
// tcp_port
|
|
o = s.taboption('main', form.Value,
|
|
'tcp_port', _('TCP port'),
|
|
_('Default port value for TCP connections.')
|
|
);
|
|
o.datatype = 'port';
|
|
o.default = '53';
|
|
o.depends({ check_type: '0' });
|
|
o.modalonly = true;
|
|
|
|
// icmp_packet_size
|
|
o = s.taboption('main', form.ListValue,
|
|
'icmp_packet_size', _('ICMP packet data size'));
|
|
o.value(1, _('Small: 1 byte'));
|
|
o.value(32, _('Windows: 32 bytes'));
|
|
o.value(56, _('Standard: 56 bytes'));
|
|
o.value(248, _('Big: 248 bytes'));
|
|
o.value(1492, _('Huge: 1492 bytes'));
|
|
o.value(9000, _('Jumbo: 9000 bytes'));
|
|
o.default = '56';
|
|
o.depends({ check_type: '1' });
|
|
o.modalonly = true;
|
|
|
|
if(this.curlExec) {
|
|
|
|
// proxy_type
|
|
o = s.taboption('main', form.ListValue,
|
|
'proxy_type', _('Proxy')
|
|
);
|
|
o.value('', _('Disabled'));
|
|
o.value('http');
|
|
o.value('socks4');
|
|
o.value('socks4a');
|
|
o.value('socks5');
|
|
o.value('socks5h');
|
|
o.default = '';
|
|
o.depends({ check_type: '2' });
|
|
o.modalonly = true;
|
|
|
|
// proxy_host
|
|
o = s.taboption('main', form.Value,
|
|
'proxy_host', _('Proxy host')
|
|
);
|
|
o.datatype = 'host';
|
|
o.rmempty = false;
|
|
o.depends({ proxy_type: /.+/ });
|
|
o.modalonly = true;
|
|
|
|
// proxy_port
|
|
o = s.taboption('main', form.Value,
|
|
'proxy_port', _('Proxy port')
|
|
);
|
|
o.datatype = 'port';
|
|
o.rmempty = false;
|
|
o.depends({ proxy_type: /.+/ });
|
|
o.modalonly = true;
|
|
|
|
// proxy_user
|
|
o = s.taboption('main', form.Value,
|
|
'proxy_user', _('Proxy user')
|
|
);
|
|
o.depends({ proxy_type: /(http|socks5h?)/ });
|
|
o.modalonly = true;
|
|
|
|
// proxy_passwd
|
|
o = s.taboption('main', form.Value,
|
|
'proxy_passwd', _('Proxy password')
|
|
);
|
|
o.depends({ proxy_type: /(http|socks5h?)/ });
|
|
o.modalonly = true;
|
|
o.password = true;
|
|
};
|
|
|
|
// iface
|
|
o = s.taboption('main', widgets.DeviceSelect,
|
|
'iface', _('Device'),
|
|
_('Network device for Internet access. If not specified, the default device is used.')
|
|
);
|
|
o.noaliases = true;
|
|
o.modalonly = true;
|
|
|
|
// interval_up
|
|
o = s.taboption('main', form.ListValue,
|
|
'interval_up', _('Alive interval'),
|
|
_('Hosts polling interval when the Internet is up.')
|
|
);
|
|
o.default = '30';
|
|
o.modalonly = true;
|
|
makeIntervalOptions(o);
|
|
|
|
// interval_down
|
|
o = s.taboption('main', form.ListValue,
|
|
'interval_down', _('Dead interval'),
|
|
_('Hosts polling interval when the Internet is down.')
|
|
);
|
|
o.default = '5';
|
|
o.modalonly = true;
|
|
makeIntervalOptions(o);
|
|
|
|
// connection_attempts
|
|
o = s.taboption('main', form.ListValue,
|
|
'connection_attempts', _('Connection attempts'),
|
|
_('Maximum number of attempts to connect to each host.')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(1);
|
|
o.value(2);
|
|
o.value(3);
|
|
o.default = '2';
|
|
|
|
// connection_timeout
|
|
o = s.taboption('main', form.ListValue,
|
|
'connection_timeout', _('Connection timeout'),
|
|
_('Maximum timeout for waiting for a response from the host.')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(1, '1 ' + _('sec'));
|
|
o.value(2, '2 ' + _('sec'));
|
|
o.value(3, '3 ' + _('sec'));
|
|
o.value(4, '4 ' + _('sec'));
|
|
o.value(5, '5 ' + _('sec'));
|
|
o.value(6, '6 ' + _('sec'));
|
|
o.value(7, '7 ' + _('sec'));
|
|
o.value(8, '8 ' + _('sec'));
|
|
o.value(9, '9 ' + _('sec'));
|
|
o.value(10, '10 ' + _('sec'));
|
|
o.default = '2';
|
|
|
|
// enabled
|
|
o = s.taboption('main', form.Flag, 'enabled',
|
|
_('Enabled'),
|
|
);
|
|
o.rmempty = false;
|
|
o.default = '1';
|
|
o.editable = true;
|
|
o.modalonly = false;
|
|
|
|
|
|
/* Modules */
|
|
|
|
if(this.currentAppMode != '2') {
|
|
s.tab('led_control', _('LED control'));
|
|
s.tab('reboot_device', _('Reboot device'));
|
|
s.tab('restart_network', _('Restart network'));
|
|
if(this.mm) {
|
|
s.tab('restart_modem', _('Restart modem'));
|
|
};
|
|
};
|
|
|
|
s.tab('public_ip', _('Public IP address'));
|
|
|
|
if(this.currentAppMode != '2') {
|
|
if(this.email) {
|
|
s.tab('email', _('Email notification'));
|
|
};
|
|
if(this.telegram) {
|
|
s.tab('telegram', _('Telegram notification'));
|
|
};
|
|
s.tab('user_scripts', _('User scripts'));
|
|
s.tab('regular_script', _('Regular script'));
|
|
};
|
|
|
|
s.addModalOptions = (s, section_id, ev) => {
|
|
|
|
if(section_id == 'config') {
|
|
s.map.children = [];
|
|
s.map.readonly = true;
|
|
s.map.children.push(new form.NamedSection(s.map, '_dummy', '_dummy',
|
|
_('Error!'), _('Invalid instance name...')));
|
|
return;
|
|
};
|
|
|
|
if(this.currentAppMode != '2') {
|
|
|
|
// LED control
|
|
|
|
o = s.taboption('led_control', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<div class="cbi-section-descr">' +
|
|
_('<abbr title="Light Emitting Diode">LED</abbr> indicates the Internet status.') +
|
|
'</div>';
|
|
o.modalonly = true;
|
|
|
|
if(this.leds.length > 0) {
|
|
this.leds.sort((a, b) => (a.name > b.name) ? 1 : (a.name < b.name) ? -1 : 0);
|
|
|
|
// enabled
|
|
o = s.taboption('led_control', form.Flag,
|
|
'mod_led_control_enabled',
|
|
_('Enabled'));
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
o = s.taboption('led_control', form.SectionValue,
|
|
s.section, form.NamedSection, s.section);
|
|
o.depends({ mod_led_control_enabled: '1' });
|
|
ss = o.subsection;
|
|
|
|
for(let i = 1; i <= this.ledsPerInstance; i++) {
|
|
ss.tab('led' + i + '_tab', _('LED') + ' ' + i);
|
|
|
|
// led_name
|
|
o = ss.taboption('led' + i + '_tab', form.ListValue,
|
|
'mod_led_control_led' + i + '_name',
|
|
_('<abbr title="Light Emitting Diode">LED</abbr> Name'));
|
|
o.modalonly = true;
|
|
if(i > 1) {
|
|
o.rmempty = true;
|
|
o.optional = true;
|
|
};
|
|
this.leds.forEach(e => o.value(e.name));
|
|
|
|
// led_action_1
|
|
o = ss.taboption('led' + i + '_tab', form.ListValue,
|
|
'mod_led_control_led' + i + '_action_1',
|
|
_('After connection'));
|
|
o.depends({ ['mod_led_control_led' + i + '_name']: /.+/ });
|
|
o.modalonly = true;
|
|
o.value(1, _('Off'));
|
|
o.value(2, _('On'));
|
|
o.value(3, _('Blinking (kernel: timer)'));
|
|
o.value(4, _('Network device activity (kernel: netdev)'));
|
|
o.default = '2';
|
|
|
|
// blink_on_delay_1
|
|
o = ss.taboption('led' + i + '_tab', form.ListValue,
|
|
'mod_led_control_led' + i + '_blink_on_delay_1',
|
|
_('On-state delay'),
|
|
_('On-state delay for blinking option.'));
|
|
makeTimerDelayOptions(o);
|
|
o.depends({ ['mod_led_control_led' + i + '_action_1']: '3' });
|
|
o.modalonly = true;
|
|
o.default = '500';
|
|
|
|
// blink_off_delay_1
|
|
o = ss.taboption('led' + i + '_tab', form.ListValue,
|
|
'mod_led_control_led' + i + '_blink_off_delay_1',
|
|
_('Off-state delay'),
|
|
_('Off-state delay for blinking option.'));
|
|
makeTimerDelayOptions(o);
|
|
o.depends({ ['mod_led_control_led' + i + '_action_1']: '3' });
|
|
o.modalonly = true;
|
|
o.default = '500';
|
|
|
|
// netdev_device_1
|
|
o = ss.taboption('led' + i + '_tab', widgets.DeviceSelect,
|
|
'mod_led_control_led' + i + '_netdev_device_1',
|
|
_('Device'),
|
|
_('<abbr title="Light Emitting Diode">LED</abbr> will display the link activity of this network device.')
|
|
);
|
|
o.depends({ ['mod_led_control_led' + i + '_action_1']: '4' });
|
|
o.modalonly = true;
|
|
o.rmempty = false;
|
|
o.noaliases = true;
|
|
|
|
// netdev_mode_1
|
|
o = ss.taboption('led' + i + '_tab', form.MultiValue,
|
|
'mod_led_control_led' + i + '_netdev_mode_1',
|
|
_('<abbr title="Light Emitting Diode">LED</abbr> mode')
|
|
);
|
|
o.depends({ ['mod_led_control_led' + i + '_action_1']: '4' });
|
|
o.modalonly = true;
|
|
o.value('link', _('Link On'));
|
|
o.value('tx', _('Transmit'));
|
|
o.value('rx', _('Receive'));
|
|
o.default = 'link';
|
|
o.rmempty = false;
|
|
|
|
// led_action_2
|
|
o = ss.taboption('led' + i + '_tab', form.ListValue,
|
|
'mod_led_control_led' + i + '_action_2',
|
|
_('After disconnection'));
|
|
o.depends({ ['mod_led_control_led' + i + '_name']: /.+/ });
|
|
o.modalonly = true;
|
|
o.value(1, _('Off'));
|
|
o.value(2, _('On'));
|
|
o.value(3, _('Blinking (kernel: timer)'));
|
|
o.value(4, _('Network device activity (kernel: netdev)'));
|
|
o.default = '1';
|
|
|
|
// blink_on_delay_2
|
|
o = ss.taboption('led' + i + '_tab', form.ListValue,
|
|
'mod_led_control_led' + i + '_blink_on_delay_2',
|
|
_('On-state delay'),
|
|
_('On-state delay for blinking option.'));
|
|
makeTimerDelayOptions(o);
|
|
o.depends({ ['mod_led_control_led' + i + '_action_2']: '3' });
|
|
o.modalonly = true;
|
|
o.default = '500';
|
|
|
|
// blink_off_delay_2
|
|
o = ss.taboption('led' + i + '_tab', form.ListValue,
|
|
'mod_led_control_led' + i + '_blink_off_delay_2',
|
|
_('Off-state delay'),
|
|
_('Off-state delay for blinking option.'));
|
|
makeTimerDelayOptions(o);
|
|
o.depends({ ['mod_led_control_led' + i + '_action_2']: '3' });
|
|
o.modalonly = true;
|
|
o.default = '500';
|
|
|
|
// netdev_device_2
|
|
o = ss.taboption('led' + i + '_tab', widgets.DeviceSelect,
|
|
'mod_led_control_led' + i + '_netdev_device_2',
|
|
_('Device'),
|
|
_('<abbr title="Light Emitting Diode">LED</abbr> will display the link activity of this network device.')
|
|
);
|
|
o.depends({ ['mod_led_control_led' + i + '_action_2']: '4' });
|
|
o.modalonly = true;
|
|
o.rmempty = false;
|
|
o.noaliases = true;
|
|
|
|
// netdev_mode_2
|
|
o = ss.taboption('led' + i + '_tab', form.MultiValue,
|
|
'mod_led_control_led' + i + '_netdev_mode_2',
|
|
_('<abbr title="Light Emitting Diode">LED</abbr> mode')
|
|
);
|
|
o.depends({ ['mod_led_control_led' + i + '_action_2']: '4' });
|
|
o.modalonly = true;
|
|
o.value('link', _('Link On'));
|
|
o.value('tx', _('Transmit'));
|
|
o.value('rx', _('Receive'));
|
|
o.default = 'link';
|
|
o.rmempty = false;
|
|
|
|
};
|
|
} else {
|
|
o = s.taboption('led_control', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<label class="cbi-value-title"></label><div class="cbi-value-field"><em>' +
|
|
_('No <abbr title="Light Emitting Diode">LED</abbr>s available...') +
|
|
'</em></div>';
|
|
o.modalonly = true;
|
|
};
|
|
|
|
// Reboot device
|
|
|
|
o = s.taboption('reboot_device', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<div class="cbi-section-descr">' +
|
|
_('Device will be rebooted when the Internet is disconnected.') +
|
|
'</div>';
|
|
o.modalonly = true;
|
|
|
|
// enabled
|
|
o = s.taboption('reboot_device', form.Flag, 'mod_reboot_enabled',
|
|
_('Enabled'));
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// dead_period
|
|
o = s.taboption('reboot_device', this.CBITimeInput,
|
|
'mod_reboot_dead_period', _('Dead period'),
|
|
_('Period of time without Internet access until the device is rebooted.')
|
|
);
|
|
o.default = '3600';
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// force_reboot_delay
|
|
o = s.taboption('reboot_device', form.ListValue,
|
|
'mod_reboot_force_reboot_delay', _('Forced reboot delay'),
|
|
_('Waiting for a reboot to complete before performing a forced reboot.')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(0, _('Disable forced reboot'));
|
|
o.value(60, '1 ' + _('min'));
|
|
o.value(120, '2 ' + _('min'));
|
|
o.value(300, '5 ' + _('min'));
|
|
o.value(600, '10 ' + _('min'));
|
|
o.value(1800, '30 ' + _('min'));
|
|
o.value(3600, '1 ' + _('hour'));
|
|
o.default = '300';
|
|
|
|
// disconnected_at_startup
|
|
o = s.taboption('reboot_device', form.Flag,
|
|
'mod_reboot_disconnected_at_startup',
|
|
_('On startup'),
|
|
_('Reboot device if the Internet is disconnected at service startup.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// Restart network
|
|
|
|
o = s.taboption('restart_network', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<div class="cbi-section-descr">' +
|
|
_('Network will be restarted when the Internet is disconnected.') +
|
|
'</div>';
|
|
o.modalonly = true;
|
|
|
|
// enabled
|
|
o = s.taboption('restart_network', form.Flag,
|
|
'mod_network_restart_enabled',
|
|
_('Enabled'));
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// dead_period
|
|
o = s.taboption('restart_network', this.CBITimeInput,
|
|
'mod_network_restart_dead_period', _('Dead period'),
|
|
_('Period of time without Internet access before network restart.')
|
|
);
|
|
o.default = '900';
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// ifaces
|
|
o = s.taboption('restart_network', widgets.DeviceSelect,
|
|
'mod_network_restart_ifaces',
|
|
_('Device'),
|
|
_('Network device or interface to restart. If not specified, then the network service is restarted.')
|
|
);
|
|
o.modalonly = true;
|
|
o.multiple = true;
|
|
o.modalonly = true;
|
|
|
|
// attempts
|
|
o = s.taboption('restart_network', form.ListValue,
|
|
'mod_network_restart_attempts', _('Restart attempts'),
|
|
_('Maximum number of network restart attempts before Internet access is available.')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(1);
|
|
o.value(2);
|
|
o.value(3);
|
|
o.value(4);
|
|
o.value(5);
|
|
o.value(10);
|
|
o.value(0, _('infinitely'));
|
|
o.default = '1';
|
|
|
|
// attempt_interval
|
|
o = s.taboption('restart_network', this.CBITimeInput,
|
|
'mod_network_restart_attempt_interval', _('Attempt interval'),
|
|
_('Interval between network restarts.')
|
|
);
|
|
o.default = '60';
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// device_timeout
|
|
o = s.taboption('restart_network', form.ListValue,
|
|
'mod_network_restart_device_timeout', _('Device timeout'),
|
|
_('Timeout between stopping and starting a network device when restarting.')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(0, '0 ' + _('sec'));
|
|
o.value(1, '1 ' + _('sec'));
|
|
o.value(2, '2 ' + _('sec'));
|
|
o.value(3, '3 ' + _('sec'));
|
|
o.value(4, '4 ' + _('sec'));
|
|
o.value(5, '5 ' + _('sec'));
|
|
o.value(6, '6 ' + _('sec'));
|
|
o.value(7, '7 ' + _('sec'));
|
|
o.value(8, '8 ' + _('sec'));
|
|
o.value(9, '9 ' + _('sec'));
|
|
o.value(10, '10 ' + _('sec'));
|
|
o.default = '0';
|
|
|
|
// disconnected_at_startup
|
|
o = s.taboption('restart_network', form.Flag,
|
|
'mod_network_restart_disconnected_at_startup',
|
|
_('On startup'),
|
|
_('Restart network if the Internet is disconnected at service startup.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// Restart modem
|
|
|
|
if(this.mm) {
|
|
if(this.mmInit) {
|
|
o = s.taboption('restart_modem', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<div class="cbi-section-descr">' +
|
|
_('Modem will be restarted when the Internet is disconnected.') +
|
|
'</div>';
|
|
o.modalonly = true;
|
|
|
|
// enabled
|
|
o = s.taboption('restart_modem', form.Flag,
|
|
'mod_modem_restart_enabled',
|
|
_('Enabled'),
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// dead_period
|
|
o = s.taboption('restart_modem', this.CBITimeInput,
|
|
'mod_modem_restart_dead_period', _('Dead period'),
|
|
_('Period of time without Internet access before modem restart.')
|
|
);
|
|
o.default = '600';
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// any_band
|
|
o = s.taboption('restart_modem', form.Flag,
|
|
'mod_modem_restart_any_band', _('Unlock modem bands'),
|
|
_('Set the modem to be allowed to use any band.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// attempts
|
|
o = s.taboption('restart_modem', form.ListValue,
|
|
'mod_modem_restart_attempts', _('Restart attempts'),
|
|
_('Maximum number of modem restart attempts before Internet access is available.')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(1);
|
|
o.value(2);
|
|
o.value(3);
|
|
o.value(4);
|
|
o.value(5);
|
|
o.value(10);
|
|
o.value(0, _('infinitely'));
|
|
o.default = '1';
|
|
|
|
// attempt_interval
|
|
o = s.taboption('restart_modem', this.CBITimeInput,
|
|
'mod_modem_restart_attempt_interval', _('Attempt interval'),
|
|
_('Interval between modem restarts.')
|
|
);
|
|
o.default = '60';
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// iface
|
|
o = s.taboption('restart_modem', widgets.NetworkSelect,
|
|
'mod_modem_restart_iface',
|
|
_('Interface'),
|
|
_('ModemManger interface. If specified, it will be restarted after restarting ModemManager.')
|
|
);
|
|
o.multiple = false;
|
|
o.nocreate = true;
|
|
o.modalonly = true;
|
|
|
|
// iface_timeout
|
|
o = s.taboption('restart_modem', form.ListValue,
|
|
'mod_modem_restart_iface_timeout', _('Interface timeout'),
|
|
_('Timeout between stopping and starting a ModemManger interface when restarting.')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(0, '0 ' + _('sec'));
|
|
o.value(1, '1 ' + _('sec'));
|
|
o.value(2, '2 ' + _('sec'));
|
|
o.value(3, '3 ' + _('sec'));
|
|
o.value(4, '4 ' + _('sec'));
|
|
o.value(5, '5 ' + _('sec'));
|
|
o.value(6, '6 ' + _('sec'));
|
|
o.value(7, '7 ' + _('sec'));
|
|
o.value(8, '8 ' + _('sec'));
|
|
o.value(9, '9 ' + _('sec'));
|
|
o.value(10, '10 ' + _('sec'));
|
|
o.default = '0';
|
|
|
|
// disconnected_at_startup
|
|
o = s.taboption('restart_modem', form.Flag,
|
|
'mod_modem_restart_disconnected_at_startup',
|
|
_('On startup'),
|
|
_('Restart modem if the Internet is disconnected at service startup.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
} else {
|
|
o = s.taboption('restart_modem', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<label class="cbi-value-title"></label><div class="cbi-value-field"><em>' +
|
|
_('ModemManager is not available...') +
|
|
'</em></div>';
|
|
o.modalonly = true;
|
|
};
|
|
};
|
|
};
|
|
|
|
// Public IP address
|
|
|
|
o = s.taboption('public_ip', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<div class="cbi-section-descr">' +
|
|
_('Checking the real public IP address.') +
|
|
'</div>';
|
|
o.modalonly = true;
|
|
|
|
// enabled
|
|
o = s.taboption('public_ip', form.Flag, 'mod_public_ip_enabled',
|
|
_('Enabled'));
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// provider
|
|
o = s.taboption('public_ip', form.ListValue,
|
|
'mod_public_ip_provider', _('Provider'),
|
|
_('Service for determining the public IP address.') + '<br />' +
|
|
((this.curlExec) ? '' :
|
|
_('To support HTTP services, you need to install curl.'))
|
|
);
|
|
o.modalonly = true;
|
|
for(let i of this.publicIPProviders.dns) {
|
|
o.value(i.name, i.title);
|
|
};
|
|
if(this.curlExec) {
|
|
for(let i of this.publicIPProviders.http) {
|
|
o.value(i.name, i.title);
|
|
};
|
|
};
|
|
o.default = this.publicIPProviders.dns[0].name;
|
|
|
|
// ipv6
|
|
o = s.taboption('public_ip', form.ListValue,
|
|
'mod_public_ip_qtype', _('DNS query type'),
|
|
_('The type of record requested in the DNS query (if the service supports it).')
|
|
);
|
|
o.modalonly = true;
|
|
o.value('0', 'A (IPv4)');
|
|
o.value('1', 'AAAA (IPv6)');
|
|
o.default = '0';
|
|
for(let i of this.publicIPProviders.dns) {
|
|
o.depends({ mod_public_ip_provider: i.name });
|
|
};
|
|
|
|
// interval
|
|
o = s.taboption('public_ip', form.ListValue,
|
|
'mod_public_ip_interval', _('Polling interval'),
|
|
_('Interval between IP address requests.')
|
|
);
|
|
o.default = '600';
|
|
o.modalonly = true;
|
|
o.value(60, '1' + ' ' + _('min'));
|
|
o.value(300, '5' + ' ' + _('min'));
|
|
o.value(600, '10' + ' ' + _('min'));
|
|
o.value(1800, '30' + ' ' + _('min'));
|
|
o.value(3600, '1' + ' ' + _('hour'));
|
|
o.value(10800, '3' + ' ' + _('hour'));
|
|
|
|
// interval_failed
|
|
o = s.taboption('public_ip', form.ListValue,
|
|
'mod_public_ip_interval_failed', _('Failed interval'),
|
|
_('Interval between IP address requests if the IP address is not defined.')
|
|
);
|
|
o.default = '60';
|
|
o.modalonly = true;
|
|
o.value(30, '30' + ' ' + _('sec'));
|
|
o.value(60, '1' + ' ' + _('min'));
|
|
o.value(180, '3' + ' ' + _('min'));
|
|
o.value(300, '5' + ' ' + _('min'));
|
|
o.value(600, '10' + ' ' + _('min'));
|
|
|
|
// request_attempts
|
|
o = s.taboption('public_ip', form.ListValue,
|
|
'mod_public_ip_request_attempts', _('Attempts'),
|
|
_('Number of attempts to request an IP address.')
|
|
);
|
|
o.default = '2'
|
|
o.modalonly = true;
|
|
for(let i = 1; i <= 3; i++) {
|
|
o.value(i);
|
|
};
|
|
|
|
// timeout
|
|
o = s.taboption('public_ip', form.ListValue,
|
|
'mod_public_ip_timeout', _('Server response timeout')
|
|
);
|
|
o.default = '3'
|
|
o.modalonly = true;
|
|
for(let i = 1; i <= 5; i++) {
|
|
o.value(i, i + ' ' + _('sec'));
|
|
};
|
|
|
|
if(this.currentAppMode != '2') {
|
|
|
|
// enable_ip_script
|
|
o = s.taboption('public_ip', form.Flag,
|
|
'mod_public_ip_enable_ip_script',
|
|
_('Enable public-ip-script'));
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// public-ip-script edit dialog
|
|
o = s.taboption('public_ip', this.CBIBlockFileEdit, this,
|
|
'public-ip-script',
|
|
this.configDir + '/public-ip-script.' + s.section,
|
|
_('Edit public-ip-script'),
|
|
_('Shell commands that run when the public IP address changes. New IP is available as value of the <code>$PUBLIC_IP</code> variable (empty string if undefined).')
|
|
);
|
|
o.modalonly = true;
|
|
|
|
// Email notification
|
|
|
|
if(this.email) {
|
|
if(this.emailExec) {
|
|
o = s.taboption('email', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<div class="cbi-section-descr">' +
|
|
_('An email will be sent when connected or disconnected from the Internet.') +
|
|
'</div>';
|
|
o.modalonly = true;
|
|
|
|
// enabled
|
|
o = s.taboption('email', form.Flag, 'mod_email_enabled',
|
|
_('Enabled'));
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// mode
|
|
o = s.taboption('email', form.ListValue,
|
|
'mod_email_mode', _('When email will be sent')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(0, _('after connection'));
|
|
o.value(1, _('after disconnection'));
|
|
o.value(2, _('after connection or disconnection'));
|
|
o.default = '0';
|
|
|
|
// alive_period
|
|
o = s.taboption('email', this.CBITimeInput,
|
|
'mod_email_alive_period', _('Alive period'),
|
|
_('Period of time after connecting to the Internet before sending a message.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
o.depends({ 'mod_email_mode': '0' });
|
|
o.depends({ 'mod_email_mode': '2' });
|
|
o.default = '0';
|
|
|
|
// dead_period
|
|
o = s.taboption('email', this.CBITimeInput,
|
|
'mod_email_dead_period', _('Dead period'),
|
|
_('Period of time after disconnecting from Internet before sending a message.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
o.depends({ 'mod_email_mode': '1' });
|
|
o.depends({ 'mod_email_mode': '2' });
|
|
o.default = '0';
|
|
|
|
// host_alias
|
|
o = s.taboption('email', form.Value,
|
|
'mod_email_host_alias',
|
|
_('Host alias'),
|
|
_('Host identifier in messages. If not specified, hostname will be used.'));
|
|
o.modalonly = true;
|
|
|
|
// mail_recipient
|
|
o = s.taboption('email', form.Value,
|
|
'mod_email_mail_recipient', _('Recipient'));
|
|
o.description = _('Email address of the recipient.');
|
|
o.modalonly = true;
|
|
|
|
// mail_sender
|
|
o = s.taboption('email', form.Value,
|
|
'mod_email_mail_sender', _('Sender'));
|
|
o.description = _('Email address of the sender.');
|
|
o.modalonly = true;
|
|
|
|
// mail_user
|
|
o = s.taboption('email', form.Value,
|
|
'mod_email_mail_user', _('User'));
|
|
o.description = _('Username for SMTP authentication.');
|
|
o.modalonly = true;
|
|
|
|
// mail_password
|
|
o = s.taboption('email', form.Value,
|
|
'mod_email_mail_password', _('Password'));
|
|
o.description = _('Password for SMTP authentication.');
|
|
o.password = true;
|
|
o.modalonly = true;
|
|
|
|
// mail_smtp
|
|
o = s.taboption('email', form.Value,
|
|
'mod_email_mail_smtp', _('SMTP server'));
|
|
o.description = _('Hostname/IP address of the SMTP server.');
|
|
o.datatype = 'host';
|
|
o.modalonly = true;
|
|
|
|
// mail_smtp_port
|
|
o = s.taboption('email', form.Value,
|
|
'mod_email_mail_smtp_port', _('SMTP server port'));
|
|
o.datatype = 'port';
|
|
o.modalonly = true;
|
|
|
|
// mail_security
|
|
o = s.taboption('email', form.ListValue,
|
|
'mod_email_mail_security', _('Security'));
|
|
o.description = '%s<br />%s'.format(
|
|
_('TLS: use STARTTLS if the server supports it.'),
|
|
_('SSL: SMTP over SSL.'),
|
|
);
|
|
o.value('tls', 'TLS');
|
|
o.value('ssl', 'SSL');
|
|
o.default = 'tls';
|
|
o.modalonly = true;
|
|
|
|
// message_at_startup
|
|
o = s.taboption('email', form.Flag,
|
|
'mod_email_message_at_startup',
|
|
_('On startup'),
|
|
_('Send message on service startup.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
} else {
|
|
o = s.taboption('email', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<label class="cbi-value-title"></label><div class="cbi-value-field"><em>' +
|
|
_('Mailsend is not available...') +
|
|
'</em></div>';
|
|
o.modalonly = true;
|
|
};
|
|
};
|
|
|
|
// Telegram notification
|
|
|
|
if(this.telegram) {
|
|
if(this.curlExec) {
|
|
o = s.taboption('telegram', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<div class="cbi-section-descr">' +
|
|
_('Telegram message will be sent when connected or disconnected from the Internet.') +
|
|
'<br />' +
|
|
_("You need to register a new %sTelegram bot%s. Then get the bot's API token and paste it into the <code>Bot token</code> field. After that, open a chat with the bot, write something (in the Telegram app) and you will be able to get the chat ID using the <code>ID</code> button.").format("<a href='https://core.telegram.org/bots#how-do-i-create-a-bot' target='_blank'>", '</a>') +
|
|
'</div>';
|
|
|
|
o.modalonly = true;
|
|
|
|
// enabled
|
|
o = s.taboption('telegram', form.Flag,
|
|
'mod_telegram_enabled',
|
|
_('Enabled'));
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// mode
|
|
o = s.taboption('telegram', form.ListValue,
|
|
'mod_telegram_mode', _('When message will be sent')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(0, _('after connection'));
|
|
o.value(1, _('after disconnection'));
|
|
o.value(2, _('after connection or disconnection'));
|
|
o.default = '0';
|
|
|
|
// alive_period
|
|
o = s.taboption('telegram', this.CBITimeInput,
|
|
'mod_telegram_alive_period', _('Alive period'),
|
|
_('Period of time after connecting to the Internet before sending a message.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
o.depends({ 'mod_telegram_mode': '0' });
|
|
o.depends({ 'mod_telegram_mode': '2' });
|
|
o.default = '0';
|
|
|
|
// dead_period
|
|
o = s.taboption('telegram', this.CBITimeInput,
|
|
'mod_telegram_dead_period', _('Dead period'),
|
|
_('Period of time after disconnecting from Internet before sending a message.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
o.depends({ 'mod_telegram_mode': '1' });
|
|
o.depends({ 'mod_telegram_mode': '2' });
|
|
o.default = '0';
|
|
|
|
// host_alias
|
|
o = s.taboption('telegram', form.Value,
|
|
'mod_telegram_host_alias',
|
|
_('Host alias'),
|
|
_('Host identifier in messages. If not specified, hostname will be used.'));
|
|
o.modalonly = true;
|
|
|
|
// tg_api_token
|
|
o = s.taboption('telegram', form.Value,
|
|
'mod_telegram_api_token', _('Bot token'),
|
|
_('Telegram bot API token.'));
|
|
o.password = true;
|
|
o.modalonly = true;
|
|
|
|
// tg_chat_id
|
|
o = s.taboption('telegram', this.CBITextfieldButtonInput,
|
|
'mod_telegram_chat_id', _('Chat ID'),
|
|
_('ID of the Telegram chat to which messages will be sent.')
|
|
);
|
|
o.btntext = _('ID'),
|
|
o.btntitle = _('Request chat ID from bot API'),
|
|
o.btnstyle = 'action',
|
|
o.onclick = ui.createHandlerFn(this,
|
|
(ev) => this.getTgChatIdHandler(ev, s.section));
|
|
o.modalonly = true;
|
|
o.optional = false;
|
|
o.rmempty = false;
|
|
o.depends({ 'mod_telegram_api_token': /.+/ });
|
|
|
|
// proxy_type
|
|
o = s.taboption('telegram', form.ListValue,
|
|
'mod_telegram_proxy_type', _('Proxy')
|
|
);
|
|
o.value('', _('Disabled'));
|
|
o.value('http');
|
|
o.value('socks4');
|
|
o.value('socks4a');
|
|
o.value('socks5');
|
|
o.value('socks5h');
|
|
o.default = '';
|
|
o.modalonly = true;
|
|
|
|
// proxy_host
|
|
o = s.taboption('telegram', form.Value,
|
|
'mod_telegram_proxy_host', _('Proxy host')
|
|
);
|
|
o.datatype = 'host';
|
|
o.rmempty = false;
|
|
o.depends({ mod_telegram_proxy_type: /.+/ });
|
|
o.modalonly = true;
|
|
|
|
// proxy_port
|
|
o = s.taboption('telegram', form.Value,
|
|
'mod_telegram_proxy_port', _('Proxy port')
|
|
);
|
|
o.datatype = 'port';
|
|
o.rmempty = false;
|
|
o.depends({ mod_telegram_proxy_type: /.+/ });
|
|
o.modalonly = true;
|
|
|
|
// proxy_user
|
|
o = s.taboption('telegram', form.Value,
|
|
'mod_telegram_proxy_user', _('Proxy user')
|
|
);
|
|
o.depends({ mod_telegram_proxy_type: /(http|socks5h?)/ });
|
|
o.modalonly = true;
|
|
|
|
// proxy_passwd
|
|
o = s.taboption('telegram', form.Value,
|
|
'mod_telegram_proxy_passwd', _('Proxy password')
|
|
);
|
|
o.depends({ mod_telegram_proxy_type: /(http|socks5h?)/ });
|
|
o.modalonly = true;
|
|
o.password = true;
|
|
|
|
// iface
|
|
o = s.taboption('telegram', widgets.DeviceSelect,
|
|
'mod_telegram_iface', _('Device'),
|
|
_('Network device for sending messages. If not specified, the default device is used.')
|
|
);
|
|
o.noaliases = true;
|
|
o.modalonly = true;
|
|
|
|
// message_at_startup
|
|
o = s.taboption('telegram', form.Flag,
|
|
'mod_telegram_message_at_startup',
|
|
_('On startup'),
|
|
_('Send message on service startup.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
} else {
|
|
o = s.taboption('telegram', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<label class="cbi-value-title"></label><div class="cbi-value-field"><em>' +
|
|
_('Curl is not available...') +
|
|
'</em></div>';
|
|
o.modalonly = true;
|
|
};
|
|
};
|
|
|
|
// User scripts
|
|
|
|
o = s.taboption('user_scripts', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<div class="cbi-section-descr">' +
|
|
_('Shell commands to run when connected or disconnected from the Internet.') +
|
|
'</div>';
|
|
o.modalonly = true;
|
|
|
|
// enabled
|
|
o = s.taboption('user_scripts', form.Flag, 'mod_user_scripts_enabled',
|
|
_('Enabled'));
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
o = s.taboption('user_scripts', form.SectionValue,
|
|
'user_scripts_section', form.NamedSection, s.section);
|
|
ss = o.subsection;
|
|
|
|
// up-script tab
|
|
ss.tab('user_scripts_up_script', 'up-script');
|
|
|
|
o = ss.taboption('user_scripts_up_script', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<div class="cbi-section-descr">' +
|
|
_('Shell commands that run when connected to the Internet.') +
|
|
'</div>';
|
|
o.modalonly = true;
|
|
|
|
// up_script edit
|
|
o = ss.taboption('user_scripts_up_script', this.CBIBlockFileEdit, this,
|
|
'up_script',
|
|
this.configDir + '/up-script.' + s.section,
|
|
_('Edit up-script')
|
|
);
|
|
o.modalonly = true;
|
|
|
|
// alive_period
|
|
o = ss.taboption('user_scripts_up_script', this.CBITimeInput,
|
|
'mod_user_scripts_alive_period', _('Alive period'),
|
|
_('Period of time after connecting to Internet before up-script runs.')
|
|
);
|
|
o.default = '0';
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// up_script_attempts
|
|
o = ss.taboption('user_scripts_up_script', form.ListValue,
|
|
'mod_user_scripts_up_script_attempts', _('Attempts'),
|
|
_('Maximum number of up-script run attempts when connected to the Internet.')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(1);
|
|
o.value(2);
|
|
o.value(3);
|
|
o.value(4);
|
|
o.value(5);
|
|
o.value(10);
|
|
o.value(0, _('infinitely'));
|
|
o.default = '1';
|
|
|
|
// up_script_attempt_interval
|
|
o = ss.taboption('user_scripts_up_script', this.CBITimeInput,
|
|
'mod_user_scripts_up_script_attempt_interval',
|
|
_('Attempt interval'),
|
|
_('Interval between up-script runs.')
|
|
);
|
|
o.default = '60';
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// connected_at_startup
|
|
o = ss.taboption('user_scripts_up_script', form.Flag,
|
|
'mod_user_scripts_connected_at_startup',
|
|
_('On startup'),
|
|
_('Run up-script if the Internet is connected at service startup.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// down-script tab
|
|
ss.tab('user_scripts_down_script', 'down-script');
|
|
|
|
o = ss.taboption('user_scripts_down_script', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<div class="cbi-section-descr">' +
|
|
_('Shell commands to run when disconnected from the Internet.') +
|
|
'</div>';
|
|
o.modalonly = true;
|
|
|
|
// down_script edit
|
|
o = ss.taboption('user_scripts_down_script', this.CBIBlockFileEdit, this,
|
|
'down_script',
|
|
this.configDir + '/down-script.' + s.section,
|
|
_('Edit down-script')
|
|
);
|
|
o.modalonly = true;
|
|
|
|
// dead_period
|
|
o = ss.taboption('user_scripts_down_script', this.CBITimeInput,
|
|
'mod_user_scripts_dead_period', _('Dead period'),
|
|
_('Period of time after disconnecting from Internet before down-script runs.')
|
|
);
|
|
o.default = '0';
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// down_script_attempts
|
|
o = ss.taboption('user_scripts_down_script', form.ListValue,
|
|
'mod_user_scripts_down_script_attempts', _('Attempts'),
|
|
_('Maximum number of down-script run attempts before Internet access is available.')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(1);
|
|
o.value(2);
|
|
o.value(3);
|
|
o.value(4);
|
|
o.value(5);
|
|
o.value(10);
|
|
o.value(0, _('infinitely'));
|
|
o.default = '1';
|
|
|
|
// down_script_attempt_interval
|
|
o = ss.taboption('user_scripts_down_script', this.CBITimeInput,
|
|
'mod_user_scripts_down_script_attempt_interval',
|
|
_('Attempt interval'),
|
|
_('Interval between down-script runs.')
|
|
);
|
|
o.default = '60';
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// disconnected_at_startup
|
|
o = ss.taboption('user_scripts_down_script', form.Flag,
|
|
'mod_user_scripts_disconnected_at_startup',
|
|
_('On startup'),
|
|
_('Run down-script if the Internet is disconnected at service startup.')
|
|
);
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// Regular script
|
|
|
|
o = s.taboption('regular_script', form.DummyValue, '_dummy');
|
|
o.rawhtml = true;
|
|
o.default = '<div class="cbi-section-descr">' +
|
|
_('Shell commands that are run regularly.') +
|
|
'</div>';
|
|
o.modalonly = true;
|
|
|
|
// enabled
|
|
o = s.taboption('regular_script', form.Flag,
|
|
'mod_regular_script_enabled',
|
|
_('Enabled'));
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// next run
|
|
o = s.taboption('regular_script', form.DummyValue,
|
|
'_dummy', _('Next run'));
|
|
o.rawhtml = true;
|
|
o.default = '<span id="id_next_run_' + s.section + '">' + (this.modRegularScriptNextRun[s.section] || _('Not scheduled')) + '</span>';
|
|
o.modalonly = true;
|
|
|
|
// interval
|
|
o = s.taboption('regular_script', this.CBITimeInput,
|
|
'mod_regular_script_interval', _('Run interval')
|
|
);
|
|
o.default = '3600';
|
|
o.rmempty = false;
|
|
o.modalonly = true;
|
|
|
|
// inet_state
|
|
o = s.taboption('regular_script', form.ListValue,
|
|
'mod_regular_script_inet_state', _('Run if Internet state is')
|
|
);
|
|
o.modalonly = true;
|
|
o.value(0, _('connected'));
|
|
o.value(1, _('disconnected'));
|
|
o.value(2, _('connected or disconnected'));
|
|
o.default = '2';
|
|
|
|
// regular_script edit
|
|
o = s.taboption('regular_script', this.CBIBlockFileEdit, this,
|
|
'regular_script',
|
|
this.configDir + '/regular-script.' + s.section,
|
|
_('Edit regular-script'),
|
|
_('Shell commands that run regularly at a specified interval. Current state of the Internet is available as value of the <code>$INET_STATE</code> variable (<code>0</code> - connected, <code>1</code> - disconnected).')
|
|
);
|
|
o.modalonly = true;
|
|
};
|
|
|
|
};
|
|
|
|
if(this.currentAppMode != '0') {
|
|
poll.add(
|
|
L.bind((this.currentAppMode == '1') ? this.servicePoll : this.uiPoll, this),
|
|
this.pollInterval
|
|
);
|
|
};
|
|
|
|
let mapPromise = m.render();
|
|
mapPromise.then(node => node.classList.add('fade-in'));
|
|
return mapPromise;
|
|
},
|
|
});
|