mirror of
https://github.com/gSpotx2f/luci-app-internet-detector.git
synced 2025-12-06 11:36:49 +03:00
v1.0. Luaposix, multiple service instances.
This commit is contained in:
24
README.md
24
README.md
@@ -3,7 +3,7 @@ Internet-detector is an application for checking the availability of the Interne
|
|||||||
|
|
||||||
**OpenWrt** >= 19.07.
|
**OpenWrt** >= 19.07.
|
||||||
|
|
||||||
**Dependences:** lua, luci-lib-nixio, libuci-lua.
|
**Dependences:** lua, luaposix, libuci-lua.
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
- It can run continuously as a system service or only in an open web interface.
|
- It can run continuously as a system service or only in an open web interface.
|
||||||
@@ -12,22 +12,22 @@ Internet-detector is an application for checking the availability of the Interne
|
|||||||

|

|
||||||
- Performing actions when connecting and disconnecting the Internet (Restarting network, modem or device. Executing custom shell scripts).
|
- Performing actions when connecting and disconnecting the Internet (Restarting network, modem or device. Executing custom shell scripts).
|
||||||
- Sending email notification when Internet access is restored.
|
- Sending email notification when Internet access is restored.
|
||||||
- The daemon is written entirely in Lua using the nixio library.
|
- The daemon is written entirely in Lua using the luaposix library.
|
||||||
|
|
||||||
## Installation notes
|
## Installation notes
|
||||||
|
|
||||||
**OpenWrt >= 21.02:**
|
**OpenWrt >= 21.02:**
|
||||||
|
|
||||||
opkg update
|
opkg update
|
||||||
wget --no-check-certificate -O /tmp/internet-detector_0.6-0_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector_0.6-0_all.ipk
|
wget --no-check-certificate -O /tmp/internet-detector_1.0-0_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector_1.0-0_all.ipk
|
||||||
opkg install /tmp/internet-detector_0.6-0_all.ipk
|
opkg install /tmp/internet-detector_1.0-0_all.ipk
|
||||||
rm /tmp/internet-detector_0.6-0_all.ipk
|
rm /tmp/internet-detector_1.0-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_0.6-1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-app-internet-detector_0.6-1_all.ipk
|
wget --no-check-certificate -O /tmp/luci-app-internet-detector_1.0-0_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-app-internet-detector_1.0-0_all.ipk
|
||||||
opkg install /tmp/luci-app-internet-detector_0.6-1_all.ipk
|
opkg install /tmp/luci-app-internet-detector_1.0-0_all.ipk
|
||||||
rm /tmp/luci-app-internet-detector_0.6-1_all.ipk
|
rm /tmp/luci-app-internet-detector_1.0-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_0.6-1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-i18n-internet-detector-ru_0.6-1_all.ipk
|
wget --no-check-certificate -O /tmp/luci-i18n-internet-detector-ru_1.0-0_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-i18n-internet-detector-ru_1.0-0_all.ipk
|
||||||
opkg install /tmp/luci-i18n-internet-detector-ru_0.6-1_all.ipk
|
opkg install /tmp/luci-i18n-internet-detector-ru_1.0-0_all.ipk
|
||||||
rm /tmp/luci-i18n-internet-detector-ru_0.6-1_all.ipk
|
rm /tmp/luci-i18n-internet-detector-ru_1.0-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)**
|
||||||
|
|
||||||
@@ -46,3 +46,5 @@ i18n-ru:
|
|||||||
|
|
||||||

|

|
||||||

|

|
||||||
|

|
||||||
|

|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#
|
#
|
||||||
# (с) 2021 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
# (с) 2023 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:=0.6
|
PKG_VERSION:=1.0
|
||||||
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>
|
||||||
|
|
||||||
@@ -17,17 +17,19 @@ define Package/$(PKG_NAME)
|
|||||||
TITLE:=Internet detector
|
TITLE:=Internet detector
|
||||||
URL:=https://github.com/gSpotx2f/luci-app-internet-detector
|
URL:=https://github.com/gSpotx2f/luci-app-internet-detector
|
||||||
PKGARCH:=all
|
PKGARCH:=all
|
||||||
DEPENDS:=+lua +luci-lib-nixio +libuci-lua
|
DEPENDS:=+lua +luaposix +libuci-lua
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Package/$(PKG_NAME)/description
|
define Package/$(PKG_NAME)/description
|
||||||
Internet-detector is a small daemon
|
Internet-detector is a small daemon
|
||||||
for checking Internet availability.
|
for checking Internet availability.
|
||||||
Written in Lua using the nixio library.
|
Written in Lua using the luaposix library.
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Package/$(PKG_NAME)/conffiles
|
define Package/$(PKG_NAME)/conffiles
|
||||||
/etc/config/internet-detector
|
/etc/config/internet-detector
|
||||||
|
/etc/internet-detector/down-script.internet
|
||||||
|
/etc/internet-detector/up-script.internet
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Build/Configure
|
define Build/Configure
|
||||||
@@ -40,8 +42,8 @@ define Package/$(PKG_NAME)/install
|
|||||||
$(INSTALL_DIR) $(1)/etc/config
|
$(INSTALL_DIR) $(1)/etc/config
|
||||||
$(INSTALL_CONF) ./files/etc/config/internet-detector $(1)/etc/config/internet-detector
|
$(INSTALL_CONF) ./files/etc/config/internet-detector $(1)/etc/config/internet-detector
|
||||||
$(INSTALL_DIR) $(1)/etc/internet-detector
|
$(INSTALL_DIR) $(1)/etc/internet-detector
|
||||||
$(INSTALL_BIN) ./files/etc/internet-detector/down-script $(1)/etc/internet-detector/down-script
|
$(INSTALL_DATA) ./files/etc/internet-detector/down-script.internet $(1)/etc/internet-detector/down-script.internet
|
||||||
$(INSTALL_BIN) ./files/etc/internet-detector/up-script $(1)/etc/internet-detector/up-script
|
$(INSTALL_DATA) ./files/etc/internet-detector/up-script.internet $(1)/etc/internet-detector/up-script.internet
|
||||||
$(INSTALL_DIR) $(1)/etc/init.d
|
$(INSTALL_DIR) $(1)/etc/init.d
|
||||||
$(INSTALL_BIN) ./files/etc/init.d/internet-detector $(1)/etc/init.d/internet-detector
|
$(INSTALL_BIN) ./files/etc/init.d/internet-detector $(1)/etc/init.d/internet-detector
|
||||||
$(INSTALL_DIR) $(1)/usr/bin
|
$(INSTALL_DIR) $(1)/usr/bin
|
||||||
|
|||||||
@@ -1,52 +1,48 @@
|
|||||||
config main 'config'
|
config main 'config'
|
||||||
option mode '2'
|
option mode '1'
|
||||||
|
option enable_logger '1'
|
||||||
|
|
||||||
|
config ui 'ui'
|
||||||
list hosts '8.8.8.8'
|
list hosts '8.8.8.8'
|
||||||
list hosts '1.1.1.1'
|
list hosts '1.1.1.1'
|
||||||
option check_type '0'
|
option check_type '0'
|
||||||
option tcp_port '53'
|
option tcp_port '53'
|
||||||
option ui_interval_up '6'
|
option interval_up '6'
|
||||||
option ui_interval_down '1'
|
option interval_down '1'
|
||||||
option ui_connection_attempts '1'
|
option connection_attempts '1'
|
||||||
option ui_connection_timeout '1'
|
option connection_timeout '1'
|
||||||
option service_interval_up '30'
|
|
||||||
option service_interval_down '5'
|
|
||||||
option service_connection_attempts '2'
|
|
||||||
option service_connection_timeout '2'
|
|
||||||
option service_enable_logger '1'
|
|
||||||
|
|
||||||
config module 'mod_led_control'
|
config instance 'internet'
|
||||||
option enabled '0'
|
option enabled '1'
|
||||||
|
list hosts '8.8.8.8'
|
||||||
config module 'mod_reboot'
|
list hosts '1.1.1.1'
|
||||||
option enabled '0'
|
option check_type '0'
|
||||||
option dead_period '3600'
|
option tcp_port '53'
|
||||||
option force_reboot_delay '300'
|
option interval_up '30'
|
||||||
|
option interval_down '5'
|
||||||
config module 'mod_network_restart'
|
option connection_attempts '2'
|
||||||
option enabled '0'
|
option connection_timeout '2'
|
||||||
option dead_period '900'
|
option mod_led_control_enabled '0'
|
||||||
option attempts '1'
|
option mod_reboot_enabled '0'
|
||||||
option restart_timeout '0'
|
option mod_reboot_dead_period '3600'
|
||||||
|
option mod_reboot_force_reboot_delay '300'
|
||||||
config module 'mod_modem_restart'
|
option mod_network_restart_enabled '0'
|
||||||
option enabled '0'
|
option mod_network_restart_dead_period '900'
|
||||||
option dead_period '600'
|
option mod_network_restart_attempts '1'
|
||||||
option any_band '0'
|
option mod_network_restart_restart_timeout '0'
|
||||||
|
option mod_modem_restart_enabled '0'
|
||||||
config module 'mod_public_ip'
|
option mod_modem_restart_dead_period '600'
|
||||||
option enabled '0'
|
option mod_modem_restart_any_band '0'
|
||||||
option provider 'opendns1'
|
option mod_public_ip_enabled '0'
|
||||||
option interval '600'
|
option mod_public_ip_provider 'opendns1'
|
||||||
option timeout '3'
|
option mod_public_ip_qtype '0'
|
||||||
|
option mod_public_ip_interval '600'
|
||||||
config module 'mod_email'
|
option mod_public_ip_timeout '3'
|
||||||
option enabled '0'
|
option mod_email_enabled '0'
|
||||||
option alive_period '0'
|
option mod_email_alive_period '0'
|
||||||
option mail_smtp 'smtp.gmail.com'
|
option mod_email_mail_smtp 'smtp.gmail.com'
|
||||||
option mail_smtp_port '587'
|
option mod_email_mail_smtp_port '587'
|
||||||
option mail_security 'tls'
|
option mod_email_mail_security 'tls'
|
||||||
|
option mod_user_scripts_enabled '0'
|
||||||
config module 'mod_user_scripts'
|
option mod_user_scripts_alive_period '0'
|
||||||
option enabled '0'
|
option mod_user_scripts_dead_period '0'
|
||||||
option alive_period '0'
|
|
||||||
option dead_period '0'
|
|
||||||
|
|||||||
@@ -3,17 +3,23 @@
|
|||||||
START=97
|
START=97
|
||||||
STOP=01
|
STOP=01
|
||||||
|
|
||||||
ID="/usr/bin/internet-detector"
|
PROG=/usr/bin/internet-detector
|
||||||
|
|
||||||
|
config_app() {
|
||||||
|
config_get enabled "$1" enabled "0"
|
||||||
|
if [ $enabled = "1" ]; then
|
||||||
|
$PROG service "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
$ID
|
config_load internet-detector
|
||||||
|
config_get mode "config" mode "0"
|
||||||
|
if [ $mode = "1" ]; then
|
||||||
|
config_foreach config_app "instance"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
$ID stop
|
$PROG stop
|
||||||
}
|
|
||||||
|
|
||||||
restart() {
|
|
||||||
stop
|
|
||||||
start
|
|
||||||
}
|
}
|
||||||
|
|||||||
0
internet-detector/files/etc/internet-detector/down-script → internet-detector/files/etc/internet-detector/down-script.internet
Executable file → Normal file
0
internet-detector/files/etc/internet-detector/down-script → internet-detector/files/etc/internet-detector/down-script.internet
Executable file → Normal file
0
internet-detector/files/etc/internet-detector/up-script → internet-detector/files/etc/internet-detector/up-script.internet
Executable file → Normal file
0
internet-detector/files/etc/internet-detector/up-script → internet-detector/files/etc/internet-detector/up-script.internet
Executable file → Normal file
@@ -5,112 +5,103 @@
|
|||||||
|
|
||||||
Dependences:
|
Dependences:
|
||||||
lua
|
lua
|
||||||
luci-lib-nixio
|
luaposix
|
||||||
libuci-lua
|
libuci-lua
|
||||||
|
|
||||||
(с) 2021 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
(с) 2023 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
-- Default settings
|
|
||||||
|
|
||||||
local Config = {
|
|
||||||
mode = 2,
|
|
||||||
enableLogger = true,
|
|
||||||
intervalUp = 30,
|
|
||||||
intervalDown = 5,
|
|
||||||
connectionAttempts = 2,
|
|
||||||
connectionTimeout = 2,
|
|
||||||
UIConnectionAttempts = 1,
|
|
||||||
UIConnectionTimeout = 1,
|
|
||||||
hosts = {
|
|
||||||
[1] = "8.8.8.8",
|
|
||||||
[2] = "1.1.1.1",
|
|
||||||
},
|
|
||||||
tcpPort = 53,
|
|
||||||
pingPacketSize = 56,
|
|
||||||
iface = nil,
|
|
||||||
checkType = 0, -- 0: TCP, 1: ping
|
|
||||||
hostname = "OpenWrt",
|
|
||||||
appName = "internet-detector",
|
|
||||||
commonDir = "/tmp/run",
|
|
||||||
debugLog = "/tmp/internet-detector.debug",
|
|
||||||
pingCmd = "/bin/ping",
|
|
||||||
pingParams = "-c 1",
|
|
||||||
debug = false,
|
|
||||||
modules = {},
|
|
||||||
parsedHosts = {},
|
|
||||||
}
|
|
||||||
Config.configDir = string.format("/etc/%s", Config.appName)
|
|
||||||
Config.modulesDir = string.format("/usr/lib/%s", Config.appName)
|
|
||||||
Config.pidFile = string.format("%s/%s.pid", Config.commonDir, Config.appName)
|
|
||||||
Config.statusFile = string.format("%s/%s.status", Config.commonDir, Config.appName)
|
|
||||||
|
|
||||||
-- Importing packages
|
-- Importing packages
|
||||||
|
|
||||||
local function prequire(package)
|
local dirent = require("posix.dirent")
|
||||||
|
local fcntl = require("posix.fcntl")
|
||||||
|
local signal = require("posix.signal")
|
||||||
|
local socket = require("posix.sys.socket")
|
||||||
|
local stat = require("posix.sys.stat")
|
||||||
|
local syslog = require("posix.syslog")
|
||||||
|
local time = require("posix.time")
|
||||||
|
local unistd = require("posix.unistd")
|
||||||
|
local uci = require("uci")
|
||||||
|
|
||||||
|
-- Default settings
|
||||||
|
|
||||||
|
local InternetDetector = {
|
||||||
|
mode = 0,
|
||||||
|
enableLogger = true,
|
||||||
|
hostname = "OpenWrt",
|
||||||
|
appName = "internet-detector",
|
||||||
|
commonDir = "/tmp/run",
|
||||||
|
pingCmd = "/bin/ping",
|
||||||
|
pingParams = "-c 1",
|
||||||
|
debug = false,
|
||||||
|
serviceConfig = {
|
||||||
|
hosts = {
|
||||||
|
[1] = "8.8.8.8",
|
||||||
|
[2] = "1.1.1.1",
|
||||||
|
},
|
||||||
|
check_type = 0, -- 0: TCP, 1: ICMP
|
||||||
|
tcp_port = 53,
|
||||||
|
icmp_packet_size = 56,
|
||||||
|
interval_up = 30,
|
||||||
|
interval_down = 5,
|
||||||
|
connection_attempts = 2,
|
||||||
|
connection_timeout = 2,
|
||||||
|
iface = nil,
|
||||||
|
instance = nil,
|
||||||
|
},
|
||||||
|
modules = {},
|
||||||
|
parsedHosts = {},
|
||||||
|
}
|
||||||
|
InternetDetector.configDir = string.format("/etc/%s", InternetDetector.appName)
|
||||||
|
InternetDetector.modulesDir = string.format("/usr/lib/%s", InternetDetector.appName)
|
||||||
|
|
||||||
|
-- Loading settings from UCI
|
||||||
|
local uciCursor = uci.cursor()
|
||||||
|
InternetDetector.mode = tonumber(
|
||||||
|
uciCursor:get(InternetDetector.appName, "config", "mode"))
|
||||||
|
InternetDetector.enableLogger = (tonumber(
|
||||||
|
uciCursor:get(InternetDetector.appName, "config", "enable_logger")) ~= 0)
|
||||||
|
local hostname = uciCursor:get("system", "@[0]", "hostname")
|
||||||
|
if hostname ~= nil then
|
||||||
|
InternetDetector.hostname = hostname
|
||||||
|
end
|
||||||
|
|
||||||
|
local RUNNING
|
||||||
|
|
||||||
|
function InternetDetector:prequire(package)
|
||||||
local retVal, pkg = pcall(require, package)
|
local retVal, pkg = pcall(require, package)
|
||||||
return retVal and pkg
|
return retVal and pkg
|
||||||
end
|
end
|
||||||
|
|
||||||
local nixio = prequire("nixio")
|
function InternetDetector:loadUCIConfig(sType, instance)
|
||||||
if not nixio then
|
local success
|
||||||
error("You need to install nixio...")
|
local num = 0
|
||||||
|
uciCursor:foreach(
|
||||||
|
self.appName,
|
||||||
|
sType,
|
||||||
|
function(s)
|
||||||
|
if s[".name"] == instance then
|
||||||
|
for k, v in pairs(s) do
|
||||||
|
if type(v) == "string" and v:match("^[%d]+$") then
|
||||||
|
v = tonumber(v)
|
||||||
|
end
|
||||||
|
self.serviceConfig[k] = v
|
||||||
|
end
|
||||||
|
success = true
|
||||||
|
self.serviceConfig.instanceNum = num
|
||||||
|
end
|
||||||
|
num = num + 1
|
||||||
|
end
|
||||||
|
)
|
||||||
|
self.serviceConfig.instance = instance
|
||||||
|
self.pidFile = string.format(
|
||||||
|
"%s/%s.%s.pid", self.commonDir, self.appName, instance)
|
||||||
|
self.statusFile = string.format(
|
||||||
|
"%s/%s.%s.status", self.commonDir, self.appName, instance)
|
||||||
|
return success
|
||||||
end
|
end
|
||||||
|
|
||||||
local uci = prequire("uci")
|
function InternetDetector:writeValueToFile(filePath, str)
|
||||||
if not uci then
|
|
||||||
error("You need to install libuci-lua...")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Loading settings from UCI
|
|
||||||
|
|
||||||
local uciCursor = uci.cursor()
|
|
||||||
Config.mode = tonumber(uciCursor:get(
|
|
||||||
Config.appName, "config", "mode"))
|
|
||||||
Config.enableLogger = (tonumber(uciCursor:get(
|
|
||||||
Config.appName, "config", "service_enable_logger")) ~= 0)
|
|
||||||
Config.intervalUp = tonumber(uciCursor:get(
|
|
||||||
Config.appName, "config", "service_interval_up"))
|
|
||||||
Config.intervalDown = tonumber(uciCursor:get(
|
|
||||||
Config.appName, "config", "service_interval_down"))
|
|
||||||
Config.connectionAttempts = tonumber(uciCursor:get(
|
|
||||||
Config.appName, "config", "service_connection_attempts"))
|
|
||||||
Config.connectionTimeout = tonumber(uciCursor:get(
|
|
||||||
Config.appName, "config", "service_connection_timeout"))
|
|
||||||
Config.UIConnectionAttempts = tonumber(uciCursor:get(
|
|
||||||
Config.appName, "config", "ui_connection_attempts"))
|
|
||||||
Config.UIConnectionTimeout = tonumber(uciCursor:get(
|
|
||||||
Config.appName, "config", "ui_connection_timeout"))
|
|
||||||
Config.hosts = uciCursor:get(Config.appName, "config", "hosts")
|
|
||||||
|
|
||||||
local tcpPort = uciCursor:get(
|
|
||||||
Config.appName, "config", "tcp_port")
|
|
||||||
if tcpPort ~= nil then
|
|
||||||
Config.tcpPort = tonumber(tcpPort)
|
|
||||||
end
|
|
||||||
|
|
||||||
local pingPacketSize = uciCursor:get(
|
|
||||||
Config.appName, "config", "ping_packet_size")
|
|
||||||
if pingPacketSize ~= nil then
|
|
||||||
Config.pingPacketSize = tonumber(pingPacketSize)
|
|
||||||
end
|
|
||||||
|
|
||||||
local iface = uciCursor:get(
|
|
||||||
Config.appName, "config", "iface")
|
|
||||||
if iface ~= nil then
|
|
||||||
Config.iface = iface
|
|
||||||
end
|
|
||||||
|
|
||||||
Config.checkType = tonumber(uciCursor:get(
|
|
||||||
Config.appName, "config", "check_type"))
|
|
||||||
|
|
||||||
local hostname = uciCursor:get("system", "@[0]", "hostname")
|
|
||||||
if hostname ~= nil then
|
|
||||||
Config.hostname = hostname
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function writeValueToFile(filePath, str)
|
|
||||||
local retValue = false
|
local retValue = false
|
||||||
local fh = io.open(filePath, "w")
|
local fh = io.open(filePath, "w")
|
||||||
if fh then
|
if fh then
|
||||||
@@ -122,7 +113,7 @@ local function writeValueToFile(filePath, str)
|
|||||||
return retValue
|
return retValue
|
||||||
end
|
end
|
||||||
|
|
||||||
local function readValueFromFile(filePath)
|
function InternetDetector:readValueFromFile(filePath)
|
||||||
local retValue
|
local retValue
|
||||||
local fh = io.open(filePath, "r")
|
local fh = io.open(filePath, "r")
|
||||||
if fh then
|
if fh then
|
||||||
@@ -132,72 +123,97 @@ local function readValueFromFile(filePath)
|
|||||||
return retValue
|
return retValue
|
||||||
end
|
end
|
||||||
|
|
||||||
local function statusJson(inet, t)
|
function InternetDetector:statusJson(inet, instance, t)
|
||||||
local lines = { [1] = string.format('"inet":%d', inet) }
|
local lines = { [1] = string.format(
|
||||||
|
'{"instance":"%s","num":"%d","inet":%d',
|
||||||
|
instance,
|
||||||
|
self.serviceConfig.instanceNum,
|
||||||
|
inet)}
|
||||||
if t then
|
if t then
|
||||||
for k, v in pairs(t) do
|
for k, v in pairs(t) do
|
||||||
lines[#lines + 1] = string.format('"%s":"%s"', k, v)
|
lines[#lines + 1] = string.format('"%s":"%s"', k, v)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return "{" .. table.concat(lines, ",") .. "}"
|
return table.concat(lines, ",") .. "}"
|
||||||
end
|
end
|
||||||
|
|
||||||
local function writeLogMessage(level, msg)
|
function InternetDetector:writeLogMessage(level, msg)
|
||||||
if Config.enableLogger then
|
if self.enableLogger then
|
||||||
nixio.syslog(level, msg)
|
local levels = {
|
||||||
|
emerg = syslog.LOG_EMERG,
|
||||||
|
alert = syslog.LOG_ALERT,
|
||||||
|
crit = syslog.LOG_CRIT,
|
||||||
|
err = syslog.LOG_ERR,
|
||||||
|
warning = syslog.LOG_WARNING,
|
||||||
|
notice = syslog.LOG_NOTICE,
|
||||||
|
info = syslog.LOG_INFO,
|
||||||
|
debug = syslog.LOG_DEBUG,
|
||||||
|
}
|
||||||
|
syslog.syslog(levels[level] or syslog.LOG_INFO, string.format(
|
||||||
|
"%s: %s", self.serviceConfig.instance or "", msg))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function loadModules()
|
function InternetDetector:loadModules()
|
||||||
package.path = string.format("%s;%s/?.lua", package.path, Config.modulesDir)
|
package.path = string.format("%s;%s/?.lua", package.path, self.modulesDir)
|
||||||
Config.modules = {}
|
self.modules = {}
|
||||||
uciCursor:foreach(
|
local ok, modulesDir = pcall(dirent.files, self.modulesDir)
|
||||||
Config.appName,
|
if ok then
|
||||||
"module",
|
for item in modulesDir do
|
||||||
function(s)
|
if item:match("^mod_") then
|
||||||
local mod_name = s[".name"]
|
local modName = item:gsub("%.lua$", "")
|
||||||
if mod_name and s.enabled == "1" then
|
local modConfig = {}
|
||||||
local m = prequire(mod_name)
|
for k, v in pairs(self.serviceConfig) do
|
||||||
if m then
|
if k:match("^" .. modName) then
|
||||||
m.config = Config
|
modConfig[k:gsub("^" .. modName .. "_", "")] = v
|
||||||
m.syslog = writeLogMessage
|
end
|
||||||
m.writeValue = writeValueToFile
|
end
|
||||||
m.readValue = readValueFromFile
|
if modConfig.enabled == 1 then
|
||||||
m:init(s)
|
local m = self:prequire(modName)
|
||||||
Config.modules[#Config.modules + 1] = m
|
if m then
|
||||||
|
m.config = self
|
||||||
|
m.syslog = function(level, msg) self:writeLogMessage(level, msg) end
|
||||||
|
m.writeValue = function(filePath, str) return self:writeValueToFile(filePath, str) end
|
||||||
|
m.readValue = function(filePath) return self:readValueFromFile(filePath) end
|
||||||
|
m:init(modConfig)
|
||||||
|
self.modules[#self.modules + 1] = m
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function parseHost(host)
|
|
||||||
local addr, port = host:match("^([^:]+):?(%d*)")
|
|
||||||
return addr, tonumber(port) or false
|
|
||||||
end
|
|
||||||
|
|
||||||
local function parseHosts()
|
|
||||||
Config.parsedHosts = {}
|
|
||||||
for k, v in ipairs(Config.hosts) do
|
|
||||||
local addr, port = parseHost(v)
|
|
||||||
Config.parsedHosts[k] = { addr = addr, port = port }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function pingHost(host)
|
function InternetDetector:parseHost(host)
|
||||||
|
local addr, port = host:match("^([^%[%]:]+):?(%d?%d?%d?%d?%d?)$")
|
||||||
|
if not addr then
|
||||||
|
addr, port = host:match("^%[?([^%[%]]+)%]?:?(%d?%d?%d?%d?%d?)$")
|
||||||
|
end
|
||||||
|
return addr, tonumber(port)
|
||||||
|
end
|
||||||
|
|
||||||
|
function InternetDetector:parseHosts()
|
||||||
|
self.parsedHosts = {}
|
||||||
|
for k, v in ipairs(self.serviceConfig.hosts) do
|
||||||
|
local addr, port = self:parseHost(v)
|
||||||
|
self.parsedHosts[k] = { addr = addr, port = port }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function InternetDetector:pingHost(host)
|
||||||
local ping = string.format(
|
local ping = string.format(
|
||||||
"%s %s -W %d -s %d%s %s > /dev/null 2>&1",
|
"%s %s -W %d -s %d%s %s > /dev/null 2>&1",
|
||||||
Config.pingCmd,
|
self.pingCmd,
|
||||||
Config.pingParams,
|
self.pingParams,
|
||||||
Config.connectionTimeout,
|
self.serviceConfig.connection_timeout,
|
||||||
Config.pingPacketSize,
|
self.serviceConfig.icmp_packet_size,
|
||||||
Config.iface and (" -I " .. Config.iface) or "",
|
self.serviceConfig.iface and (" -I " .. self.serviceConfig.iface) or "",
|
||||||
host
|
host
|
||||||
)
|
)
|
||||||
local retCode = os.execute(ping)
|
local retCode = os.execute(ping)
|
||||||
|
|
||||||
-- Debug
|
-- Debug
|
||||||
if Config.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)
|
||||||
)
|
)
|
||||||
@@ -207,53 +223,94 @@ local function pingHost(host)
|
|||||||
return retCode
|
return retCode
|
||||||
end
|
end
|
||||||
|
|
||||||
local function TCPConnectionToHost(host, port)
|
function InternetDetector:TCPConnectionToHost(host, port)
|
||||||
local retCode = 1
|
local retCode = 1
|
||||||
local addrInfo = nixio.getaddrinfo(host, "any")
|
local saTable, errMsg, errNum = socket.getaddrinfo(host, port or self.serviceConfig.tcp_port)
|
||||||
if addrInfo then
|
|
||||||
local family = addrInfo[1].family
|
|
||||||
if family then
|
|
||||||
local socket = nixio.socket(family, "stream")
|
|
||||||
socket:setopt("socket", "sndtimeo", Config.connectionTimeout)
|
|
||||||
socket:setopt("socket", "rcvtimeo", Config.connectionTimeout)
|
|
||||||
if Config.iface then
|
|
||||||
socket:setopt("socket", "bindtodevice", Config.iface)
|
|
||||||
end
|
|
||||||
local success = socket:connect(host, port or Config.tcpPort)
|
|
||||||
|
|
||||||
-- Debug
|
if not saTable then
|
||||||
if Config.debug then
|
if self.debug then
|
||||||
local sockAddr, sockPort = socket:getsockname()
|
io.stdout:write(string.format(
|
||||||
local peerAddr, peerPort = socket:getpeername()
|
"GETADDRINFO ERROR: %s, %s\n", errMsg, errNum))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local family = saTable[1].family
|
||||||
|
|
||||||
|
if family then
|
||||||
|
local sock, errMsg, errNum = socket.socket(family, socket.SOCK_STREAM, 0)
|
||||||
|
|
||||||
|
if not sock then
|
||||||
|
if self.debug then
|
||||||
|
io.stdout:write(string.format(
|
||||||
|
"SOCKET ERROR: %s, %s\n", errMsg, errNum))
|
||||||
|
end
|
||||||
|
return retCode
|
||||||
|
end
|
||||||
|
|
||||||
|
socket.setsockopt(sock, socket.SOL_SOCKET,
|
||||||
|
socket.SO_SNDTIMEO, self.serviceConfig.connection_timeout, 0)
|
||||||
|
socket.setsockopt(sock, socket.SOL_SOCKET,
|
||||||
|
socket.SO_RCVTIMEO, self.serviceConfig.connection_timeout, 0)
|
||||||
|
|
||||||
|
if self.serviceConfig.iface then
|
||||||
|
local ok, errMsg, errNum = socket.setsockopt(sock, socket.SOL_SOCKET,
|
||||||
|
socket.SO_BINDTODEVICE, self.serviceConfig.iface)
|
||||||
|
if not ok then
|
||||||
|
if self.debug then
|
||||||
|
io.stdout:write(string.format(
|
||||||
|
"SOCKET ERROR: %s, %s\n", errMsg, errNum))
|
||||||
|
end
|
||||||
|
return retCode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local success = socket.connect(sock, saTable[1])
|
||||||
|
|
||||||
|
if self.debug then
|
||||||
|
if not success then
|
||||||
|
io.stdout:write(string.format(
|
||||||
|
"SOCKET CONNECT ERROR: %s\n", tostring(success)))
|
||||||
|
end
|
||||||
|
local sockTable, err_s, e_s = socket.getsockname(sock)
|
||||||
|
local peerTable, err_p, e_p = socket.getpeername(sock)
|
||||||
|
if not sockTable then
|
||||||
|
sockTable = {}
|
||||||
|
io.stdout:write(
|
||||||
|
string.format("SOCKET ERROR: %s, %s\n", err_s, e_s))
|
||||||
|
end
|
||||||
|
if not peerTable then
|
||||||
|
peerTable = {}
|
||||||
|
io.stdout:write(
|
||||||
|
string.format("SOCKET ERROR: %s, %s\n", err_p, e_p))
|
||||||
|
end
|
||||||
io.stdout:write(string.format(
|
io.stdout:write(string.format(
|
||||||
"--- TCP ---\ntime = %s\nconnectionTimeout = %s\niface = %s\nhost:port = %s:%s\nsockname = %s:%s\npeername = %s:%s\nsuccess = %s\n",
|
"--- TCP ---\ntime = %s\nconnection_timeout = %s\niface = %s\nhost:port = [%s]:%s\nsockname = [%s]:%s\npeername = [%s]:%s\nsuccess = %s\n",
|
||||||
os.time(),
|
os.time(),
|
||||||
Config.connectionTimeout,
|
self.serviceConfig.connection_timeout,
|
||||||
tostring(Config.iface),
|
tostring(self.serviceConfig.iface),
|
||||||
host,
|
host,
|
||||||
port or Config.tcpPort,
|
port or self.serviceConfig.tcp_port,
|
||||||
tostring(sockAddr),
|
tostring(sockTable.addr),
|
||||||
tostring(sockPort),
|
tostring(sockTable.port),
|
||||||
tostring(peerAddr),
|
tostring(peerTable.addr),
|
||||||
tostring(peerPort),
|
tostring(peerTable.port),
|
||||||
tostring(success))
|
tostring(success))
|
||||||
)
|
)
|
||||||
io.stdout:flush()
|
io.stdout:flush()
|
||||||
end
|
end
|
||||||
|
|
||||||
socket:close()
|
unistd.close(sock)
|
||||||
retCode = success and 0 or 1
|
retCode = success and 0 or 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return retCode
|
return retCode
|
||||||
end
|
end
|
||||||
|
|
||||||
local function checkHosts()
|
function InternetDetector:checkHosts()
|
||||||
local checkFunc = (Config.checkType == 1) and pingHost or TCPConnectionToHost
|
local checkFunc = (self.serviceConfig.check_type == 1) and self.pingHost or self.TCPConnectionToHost
|
||||||
local retCode = 1
|
local retCode = 1
|
||||||
for k, v in ipairs(Config.parsedHosts) do
|
for k, v in ipairs(self.parsedHosts) do
|
||||||
for i = 1, Config.connectionAttempts do
|
for i = 1, self.serviceConfig.connection_attempts do
|
||||||
if checkFunc(v.addr, v.port) == 0 then
|
if checkFunc(self, v.addr, v.port) == 0 then
|
||||||
retCode = 0
|
retCode = 0
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
@@ -265,37 +322,51 @@ local function checkHosts()
|
|||||||
return retCode
|
return retCode
|
||||||
end
|
end
|
||||||
|
|
||||||
local function main()
|
function InternetDetector:breakMain(signo)
|
||||||
local lastStatus, currentStatus, timeNow, timeDiff, lastTime
|
RUNNING = false
|
||||||
local interval = Config.intervalUp
|
end
|
||||||
local counter = 0
|
|
||||||
|
|
||||||
while true do
|
function InternetDetector:main()
|
||||||
|
signal.signal(signal.SIGTERM, 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)
|
||||||
|
|
||||||
|
local lastStatus, currentStatus, timeNow, timeDiff, lastTime
|
||||||
|
local interval = self.serviceConfig.interval_up
|
||||||
|
local counter = 0
|
||||||
|
local onStart = true
|
||||||
|
RUNNING = true
|
||||||
|
while RUNNING do
|
||||||
if counter == 0 or counter >= interval then
|
if counter == 0 or counter >= interval then
|
||||||
currentStatus = checkHosts()
|
currentStatus = self:checkHosts()
|
||||||
if not nixio.fs.access(Config.statusFile, "r") then
|
if onStart or not stat.stat(self.statusFile) then
|
||||||
writeValueToFile(Config.statusFile, statusJson(currentStatus))
|
self:writeValueToFile(self.statusFile, self:statusJson(
|
||||||
|
currentStatus, self.serviceConfig.instance))
|
||||||
|
onStart = false
|
||||||
end
|
end
|
||||||
|
|
||||||
if currentStatus == 0 then
|
if currentStatus == 0 then
|
||||||
interval = Config.intervalUp
|
interval = self.serviceConfig.interval_up
|
||||||
if lastStatus ~= nil and currentStatus ~= lastStatus then
|
if lastStatus ~= nil and currentStatus ~= lastStatus then
|
||||||
writeValueToFile(Config.statusFile, statusJson(currentStatus))
|
self:writeValueToFile(self.statusFile, self:statusJson(
|
||||||
writeLogMessage("notice", "Internet connected")
|
currentStatus, self.serviceConfig.instance))
|
||||||
|
self:writeLogMessage("notice", "Connected")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
interval = Config.intervalDown
|
interval = self.serviceConfig.interval_down
|
||||||
if lastStatus ~= nil and currentStatus ~= lastStatus then
|
if lastStatus ~= nil and currentStatus ~= lastStatus then
|
||||||
writeValueToFile(Config.statusFile, statusJson(currentStatus))
|
self:writeValueToFile(self.statusFile, self:statusJson(
|
||||||
writeLogMessage("notice", "Internet disconnected")
|
currentStatus, self.serviceConfig.instance))
|
||||||
|
self:writeLogMessage("notice", "Disconnected")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
counter = 0
|
counter = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
timeDiff = 0
|
timeDiff = 0
|
||||||
for _, e in ipairs(Config.modules) do
|
for _, e in ipairs(self.modules) do
|
||||||
timeNow = nixio.sysinfo().uptime
|
timeNow = time.clock_gettime(time.CLOCK_MONOTONIC).tv_sec
|
||||||
if lastTime then
|
if lastTime then
|
||||||
timeDiff = timeDiff + timeNow - lastTime
|
timeDiff = timeDiff + timeNow - lastTime
|
||||||
else
|
else
|
||||||
@@ -306,142 +377,156 @@ local function main()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local modulesStatus = {}
|
local modulesStatus = {}
|
||||||
for k, v in ipairs(Config.modules) do
|
for k, v in ipairs(self.modules) do
|
||||||
if v.status ~= nil then
|
if v.status ~= nil then
|
||||||
modulesStatus[v.name] = v.status
|
modulesStatus[v.name] = v.status
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if next(modulesStatus) then
|
if next(modulesStatus) then
|
||||||
writeValueToFile(Config.statusFile, statusJson(currentStatus, modulesStatus))
|
self:writeValueToFile(self.statusFile, self:statusJson(
|
||||||
|
currentStatus, self.serviceConfig.instance, modulesStatus))
|
||||||
end
|
end
|
||||||
|
|
||||||
lastStatus = currentStatus
|
lastStatus = currentStatus
|
||||||
nixio.nanosleep(1)
|
unistd.sleep(1)
|
||||||
counter = counter + 1
|
counter = counter + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function removeProcessFiles()
|
function InternetDetector:removeProcessFiles()
|
||||||
os.remove(Config.pidFile)
|
os.remove(string.format(
|
||||||
os.remove(Config.statusFile)
|
"%s/%s.%s.pid", self.commonDir, self.appName, self.serviceConfig.instance))
|
||||||
|
os.remove(string.format(
|
||||||
|
"%s/%s.%s.status", self.commonDir, self.appName, self.serviceConfig.instance))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function status()
|
function InternetDetector:status()
|
||||||
if nixio.fs.access(Config.pidFile, "r") then
|
local ok, commonDir = pcall(dirent.files, self.commonDir)
|
||||||
return "running"
|
if ok then
|
||||||
else
|
local appName = self.appName:gsub("-", "%%-")
|
||||||
return "stoped"
|
for item in commonDir do
|
||||||
end
|
if item:match("^" .. appName .. ".-%.pid$") then
|
||||||
end
|
return "running"
|
||||||
|
end
|
||||||
local function poll(attempts, timeout)
|
|
||||||
if Config.mode == 1 then
|
|
||||||
Config.connectionAttempts = Config.UIConnectionAttempts
|
|
||||||
Config.connectionTimeout = Config.UIConnectionTimeout
|
|
||||||
end
|
|
||||||
if attempts then
|
|
||||||
Config.connectionAttempts = attempts
|
|
||||||
end
|
|
||||||
if timeout then
|
|
||||||
Config.connectionTimeout = timeout
|
|
||||||
end
|
|
||||||
if checkHosts() == 0 then
|
|
||||||
return statusJson(0)
|
|
||||||
else
|
|
||||||
return statusJson(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function inetStatus(json)
|
|
||||||
local inetStat = 1
|
|
||||||
if nixio.fs.access(Config.statusFile, "r") then
|
|
||||||
local inetStatVal = readValueFromFile(Config.statusFile)
|
|
||||||
inetStat = inetStatVal
|
|
||||||
elseif Config.mode == 1 then
|
|
||||||
inetStat = poll()
|
|
||||||
else
|
|
||||||
os.exit(126)
|
|
||||||
end
|
|
||||||
if not json then
|
|
||||||
local sVal = inetStat:match('"inet":[0-9]')
|
|
||||||
if sVal then
|
|
||||||
sVal = sVal:match("[0-9]")
|
|
||||||
inetStat = (tonumber(sVal) == 0) and "up" or "down"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return "stoped"
|
||||||
|
end
|
||||||
|
|
||||||
|
function InternetDetector:poll()
|
||||||
|
local retCode = self:checkHosts()
|
||||||
|
return string.format('{"instances":[%s]}', self:statusJson(
|
||||||
|
retCode, self.serviceConfig.instance))
|
||||||
|
end
|
||||||
|
|
||||||
|
function InternetDetector:inetStatus()
|
||||||
|
local inetStat = '{"instances":[]}'
|
||||||
|
local ok, commonDir = pcall(dirent.files, self.commonDir)
|
||||||
|
if ok then
|
||||||
|
local appName = self.appName:gsub("-", "%%-")
|
||||||
|
local lines = {}
|
||||||
|
for item in commonDir do
|
||||||
|
if item:match("^" .. appName .. ".-%.status$") then
|
||||||
|
lines[#lines + 1] = self:readValueFromFile(
|
||||||
|
string.format("%s/%s", self.commonDir, item))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
inetStat = '{"instances":[' .. table.concat(lines, ",") .. "]}"
|
||||||
|
end
|
||||||
return inetStat
|
return inetStat
|
||||||
end
|
end
|
||||||
|
|
||||||
local function stop()
|
function InternetDetector:stopInstance(pidFile)
|
||||||
local pidValue
|
local retVal
|
||||||
if Config.enableLogger then
|
if stat.stat(pidFile) then
|
||||||
nixio.openlog(Config.appName)
|
pidValue = self:readValueFromFile(pidFile)
|
||||||
end
|
|
||||||
if nixio.fs.access(Config.pidFile, "r") then
|
|
||||||
pidValue = readValueFromFile(Config.pidFile)
|
|
||||||
if pidValue then
|
if pidValue then
|
||||||
local success
|
local ok, errMsg, errNum
|
||||||
for i = 0, 10 do
|
for i = 0, 10 do
|
||||||
success = nixio.kill(tonumber(pidValue), 15)
|
ok, errMsg, errNum = signal.kill(tonumber(pidValue), signal.SIGTERM)
|
||||||
if success then
|
if ok then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not success then
|
if not ok then
|
||||||
io.stderr:write(string.format('No such process: "%s"\n', pidValue))
|
io.stderr:write(string.format(
|
||||||
|
'Process stop error: %s (%s). PID: "%s"\n', errMsg, errNum, pidValue))
|
||||||
end
|
end
|
||||||
writeLogMessage("info", string.format("[%s] stoped", pidValue))
|
if errNum == 3 then
|
||||||
removeProcessFiles()
|
os.remove(pidFile)
|
||||||
|
end
|
||||||
|
retVal = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not pidValue then
|
if not pidValue then
|
||||||
io.stderr:write(
|
io.stderr:write(
|
||||||
string.format('PID file "%s" does not exist. %s not running?\n',
|
string.format('PID file "%s" does not exist. %s not running?\n',
|
||||||
Config.pidFile, Config.appName))
|
pidFile, self.appName))
|
||||||
end
|
|
||||||
if Config.enableLogger then
|
|
||||||
nixio.closelog()
|
|
||||||
end
|
end
|
||||||
|
return retVal
|
||||||
end
|
end
|
||||||
|
|
||||||
local function preRun()
|
function InternetDetector:stop()
|
||||||
-- Exit if internet-detector mode != 2(Service)
|
local appName = self.appName:gsub("-", "%%-")
|
||||||
if Config.mode ~= 2 then
|
local success
|
||||||
io.stderr:write(string.format('Start failed, mode != 2\n', Config.appName))
|
for i = 0, 10 do
|
||||||
|
success = true
|
||||||
|
local ok, commonDir = pcall(dirent.files, self.commonDir)
|
||||||
|
if ok then
|
||||||
|
for item in commonDir do
|
||||||
|
if item:match("^" .. appName .. ".-%.pid$") then
|
||||||
|
self:stopInstance(string.format("%s/%s", self.commonDir, item))
|
||||||
|
success = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if success then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
unistd.sleep(1)
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function InternetDetector:preRun()
|
||||||
|
-- Exit if internet-detector mode != 1(Service)
|
||||||
|
if self.mode ~= 1 then
|
||||||
|
io.stderr:write(string.format('Start failed, mode != 1\n', self.appName))
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
end
|
end
|
||||||
if nixio.fs.access(Config.pidFile, "r") then
|
if stat.stat(self.pidFile) then
|
||||||
io.stderr:write(
|
io.stderr:write(
|
||||||
string.format('PID file "%s" already exist. %s already running?\n',
|
string.format('PID file "%s" already exist. %s already running?\n',
|
||||||
Config.pidFile, Config.appName))
|
self.pidFile, self.appName))
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function run()
|
function InternetDetector:run()
|
||||||
local pidValue = nixio.getpid()
|
local pidValue = unistd.getpid()
|
||||||
writeValueToFile(Config.pidFile, pidValue)
|
self:writeValueToFile(self.pidFile, pidValue)
|
||||||
if Config.enableLogger then
|
if self.enableLogger then
|
||||||
nixio.openlog(Config.appName, "pid")
|
syslog.openlog(self.appName, syslog.LOG_PID, syslog.LOG_DAEMON)
|
||||||
end
|
end
|
||||||
writeLogMessage("info", "started")
|
self:writeLogMessage("info", "started")
|
||||||
loadModules()
|
self:loadModules()
|
||||||
|
|
||||||
-- Loaded modules
|
-- Loaded modules
|
||||||
local modules = {}
|
local modules = {}
|
||||||
for _, v in ipairs(Config.modules) do
|
for _, v in ipairs(self.modules) do
|
||||||
modules[#modules + 1] = string.format("%s", v.name)
|
modules[#modules + 1] = string.format("%s", v.name)
|
||||||
end
|
end
|
||||||
if #modules > 0 then
|
if #modules > 0 then
|
||||||
writeLogMessage(
|
self:writeLogMessage(
|
||||||
"info", string.format("Loaded modules: %s", table.concat(modules, ", "))
|
"info", string.format("Loaded modules: %s", table.concat(modules, ", "))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Debug
|
-- Debug
|
||||||
if Config.debug then
|
if self.debug then
|
||||||
|
|
||||||
local function inspectTable()
|
local function inspectTable()
|
||||||
local tables = {}, f
|
local tables = {}, f
|
||||||
f = function(t, prefix)
|
f = function(t, prefix)
|
||||||
@@ -459,92 +544,125 @@ local function run()
|
|||||||
end
|
end
|
||||||
|
|
||||||
io.stdout:write("--- Config ---\n")
|
io.stdout:write("--- Config ---\n")
|
||||||
inspectTable()(Config, "Config.")
|
inspectTable()(self, "self.")
|
||||||
io.stdout:flush()
|
io.stdout:flush()
|
||||||
end
|
end
|
||||||
|
|
||||||
main()
|
self:writeValueToFile(
|
||||||
if Config.enableLogger then
|
self.statusFile, self:statusJson(-1, self.serviceConfig.instance))
|
||||||
nixio.closelog()
|
|
||||||
|
self:main()
|
||||||
|
|
||||||
|
self:removeProcessFiles()
|
||||||
|
if self.enableLogger then
|
||||||
|
self:writeLogMessage("info", "stoped")
|
||||||
|
syslog.closelog()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function noDaemon()
|
function InternetDetector:noDaemon()
|
||||||
if not preRun() then
|
if not self:preRun() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
run()
|
self:run()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function daemon(debug)
|
function InternetDetector:daemon()
|
||||||
if not preRun() then
|
if not self:preRun() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- UNIX double fork
|
-- UNIX double fork
|
||||||
if nixio.fork() == 0 then
|
if unistd.fork() == 0 then
|
||||||
nixio.setsid()
|
unistd.setpid("s")
|
||||||
if nixio.fork() == 0 then
|
if unistd.fork() == 0 then
|
||||||
nixio.chdir("/")
|
unistd.chdir("/")
|
||||||
nixio.umask(0)
|
stat.umask(0)
|
||||||
local output = "/dev/null"
|
local devnull = fcntl.open("/dev/null", fcntl.O_RDWR)
|
||||||
if debug then
|
|
||||||
output = Config.debugLog
|
|
||||||
Config.debug = true
|
|
||||||
end
|
|
||||||
io.stdout:flush()
|
io.stdout:flush()
|
||||||
io.stderr:flush()
|
io.stderr:flush()
|
||||||
nixio.dup(io.open("/dev/null", "r"), io.stdin)
|
unistd.dup2(devnull, 0) -- io.stdin
|
||||||
nixio.dup(io.open(output, "a+"), io.stdout)
|
unistd.dup2(devnull, 1) -- io.stdout
|
||||||
nixio.dup(io.open(output, "a+"), io.stderr)
|
unistd.dup2(devnull, 2) -- io.stderr
|
||||||
run()
|
self:run()
|
||||||
|
unistd.close(devnull)
|
||||||
end
|
end
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
end
|
end
|
||||||
os.exit(0)
|
os.exit(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function restart()
|
function InternetDetector:setServiceConfig(instance)
|
||||||
stop()
|
if self:loadUCIConfig("instance", instance) then
|
||||||
daemon()
|
self:parseHosts()
|
||||||
|
return true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Main section
|
-- Main section
|
||||||
|
|
||||||
parseHosts()
|
|
||||||
|
|
||||||
local function help()
|
local function help()
|
||||||
return string.format(
|
return string.format(
|
||||||
"Usage: %s [start|stop|restart|no-daemon|debug|status|inet-status|inet-status-json|poll [<attempts num>] [<timeout sec>]|--help]",
|
"Usage: %s service <UCI instance> | nodaemon <UCI instance> | debug <UCI instance> | stop | status | inet-status | poll [<attempts num>] [<timeout sec>] | --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] == "start" or #arg == 0 then
|
if arg[1] == "service" then
|
||||||
daemon()
|
if arg[2] then
|
||||||
elseif arg[1] == "no-daemon" then
|
if InternetDetector:setServiceConfig(arg[2]) then
|
||||||
noDaemon()
|
InternetDetector:daemon()
|
||||||
elseif arg[1] == "debug" then
|
else
|
||||||
daemon(true)
|
os.exit(126)
|
||||||
elseif arg[1] == "stop" then
|
|
||||||
stop()
|
|
||||||
elseif arg[1] == "restart" then
|
|
||||||
restart()
|
|
||||||
elseif arg[1] == "status" then
|
|
||||||
print(status())
|
|
||||||
elseif arg[1] == "inet-status" then
|
|
||||||
print(inetStatus())
|
|
||||||
elseif arg[1] == "inet-status-json" then
|
|
||||||
print(inetStatus(true))
|
|
||||||
elseif arg[1] == "poll" then
|
|
||||||
local attempts, timeout
|
|
||||||
if arg[2] and arg[2]:match("[0-9]+") then
|
|
||||||
attempts = tonumber(arg[2])
|
|
||||||
if arg[3] and arg[3]:match("[0-9]+") then
|
|
||||||
timeout = tonumber(arg[3])
|
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
print(help())
|
||||||
|
os.exit(1)
|
||||||
|
end
|
||||||
|
elseif arg[1] == "nodaemon" then
|
||||||
|
if arg[2] then
|
||||||
|
if InternetDetector:setServiceConfig(arg[2]) then
|
||||||
|
InternetDetector:noDaemon()
|
||||||
|
else
|
||||||
|
os.exit(126)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print(help())
|
||||||
|
os.exit(1)
|
||||||
|
end
|
||||||
|
elseif arg[1] == "debug" then
|
||||||
|
if arg[2] then
|
||||||
|
if InternetDetector:setServiceConfig(arg[2]) then
|
||||||
|
InternetDetector.debug = true
|
||||||
|
InternetDetector:noDaemon()
|
||||||
|
else
|
||||||
|
os.exit(126)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print(help())
|
||||||
|
os.exit(1)
|
||||||
|
end
|
||||||
|
elseif arg[1] == "stop" then
|
||||||
|
InternetDetector:stop()
|
||||||
|
elseif arg[1] == "status" then
|
||||||
|
print(InternetDetector:status())
|
||||||
|
elseif arg[1] == "inet-status" then
|
||||||
|
print(InternetDetector:inetStatus())
|
||||||
|
elseif arg[1] == "poll" then
|
||||||
|
if InternetDetector:loadUCIConfig("ui", "ui") 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)
|
||||||
end
|
end
|
||||||
print(poll(attempts, timeout))
|
|
||||||
elseif helpArgs[arg[1]] then
|
elseif helpArgs[arg[1]] then
|
||||||
print(help())
|
print(help())
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
Dependences:
|
Dependences:
|
||||||
mailsend
|
mailsend
|
||||||
--]]
|
--]]
|
||||||
local nixio = require("nixio")
|
local unistd = require("posix.unistd")
|
||||||
|
|
||||||
local Module = {
|
local Module = {
|
||||||
name = "mod_email",
|
name = "mod_email",
|
||||||
config = {},
|
config = {
|
||||||
|
debug = false,
|
||||||
|
},
|
||||||
syslog = function(level, msg) return true end,
|
syslog = function(level, msg) return true end,
|
||||||
writeValue = function(filePath, str) return false end,
|
writeValue = function(filePath, str) return false end,
|
||||||
readValue = function(filePath) return nil end,
|
readValue = function(filePath) return nil end,
|
||||||
@@ -45,7 +47,7 @@ function Module:init(t)
|
|||||||
self.mailSmtpPort = t.mail_smtp_port
|
self.mailSmtpPort = t.mail_smtp_port
|
||||||
self.mailSecurity = t.mail_security
|
self.mailSecurity = t.mail_security
|
||||||
|
|
||||||
if nixio.fs.access(self.mta, "x") then
|
if unistd.access(self.mta, "x") then
|
||||||
self._enabled = true
|
self._enabled = true
|
||||||
else
|
else
|
||||||
self._enabled = false
|
self._enabled = false
|
||||||
@@ -66,16 +68,19 @@ end
|
|||||||
|
|
||||||
function Module:sendMessage(msg)
|
function Module:sendMessage(msg)
|
||||||
local verboseArg = ""
|
local verboseArg = ""
|
||||||
|
|
||||||
-- Debug
|
-- Debug
|
||||||
if self.config.debug then
|
if self.config.debug then
|
||||||
verboseArg = " -v"
|
verboseArg = " -v"
|
||||||
io.stdout:write("--- mod_email ---\n")
|
io.stdout:write(string.format("--- %s ---\n", self.name))
|
||||||
io.stdout:flush()
|
io.stdout:flush()
|
||||||
end
|
end
|
||||||
|
|
||||||
local securityArgs = "-starttls -auth-login"
|
local securityArgs = "-starttls -auth-login"
|
||||||
if self.mailSecurity == "ssl" then
|
if self.mailSecurity == "ssl" then
|
||||||
securityArgs = "-ssl -auth"
|
securityArgs = "-ssl -auth"
|
||||||
end
|
end
|
||||||
|
|
||||||
local mtaCmd = string.format(
|
local mtaCmd = string.format(
|
||||||
'%s%s %s -smtp "%s" -port %s -cs utf-8 -user "%s" -pass "%s" -f "%s" -t "%s" -sub "%s" -M "%s"',
|
'%s%s %s -smtp "%s" -port %s -cs utf-8 -user "%s" -pass "%s" -f "%s" -t "%s" -sub "%s" -M "%s"',
|
||||||
self.mta, verboseArg, securityArgs, self.mailSmtp, self.mailSmtpPort,
|
self.mta, verboseArg, securityArgs, self.mailSmtp, self.mailSmtpPort,
|
||||||
@@ -102,12 +107,14 @@ function Module:run(currentStatus, lastStatus, timeDiff)
|
|||||||
self._msgSent = false
|
self._msgSent = false
|
||||||
self._lastConnection = nil
|
self._lastConnection = nil
|
||||||
if not self._disconnected then
|
if not self._disconnected then
|
||||||
self._disconnected = true
|
self._disconnected = true
|
||||||
if not self._lastDisconnection then
|
if not self._lastDisconnection then
|
||||||
self._lastDisconnection = os.date("%Y.%m.%d %H:%M:%S", os.time())
|
self._lastDisconnection = os.date("%Y.%m.%d %H:%M:%S", os.time())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
if not self._msgSent then
|
if not self._msgSent then
|
||||||
|
|
||||||
if not self._lastConnection then
|
if not self._lastConnection then
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
local nixio = require("nixio")
|
local unistd = require("posix.unistd")
|
||||||
|
local dirent = require("posix.dirent")
|
||||||
|
|
||||||
local Module = {
|
local Module = {
|
||||||
name = "mod_led_control",
|
name = "mod_led_control",
|
||||||
@@ -20,13 +21,13 @@ local Module = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Module:resetLeds()
|
function Module:resetLeds()
|
||||||
local dir = nixio.fs.dir(self.sysLedsDir)
|
local ok, dir = pcall(dirent.files, self.sysLedsDir)
|
||||||
if not dir then
|
if not ok then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for led in dir do
|
for led in dir do
|
||||||
local brightness = string.format("%s/%s/brightness", self.sysLedsDir, led)
|
local brightness = string.format("%s/%s/brightness", self.sysLedsDir, led)
|
||||||
if nixio.fs.access(brightness, "w") then
|
if unistd.access(brightness, "w") then
|
||||||
self.writeValue(brightness, 0)
|
self.writeValue(brightness, 0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -41,10 +42,11 @@ function Module:init(t)
|
|||||||
self._ledMaxBrightnessFile = string.format("%s/max_brightness", self._ledDir)
|
self._ledMaxBrightnessFile = string.format("%s/max_brightness", self._ledDir)
|
||||||
self._ledBrightnessFile = string.format("%s/brightness", self._ledDir)
|
self._ledBrightnessFile = string.format("%s/brightness", self._ledDir)
|
||||||
self._ledMaxBrightness = self.readValue(self._ledMaxBrightnessFile) or 1
|
self._ledMaxBrightness = self.readValue(self._ledMaxBrightnessFile) or 1
|
||||||
if (not nixio.fs.access(self._ledDir, "r") or
|
if (not unistd.access(self._ledDir, "r") or
|
||||||
not nixio.fs.access(self._ledBrightnessFile, "r", "w")) then
|
not unistd.access(self._ledBrightnessFile, "rw")) then
|
||||||
self._enabled = false
|
self._enabled = false
|
||||||
self.syslog("warning", string.format("%s: LED '%s' is not available", self.name, self.ledName))
|
self.syslog("warning", string.format(
|
||||||
|
"%s: LED '%s' is not available", self.name, self.ledName))
|
||||||
else
|
else
|
||||||
self._enabled = true
|
self._enabled = true
|
||||||
-- Reset all LEDs
|
-- Reset all LEDs
|
||||||
@@ -85,6 +87,7 @@ function Module:run(currentStatus, lastStatus, timeDiff)
|
|||||||
|
|
||||||
self._counter = 0
|
self._counter = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
self._counter = self._counter + timeDiff
|
self._counter = self._counter + timeDiff
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Dependences:
|
Dependences:
|
||||||
modemmanager
|
modemmanager
|
||||||
--]]
|
--]]
|
||||||
local nixio = require("nixio")
|
local unistd = require("posix.unistd")
|
||||||
|
|
||||||
local Module = {
|
local Module = {
|
||||||
name = "mod_modem_restart",
|
name = "mod_modem_restart",
|
||||||
@@ -50,11 +50,11 @@ function Module:init(t)
|
|||||||
self.iface = t.iface
|
self.iface = t.iface
|
||||||
self.anyBand = (tonumber(t.any_band) ~= 0)
|
self.anyBand = (tonumber(t.any_band) ~= 0)
|
||||||
|
|
||||||
if not nixio.fs.access(self.mmcli, "x") then
|
if not unistd.access(self.mmcli, "x") then
|
||||||
self.anyBand = false
|
self.anyBand = false
|
||||||
end
|
end
|
||||||
|
|
||||||
if nixio.fs.access(self.mmInit, "x") then
|
if unistd.access(self.mmInit, "x") then
|
||||||
self._enabled = true
|
self._enabled = true
|
||||||
else
|
else
|
||||||
self._enabled = false
|
self._enabled = false
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
local nixio = require("nixio")
|
local unistd = require("posix.unistd")
|
||||||
|
|
||||||
local Module = {
|
local Module = {
|
||||||
name = "mod_network_restart",
|
name = "mod_network_restart",
|
||||||
@@ -22,9 +22,9 @@ end
|
|||||||
|
|
||||||
function Module:toggleDevice(flag)
|
function Module:toggleDevice(flag)
|
||||||
local ip = "/sbin/ip"
|
local ip = "/sbin/ip"
|
||||||
if nixio.fs.access(ip, "x") then
|
if unistd.access(ip, "x") then
|
||||||
return os.execute(
|
return os.execute(string.format(
|
||||||
string.format("%s link set dev %s %s", ip, self.iface, (flag and "up" or "down"))
|
"%s link set dev %s %s", ip, self.iface, (flag and "up" or "down"))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -71,10 +71,11 @@ function Module:run(currentStatus, lastStatus, timeDiff)
|
|||||||
self.syslog("info", string.format(
|
self.syslog("info", string.format(
|
||||||
"%s: restarting network interface '%s'", self.name, self.iface))
|
"%s: restarting network interface '%s'", self.name, self.iface))
|
||||||
self:ifaceDown()
|
self:ifaceDown()
|
||||||
nixio.nanosleep(self.restartTimeout)
|
unistd.sleep(self.restartTimeout)
|
||||||
self:ifaceUp()
|
self:ifaceUp()
|
||||||
else
|
else
|
||||||
self.syslog("info", string.format("%s: restarting network", self.name))
|
self.syslog("info", string.format(
|
||||||
|
"%s: restarting network", self.name))
|
||||||
self:networkRestart()
|
self:networkRestart()
|
||||||
end
|
end
|
||||||
self._deadCounter = 0
|
self._deadCounter = 0
|
||||||
|
|||||||
@@ -1,79 +1,322 @@
|
|||||||
|
|
||||||
local nixio = require("nixio")
|
local socket = require("posix.sys.socket")
|
||||||
|
local unistd = require("posix.unistd")
|
||||||
|
|
||||||
local Module = {
|
local Module = {
|
||||||
name = "mod_public_ip",
|
name = "mod_public_ip",
|
||||||
config = {},
|
config = {
|
||||||
syslog = function(level, msg) return true end,
|
debug = false,
|
||||||
writeValue = function(filePath, str) return false end,
|
serviceConfig = {
|
||||||
readValue = function(filePath) return nil end,
|
iface = nil,
|
||||||
runInterval = 600,
|
|
||||||
nslookup = "/usr/bin/nslookup",
|
|
||||||
timeout = 3,
|
|
||||||
providers = {
|
|
||||||
opendns1 = {
|
|
||||||
name = "opendns1", server = "208.67.222.222",
|
|
||||||
host = "myip.opendns.com", queryType = "a"
|
|
||||||
},
|
|
||||||
opendns2 = {
|
|
||||||
name = "opendns2", server = "208.67.220.220",
|
|
||||||
host = "myip.opendns.com", queryType = "a"
|
|
||||||
},
|
|
||||||
opendns3 = {
|
|
||||||
name = "opendns3", server = "208.67.222.220",
|
|
||||||
host = "myip.opendns.com", queryType = "a"
|
|
||||||
},
|
|
||||||
opendns4 = {
|
|
||||||
name = "opendns4", server = "208.67.220.222",
|
|
||||||
host = "myip.opendns.com", queryType = "a"
|
|
||||||
},
|
|
||||||
akamai = {
|
|
||||||
name = "akamai", server = "ns1-1.akamaitech.net",
|
|
||||||
host = "whoami.akamai.net", queryType = "a"
|
|
||||||
},
|
|
||||||
google = {
|
|
||||||
name = "google", server = "ns1.google.com",
|
|
||||||
host = "o-o.myaddr.l.google.com", queryType = "txt"
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
status = nil,
|
syslog = function(level, msg) return true end,
|
||||||
_provider = nil,
|
writeValue = function(filePath, str) return false end,
|
||||||
_nslookupCmd = nil,
|
readValue = function(filePath) return nil end,
|
||||||
_currentIp = nil,
|
port = 53,
|
||||||
_enabled = false,
|
runInterval = 600,
|
||||||
_counter = 0,
|
runIntervalFailed = 60,
|
||||||
|
timeout = 3,
|
||||||
|
reqAttempts = 3,
|
||||||
|
providers = {
|
||||||
|
opendns1 = {
|
||||||
|
name = "opendns1", host = "myip.opendns.com",
|
||||||
|
server = "208.67.222.222", server6 = "2620:119:35::35",
|
||||||
|
port = 53, queryType = "A", queryType6 = "AAAA",
|
||||||
|
},
|
||||||
|
opendns2 = {
|
||||||
|
name = "opendns2", host = "myip.opendns.com",
|
||||||
|
server = "208.67.220.220", server6 = "2620:119:35::35",
|
||||||
|
port = 53, queryType = "A", queryType6 = "AAAA",
|
||||||
|
},
|
||||||
|
opendns3 = {
|
||||||
|
name = "opendns3", host = "myip.opendns.com",
|
||||||
|
server = "208.67.222.220", server6 = "2620:119:35::35",
|
||||||
|
port = 53, queryType = "A", queryType6 = "AAAA",
|
||||||
|
},
|
||||||
|
opendns4 = {
|
||||||
|
name = "opendns4", host = "myip.opendns.com",
|
||||||
|
server = "208.67.220.222", server6 = "2620:119:35::35",
|
||||||
|
port = 53, queryType = "A", queryType6 = "AAAA",
|
||||||
|
},
|
||||||
|
akamai = {
|
||||||
|
name = "akamai", host = "whoami.akamai.net",
|
||||||
|
server = "ns1-1.akamaitech.net", server6 = "ns1-1.akamaitech.net",
|
||||||
|
port = 53, queryType = "A", queryType6 = "AAAA",
|
||||||
|
},
|
||||||
|
google = {
|
||||||
|
name = "google", host = "o-o.myaddr.l.google.com",
|
||||||
|
server = "ns1.google.com", server6 = "ns1.google.com",
|
||||||
|
port = 53, queryType = "TXT", queryType6 = "TXT",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
status = nil,
|
||||||
|
_provider = nil,
|
||||||
|
_qtype = false,
|
||||||
|
_currentIp = nil,
|
||||||
|
_enabled = false,
|
||||||
|
_counter = 0,
|
||||||
|
_interval = 600,
|
||||||
|
_DNSPacket = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
function Module:parseA(str)
|
function Module:getQueryType(type)
|
||||||
res = str:match("Name:%s+" .. self._provider.host .. "\nAddress:%s+[%w.:]+")
|
local types = {
|
||||||
if res then
|
A = 1,
|
||||||
return res:match("[%w.:]+$")
|
NS = 2,
|
||||||
|
MD = 3,
|
||||||
|
MF = 4,
|
||||||
|
CNAME = 5,
|
||||||
|
SOA = 6,
|
||||||
|
MB = 7,
|
||||||
|
MG = 8,
|
||||||
|
MR = 9,
|
||||||
|
NULL = 10,
|
||||||
|
WKS = 11,
|
||||||
|
PTS = 12,
|
||||||
|
HINFO = 13,
|
||||||
|
MINFO = 14,
|
||||||
|
MX = 15,
|
||||||
|
TXT = 16,
|
||||||
|
AAAA = 28,
|
||||||
|
}
|
||||||
|
return types[type]
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:buildMessage(address, queryType)
|
||||||
|
if not queryType then
|
||||||
|
queryType = "A"
|
||||||
|
end
|
||||||
|
queryType = self:getQueryType(queryType)
|
||||||
|
|
||||||
|
local addressString = ""
|
||||||
|
for part in address:gmatch("[^.]+") do
|
||||||
|
local t = {}
|
||||||
|
for i in part:gmatch(".") do
|
||||||
|
t[#t + 1] = i
|
||||||
|
end
|
||||||
|
addrLen = #part
|
||||||
|
addrPart = table.concat(t)
|
||||||
|
addressString = addressString .. string.char(addrLen) .. addrPart
|
||||||
|
end
|
||||||
|
|
||||||
|
local data = (
|
||||||
|
string.char(
|
||||||
|
0xaa, 0xaa,
|
||||||
|
0x01, 0x00,
|
||||||
|
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
) ..
|
||||||
|
addressString ..
|
||||||
|
string.char(
|
||||||
|
0x00,
|
||||||
|
0x00, queryType,
|
||||||
|
0x00, 0x01
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:sendUDPMessage(message, server, port)
|
||||||
|
local success
|
||||||
|
local retCode = 1
|
||||||
|
local data
|
||||||
|
|
||||||
|
if self.config.debug then
|
||||||
|
io.stdout:write(string.format("--- %s ---\n", self.name))
|
||||||
|
io.stdout:flush()
|
||||||
|
end
|
||||||
|
|
||||||
|
local saTable, errMsg, errNum = socket.getaddrinfo(server, port)
|
||||||
|
|
||||||
|
if not saTable then
|
||||||
|
if self.config.debug then
|
||||||
|
io.stdout:write(string.format(
|
||||||
|
"GETADDRINFO ERROR: %s, %s\n", errMsg, errNum))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local family = saTable[1].family
|
||||||
|
|
||||||
|
if family then
|
||||||
|
local sock, errMsg, errNum = socket.socket(family, socket.SOCK_DGRAM, 0)
|
||||||
|
|
||||||
|
if not sock then
|
||||||
|
if self.config.debug then
|
||||||
|
io.stdout:write(string.format(
|
||||||
|
"SOCKET ERROR: %s, %s\n", errMsg, errNum))
|
||||||
|
end
|
||||||
|
return retCode
|
||||||
|
end
|
||||||
|
|
||||||
|
socket.setsockopt(sock, socket.SOL_SOCKET,
|
||||||
|
socket.SO_SNDTIMEO, self.timeout, 0)
|
||||||
|
socket.setsockopt(sock, socket.SOL_SOCKET,
|
||||||
|
socket.SO_RCVTIMEO, self.timeout, 0)
|
||||||
|
|
||||||
|
if self.config.serviceConfig.iface then
|
||||||
|
local ok, errMsg, errNum = socket.setsockopt(sock, socket.SOL_SOCKET,
|
||||||
|
socket.SO_BINDTODEVICE, self.config.serviceConfig.iface)
|
||||||
|
if not ok then
|
||||||
|
if self.config.debug then
|
||||||
|
io.stdout:write(string.format(
|
||||||
|
"SOCKET ERROR: %s, %s\n", errMsg, errNum))
|
||||||
|
end
|
||||||
|
return retCode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, errMsg, errNum = socket.sendto(sock, message, saTable[1])
|
||||||
|
local response = {}
|
||||||
|
if ok then
|
||||||
|
local ret, resp, errNum = socket.recvfrom(sock, 1024)
|
||||||
|
data = ret
|
||||||
|
if data then
|
||||||
|
success = true
|
||||||
|
response = resp
|
||||||
|
elseif self.config.debug then
|
||||||
|
io.stdout:write(string.format(
|
||||||
|
"SOCKET RECV ERROR: %s, %s\n", tostring(resp), tostring(errNum)))
|
||||||
|
end
|
||||||
|
elseif self.config.debug then
|
||||||
|
io.stdout:write(string.format(
|
||||||
|
"SOCKET SEND ERROR: %s, %s\n", tostring(errMsg), tostring(errNum)))
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.config.debug then
|
||||||
|
io.stdout:write(string.format(
|
||||||
|
"--- UDP ---\ntime = %s\nconnection_timeout = %s\niface = %s\nserver = %s:%s\nsockname = %s:%s\nsuccess = %s\n",
|
||||||
|
os.time(),
|
||||||
|
self.timeout,
|
||||||
|
tostring(self.config.serviceConfig.iface),
|
||||||
|
server,
|
||||||
|
tostring(port),
|
||||||
|
tostring(response.addr),
|
||||||
|
tostring(response.port),
|
||||||
|
tostring(success))
|
||||||
|
)
|
||||||
|
io.stdout:flush()
|
||||||
|
end
|
||||||
|
|
||||||
|
unistd.close(sock)
|
||||||
|
retCode = success and 0 or 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return retCode, tostring(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:parseParts(message, start, parts)
|
||||||
|
local partStart = start + 2
|
||||||
|
local partLen = message:sub(start, start + 1)
|
||||||
|
|
||||||
|
if #partLen == 0 then
|
||||||
|
return parts
|
||||||
|
end
|
||||||
|
|
||||||
|
local partEnd = partStart + (tonumber(partLen, 16) * 2)
|
||||||
|
parts[#parts + 1] = message:sub(partStart, partEnd - 1)
|
||||||
|
if message:sub(partEnd, partEnd + 1) == "00" or partEnd > #message then
|
||||||
|
return parts
|
||||||
|
else
|
||||||
|
return self:parseParts(message, partEnd, parts)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Module:parseGoogle(str)
|
function Module:decodeMessage(message)
|
||||||
res = str:match(self._provider.host .. '%s+text%s+=%s+"[%w.:]+"')
|
local retTable = {}
|
||||||
if res then
|
|
||||||
return res:gsub('"', ''):match("[%w.:]+$")
|
local t = {}
|
||||||
|
for i = 1, #message do
|
||||||
|
t[#t + 1] = string.format("%.2x", string.byte(message, i))
|
||||||
end
|
end
|
||||||
|
message = table.concat(t)
|
||||||
|
|
||||||
|
local ANCOUNT = message:sub(13, 16)
|
||||||
|
local NSCOUNT = message:sub(17, 20)
|
||||||
|
local ARCOUNT = message:sub(21, 24)
|
||||||
|
|
||||||
|
local questionSectionStarts = 25
|
||||||
|
local questionParts = self:parseParts(message, questionSectionStarts, {})
|
||||||
|
local qtypeStarts = questionSectionStarts + (#table.concat(questionParts)) + (#questionParts * 2) + 1
|
||||||
|
local qclassStarts = qtypeStarts + 4
|
||||||
|
|
||||||
|
local answerSectionStarts = qclassStarts + 4
|
||||||
|
local numAnswers = math.max(
|
||||||
|
tonumber(ANCOUNT, 16), tonumber(NSCOUNT, 16), tonumber(ARCOUNT, 16))
|
||||||
|
|
||||||
|
if numAnswers > 0 then
|
||||||
|
for answerCount = 1, numAnswers do
|
||||||
|
|
||||||
|
if answerSectionStarts < #message then
|
||||||
|
local ATYPE = tonumber(
|
||||||
|
message:sub(answerSectionStarts + 5, answerSectionStarts + 8), 16)
|
||||||
|
local RDLENGTH = tonumber(
|
||||||
|
message:sub(answerSectionStarts + 21, answerSectionStarts + 24), 16)
|
||||||
|
local RDDATA = message:sub(
|
||||||
|
answerSectionStarts + 25, answerSectionStarts + 24 + (RDLENGTH * 2))
|
||||||
|
local RDDATA_decoded = ""
|
||||||
|
|
||||||
|
if #RDDATA > 0 then
|
||||||
|
if ATYPE == self:getQueryType("A") or ATYPE == self:getQueryType("AAAA") then
|
||||||
|
local octets = {}
|
||||||
|
local sep = "."
|
||||||
|
if #RDDATA > 8 then
|
||||||
|
sep = ":"
|
||||||
|
for i = 1, #RDDATA, 4 do
|
||||||
|
local string = RDDATA:sub(i, i + 3)
|
||||||
|
string = string:gsub("^00?0?", "")
|
||||||
|
octets[#octets + 1] = string
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i = 1, #RDDATA, 2 do
|
||||||
|
octets[#octets + 1] = tonumber(RDDATA:sub(i, i + 1), 16)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
RDDATA_decoded = table.concat(octets, sep):gsub("0:[0:]+", "::", 1):gsub("::+", "::")
|
||||||
|
else
|
||||||
|
local rdata_t = {}
|
||||||
|
for _, v in ipairs(self:parseParts(RDDATA, 1, {})) do
|
||||||
|
local t = {}
|
||||||
|
for i = 1, #v, 2 do
|
||||||
|
t[#t + 1] = string.char(tonumber(v:sub(i, i + 1), 16))
|
||||||
|
end
|
||||||
|
rdata_t[#rdata_t + 1] = table.concat(t)
|
||||||
|
end
|
||||||
|
RDDATA_decoded = table.concat(rdata_t)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
answerSectionStarts = answerSectionStarts + 24 + (RDLENGTH * 2)
|
||||||
|
|
||||||
|
if RDDATA_decoded:match("^[a-f0-9.:]+$") then
|
||||||
|
retTable[#retTable + 1] = RDDATA_decoded
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return retTable
|
||||||
end
|
end
|
||||||
|
|
||||||
function Module:resolveIP()
|
function Module:resolveIP()
|
||||||
local res
|
local res
|
||||||
local fh = io.popen(self._nslookupCmd, "r")
|
local qtype = self._qtype and self._provider.queryType6 or self._provider.queryType
|
||||||
if fh then
|
local server = self._qtype and self._provider.server6 or self._provider.server
|
||||||
output = fh:read("*a")
|
local port = self._provider.port or self.port
|
||||||
fh:close()
|
|
||||||
if self._provider.name == "google" then
|
if not self._DNSPacket then
|
||||||
res = self:parseGoogle(output)
|
self._DNSPacket = self:buildMessage(self._provider.host, qtype)
|
||||||
else
|
end
|
||||||
res = self:parseA(output)
|
|
||||||
|
local retCode, response = self:sendUDPMessage(self._DNSPacket, server, port)
|
||||||
|
if retCode == 0 then
|
||||||
|
local retTable = self:decodeMessage(response)
|
||||||
|
if #retTable > 0 then
|
||||||
|
res = table.concat(retTable, ", ")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.syslog("err", string.format(
|
self.syslog("err", string.format(
|
||||||
"%s: Nslookup call failed (%s)", self.name, self.nslookup))
|
"%s: DNS error when requesting an IP address", self.name))
|
||||||
end
|
end
|
||||||
return res or "Undefined"
|
|
||||||
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
function Module:init(t)
|
function Module:init(t)
|
||||||
@@ -88,23 +331,11 @@ function Module:init(t)
|
|||||||
else
|
else
|
||||||
self._provider = self.providers.opendns1
|
self._provider = self.providers.opendns1
|
||||||
end
|
end
|
||||||
if not nixio.fs.access(self.nslookup, "x") then
|
self._qtype = (tonumber(t.qtype) ~= 0)
|
||||||
self._enabled = false
|
self._currentIp = nil
|
||||||
self.syslog(
|
self._DNSPacket = nil
|
||||||
"warning",
|
self._interval = self.runInterval
|
||||||
string.format("%s: '%s' does not exists", self.name, self.nslookup)
|
self._enabled = true
|
||||||
)
|
|
||||||
else
|
|
||||||
self._enabled = true
|
|
||||||
self._nslookupCmd = string.format(
|
|
||||||
"%s -type=%s -timeout=%d %s %s",
|
|
||||||
self.nslookup,
|
|
||||||
self._provider.queryType,
|
|
||||||
self.timeout,
|
|
||||||
self._provider.host,
|
|
||||||
self._provider.server
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Module:run(currentStatus, lastStatus, timeDiff)
|
function Module:run(currentStatus, lastStatus, timeDiff)
|
||||||
@@ -112,8 +343,17 @@ function Module:run(currentStatus, lastStatus, timeDiff)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
if currentStatus == 0 then
|
if currentStatus == 0 then
|
||||||
if self._counter == 0 or self._counter >= self.runInterval or currentStatus ~= lastStatus then
|
if self._counter == 0 or self._counter >= self._interval or currentStatus ~= lastStatus then
|
||||||
|
|
||||||
local ip = self:resolveIP()
|
local ip = self:resolveIP()
|
||||||
|
|
||||||
|
if not ip then
|
||||||
|
ip = "Undefined"
|
||||||
|
self._interval = self.runIntervalFailed
|
||||||
|
else
|
||||||
|
self._interval = self.runInterval
|
||||||
|
end
|
||||||
|
|
||||||
if ip ~= self._currentIp then
|
if ip ~= self._currentIp then
|
||||||
self.status = ip
|
self.status = ip
|
||||||
self.syslog(
|
self.syslog(
|
||||||
@@ -123,6 +363,7 @@ function Module:run(currentStatus, lastStatus, timeDiff)
|
|||||||
else
|
else
|
||||||
self.status = nil
|
self.status = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
self._currentIp = ip
|
self._currentIp = ip
|
||||||
self._counter = 0
|
self._counter = 0
|
||||||
else
|
else
|
||||||
@@ -132,7 +373,9 @@ function Module:run(currentStatus, lastStatus, timeDiff)
|
|||||||
self.status = nil
|
self.status = nil
|
||||||
self._currentIp = nil
|
self._currentIp = nil
|
||||||
self._counter = 0
|
self._counter = 0
|
||||||
|
self._interval = self.runInterval
|
||||||
end
|
end
|
||||||
|
|
||||||
self._counter = self._counter + timeDiff
|
self._counter = self._counter + timeDiff
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
local nixio = require("nixio")
|
local unistd = require("posix.unistd")
|
||||||
|
|
||||||
local Module = {
|
local Module = {
|
||||||
name = "mod_reboot",
|
name = "mod_reboot",
|
||||||
@@ -16,9 +16,8 @@ local Module = {
|
|||||||
function Module:rebootDevice()
|
function Module:rebootDevice()
|
||||||
self.syslog("warning", string.format("%s: reboot", self.name))
|
self.syslog("warning", string.format("%s: reboot", self.name))
|
||||||
os.execute("/sbin/reboot &")
|
os.execute("/sbin/reboot &")
|
||||||
|
|
||||||
if self.forceRebootDelay > 0 then
|
if self.forceRebootDelay > 0 then
|
||||||
nixio.nanosleep(self.forceRebootDelay)
|
unistd.sleep(self.forceRebootDelay)
|
||||||
self.syslog("warning", string.format("%s: force reboot", self.name))
|
self.syslog("warning", string.format("%s: force reboot", self.name))
|
||||||
self.writeValue("/proc/sys/kernel/sysrq", "1")
|
self.writeValue("/proc/sys/kernel/sysrq", "1")
|
||||||
self.writeValue("/proc/sysrq-trigger", "b")
|
self.writeValue("/proc/sysrq-trigger", "b")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
local nixio = require("nixio")
|
local unistd = require("posix.unistd")
|
||||||
|
|
||||||
local Module = {
|
local Module = {
|
||||||
name = "mod_user_scripts",
|
name = "mod_user_scripts",
|
||||||
@@ -19,8 +19,8 @@ local Module = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Module:runExternalScript(scriptPath)
|
function Module:runExternalScript(scriptPath)
|
||||||
if nixio.fs.access(scriptPath, "x") then
|
if unistd.access(scriptPath, "r") then
|
||||||
os.execute(string.format('/bin/sh -c "%s" &', scriptPath))
|
os.execute(string.format('/bin/sh "%s" &', scriptPath))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -28,8 +28,10 @@ function Module:init(t)
|
|||||||
self.deadPeriod = tonumber(t.dead_period)
|
self.deadPeriod = tonumber(t.dead_period)
|
||||||
self.alivePeriod = tonumber(t.alive_period)
|
self.alivePeriod = tonumber(t.alive_period)
|
||||||
if self.config.configDir then
|
if self.config.configDir then
|
||||||
self.upScript = string.format("%s/up-script", self.config.configDir)
|
self.upScript = string.format(
|
||||||
self.downScript = string.format("%s/down-script", self.config.configDir)
|
"%s/up-script.%s", self.config.configDir, self.config.serviceConfig.instance)
|
||||||
|
self.downScript = string.format(
|
||||||
|
"%s/down-script.%s", self.config.configDir, self.config.serviceConfig.instance)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -37,7 +39,6 @@ function Module:run(currentStatus, lastStatus, timeDiff)
|
|||||||
if currentStatus == 1 then
|
if currentStatus == 1 then
|
||||||
self._aliveCounter = 0
|
self._aliveCounter = 0
|
||||||
self._downScriptExecuted = false
|
self._downScriptExecuted = false
|
||||||
|
|
||||||
if not self._upScriptExecuted then
|
if not self._upScriptExecuted then
|
||||||
if self._deadCounter >= self.deadPeriod then
|
if self._deadCounter >= self.deadPeriod then
|
||||||
self:runExternalScript(self.downScript)
|
self:runExternalScript(self.downScript)
|
||||||
@@ -49,7 +50,6 @@ function Module:run(currentStatus, lastStatus, timeDiff)
|
|||||||
else
|
else
|
||||||
self._deadCounter = 0
|
self._deadCounter = 0
|
||||||
self._upScriptExecuted = false
|
self._upScriptExecuted = false
|
||||||
|
|
||||||
if not self._downScriptExecuted then
|
if not self._downScriptExecuted then
|
||||||
if self._aliveCounter >= self.alivePeriod then
|
if self._aliveCounter >= self.alivePeriod then
|
||||||
self:runExternalScript(self.upScript)
|
self:runExternalScript(self.upScript)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#
|
#
|
||||||
# (с) 2021 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
# (с) 2023 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
||||||
#
|
#
|
||||||
|
|
||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_VERSION:=0.6-1
|
PKG_VERSION:=1.0-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
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,113 +6,154 @@
|
|||||||
document.head.append(E('style', {'type': 'text/css'},
|
document.head.append(E('style', {'type': 'text/css'},
|
||||||
`
|
`
|
||||||
:root {
|
:root {
|
||||||
--app-id-font-color: #fff;
|
--app-id-font-color: #454545;
|
||||||
--app-id-connected-color: #2ea256;
|
--app-id-font-shadow: #fff;
|
||||||
--app-id-disconnected-color: #ff4e54;
|
--app-id-connected-color: #6bdebb;
|
||||||
--app-id-undefined-color: #8a8a8a;
|
--app-id-disconnected-color: #f8aeba;
|
||||||
|
--app-id-undefined-color: #dfdfdf;
|
||||||
}
|
}
|
||||||
:root[data-darkmode="true"] {
|
:root[data-darkmode="true"] {
|
||||||
|
--app-id-font-color: #f6f6f6;
|
||||||
|
--app-id-font-shadow: #4d4d4d;
|
||||||
--app-id-connected-color: #005F20;
|
--app-id-connected-color: #005F20;
|
||||||
--app-id-disconnected-color: #a93734;
|
--app-id-disconnected-color: #a93734;
|
||||||
--app-id-undefined-color: #4d4d4d;
|
--app-id-undefined-color: #4d4d4d;
|
||||||
}
|
}
|
||||||
.id-connected {
|
.id-connected {
|
||||||
|
--on-color: var(--app-id-font-color);
|
||||||
background-color: var(--app-id-connected-color) !important;
|
background-color: var(--app-id-connected-color) !important;
|
||||||
|
border-color: var(--app-id-connected-color) !important;
|
||||||
color: var(--app-id-font-color) !important;
|
color: var(--app-id-font-color) !important;
|
||||||
|
text-shadow: 0 1px 1px var(--app-id-font-shadow);
|
||||||
}
|
}
|
||||||
.id-disconnected {
|
.id-disconnected {
|
||||||
|
--on-color: var(--app-id-font-color);
|
||||||
background-color: var(--app-id-disconnected-color) !important;
|
background-color: var(--app-id-disconnected-color) !important;
|
||||||
|
border-color: var(--app-id-disconnected-color) !important;
|
||||||
color: var(--app-id-font-color) !important;
|
color: var(--app-id-font-color) !important;
|
||||||
|
text-shadow: 0 1px 1px var(--app-id-font-shadow);
|
||||||
}
|
}
|
||||||
.id-undefined {
|
.id-undefined {
|
||||||
|
--on-color: var(--app-id-font-color);
|
||||||
background-color: var(--app-id-undefined-color) !important;
|
background-color: var(--app-id-undefined-color) !important;
|
||||||
|
border-color: var(--app-id-undefined-color) !important;
|
||||||
color: var(--app-id-font-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;
|
||||||
}
|
}
|
||||||
`));
|
`));
|
||||||
|
|
||||||
return baseclass.extend({
|
return baseclass.extend({
|
||||||
title : _('Internet'),
|
title : _('Internet'),
|
||||||
appName : 'internet-detector',
|
appName : 'internet-detector',
|
||||||
execPath : '/usr/bin/internet-detector',
|
execPath : '/usr/bin/internet-detector',
|
||||||
inetStatus : null,
|
uiCheckIntervalUp : null,
|
||||||
publicIp : null,
|
uiCheckIntervalDown : null,
|
||||||
|
currentAppMode : null,
|
||||||
|
inetStatus : null,
|
||||||
|
|
||||||
inetStatusFromJson: function(res) {
|
inetStatusFromJson : function(res) {
|
||||||
let curInetStatus = null;
|
let inetStatData = null;
|
||||||
let curPubIp = null;
|
|
||||||
if(res.code === 0) {
|
if(res.code === 0) {
|
||||||
try {
|
try {
|
||||||
let json = JSON.parse(res.stdout.trim());
|
inetStatData = JSON.parse(res.stdout.trim());
|
||||||
curInetStatus = json.inet;
|
|
||||||
curPubIp = json.mod_public_ip;
|
|
||||||
} catch(e) {};
|
} catch(e) {};
|
||||||
};
|
};
|
||||||
return [ curInetStatus, curPubIp ];
|
return inetStatData;
|
||||||
},
|
},
|
||||||
|
|
||||||
load: async function() {
|
load: async function() {
|
||||||
if(!(
|
if(!(
|
||||||
'uiCheckIntervalUp' in window &&
|
this.uiCheckIntervalUp &&
|
||||||
'uiCheckIntervalDown' in window &&
|
this.uiCheckIntervalDown &&
|
||||||
'currentAppMode' in window
|
this.currentAppMode
|
||||||
)) {
|
)) {
|
||||||
await uci.load(this.appName).then(data => {
|
await uci.load(this.appName).then(data => {
|
||||||
window.uiCheckIntervalUp = Number(uci.get(this.appName, 'config', 'ui_interval_up'));
|
this.uiCheckIntervalUp = Number(uci.get(this.appName, 'ui', 'interval_up'));
|
||||||
window.uiCheckIntervalDown = Number(uci.get(this.appName, 'config', 'ui_interval_down'));
|
this.uiCheckIntervalDown = Number(uci.get(this.appName, 'ui', 'interval_down'));
|
||||||
window.currentAppMode = uci.get(this.appName, 'config', 'mode');
|
this.currentAppMode = uci.get(this.appName, 'config', 'mode');
|
||||||
}).catch(e => {});
|
}).catch(e => {});
|
||||||
};
|
};
|
||||||
|
|
||||||
if(window.currentAppMode === '1' || window.currentAppMode === '2') {
|
if(this.currentAppMode === '2') {
|
||||||
window.internetDetectorCounter = ('internetDetectorCounter' in window) ?
|
this.internetDetectorCounter = ('internetDetectorCounter' in this) ?
|
||||||
++window.internetDetectorCounter : 0;
|
++this.internetDetectorCounter : 0;
|
||||||
|
|
||||||
if(!('internetDetectorState' in window)) {
|
if((this.internetDetectorStateUi === 0 &&
|
||||||
window.internetDetectorState = 2;
|
this.internetDetectorCounter % this.uiCheckIntervalUp) ||
|
||||||
};
|
(this.internetDetectorStateUi === 1 &&
|
||||||
|
this.internetDetectorCounter % this.uiCheckIntervalDown)
|
||||||
if(window.currentAppMode === '1' && (
|
) {
|
||||||
(window.internetDetectorState === 0 && window.internetDetectorCounter % window.uiCheckIntervalUp) ||
|
|
||||||
(window.internetDetectorState === 1 && window.internetDetectorCounter % window.uiCheckIntervalDown)
|
|
||||||
)) {
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
window.internetDetectorCounter = 0;
|
this.internetDetectorCounter = 0;
|
||||||
return L.resolveDefault(fs.exec(this.execPath, [ 'inet-status-json' ]), null);
|
return L.resolveDefault(fs.exec(this.execPath, [ 'poll' ]), null);
|
||||||
}
|
}
|
||||||
else {
|
else if(this.currentAppMode === '1') {
|
||||||
window.internetDetectorState = 2;
|
return L.resolveDefault(fs.exec(this.execPath, [ 'inet-status' ]), null);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function(data) {
|
render: function(data) {
|
||||||
if(window.currentAppMode === '0') {
|
if(this.currentAppMode === '0') {
|
||||||
return
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if(data) {
|
if(data) {
|
||||||
[ window.internetDetectorState, this.publicIp ] = this.inetStatusFromJson(data);
|
this.inetStatus = this.inetStatusFromJson(data);
|
||||||
|
if(this.currentAppMode === '2') {
|
||||||
|
this.internetDetectorStateUi = this.inetStatus.instances[0].inet;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
let internetStatus = E('span', { 'class': 'label' });
|
let inetStatusArea = E('div', {});
|
||||||
|
|
||||||
if(window.internetDetectorState === 0) {
|
if(!this.inetStatus || !this.inetStatus.instances || this.inetStatus.instances.length === 0) {
|
||||||
internetStatus.textContent = _('Connected') + (this.publicIp ? ' | %s: %s'.format(_('Public IP'), _(this.publicIp)) : '');
|
inetStatusArea.append(
|
||||||
internetStatus.className = "label id-connected";
|
E('span', { 'class': 'id-label-status id-undefined' }, _('Undefined'))
|
||||||
}
|
);
|
||||||
else if(window.internetDetectorState === 1) {
|
} else {
|
||||||
internetStatus.textContent = _('Disconnected');
|
this.inetStatus.instances.sort((a, b) => a.num > b.num);
|
||||||
internetStatus.className = "label id-disconnected";
|
|
||||||
}
|
for(let i of this.inetStatus.instances) {
|
||||||
else {
|
let status = _('Disconnected');
|
||||||
internetStatus.textContent = _('Undefined');
|
let className = 'id-label-status id-disconnected';
|
||||||
internetStatus.className = "label id-undefined";
|
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) ? ' | %s: %s'.format(
|
||||||
|
_('Public IP'), _(i.mod_public_ip)
|
||||||
|
) : '';
|
||||||
|
|
||||||
|
inetStatusArea.append(
|
||||||
|
E('span', { 'class': className }, '%s%s%s'.format(
|
||||||
|
(this.currentAppMode === '1') ? i.instance + ': ' : '',
|
||||||
|
status, publicIp)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return E('div', {
|
return E('div', {
|
||||||
'class': 'cbi-section',
|
'class': 'cbi-section',
|
||||||
'style': 'margin-bottom:1em',
|
'style': 'margin-bottom:1em',
|
||||||
}, internetStatus);
|
}, inetStatusArea);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ msgid ""
|
|||||||
"available."
|
"available."
|
||||||
msgstr "<abbr title=\"Светодиод\">LED</abbr> включен если Интернет доступен."
|
msgstr "<abbr title=\"Светодиод\">LED</abbr> включен если Интернет доступен."
|
||||||
|
|
||||||
|
msgid "Add instance"
|
||||||
|
msgstr "Добавить экземпляр"
|
||||||
|
|
||||||
msgid "Alive interval"
|
msgid "Alive interval"
|
||||||
msgstr "Интервал при подключении"
|
msgstr "Интервал при подключении"
|
||||||
|
|
||||||
@@ -92,6 +95,9 @@ msgstr "Отключен"
|
|||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr "Закрыть"
|
msgstr "Закрыть"
|
||||||
|
|
||||||
|
msgid "DNS query type"
|
||||||
|
msgstr "Тип DNS-запроса"
|
||||||
|
|
||||||
msgid "DNS provider"
|
msgid "DNS provider"
|
||||||
msgstr "DNS провайдер"
|
msgstr "DNS провайдер"
|
||||||
|
|
||||||
@@ -117,7 +123,7 @@ msgid "Enable"
|
|||||||
msgstr "Включить"
|
msgstr "Включить"
|
||||||
|
|
||||||
msgid "Enable logging"
|
msgid "Enable logging"
|
||||||
msgstr "Включить запись событий в лог"
|
msgstr "Запись событий в лог"
|
||||||
|
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Включен"
|
msgstr "Включен"
|
||||||
@@ -168,6 +174,12 @@ msgstr ""
|
|||||||
msgid "Huge: 1492 bytes"
|
msgid "Huge: 1492 bytes"
|
||||||
msgstr "Огромный: 1492 байта"
|
msgstr "Огромный: 1492 байта"
|
||||||
|
|
||||||
|
msgid "ICMP-echo request (ping)"
|
||||||
|
msgstr "Запрос ICMP-echo (ping)"
|
||||||
|
|
||||||
|
msgid "ICMP packet data size"
|
||||||
|
msgstr "Размер данных ICMP-пакета"
|
||||||
|
|
||||||
msgid "Interface"
|
msgid "Interface"
|
||||||
msgstr "Интерфейс"
|
msgstr "Интерфейс"
|
||||||
|
|
||||||
@@ -288,19 +300,6 @@ msgstr "Пароль"
|
|||||||
msgid "Password for SMTP authentication."
|
msgid "Password for SMTP authentication."
|
||||||
msgstr "Пароль для SMTP-аутентификации."
|
msgstr "Пароль для SMTP-аутентификации."
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Performing actions when connecting and disconnecting the Internet (available "
|
|
||||||
"in the \"Service\" mode)."
|
|
||||||
msgstr ""
|
|
||||||
"Выполнение действий при подключении и отключении Интернет (доступно в режиме "
|
|
||||||
"\"Служба\")."
|
|
||||||
|
|
||||||
msgid "Ping host"
|
|
||||||
msgstr "Пинг хоста"
|
|
||||||
|
|
||||||
msgid "Ping packet size"
|
|
||||||
msgstr "Размер пакета Ping"
|
|
||||||
|
|
||||||
msgid "Polling interval"
|
msgid "Polling interval"
|
||||||
msgstr "Интервал опроса"
|
msgstr "Интервал опроса"
|
||||||
|
|
||||||
@@ -367,12 +366,12 @@ msgstr "Конфигурация службы"
|
|||||||
msgid "Service for determining the public IP address through DNS."
|
msgid "Service for determining the public IP address through DNS."
|
||||||
msgstr "Сервис для определения публичного IP адреса через DNS."
|
msgstr "Сервис для определения публичного IP адреса через DNS."
|
||||||
|
|
||||||
msgid "Service modules"
|
|
||||||
msgstr "Модули службы"
|
|
||||||
|
|
||||||
msgid "Service: detector always runs as a system service."
|
msgid "Service: detector always runs as a system service."
|
||||||
msgstr "Служба: детектор работает постоянно, как системная служба."
|
msgstr "Служба: детектор работает постоянно, как системная служба."
|
||||||
|
|
||||||
|
msgid "Service instances"
|
||||||
|
msgstr "Экземпляры службы"
|
||||||
|
|
||||||
msgid "Set the modem to be allowed to use any band."
|
msgid "Set the modem to be allowed to use any band."
|
||||||
msgstr "Разрешить модему использование любой частоты."
|
msgstr "Разрешить модему использование любой частоты."
|
||||||
|
|
||||||
@@ -400,6 +399,9 @@ msgstr "TCP-порт"
|
|||||||
msgid "TCP port connection"
|
msgid "TCP port connection"
|
||||||
msgstr "Подключение к TCP-порту"
|
msgstr "Подключение к TCP-порту"
|
||||||
|
|
||||||
|
msgid "The type of record requested in the DNS query (if the service supports it)."
|
||||||
|
msgstr "Тип записи запрашиваемой в DNS-запросе (если сервис поддерживает)."
|
||||||
|
|
||||||
msgid "TLS: use STARTTLS if the server supports it."
|
msgid "TLS: use STARTTLS if the server supports it."
|
||||||
msgstr "TLS: использовать STARTTLS если сервер поддерживает."
|
msgstr "TLS: использовать STARTTLS если сервер поддерживает."
|
||||||
|
|
||||||
@@ -438,8 +440,8 @@ msgstr ""
|
|||||||
"Ожидание завершения перезагрузки перед выполнением принудительной "
|
"Ожидание завершения перезагрузки перед выполнением принудительной "
|
||||||
"перезагрузки."
|
"перезагрузки."
|
||||||
|
|
||||||
msgid "Web UI only"
|
msgid "Web UI only (UI detector)"
|
||||||
msgstr "Только web-интерфейс"
|
msgstr "Только web-интерфейс (UI детектор)"
|
||||||
|
|
||||||
msgid "Web UI only: detector works only when the Web UI is open (UI detector)."
|
msgid "Web UI only: detector works only when the Web UI is open (UI detector)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ msgid ""
|
|||||||
"available."
|
"available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Add instance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Alive interval"
|
msgid "Alive interval"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -80,6 +83,9 @@ msgstr ""
|
|||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DNS query type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "DNS provider"
|
msgid "DNS provider"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -154,6 +160,12 @@ msgstr ""
|
|||||||
msgid "Huge: 1492 bytes"
|
msgid "Huge: 1492 bytes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ICMP-echo request (ping)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ICMP packet data size"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Interface"
|
msgid "Interface"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -258,17 +270,6 @@ msgstr ""
|
|||||||
msgid "Password for SMTP authentication."
|
msgid "Password for SMTP authentication."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Performing actions when connecting and disconnecting the Internet (available "
|
|
||||||
"in the \"Service\" mode)."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Ping host"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Ping packet size"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Polling interval"
|
msgid "Polling interval"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -335,10 +336,10 @@ msgstr ""
|
|||||||
msgid "Service for determining the public IP address through DNS."
|
msgid "Service for determining the public IP address through DNS."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Service modules"
|
msgid "Service: detector always runs as a system service."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Service: detector always runs as a system service."
|
msgid "Service instances"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Set the modem to be allowed to use any band."
|
msgid "Set the modem to be allowed to use any band."
|
||||||
@@ -368,6 +369,9 @@ msgstr ""
|
|||||||
msgid "TCP port connection"
|
msgid "TCP port connection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "The type of record requested in the DNS query (if the service supports it)."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "TLS: use STARTTLS if the server supports it."
|
msgid "TLS: use STARTTLS if the server supports it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -404,7 +408,7 @@ msgstr ""
|
|||||||
msgid "Waiting for a reboot to complete before performing a forced reboot."
|
msgid "Waiting for a reboot to complete before performing a forced reboot."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Web UI only"
|
msgid "Web UI only (UI detector)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Web UI only: detector works only when the Web UI is open (UI detector)."
|
msgid "Web UI only: detector works only when the Web UI is open (UI detector)."
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
"read": {
|
"read": {
|
||||||
"file": {
|
"file": {
|
||||||
"/sys/class/leds": [ "list" ],
|
"/sys/class/leds": [ "list" ],
|
||||||
"/etc/internet-detector/up-script": [ "read" ],
|
"/etc/internet-detector/up-script*": [ "read" ],
|
||||||
"/etc/internet-detector/down-script": [ "read" ],
|
"/etc/internet-detector/down-script*": [ "read" ],
|
||||||
"/usr/bin/internet-detector*": [ "exec" ],
|
"/usr/bin/internet-detector*": [ "exec" ],
|
||||||
"/usr/bin/mailsend": [ "exec" ]
|
"/usr/bin/mailsend": [ "exec" ]
|
||||||
},
|
},
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
},
|
},
|
||||||
"write": {
|
"write": {
|
||||||
"file": {
|
"file": {
|
||||||
"/etc/internet-detector/up-script": [ "write" ],
|
"/etc/internet-detector/up-script*": [ "write" ],
|
||||||
"/etc/internet-detector/down-script": [ "write" ]
|
"/etc/internet-detector/down-script*": [ "write" ]
|
||||||
},
|
},
|
||||||
"uci": [ "internet-detector" ]
|
"uci": [ "internet-detector" ]
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 233 KiB After Width: | Height: | Size: 111 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 115 KiB |
BIN
screenshots/03.jpg
Normal file
BIN
screenshots/03.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 165 KiB |
BIN
screenshots/04.jpg
Normal file
BIN
screenshots/04.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
Reference in New Issue
Block a user