v1.2. UI detector refactoring
19
README.md
@@ -19,15 +19,15 @@ Internet-detector is an application for checking the availability of the Interne
|
|||||||
**OpenWrt >= 21.02:**
|
**OpenWrt >= 21.02:**
|
||||||
|
|
||||||
opkg update
|
opkg update
|
||||||
wget --no-check-certificate -O /tmp/internet-detector_1.1-0_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector_1.1-0_all.ipk
|
wget --no-check-certificate -O /tmp/internet-detector_1.2-0_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector_1.2-0_all.ipk
|
||||||
opkg install /tmp/internet-detector_1.1-0_all.ipk
|
opkg install /tmp/internet-detector_1.2-0_all.ipk
|
||||||
rm /tmp/internet-detector_1.1-0_all.ipk
|
rm /tmp/internet-detector_1.2-0_all.ipk
|
||||||
/etc/init.d/internet-detector start
|
/etc/init.d/internet-detector start
|
||||||
/etc/init.d/internet-detector enable
|
/etc/init.d/internet-detector enable
|
||||||
|
|
||||||
wget --no-check-certificate -O /tmp/luci-app-internet-detector_1.1-0_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-app-internet-detector_1.1-0_all.ipk
|
wget --no-check-certificate -O /tmp/luci-app-internet-detector_1.2-0_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-app-internet-detector_1.2-0_all.ipk
|
||||||
opkg install /tmp/luci-app-internet-detector_1.1-0_all.ipk
|
opkg install /tmp/luci-app-internet-detector_1.2-0_all.ipk
|
||||||
rm /tmp/luci-app-internet-detector_1.1-0_all.ipk
|
rm /tmp/luci-app-internet-detector_1.2-0_all.ipk
|
||||||
/etc/init.d/rpcd restart
|
/etc/init.d/rpcd restart
|
||||||
|
|
||||||
Email notification:
|
Email notification:
|
||||||
@@ -36,9 +36,9 @@ Email notification:
|
|||||||
|
|
||||||
i18n-ru:
|
i18n-ru:
|
||||||
|
|
||||||
wget --no-check-certificate -O /tmp/luci-i18n-internet-detector-ru_1.1-0_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-i18n-internet-detector-ru_1.1-0_all.ipk
|
wget --no-check-certificate -O /tmp/luci-i18n-internet-detector-ru_1.2-0_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-i18n-internet-detector-ru_1.2-0_all.ipk
|
||||||
opkg install /tmp/luci-i18n-internet-detector-ru_1.1-0_all.ipk
|
opkg install /tmp/luci-i18n-internet-detector-ru_1.2-0_all.ipk
|
||||||
rm /tmp/luci-i18n-internet-detector-ru_1.1-0_all.ipk
|
rm /tmp/luci-i18n-internet-detector-ru_1.2-0_all.ipk
|
||||||
|
|
||||||
**[OpenWrt 19.07](https://github.com/gSpotx2f/luci-app-internet-detector/tree/19.07)**
|
**[OpenWrt 19.07](https://github.com/gSpotx2f/luci-app-internet-detector/tree/19.07)**
|
||||||
|
|
||||||
@@ -47,4 +47,3 @@ i18n-ru:
|
|||||||

|

|
||||||

|

|
||||||

|

|
||||||

|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#
|
#
|
||||||
# (с) 2023 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
# (с) 2024 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
||||||
#
|
#
|
||||||
|
|
||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=internet-detector
|
PKG_NAME:=internet-detector
|
||||||
PKG_VERSION:=1.1
|
PKG_VERSION:=1.2
|
||||||
PKG_RELEASE:=0
|
PKG_RELEASE:=0
|
||||||
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,6 @@ config main 'config'
|
|||||||
option mode '1'
|
option mode '1'
|
||||||
option enable_logger '1'
|
option enable_logger '1'
|
||||||
|
|
||||||
config ui 'ui'
|
|
||||||
list hosts '8.8.8.8'
|
|
||||||
list hosts '1.1.1.1'
|
|
||||||
option check_type '0'
|
|
||||||
option tcp_port '53'
|
|
||||||
option interval_up '6'
|
|
||||||
option interval_down '1'
|
|
||||||
option connection_attempts '1'
|
|
||||||
option connection_timeout '1'
|
|
||||||
|
|
||||||
config instance 'internet'
|
config instance 'internet'
|
||||||
option enabled '1'
|
option enabled '1'
|
||||||
list hosts '8.8.8.8'
|
list hosts '8.8.8.8'
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
START=97
|
START=97
|
||||||
STOP=01
|
STOP=01
|
||||||
|
|
||||||
PROG=/usr/bin/internet-detector
|
PROG="/usr/bin/internet-detector"
|
||||||
|
|
||||||
config_app() {
|
run_instance() {
|
||||||
config_get enabled "$1" enabled "0"
|
config_get enabled "$1" enabled "0"
|
||||||
if [ $enabled = "1" ]; then
|
if [ $enabled = "1" ]; then
|
||||||
$PROG service "$1"
|
$PROG service "$1"
|
||||||
@@ -16,7 +16,7 @@ start() {
|
|||||||
config_load internet-detector
|
config_load internet-detector
|
||||||
config_get mode "config" mode "0"
|
config_get mode "config" mode "0"
|
||||||
if [ $mode = "1" ]; then
|
if [ $mode = "1" ]; then
|
||||||
config_foreach config_app "instance"
|
config_foreach run_instance "instance"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
luaposix
|
luaposix
|
||||||
libuci-lua
|
libuci-lua
|
||||||
|
|
||||||
(с) 2023 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
(с) 2024 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
-- Importing packages
|
-- Importing packages
|
||||||
@@ -26,13 +26,16 @@ local uci = require("uci")
|
|||||||
-- Default settings
|
-- Default settings
|
||||||
|
|
||||||
local InternetDetector = {
|
local InternetDetector = {
|
||||||
mode = 0,
|
mode = 0, -- 0: disabled, 1: Service, 2: UI detector
|
||||||
enableLogger = true,
|
enableLogger = true,
|
||||||
hostname = "OpenWrt",
|
hostname = "OpenWrt",
|
||||||
appName = "internet-detector",
|
appName = "internet-detector",
|
||||||
commonDir = "/tmp/run",
|
commonDir = "/tmp/run",
|
||||||
pingCmd = "/bin/ping",
|
pingCmd = "/bin/ping",
|
||||||
pingParams = "-c 1",
|
pingParams = "-c 1",
|
||||||
|
uiRunTime = 30,
|
||||||
|
noModules = false,
|
||||||
|
uiAvailModules = { mod_public_ip = true },
|
||||||
debug = false,
|
debug = false,
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
hosts = {
|
hosts = {
|
||||||
@@ -51,11 +54,13 @@ local InternetDetector = {
|
|||||||
},
|
},
|
||||||
modules = {},
|
modules = {},
|
||||||
parsedHosts = {},
|
parsedHosts = {},
|
||||||
|
uiCounter = 0,
|
||||||
}
|
}
|
||||||
InternetDetector.configDir = string.format("/etc/%s", InternetDetector.appName)
|
InternetDetector.configDir = string.format("/etc/%s", InternetDetector.appName)
|
||||||
InternetDetector.modulesDir = string.format("/usr/lib/%s", InternetDetector.appName)
|
InternetDetector.modulesDir = string.format("/usr/lib/%s", InternetDetector.appName)
|
||||||
|
|
||||||
-- Loading settings from UCI
|
-- Loading settings from UCI
|
||||||
|
|
||||||
local uciCursor = uci.cursor()
|
local uciCursor = uci.cursor()
|
||||||
InternetDetector.mode = tonumber(
|
InternetDetector.mode = tonumber(
|
||||||
uciCursor:get(InternetDetector.appName, "config", "mode"))
|
uciCursor:get(InternetDetector.appName, "config", "mode"))
|
||||||
@@ -162,6 +167,8 @@ function InternetDetector:loadModules()
|
|||||||
for item in modulesDir do
|
for item in modulesDir do
|
||||||
if item:match("^mod_") then
|
if item:match("^mod_") then
|
||||||
local modName = item:gsub("%.lua$", "")
|
local modName = item:gsub("%.lua$", "")
|
||||||
|
if self.noModules and not self.uiAvailModules[modName] then
|
||||||
|
else
|
||||||
local modConfig = {}
|
local modConfig = {}
|
||||||
for k, v in pairs(self.serviceConfig) do
|
for k, v in pairs(self.serviceConfig) do
|
||||||
if k:match("^" .. modName) then
|
if k:match("^" .. modName) then
|
||||||
@@ -181,6 +188,7 @@ function InternetDetector:loadModules()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
table.sort(self.modules, function(a, b) return a.runPrio < b.runPrio end)
|
table.sort(self.modules, function(a, b) return a.runPrio < b.runPrio end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -213,7 +221,6 @@ function InternetDetector:pingHost(host)
|
|||||||
)
|
)
|
||||||
local retCode = os.execute(ping)
|
local retCode = os.execute(ping)
|
||||||
|
|
||||||
-- Debug
|
|
||||||
if self.debug then
|
if self.debug then
|
||||||
io.stdout:write(string.format(
|
io.stdout:write(string.format(
|
||||||
"--- Ping ---\ntime = %s\n%s\nretCode = %s\n", os.time(), ping, retCode)
|
"--- Ping ---\ntime = %s\n%s\nretCode = %s\n", os.time(), ping, retCode)
|
||||||
@@ -329,12 +336,17 @@ function InternetDetector:breakMain(signo)
|
|||||||
RUNNING = false
|
RUNNING = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function InternetDetector:resetUiCounter(signo)
|
||||||
|
self.uiCounter = 0
|
||||||
|
end
|
||||||
|
|
||||||
function InternetDetector:main()
|
function InternetDetector:main()
|
||||||
signal.signal(signal.SIGTERM, function(signo) self:breakMain(signo) end)
|
signal.signal(signal.SIGTERM, function(signo) self:breakMain(signo) end)
|
||||||
signal.signal(signal.SIGINT, function(signo) self:breakMain(signo) end)
|
signal.signal(signal.SIGINT, function(signo) self:breakMain(signo) end)
|
||||||
signal.signal(signal.SIGQUIT, function(signo) self:breakMain(signo) end)
|
signal.signal(signal.SIGQUIT, function(signo) self:breakMain(signo) end)
|
||||||
|
signal.signal(signal.SIGUSR1, function(signo) self:resetUiCounter(signo) end)
|
||||||
|
|
||||||
local lastStatus, currentStatus, timeNow, timeDiff, lastTime
|
local lastStatus, currentStatus, mTimeNow, mTimeDiff, mLastTime, uiTimeNow, uiLastTime
|
||||||
local interval = self.serviceConfig.interval_up
|
local interval = self.serviceConfig.interval_up
|
||||||
local counter = 0
|
local counter = 0
|
||||||
local onStart = true
|
local onStart = true
|
||||||
@@ -367,16 +379,16 @@ function InternetDetector:main()
|
|||||||
counter = 0
|
counter = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
timeDiff = 0
|
mTimeDiff = 0
|
||||||
for _, e in ipairs(self.modules) do
|
for _, e in ipairs(self.modules) do
|
||||||
timeNow = time.clock_gettime(time.CLOCK_MONOTONIC).tv_sec
|
mTimeNow = time.clock_gettime(time.CLOCK_MONOTONIC).tv_sec
|
||||||
if lastTime then
|
if mLastTime then
|
||||||
timeDiff = timeDiff + timeNow - lastTime
|
mTimeDiff = mTimeDiff + mTimeNow - mLastTime
|
||||||
else
|
else
|
||||||
timeDiff = 1
|
mTimeDiff = 1
|
||||||
end
|
end
|
||||||
lastTime = timeNow
|
mLastTime = mTimeNow
|
||||||
e:run(currentStatus, lastStatus, timeDiff)
|
e:run(currentStatus, lastStatus, mTimeDiff)
|
||||||
end
|
end
|
||||||
|
|
||||||
local modulesStatus = {}
|
local modulesStatus = {}
|
||||||
@@ -393,6 +405,19 @@ function InternetDetector:main()
|
|||||||
lastStatus = currentStatus
|
lastStatus = currentStatus
|
||||||
unistd.sleep(1)
|
unistd.sleep(1)
|
||||||
counter = counter + 1
|
counter = counter + 1
|
||||||
|
|
||||||
|
if self.mode == 2 then
|
||||||
|
uiTimeNow = time.clock_gettime(time.CLOCK_MONOTONIC).tv_sec
|
||||||
|
if uiLastTime then
|
||||||
|
self.uiCounter = self.uiCounter + uiTimeNow - uiLastTime
|
||||||
|
else
|
||||||
|
self.uiCounter = self.uiCounter + 1
|
||||||
|
end
|
||||||
|
uiLastTime = uiTimeNow
|
||||||
|
if self.uiCounter >= self.uiRunTime then
|
||||||
|
self:breakMain(signal.SIGTERM)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -490,13 +515,27 @@ function InternetDetector:stop()
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function InternetDetector:setSIGUSR()
|
||||||
|
local appName = self.appName:gsub("-", "%%-")
|
||||||
|
local ok, commonDir = pcall(dirent.files, self.commonDir)
|
||||||
|
if ok then
|
||||||
|
for item in commonDir do
|
||||||
|
if item:match("^" .. appName .. ".-%.pid$") then
|
||||||
|
pidValue = self:readValueFromFile(string.format("%s/%s", self.commonDir, item))
|
||||||
|
if pidValue then
|
||||||
|
signal.kill(tonumber(pidValue), signal.SIGUSR1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function InternetDetector:preRun()
|
function InternetDetector:preRun()
|
||||||
-- Exit if internet-detector mode != 1(Service)
|
-- Exit if internet-detector mode != (1 or 2)
|
||||||
if self.mode ~= 1 then
|
if self.mode ~= 1 and self.mode ~= 2 then
|
||||||
io.stderr:write(string.format('Start failed, mode != 1\n', self.appName))
|
io.stderr:write(string.format('Start failed, mode != (1 or 2)\n', self.appName))
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
end
|
end
|
||||||
if stat.stat(self.pidFile) then
|
if stat.stat(self.pidFile) then
|
||||||
@@ -528,7 +567,6 @@ function InternetDetector:run()
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Debug
|
|
||||||
if self.debug then
|
if self.debug then
|
||||||
local function inspectTable()
|
local function inspectTable()
|
||||||
local tables = {}, f
|
local tables = {}, f
|
||||||
@@ -597,6 +635,10 @@ end
|
|||||||
function InternetDetector:setServiceConfig(instance)
|
function InternetDetector:setServiceConfig(instance)
|
||||||
if self:loadUCIConfig("instance", instance) then
|
if self:loadUCIConfig("instance", instance) then
|
||||||
self:parseHosts()
|
self:parseHosts()
|
||||||
|
if self.mode == 2 then
|
||||||
|
self.enableLogger = false
|
||||||
|
self.noModules = true
|
||||||
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -605,12 +647,12 @@ end
|
|||||||
|
|
||||||
local function help()
|
local function help()
|
||||||
return string.format(
|
return string.format(
|
||||||
"Usage: %s service <UCI instance> | nodaemon <UCI instance> | debug <UCI instance> | stop | status | inet-status | poll [<attempts num>] [<timeout sec>] | --help",
|
"Usage: %s service <UCI instance> | nodaemon <UCI instance> | debug <UCI instance> | stop | status | inet-status | uipoll | --help",
|
||||||
arg[0]
|
arg[0]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local helpArgs = { ["-h"] = true, ["--help"] = true, ["help"] = true }
|
local helpArgs = { ["-h"] = true, ["--help"] = true, help = true }
|
||||||
if arg[1] == "service" then
|
if arg[1] == "service" then
|
||||||
if arg[2] then
|
if arg[2] then
|
||||||
if InternetDetector:setServiceConfig(arg[2]) then
|
if InternetDetector:setServiceConfig(arg[2]) then
|
||||||
@@ -651,20 +693,12 @@ elseif arg[1] == "status" then
|
|||||||
print(InternetDetector:status())
|
print(InternetDetector:status())
|
||||||
elseif arg[1] == "inet-status" then
|
elseif arg[1] == "inet-status" then
|
||||||
print(InternetDetector:inetStatus())
|
print(InternetDetector:inetStatus())
|
||||||
elseif arg[1] == "poll" then
|
elseif arg[1] == "uipoll" then
|
||||||
if InternetDetector:loadUCIConfig("ui", "ui") then
|
if InternetDetector:status() == "stoped" then
|
||||||
InternetDetector:parseHosts()
|
|
||||||
|
|
||||||
if arg[2] and arg[2]:match("[0-9]+") then
|
|
||||||
InternetDetector.serviceConfig.connection_attempts = tonumber(arg[2])
|
|
||||||
if arg[3] and arg[3]:match("[0-9]+") then
|
|
||||||
InternetDetector.serviceConfig.connection_timeout = tonumber(arg[3])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
print(InternetDetector:poll())
|
|
||||||
else
|
|
||||||
os.exit(126)
|
os.exit(126)
|
||||||
|
else
|
||||||
|
InternetDetector:setSIGUSR()
|
||||||
|
print(InternetDetector:inetStatus())
|
||||||
end
|
end
|
||||||
elseif helpArgs[arg[1]] then
|
elseif helpArgs[arg[1]] then
|
||||||
print(help())
|
print(help())
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ local Module = {
|
|||||||
runInterval = 5,
|
runInterval = 5,
|
||||||
sysLedsDir = "/sys/class/leds",
|
sysLedsDir = "/sys/class/leds",
|
||||||
ledName = nil,
|
ledName = nil,
|
||||||
ledAction1 = 2,
|
ledAction1 = 2, -- 1: off, 2: on, 3: blink
|
||||||
ledAction2 = 1,
|
ledAction2 = 1, -- 1: off, 2: on, 3: blink
|
||||||
status = nil,
|
status = nil,
|
||||||
_enabled = false,
|
_enabled = false,
|
||||||
_ledDir = nil,
|
_ledDir = nil,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ local Module = {
|
|||||||
name = "mod_public_ip",
|
name = "mod_public_ip",
|
||||||
runPrio = 50,
|
runPrio = 50,
|
||||||
config = {
|
config = {
|
||||||
|
noModules = false,
|
||||||
debug = false,
|
debug = false,
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
iface = nil,
|
iface = nil,
|
||||||
@@ -65,7 +66,7 @@ local Module = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Module:runIpScript()
|
function Module:runIpScript()
|
||||||
if self.enableIpScript and unistd.access(self.ipScript, "r") then
|
if not self.config.noModules and self.enableIpScript and unistd.access(self.ipScript, "r") then
|
||||||
stdlib.setenv("PUBLIC_IP", self.status)
|
stdlib.setenv("PUBLIC_IP", self.status)
|
||||||
os.execute(string.format('/bin/sh "%s" &', self.ipScript))
|
os.execute(string.format('/bin/sh "%s" &', self.ipScript))
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#
|
#
|
||||||
# (с) 2023 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
# (с) 2024 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
||||||
#
|
#
|
||||||
|
|
||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_VERSION:=1.1-0
|
PKG_VERSION:=1.2-0
|
||||||
LUCI_TITLE:=LuCI support for internet-detector
|
LUCI_TITLE:=LuCI support for internet-detector
|
||||||
LUCI_DEPENDS:=+internet-detector
|
LUCI_DEPENDS:=+internet-detector
|
||||||
LUCI_PKGARCH:=all
|
LUCI_PKGARCH:=all
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ const btnStyleDisabled = 'btn cbi-button-reset';
|
|||||||
const btnStyleApply = 'btn cbi-button-apply';
|
const btnStyleApply = 'btn cbi-button-apply';
|
||||||
|
|
||||||
var Timefield = ui.Textfield.extend({
|
var Timefield = ui.Textfield.extend({
|
||||||
secToString: function(value) {
|
secToString(value) {
|
||||||
let string = '0';
|
let string = '0';
|
||||||
if(/^\d+$/.test(value)) {
|
if(/^\d+$/.test(value)) {
|
||||||
value = Number(value);
|
value = Number(value);
|
||||||
@@ -81,7 +81,7 @@ var Timefield = ui.Textfield.extend({
|
|||||||
return string;
|
return string;
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render() {
|
||||||
let frameEl = E('div', { 'id': this.options.id }),
|
let frameEl = E('div', { 'id': this.options.id }),
|
||||||
inputEl = E('input', {
|
inputEl = E('input', {
|
||||||
'id' : this.options.id ? 'widget.' + this.options.id : null,
|
'id' : this.options.id ? 'widget.' + this.options.id : null,
|
||||||
@@ -98,7 +98,7 @@ var Timefield = ui.Textfield.extend({
|
|||||||
return this.bind(frameEl);
|
return this.bind(frameEl);
|
||||||
},
|
},
|
||||||
|
|
||||||
getValue: function() {
|
getValue() {
|
||||||
let rawValue = this.node.querySelector('input').value,
|
let rawValue = this.node.querySelector('input').value,
|
||||||
value = 0,
|
value = 0,
|
||||||
res = rawValue.match(/^(\d+)([hms]?)$/);
|
res = rawValue.match(/^(\d+)([hms]?)$/);
|
||||||
@@ -121,7 +121,7 @@ var Timefield = ui.Textfield.extend({
|
|||||||
return String(value);
|
return String(value);
|
||||||
},
|
},
|
||||||
|
|
||||||
setValue: function(value) {
|
setValue(value) {
|
||||||
let inputEl = this.node.querySelector('input');
|
let inputEl = this.node.querySelector('input');
|
||||||
inputEl.value = this.secToString(value);
|
inputEl.value = this.secToString(value);
|
||||||
},
|
},
|
||||||
@@ -140,10 +140,6 @@ return view.extend({
|
|||||||
inetStatusArea : E('div', { 'class': 'cbi-value-field', 'id': 'inetStatusArea' }),
|
inetStatusArea : E('div', { 'class': 'cbi-value-field', 'id': 'inetStatusArea' }),
|
||||||
serviceStatusLabel : E('em', { 'id': 'serviceStatusLabel' }),
|
serviceStatusLabel : E('em', { 'id': 'serviceStatusLabel' }),
|
||||||
initButton : null,
|
initButton : null,
|
||||||
uiPollCounter : 0,
|
|
||||||
uiPollState : null,
|
|
||||||
uiCheckIntervalUp : null,
|
|
||||||
uiCheckIntervalDown : null,
|
|
||||||
currentAppMode : '0',
|
currentAppMode : '0',
|
||||||
defaultHosts : [ '8.8.8.8', '1.1.1.1' ],
|
defaultHosts : [ '8.8.8.8', '1.1.1.1' ],
|
||||||
leds : [],
|
leds : [],
|
||||||
@@ -164,7 +160,7 @@ return view.extend({
|
|||||||
expect: { result: false }
|
expect: { result: false }
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getInitStatus: function() {
|
getInitStatus() {
|
||||||
return this.callInitStatus(this.appName).then(res => {
|
return this.callInitStatus(this.appName).then(res => {
|
||||||
if(res) {
|
if(res) {
|
||||||
return res[this.appName].enabled;
|
return res[this.appName].enabled;
|
||||||
@@ -177,7 +173,7 @@ return view.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
handleServiceAction: function(action) {
|
handleServiceAction(action) {
|
||||||
return this.callInitAction(this.appName, action).then(success => {
|
return this.callInitAction(this.appName, action).then(success => {
|
||||||
if(!success) {
|
if(!success) {
|
||||||
throw _('Command failed');
|
throw _('Command failed');
|
||||||
@@ -189,12 +185,24 @@ return view.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setInternetStatus: function() {
|
callUIPoll: rpc.declare({
|
||||||
|
object: 'luci.internet-detector',
|
||||||
|
method: 'UIPoll',
|
||||||
|
expect: { '': {} }
|
||||||
|
}),
|
||||||
|
|
||||||
|
getUIPoll() {
|
||||||
|
return this.callUIPoll().then(data => {
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setInternetStatus() {
|
||||||
this.inetStatusArea.innerHTML = '';
|
this.inetStatusArea.innerHTML = '';
|
||||||
|
|
||||||
if(!this.inetStatus || !this.inetStatus.instances || this.inetStatus.instances.length === 0) {
|
if(!this.inetStatus || !this.inetStatus.instances || this.inetStatus.instances.length === 0) {
|
||||||
let label = E('span', { 'class': 'id-label-status id-undefined' }, _('Undefined'))
|
let label = E('span', { 'class': 'id-label-status id-undefined' }, _('Undefined'));
|
||||||
if(this.currentAppMode !== '0' && this.appStatus !== 'stoped') {
|
if((this.currentAppMode === '1' && this.appStatus !== 'stoped') || this.currentAppMode === '2') {
|
||||||
label.classList.add('spinning');
|
label.classList.add('spinning');
|
||||||
};
|
};
|
||||||
this.inetStatusArea.append(label);
|
this.inetStatusArea.append(label);
|
||||||
@@ -219,8 +227,7 @@ return view.extend({
|
|||||||
|
|
||||||
this.inetStatusArea.append(
|
this.inetStatusArea.append(
|
||||||
E('span', { 'class': className }, '%s%s%s'.format(
|
E('span', { 'class': className }, '%s%s%s'.format(
|
||||||
(this.currentAppMode === '1') ? i.instance + ': ' : '',
|
i.instance + ': ', status, publicIp)
|
||||||
status, publicIp)
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -233,7 +240,7 @@ return view.extend({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
inetStatusFromJson: function(res) {
|
inetStatusFromJson(res) {
|
||||||
let inetStatData = null;
|
let inetStatData = null;
|
||||||
if(res.code === 0) {
|
if(res.code === 0) {
|
||||||
try {
|
try {
|
||||||
@@ -243,7 +250,7 @@ return view.extend({
|
|||||||
return inetStatData;
|
return inetStatData;
|
||||||
},
|
},
|
||||||
|
|
||||||
servicePoll: function() {
|
servicePoll() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
fs.exec(this.execPath, [ 'status' ]),
|
fs.exec(this.execPath, [ 'status' ]),
|
||||||
fs.exec(this.execPath, [ 'inet-status' ]),
|
fs.exec(this.execPath, [ 'inet-status' ]),
|
||||||
@@ -259,31 +266,18 @@ return view.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
uiPoll: function() {
|
uiPoll() {
|
||||||
this.uiPollCounter = ++this.uiPollCounter;
|
return this.getUIPoll().then(status => {
|
||||||
|
this.inetStatus = status;
|
||||||
if((this.uiPollState === 0 && this.uiPollCounter % this.uiCheckIntervalUp) ||
|
|
||||||
(this.uiPollState === 1 && this.uiPollCounter % this.uiCheckIntervalDown)) {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.uiPollCounter = 0;
|
|
||||||
|
|
||||||
return fs.exec(this.execPath, [ 'poll' ]).then(res => {
|
|
||||||
let inetStatData = this.inetStatusFromJson(res);
|
|
||||||
if(inetStatData.instances[0]) {
|
|
||||||
this.uiPollState = inetStatData.instances[0].inet;
|
|
||||||
};
|
|
||||||
this.inetStatus = inetStatData;
|
|
||||||
this.setInternetStatus();
|
this.setInternetStatus();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
serviceRestart: function() {
|
serviceRestart() {
|
||||||
return this.handleServiceAction('restart');
|
return this.handleServiceAction('restart');
|
||||||
},
|
},
|
||||||
|
|
||||||
serviceRestartHandler: function() {
|
serviceRestartHandler() {
|
||||||
poll.stop();
|
poll.stop();
|
||||||
return this.serviceRestart().then(() => {
|
return this.serviceRestart().then(() => {
|
||||||
window.setTimeout(() => this.servicePoll(), 1000);
|
window.setTimeout(() => this.servicePoll(), 1000);
|
||||||
@@ -294,7 +288,7 @@ return view.extend({
|
|||||||
CBITimeInput: form.Value.extend({
|
CBITimeInput: form.Value.extend({
|
||||||
__name__ : 'CBI.TimeInput',
|
__name__ : 'CBI.TimeInput',
|
||||||
|
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
renderWidget(section_id, option_index, cfgvalue) {
|
||||||
let value = (cfgvalue != null) ? cfgvalue : this.default,
|
let value = (cfgvalue != null) ? cfgvalue : this.default,
|
||||||
widget = new Timefield(value, {
|
widget = new Timefield(value, {
|
||||||
id : this.cbid(section_id),
|
id : this.cbid(section_id),
|
||||||
@@ -318,7 +312,7 @@ return view.extend({
|
|||||||
CBIBlockInetStatus: form.Value.extend({
|
CBIBlockInetStatus: form.Value.extend({
|
||||||
__name__ : 'CBI.BlockInetStatus',
|
__name__ : 'CBI.BlockInetStatus',
|
||||||
|
|
||||||
__init__ : function(map, section, ctx) {
|
__init__(map, section, ctx) {
|
||||||
this.map = map;
|
this.map = map;
|
||||||
this.section = section;
|
this.section = section;
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
@@ -326,7 +320,7 @@ return view.extend({
|
|||||||
this.rmempty = true;
|
this.rmempty = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
renderWidget(section_id, option_index, cfgvalue) {
|
||||||
this.ctx.setInternetStatus();
|
this.ctx.setInternetStatus();
|
||||||
|
|
||||||
return E([
|
return E([
|
||||||
@@ -340,7 +334,7 @@ return view.extend({
|
|||||||
CBIBlockServiceStatus: form.Value.extend({
|
CBIBlockServiceStatus: form.Value.extend({
|
||||||
__name__ : 'CBI.BlockServiceStatus',
|
__name__ : 'CBI.BlockServiceStatus',
|
||||||
|
|
||||||
__init__ : function(map, section, ctx) {
|
__init__(map, section, ctx) {
|
||||||
this.map = map;
|
this.map = map;
|
||||||
this.section = section;
|
this.section = section;
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
@@ -348,7 +342,7 @@ return view.extend({
|
|||||||
this.rmempty = true;
|
this.rmempty = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
renderWidget(section_id, option_index, cfgvalue) {
|
||||||
return E([
|
return E([
|
||||||
E('label', { 'class': 'cbi-value-title', 'for': 'serviceStatusLabel' },
|
E('label', { 'class': 'cbi-value-title', 'for': 'serviceStatusLabel' },
|
||||||
_('Service')
|
_('Service')
|
||||||
@@ -363,7 +357,7 @@ return view.extend({
|
|||||||
CBIBlockInitButton: form.Value.extend({
|
CBIBlockInitButton: form.Value.extend({
|
||||||
__name__ : 'CBI.BlockInitButton',
|
__name__ : 'CBI.BlockInitButton',
|
||||||
|
|
||||||
__init__ : function(map, section, ctx) {
|
__init__(map, section, ctx) {
|
||||||
this.map = map;
|
this.map = map;
|
||||||
this.section = section;
|
this.section = section;
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
@@ -371,7 +365,7 @@ return view.extend({
|
|||||||
this.rmempty = true;
|
this.rmempty = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
renderWidget(section_id, option_index, cfgvalue) {
|
||||||
this.ctx.initButton = E('button', {
|
this.ctx.initButton = E('button', {
|
||||||
'class': (!this.ctx.initStatus) ? btnStyleDisabled : btnStyleEnabled,
|
'class': (!this.ctx.initStatus) ? btnStyleDisabled : btnStyleEnabled,
|
||||||
'click': ui.createHandlerFn(this, () => {
|
'click': ui.createHandlerFn(this, () => {
|
||||||
@@ -413,7 +407,7 @@ return view.extend({
|
|||||||
CBIBlockFileEdit: form.Value.extend({
|
CBIBlockFileEdit: form.Value.extend({
|
||||||
__name__ : 'CBI.BlockFileEdit',
|
__name__ : 'CBI.BlockFileEdit',
|
||||||
|
|
||||||
__init__ : function(map, section, ctx, id, file, title, description, callback) {
|
__init__(map, section, ctx, id, file, title, description, callback) {
|
||||||
this.map = map;
|
this.map = map;
|
||||||
this.section = section;
|
this.section = section;
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
@@ -427,11 +421,11 @@ return view.extend({
|
|||||||
this.content = '';
|
this.content = '';
|
||||||
},
|
},
|
||||||
|
|
||||||
cfgvalue: function(section_id, option) {
|
cfgvalue(section_id, option) {
|
||||||
return this.content;
|
return this.content;
|
||||||
},
|
},
|
||||||
|
|
||||||
formvalue: function(section_id) {
|
formvalue(section_id) {
|
||||||
let value = this.content;
|
let value = this.content;
|
||||||
let textarea = document.getElementById('widget.file_edit.content.' + this.id);
|
let textarea = document.getElementById('widget.file_edit.content.' + this.id);
|
||||||
if(textarea) {
|
if(textarea) {
|
||||||
@@ -440,7 +434,7 @@ return view.extend({
|
|||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
|
|
||||||
write: function(section_id, formvalue) {
|
write(section_id, formvalue) {
|
||||||
return fs.write(this.file, formvalue).then(rc => {
|
return fs.write(this.file, formvalue).then(rc => {
|
||||||
ui.addNotification(null, E('p', _('Contents have been saved.')),
|
ui.addNotification(null, E('p', _('Contents have been saved.')),
|
||||||
'info');
|
'info');
|
||||||
@@ -453,13 +447,13 @@ return view.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
load: function() {
|
load() {
|
||||||
return L.resolveDefault(fs.read(this.file), '').then(c => {
|
return L.resolveDefault(fs.read(this.file), '').then(c => {
|
||||||
this.content = c;
|
this.content = c;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
renderWidget(section_id, option_index, cfgvalue) {
|
||||||
return E('textarea', {
|
return E('textarea', {
|
||||||
'id' : 'widget.file_edit.content.' + this.id,
|
'id' : 'widget.file_edit.content.' + this.id,
|
||||||
'class' : 'cbi-input-textarea',
|
'class' : 'cbi-input-textarea',
|
||||||
@@ -471,7 +465,7 @@ return view.extend({
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
load: function() {
|
load() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
fs.exec(this.execPath, [ 'status' ]),
|
fs.exec(this.execPath, [ 'status' ]),
|
||||||
this.getInitStatus(),
|
this.getInitStatus(),
|
||||||
@@ -484,7 +478,7 @@ return view.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function(data) {
|
render(data) {
|
||||||
if(!data) {
|
if(!data) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -498,8 +492,6 @@ return view.extend({
|
|||||||
this.mta = true;
|
this.mta = true;
|
||||||
};
|
};
|
||||||
this.currentAppMode = uci.get(this.appName, 'config', 'mode');
|
this.currentAppMode = uci.get(this.appName, 'config', 'mode');
|
||||||
this.uiCheckIntervalUp = Number(uci.get(this.appName, 'ui', 'interval_up'));
|
|
||||||
this.uiCheckIntervalDown = Number(uci.get(this.appName, 'ui', 'interval_down'));
|
|
||||||
|
|
||||||
let s, o, ss;
|
let s, o, ss;
|
||||||
let m = new form.Map(this.appName,
|
let m = new form.Map(this.appName,
|
||||||
@@ -549,32 +541,27 @@ return view.extend({
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
s = m.section(form.NamedSection, 'config', 'main');
|
|
||||||
|
|
||||||
|
|
||||||
/* Service instances configuration */
|
/* Service instances configuration */
|
||||||
|
|
||||||
s.tab('service', _('Service configuration'));
|
if(this.currentAppMode !== '2') {
|
||||||
|
|
||||||
// enable_logger
|
// enable_logger
|
||||||
o = s.taboption('service', form.Flag, 'enable_logger',
|
o = s.option(form.Flag, 'enable_logger',
|
||||||
_('Enable logging'),
|
_('Enable logging'),
|
||||||
_('Write messages to the system log.')
|
_('Write messages to the system log.')
|
||||||
);
|
);
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
};
|
||||||
|
|
||||||
o = s.taboption('service', form.SectionValue, 'instance', form.GridSection,
|
s = m.section(form.GridSection, 'instance');
|
||||||
'instance'
|
|
||||||
);
|
|
||||||
ss = o.subsection;
|
|
||||||
|
|
||||||
ss.title = _('Service instances');
|
s.title = _('Service instances');
|
||||||
ss.addremove = true;
|
s.addremove = true;
|
||||||
ss.sortable = true;
|
s.sortable = true;
|
||||||
ss.nodescriptions = true;
|
s.nodescriptions = true;
|
||||||
ss.addbtntitle = _('Add instance');
|
s.addbtntitle = _('Add instance');
|
||||||
|
|
||||||
ss.tab('main', _('Main settings'));
|
s.tab('main', _('Main settings'));
|
||||||
|
|
||||||
function makeIntervalOptions(list) {
|
function makeIntervalOptions(list) {
|
||||||
list.value(2, '2 ' + _('sec'));
|
list.value(2, '2 ' + _('sec'));
|
||||||
@@ -591,7 +578,7 @@ return view.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// enabled
|
// enabled
|
||||||
o = ss.taboption('main', form.Flag, 'enabled',
|
o = s.taboption('main', form.Flag, 'enabled',
|
||||||
_('Enabled'),
|
_('Enabled'),
|
||||||
);
|
);
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
@@ -600,16 +587,17 @@ return view.extend({
|
|||||||
o.modalonly = false;
|
o.modalonly = false;
|
||||||
|
|
||||||
// hosts
|
// hosts
|
||||||
o = ss.taboption('main', form.DynamicList,
|
o = s.taboption('main', form.DynamicList,
|
||||||
'hosts', _('Hosts'),
|
'hosts', _('Hosts'),
|
||||||
_('Hosts to check Internet availability. Hosts are polled (in list order) until at least one of them responds.')
|
_('Hosts to check Internet availability. Hosts are polled (in list order) until at least one of them responds.')
|
||||||
);
|
);
|
||||||
|
//o.datatype = 'or(host,hostport)';
|
||||||
o.datatype = 'or(or(host,hostport),ipaddrport(1))';
|
o.datatype = 'or(or(host,hostport),ipaddrport(1))';
|
||||||
o.default = this.defaultHosts;
|
o.default = this.defaultHosts;
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
// check_type
|
// check_type
|
||||||
o = ss.taboption('main', form.ListValue,
|
o = s.taboption('main', form.ListValue,
|
||||||
'check_type', _('Check type'),
|
'check_type', _('Check type'),
|
||||||
_('Host availability check type.')
|
_('Host availability check type.')
|
||||||
);
|
);
|
||||||
@@ -619,7 +607,7 @@ return view.extend({
|
|||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
|
|
||||||
// tcp_port
|
// tcp_port
|
||||||
o = ss.taboption('main', form.Value,
|
o = s.taboption('main', form.Value,
|
||||||
'tcp_port', _('TCP port'),
|
'tcp_port', _('TCP port'),
|
||||||
_('Default port value for TCP connections.')
|
_('Default port value for TCP connections.')
|
||||||
);
|
);
|
||||||
@@ -629,7 +617,7 @@ return view.extend({
|
|||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
|
|
||||||
// icmp_packet_size
|
// icmp_packet_size
|
||||||
o = ss.taboption('main', form.ListValue,
|
o = s.taboption('main', form.ListValue,
|
||||||
'icmp_packet_size', _('ICMP packet data size'));
|
'icmp_packet_size', _('ICMP packet data size'));
|
||||||
o.value(1, _('Small: 1 byte'));
|
o.value(1, _('Small: 1 byte'));
|
||||||
o.value(32, _('Windows: 32 bytes'));
|
o.value(32, _('Windows: 32 bytes'));
|
||||||
@@ -642,14 +630,14 @@ return view.extend({
|
|||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
|
|
||||||
// iface
|
// iface
|
||||||
o = ss.taboption('main', widgets.DeviceSelect,
|
o = s.taboption('main', widgets.DeviceSelect,
|
||||||
'iface', _('Interface'),
|
'iface', _('Interface'),
|
||||||
_('Network interface for Internet access. If not specified, the default interface is used.')
|
_('Network interface for Internet access. If not specified, the default interface is used.')
|
||||||
);
|
);
|
||||||
o.noaliases = true;
|
o.noaliases = true;
|
||||||
|
|
||||||
// interval_up
|
// interval_up
|
||||||
o = ss.taboption('main', form.ListValue,
|
o = s.taboption('main', form.ListValue,
|
||||||
'interval_up', _('Alive interval'),
|
'interval_up', _('Alive interval'),
|
||||||
_('Hosts polling interval when the Internet is up.')
|
_('Hosts polling interval when the Internet is up.')
|
||||||
);
|
);
|
||||||
@@ -658,7 +646,7 @@ return view.extend({
|
|||||||
makeIntervalOptions(o);
|
makeIntervalOptions(o);
|
||||||
|
|
||||||
// interval_down
|
// interval_down
|
||||||
o = ss.taboption('main', form.ListValue,
|
o = s.taboption('main', form.ListValue,
|
||||||
'interval_down', _('Dead interval'),
|
'interval_down', _('Dead interval'),
|
||||||
_('Hosts polling interval when the Internet is down.')
|
_('Hosts polling interval when the Internet is down.')
|
||||||
);
|
);
|
||||||
@@ -667,7 +655,7 @@ return view.extend({
|
|||||||
makeIntervalOptions(o);
|
makeIntervalOptions(o);
|
||||||
|
|
||||||
// connection_attempts
|
// connection_attempts
|
||||||
o = ss.taboption('main', form.ListValue,
|
o = s.taboption('main', form.ListValue,
|
||||||
'connection_attempts', _('Connection attempts'),
|
'connection_attempts', _('Connection attempts'),
|
||||||
_('Maximum number of attempts to connect to each host.')
|
_('Maximum number of attempts to connect to each host.')
|
||||||
);
|
);
|
||||||
@@ -680,7 +668,7 @@ return view.extend({
|
|||||||
o.default = '2';
|
o.default = '2';
|
||||||
|
|
||||||
// connection_timeout
|
// connection_timeout
|
||||||
o = ss.taboption('main', form.ListValue,
|
o = s.taboption('main', form.ListValue,
|
||||||
'connection_timeout', _('Connection timeout'),
|
'connection_timeout', _('Connection timeout'),
|
||||||
_('Maximum timeout for waiting for a response from the host.')
|
_('Maximum timeout for waiting for a response from the host.')
|
||||||
);
|
);
|
||||||
@@ -700,15 +688,23 @@ return view.extend({
|
|||||||
|
|
||||||
/* Modules */
|
/* Modules */
|
||||||
|
|
||||||
ss.tab('led_control', _('LED control'));
|
if(this.currentAppMode !== '2') {
|
||||||
ss.tab('reboot_device', _('Reboot device'));
|
s.tab('led_control', _('LED control'));
|
||||||
ss.tab('restart_network', _('Restart network'));
|
s.tab('reboot_device', _('Reboot device'));
|
||||||
ss.tab('restart_modem', _('Restart modem'));
|
s.tab('restart_network', _('Restart network'));
|
||||||
ss.tab('public_ip', _('Public IP address'));
|
s.tab('restart_modem', _('Restart modem'));
|
||||||
ss.tab('email', _('Email notification'));
|
};
|
||||||
ss.tab('user_scripts', _('User scripts'));
|
|
||||||
|
|
||||||
ss.addModalOptions = (s, section_id, ev) => {
|
s.tab('public_ip', _('Public IP address'));
|
||||||
|
|
||||||
|
if(this.currentAppMode !== '2') {
|
||||||
|
s.tab('email', _('Email notification'));
|
||||||
|
s.tab('user_scripts', _('User scripts'));
|
||||||
|
};
|
||||||
|
|
||||||
|
s.addModalOptions = (s, section_id, ev) => {
|
||||||
|
|
||||||
|
if(this.currentAppMode !== '2') {
|
||||||
|
|
||||||
// LED control
|
// LED control
|
||||||
|
|
||||||
@@ -740,7 +736,6 @@ return view.extend({
|
|||||||
_('Action when connected'));
|
_('Action when connected'));
|
||||||
o.depends({ mod_led_control_enabled: '1' });
|
o.depends({ mod_led_control_enabled: '1' });
|
||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
//o.value(0, _('Nothing'));
|
|
||||||
o.value(1, _('Off'));
|
o.value(1, _('Off'));
|
||||||
o.value(2, _('On'));
|
o.value(2, _('On'));
|
||||||
o.value(3, _('Blink'));
|
o.value(3, _('Blink'));
|
||||||
@@ -919,6 +914,8 @@ return view.extend({
|
|||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
// Public IP address
|
// Public IP address
|
||||||
|
|
||||||
o = s.taboption('public_ip', form.DummyValue, '_dummy');
|
o = s.taboption('public_ip', form.DummyValue, '_dummy');
|
||||||
@@ -978,10 +975,12 @@ return view.extend({
|
|||||||
);
|
);
|
||||||
o.default = '3'
|
o.default = '3'
|
||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
for(let i=1; i<=5; i++) {
|
for(let i = 1; i <= 5; i++) {
|
||||||
o.value(i, i + ' ' + _('sec'));
|
o.value(i, i + ' ' + _('sec'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(this.currentAppMode !== '2') {
|
||||||
|
|
||||||
// enable_ip_script
|
// enable_ip_script
|
||||||
o = s.taboption('public_ip', form.Flag, 'mod_public_ip_enable_ip_script',
|
o = s.taboption('public_ip', form.Flag, 'mod_public_ip_enable_ip_script',
|
||||||
_('Enable public-ip-script'));
|
_('Enable public-ip-script'));
|
||||||
@@ -997,6 +996,7 @@ return view.extend({
|
|||||||
);
|
);
|
||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
|
|
||||||
|
|
||||||
// Email notification
|
// Email notification
|
||||||
|
|
||||||
o = s.taboption('email', form.DummyValue, '_dummy');
|
o = s.taboption('email', form.DummyValue, '_dummy');
|
||||||
@@ -1141,107 +1141,7 @@ return view.extend({
|
|||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
};
|
||||||
/* UI detector configuration */
|
|
||||||
|
|
||||||
s.tab('ui_detector', _('UI detector configuration'));
|
|
||||||
|
|
||||||
o = s.taboption('ui_detector', form.SectionValue,
|
|
||||||
'ui', form.NamedSection, 'ui'
|
|
||||||
);
|
|
||||||
ss = o.subsection;
|
|
||||||
|
|
||||||
let makeUIIntervalOptions = L.bind(function(list) {
|
|
||||||
list.value(1, '%d %s'.format(this.pollInterval, _('sec')));
|
|
||||||
list.value(2, '%d %s'.format(this.pollInterval * 2, _('sec')));
|
|
||||||
list.value(3, '%d %s'.format(this.pollInterval * 3, _('sec')));
|
|
||||||
list.value(4, '%d %s'.format(this.pollInterval * 4, _('sec')));
|
|
||||||
list.value(5, '%d %s'.format(this.pollInterval * 5, _('sec')));
|
|
||||||
list.value(6, '%d %s'.format(this.pollInterval * 6, _('sec')));
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
// hosts
|
|
||||||
o = ss.option(form.DynamicList,
|
|
||||||
'hosts', _('Hosts'),
|
|
||||||
_('Hosts to check Internet availability. Hosts are polled (in list order) until at least one of them responds.')
|
|
||||||
);
|
|
||||||
o.datatype = 'or(or(host,hostport),ipaddrport(1))';
|
|
||||||
o.default = this.defaultHosts;
|
|
||||||
o.rmempty = false;
|
|
||||||
|
|
||||||
// check_type
|
|
||||||
o = ss.option(form.ListValue,
|
|
||||||
'check_type', _('Check type'),
|
|
||||||
_('Host availability check type.')
|
|
||||||
);
|
|
||||||
o.value(0, _('TCP port connection'));
|
|
||||||
o.value(1, _('ICMP-echo request (ping)'));
|
|
||||||
o.default = '0';
|
|
||||||
|
|
||||||
// tcp_port
|
|
||||||
o = ss.option(form.Value,
|
|
||||||
'tcp_port', _('TCP port'),
|
|
||||||
_('Default port value for TCP connections.')
|
|
||||||
);
|
|
||||||
o.datatype = 'port';
|
|
||||||
o.default = '53';
|
|
||||||
o.depends({ check_type: '0' });
|
|
||||||
|
|
||||||
// icmp_packet_size
|
|
||||||
o = ss.option(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' });
|
|
||||||
|
|
||||||
// iface
|
|
||||||
o = ss.option(widgets.DeviceSelect,
|
|
||||||
'iface', _('Interface'),
|
|
||||||
_('Network interface for Internet access. If not specified, the default interface is used.')
|
|
||||||
);
|
|
||||||
o.noaliases = true;
|
|
||||||
|
|
||||||
// interval_up
|
|
||||||
o = ss.option(form.ListValue,
|
|
||||||
'interval_up', _('Alive interval'),
|
|
||||||
_('Hosts polling interval when the Internet is up.')
|
|
||||||
);
|
|
||||||
makeUIIntervalOptions(o);
|
|
||||||
o.default = '6';
|
|
||||||
|
|
||||||
// interval_down
|
|
||||||
o = ss.option(form.ListValue,
|
|
||||||
'interval_down', _('Dead interval'),
|
|
||||||
_('Hosts polling interval when the Internet is down.')
|
|
||||||
);
|
|
||||||
makeUIIntervalOptions(o);
|
|
||||||
o.default = '1';
|
|
||||||
|
|
||||||
// connection_attempts
|
|
||||||
o = ss.option(form.ListValue,
|
|
||||||
'connection_attempts', _('Connection attempts'),
|
|
||||||
_('Maximum number of attempts to connect to each host.')
|
|
||||||
);
|
|
||||||
o.value(1);
|
|
||||||
o.value(2);
|
|
||||||
o.value(3);
|
|
||||||
o.default = '1';
|
|
||||||
|
|
||||||
// connection_timeout
|
|
||||||
o = ss.option(form.ListValue,
|
|
||||||
'connection_timeout', _('Connection timeout'),
|
|
||||||
_('Maximum timeout for waiting for a response from the host.')
|
|
||||||
);
|
|
||||||
o.value(1, '1 ' + _('sec'));
|
|
||||||
o.value(2, '2 ' + _('sec'));
|
|
||||||
o.value(3, '3 ' + _('sec'));
|
|
||||||
o.default = '1';
|
|
||||||
|
|
||||||
|
|
||||||
if(this.currentAppMode !== '0') {
|
if(this.currentAppMode !== '0') {
|
||||||
poll.add(
|
poll.add(
|
||||||
@@ -1255,7 +1155,7 @@ return view.extend({
|
|||||||
return mapPromise;
|
return mapPromise;
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSaveApply: function(ev, mode) {
|
handleSaveApply(ev, mode) {
|
||||||
poll.stop();
|
poll.stop();
|
||||||
return this.handleSave(ev).then(() => {
|
return this.handleSave(ev).then(() => {
|
||||||
ui.changes.apply(mode == '0');
|
ui.changes.apply(mode == '0');
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
'require baseclass';
|
'require baseclass';
|
||||||
'require fs';
|
'require fs';
|
||||||
|
'require rpc';
|
||||||
'require uci';
|
'require uci';
|
||||||
|
|
||||||
document.head.append(E('style', {'type': 'text/css'},
|
document.head.append(E('style', {'type': 'text/css'},
|
||||||
@@ -57,14 +58,22 @@ return baseclass.extend({
|
|||||||
title : _('Internet'),
|
title : _('Internet'),
|
||||||
appName : 'internet-detector',
|
appName : 'internet-detector',
|
||||||
execPath : '/usr/bin/internet-detector',
|
execPath : '/usr/bin/internet-detector',
|
||||||
uiCheckIntervalUp : null,
|
|
||||||
uiCheckIntervalDown : null,
|
|
||||||
currentAppMode : null,
|
currentAppMode : null,
|
||||||
inetStatus : null,
|
inetStatus : null,
|
||||||
uiState : null,
|
|
||||||
counter : 0,
|
|
||||||
|
|
||||||
inetStatusFromJson : function(res) {
|
callUIPoll: rpc.declare({
|
||||||
|
object: 'luci.internet-detector',
|
||||||
|
method: 'UIPoll',
|
||||||
|
expect: { '': {} }
|
||||||
|
}),
|
||||||
|
|
||||||
|
getUIPoll() {
|
||||||
|
return this.callUIPoll().then(data => {
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
inetStatusFromJson(res) {
|
||||||
let inetStatData = null;
|
let inetStatData = null;
|
||||||
if(res.code === 0) {
|
if(res.code === 0) {
|
||||||
try {
|
try {
|
||||||
@@ -74,50 +83,38 @@ return baseclass.extend({
|
|||||||
return inetStatData;
|
return inetStatData;
|
||||||
},
|
},
|
||||||
|
|
||||||
load: async function() {
|
async load() {
|
||||||
if(!(this.uiCheckIntervalUp && this.uiCheckIntervalDown && this.currentAppMode)) {
|
if(!this.currentAppMode) {
|
||||||
await uci.load(this.appName).then(data => {
|
await uci.load(this.appName).then(data => {
|
||||||
this.uiCheckIntervalUp = Number(uci.get(this.appName, 'ui', 'interval_up'));
|
|
||||||
this.uiCheckIntervalDown = Number(uci.get(this.appName, 'ui', 'interval_down'));
|
|
||||||
this.currentAppMode = uci.get(this.appName, 'config', 'mode');
|
this.currentAppMode = uci.get(this.appName, 'config', 'mode');
|
||||||
}).catch(e => {});
|
}).catch(e => {});
|
||||||
};
|
};
|
||||||
|
|
||||||
if(this.currentAppMode === '2') {
|
if(this.currentAppMode === '2') {
|
||||||
this.counter++;
|
return this.getUIPoll();
|
||||||
|
|
||||||
if((this.uiState === 0 && this.counter % this.uiCheckIntervalUp) ||
|
|
||||||
(this.uiState === 1 && this.counter % this.uiCheckIntervalDown)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.counter = 0;
|
|
||||||
return L.resolveDefault(fs.exec(this.execPath, [ 'poll' ]), null);
|
|
||||||
}
|
}
|
||||||
else if(this.currentAppMode === '1') {
|
else if(this.currentAppMode === '1') {
|
||||||
return L.resolveDefault(fs.exec(this.execPath, [ 'inet-status' ]), null);
|
return L.resolveDefault(fs.exec(this.execPath, [ 'inet-status' ]), null);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function(data) {
|
render(data) {
|
||||||
if(this.currentAppMode === '0') {
|
if(this.currentAppMode === '0') {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
else if(this.currentAppMode === '1' && data) {
|
||||||
|
data = this.inetStatusFromJson(data);
|
||||||
};
|
};
|
||||||
|
this.inetStatus = data;
|
||||||
if(data) {
|
|
||||||
this.inetStatus = this.inetStatusFromJson(data);
|
|
||||||
if(this.currentAppMode === '2') {
|
|
||||||
this.uiState = this.inetStatus.instances[0].inet;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let inetStatusArea = E('div', {});
|
let inetStatusArea = E('div', {});
|
||||||
|
|
||||||
if(!this.inetStatus || !this.inetStatus.instances || this.inetStatus.instances.length === 0) {
|
if(!this.inetStatus || !this.inetStatus.instances || this.inetStatus.instances.length === 0) {
|
||||||
inetStatusArea.append(
|
let label = E('span', { 'class': 'id-label-status id-undefined' }, _('Undefined'));
|
||||||
E('span', { 'class': 'id-label-status id-undefined' }, _('Undefined'))
|
if(this.currentAppMode === '2') {
|
||||||
);
|
label.classList.add('spinning');
|
||||||
|
};
|
||||||
|
inetStatusArea.append(label);
|
||||||
} else {
|
} else {
|
||||||
this.inetStatus.instances.sort((a, b) => a.num > b.num);
|
this.inetStatus.instances.sort((a, b) => a.num > b.num);
|
||||||
|
|
||||||
@@ -139,8 +136,7 @@ return baseclass.extend({
|
|||||||
|
|
||||||
inetStatusArea.append(
|
inetStatusArea.append(
|
||||||
E('span', { 'class': className }, '%s%s%s'.format(
|
E('span', { 'class': className }, '%s%s%s'.format(
|
||||||
(this.currentAppMode === '1') ? i.instance + ': ' : '',
|
i.instance + ': ', status, publicIp)
|
||||||
status, publicIp)
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -434,9 +434,6 @@ msgstr "Таймаут между остановкой и запуском ин
|
|||||||
msgid "Type a time string"
|
msgid "Type a time string"
|
||||||
msgstr "Введите строку времени"
|
msgstr "Введите строку времени"
|
||||||
|
|
||||||
msgid "UI detector configuration"
|
|
||||||
msgstr "Конфигурация UI детектора"
|
|
||||||
|
|
||||||
msgid "Unable to read the contents"
|
msgid "Unable to read the contents"
|
||||||
msgstr "Невозможно прочитать содержимое"
|
msgstr "Невозможно прочитать содержимое"
|
||||||
|
|
||||||
|
|||||||
@@ -404,9 +404,6 @@ msgstr ""
|
|||||||
msgid "Type a time string"
|
msgid "Type a time string"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "UI detector configuration"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Unable to read the contents"
|
msgid "Unable to read the contents"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
46
luci-app-internet-detector/root/usr/libexec/rpcd/luci.internet-detector
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
. /lib/functions.sh
|
||||||
|
. /usr/share/libubox/jshn.sh
|
||||||
|
|
||||||
|
readonly ID_EXEC="/usr/bin/internet-detector"
|
||||||
|
|
||||||
|
run_instance() {
|
||||||
|
config_get enabled "$1" enabled "0"
|
||||||
|
if [ $enabled = "1" ]; then
|
||||||
|
$ID_EXEC service "$1" > /dev/null 2>&1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
start_ui_instances() {
|
||||||
|
config_load internet-detector
|
||||||
|
config_get mode "config" mode "0"
|
||||||
|
if [ $mode = "2" ]; then
|
||||||
|
config_foreach run_instance "instance"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_poll() {
|
||||||
|
$ID_EXEC uipoll
|
||||||
|
if [ $? -eq 126 ]; then
|
||||||
|
start_ui_instances
|
||||||
|
$ID_EXEC inet-status
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
list)
|
||||||
|
json_init
|
||||||
|
json_add_object "UIPoll"
|
||||||
|
json_close_object
|
||||||
|
json_dump
|
||||||
|
json_cleanup
|
||||||
|
;;
|
||||||
|
call)
|
||||||
|
case "$2" in
|
||||||
|
UIPoll)
|
||||||
|
ui_poll
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -12,7 +12,8 @@
|
|||||||
},
|
},
|
||||||
"uci": [ "internet-detector" ],
|
"uci": [ "internet-detector" ],
|
||||||
"ubus": {
|
"ubus": {
|
||||||
"luci": [ "getInitList", "setInitAction" ]
|
"luci": [ "getInitList", "setInitAction" ],
|
||||||
|
"luci.internet-detector": [ "UIPoll" ]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"write": {
|
"write": {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 44 KiB |