mirror of
https://github.com/gSpotx2f/luci-app-internet-detector.git
synced 2025-12-09 21:17:00 +03:00
v1.6. New module: mod_telegram. mod_public_ip: Added support for HTTP services.
This commit is contained in:
42
README.md
42
README.md
@@ -13,26 +13,27 @@ Internet-detector is an application for checking the availability of the Interne
|
|||||||
**OpenWrt >= 21.02.**
|
**OpenWrt >= 21.02.**
|
||||||
|
|
||||||
**Dependences:** lua, luaposix, libuci-lua.
|
**Dependences:** lua, luaposix, libuci-lua.
|
||||||
|
**Recommended:** curl.
|
||||||
|
|
||||||
## Installation notes:
|
## Installation notes:
|
||||||
|
|
||||||
opkg update
|
opkg update
|
||||||
wget --no-check-certificate -O /tmp/internet-detector_1.5.2-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector_1.5.2-r1_all.ipk
|
wget --no-check-certificate -O /tmp/internet-detector_1.6.0-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector_1.6.0-r1_all.ipk
|
||||||
opkg install /tmp/internet-detector_1.5.2-r1_all.ipk
|
opkg install /tmp/internet-detector_1.6.0-r1_all.ipk
|
||||||
rm /tmp/internet-detector_1.5.2-r1_all.ipk
|
rm /tmp/internet-detector_1.6.0-r1_all.ipk
|
||||||
service internet-detector start
|
service internet-detector start
|
||||||
service internet-detector enable
|
service internet-detector enable
|
||||||
|
|
||||||
wget --no-check-certificate -O /tmp/luci-app-internet-detector_1.5.2-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-app-internet-detector_1.5.2-r1_all.ipk
|
wget --no-check-certificate -O /tmp/luci-app-internet-detector_1.6.0-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-app-internet-detector_1.6.0-r1_all.ipk
|
||||||
opkg install /tmp/luci-app-internet-detector_1.5.2-r1_all.ipk
|
opkg install /tmp/luci-app-internet-detector_1.6.0-r1_all.ipk
|
||||||
rm /tmp/luci-app-internet-detector_1.5.2-r1_all.ipk
|
rm /tmp/luci-app-internet-detector_1.6.0-r1_all.ipk
|
||||||
service rpcd restart
|
service rpcd restart
|
||||||
|
|
||||||
i18n-ru:
|
i18n-ru:
|
||||||
|
|
||||||
wget --no-check-certificate -O /tmp/luci-i18n-internet-detector-ru_1.5.2-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-i18n-internet-detector-ru_1.5.2-r1_all.ipk
|
wget --no-check-certificate -O /tmp/luci-i18n-internet-detector-ru_1.6.0-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/luci-i18n-internet-detector-ru_1.6.0-r1_all.ipk
|
||||||
opkg install /tmp/luci-i18n-internet-detector-ru_1.5.2-r1_all.ipk
|
opkg install /tmp/luci-i18n-internet-detector-ru_1.6.0-r1_all.ipk
|
||||||
rm /tmp/luci-i18n-internet-detector-ru_1.5.2-r1_all.ipk
|
rm /tmp/luci-i18n-internet-detector-ru_1.6.0-r1_all.ipk
|
||||||
|
|
||||||
## Screenshots:
|
## Screenshots:
|
||||||
|
|
||||||
@@ -44,9 +45,9 @@ i18n-ru:
|
|||||||
|
|
||||||
**Dependences:** modemmanager.
|
**Dependences:** modemmanager.
|
||||||
|
|
||||||
wget --no-check-certificate -O /tmp/internet-detector-mod-modem-restart_1.5.2-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector-mod-modem-restart_1.5.2-r1_all.ipk
|
wget --no-check-certificate -O /tmp/internet-detector-mod-modem-restart_1.6.0-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector-mod-modem-restart_1.6.0-r1_all.ipk
|
||||||
opkg install /tmp/internet-detector-mod-modem-restart_1.5.2-r1_all.ipk
|
opkg install /tmp/internet-detector-mod-modem-restart_1.6.0-r1_all.ipk
|
||||||
rm /tmp/internet-detector-mod-modem-restart_1.5.2-r1_all.ipk
|
rm /tmp/internet-detector-mod-modem-restart_1.6.0-r1_all.ipk
|
||||||
service internet-detector restart
|
service internet-detector restart
|
||||||
|
|
||||||

|

|
||||||
@@ -55,9 +56,20 @@ i18n-ru:
|
|||||||
|
|
||||||
**Dependences:** mailsend.
|
**Dependences:** mailsend.
|
||||||
|
|
||||||
wget --no-check-certificate -O /tmp/internet-detector-mod-email_1.5.2-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector-mod-email_1.5.2-r1_all.ipk
|
wget --no-check-certificate -O /tmp/internet-detector-mod-email_1.6.0-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector-mod-email_1.6.0-r1_all.ipk
|
||||||
opkg install /tmp/internet-detector-mod-email_1.5.2-r1_all.ipk
|
opkg install /tmp/internet-detector-mod-email_1.6.0-r1_all.ipk
|
||||||
rm /tmp/internet-detector-mod-email_1.5.2-r1_all.ipk
|
rm /tmp/internet-detector-mod-email_1.6.0-r1_all.ipk
|
||||||
service internet-detector restart
|
service internet-detector restart
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Telegram notification module (internet-detector-mod-telegram):
|
||||||
|
|
||||||
|
**Dependences:** curl.
|
||||||
|
|
||||||
|
wget --no-check-certificate -O /tmp/internet-detector-mod-telegram_1.6.0-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/current/internet-detector-mod-telegram_1.6.0-r1_all.ipk
|
||||||
|
opkg install /tmp/internet-detector-mod-telegram_1.6.0-r1_all.ipk
|
||||||
|
rm /tmp/internet-detector-mod-telegram_1.6.0-r1_all.ipk
|
||||||
|
service internet-detector restart
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=internet-detector-mod-email
|
PKG_NAME:=internet-detector-mod-email
|
||||||
PKG_VERSION:=1.5.2
|
PKG_VERSION:=1.6.0
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ function Module:init(t)
|
|||||||
self._enabled = true
|
self._enabled = true
|
||||||
else
|
else
|
||||||
self._enabled = false
|
self._enabled = false
|
||||||
self.syslog("warning", string.format("%s: %s is not available", self.name, self.mta))
|
self.syslog("err", string.format("%s: %s is not available", self.name, self.mta))
|
||||||
end
|
end
|
||||||
|
|
||||||
if (not self.mailRecipient or
|
if (not self.mailRecipient or
|
||||||
@@ -162,6 +162,7 @@ function Module:run(currentStatus, lastStatus, timeDiff, timeNow, inetChecked)
|
|||||||
if not self._enabled then
|
if not self._enabled then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if currentStatus == 1 then
|
if currentStatus == 1 then
|
||||||
self._aliveCounter = 0
|
self._aliveCounter = 0
|
||||||
self._msgSentConnect = false
|
self._msgSentConnect = false
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=internet-detector-mod-modem-restart
|
PKG_NAME:=internet-detector-mod-modem-restart
|
||||||
PKG_VERSION:=1.5.2
|
PKG_VERSION:=1.6.0
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ function Module:init(t)
|
|||||||
self._enabled = true
|
self._enabled = true
|
||||||
else
|
else
|
||||||
self._enabled = false
|
self._enabled = false
|
||||||
self.syslog("warning", string.format(
|
self.syslog("err", string.format(
|
||||||
"%s: modemmanager service is not available", self.name))
|
"%s: modemmanager service is not available", self.name))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
41
internet-detector-mod-telegram/Makefile
Normal file
41
internet-detector-mod-telegram/Makefile
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#
|
||||||
|
# (с) 2025 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
|
||||||
|
#
|
||||||
|
|
||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
PKG_NAME:=internet-detector-mod-telegram
|
||||||
|
PKG_VERSION:=1.6.0
|
||||||
|
PKG_RELEASE:=1
|
||||||
|
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
||||||
|
|
||||||
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
|
define Package/$(PKG_NAME)
|
||||||
|
SECTION:=net
|
||||||
|
CATEGORY:=Network
|
||||||
|
TITLE:=Telegram messenger module for internet-detector
|
||||||
|
URL:=https://github.com/gSpotx2f/luci-app-internet-detector
|
||||||
|
PKGARCH:=all
|
||||||
|
DEPENDS:=+internet-detector +curl
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/$(PKG_NAME)/description
|
||||||
|
Telegram messenger support for internet-detector.
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/$(PKG_NAME)/conffiles
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Build/Configure
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Build/Compile
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/$(PKG_NAME)/install
|
||||||
|
$(INSTALL_DIR) $(1)/usr/lib/lua/internet-detector/modules
|
||||||
|
$(INSTALL_DATA) ./files/usr/lib/lua/internet-detector/modules/mod_telegram.lua $(1)/usr/lib/lua/internet-detector/modules/mod_telegram.lua
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
--[[
|
||||||
|
Dependences:
|
||||||
|
curl
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local unistd = require("posix.unistd")
|
||||||
|
|
||||||
|
local Module = {
|
||||||
|
name = "mod_telegram",
|
||||||
|
runPrio = 70,
|
||||||
|
syslog = function(level, msg) return true end,
|
||||||
|
debugOutput = function(msg) return true end,
|
||||||
|
writeValue = function(filePath, str) return false end,
|
||||||
|
readValue = function(filePath) return nil end,
|
||||||
|
deadPeriod = 0,
|
||||||
|
alivePeriod = 0,
|
||||||
|
mode = 0, -- 0: connected, 1: disconnected, 2: both
|
||||||
|
hostAlias = "OpenWrt",
|
||||||
|
connectTimeout = 5,
|
||||||
|
tgAPIToken = nil,
|
||||||
|
tgChatId = nil,
|
||||||
|
tgMsgURLpattern = "https://api.telegram.org/bot%s/sendMessage?chat_id=%s&parse_mode=html&text=%s",
|
||||||
|
msgTextPattern = "<strong>[%s] (%s)</strong> @ %s", -- Message (host, instance, message)
|
||||||
|
msgConnectPattern = "Connected: %s",
|
||||||
|
msgDisconnectPattern = "Disconnected: %s",
|
||||||
|
msgSeparator = " | ",
|
||||||
|
msgMaxItems = 50,
|
||||||
|
msgSendAttempts = 3,
|
||||||
|
msgSendTimeout = 5,
|
||||||
|
curlExec = "/usr/bin/curl",
|
||||||
|
curlParams = "-s",
|
||||||
|
status = nil,
|
||||||
|
_enabled = false,
|
||||||
|
_deadCounter = 0,
|
||||||
|
_aliveCounter = 0,
|
||||||
|
_msgSentDisconnect = true,
|
||||||
|
_disconnected = true,
|
||||||
|
_msgSentConnect = true,
|
||||||
|
_connected = true,
|
||||||
|
_msgBuffer = {},
|
||||||
|
_msgSendCounter = 3,
|
||||||
|
_msgTimeoutCounter = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
local function prequire(package)
|
||||||
|
local retVal, pkg = pcall(require, package)
|
||||||
|
return retVal and pkg
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:init(t)
|
||||||
|
self._enabled = true
|
||||||
|
if t.mode ~= nil then
|
||||||
|
self.mode = tonumber(t.mode)
|
||||||
|
end
|
||||||
|
if t.dead_period ~= nil then
|
||||||
|
self.deadPeriod = tonumber(t.dead_period)
|
||||||
|
end
|
||||||
|
if t.alive_period ~= nil then
|
||||||
|
self.alivePeriod = tonumber(t.alive_period)
|
||||||
|
end
|
||||||
|
if t.host_alias then
|
||||||
|
self.hostAlias = t.host_alias
|
||||||
|
else
|
||||||
|
self.hostAlias = self.config.hostname
|
||||||
|
end
|
||||||
|
if t.api_token ~= nil then
|
||||||
|
self.tgAPIToken = t.api_token
|
||||||
|
end
|
||||||
|
if t.chat_id ~= nil then
|
||||||
|
self.tgChatId = t.chat_id
|
||||||
|
end
|
||||||
|
if tonumber(t.message_at_startup) == 1 then
|
||||||
|
self._msgSentDisconnect = false
|
||||||
|
self._disconnected = false
|
||||||
|
self._msgSentConnect = false
|
||||||
|
self._connected = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if unistd.access(self.curlExec, "x") then
|
||||||
|
self._enabled = true
|
||||||
|
else
|
||||||
|
self._enabled = false
|
||||||
|
self.syslog("err", string.format("%s: %s is not available", self.name, self.curlExec))
|
||||||
|
end
|
||||||
|
if not self.tgAPIToken then
|
||||||
|
self._enabled = false
|
||||||
|
self.syslog("err", string.format("%s: Telegram bot API token not specified.", self.name))
|
||||||
|
end
|
||||||
|
if not self.tgChatId then
|
||||||
|
self._enabled = false
|
||||||
|
self.syslog("err", string.format("%s: Telegram chat ID not specified.", self.name))
|
||||||
|
end
|
||||||
|
|
||||||
|
self._msgSendCounter = self.msgSendAttempts
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:escape(str)
|
||||||
|
local t = {}
|
||||||
|
for i in str:gmatch(".") do
|
||||||
|
if i:match("[^%w_]") then
|
||||||
|
t[#t + 1] = "%" .. string.format("%x", string.byte(i))
|
||||||
|
else
|
||||||
|
t[#t + 1] = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:appendNotice(str)
|
||||||
|
self._msgBuffer[#self._msgBuffer + 1] = str
|
||||||
|
if #self._msgBuffer > self.msgMaxItems then
|
||||||
|
local t = {}
|
||||||
|
for i = #self._msgBuffer - self.msgMaxItems + 1, #self._msgBuffer do
|
||||||
|
t[#t + 1] = self._msgBuffer[i]
|
||||||
|
end
|
||||||
|
self._msgBuffer = t
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:httpRequest(url)
|
||||||
|
local retCode = 1, data
|
||||||
|
local fh = io.popen(string.format(
|
||||||
|
'%s --connect-timeout %s %s "%s"; printf "\n$?";', self.curlExec, self.connectTimeout, self.curlParams, url), "r")
|
||||||
|
if fh then
|
||||||
|
data = fh:read("*a")
|
||||||
|
fh:close()
|
||||||
|
local s, e = data:find("[0-9]+\n?$")
|
||||||
|
retCode = tonumber(data:sub(s))
|
||||||
|
data = data:sub(0, s - 2)
|
||||||
|
if not data or data == "" then
|
||||||
|
data = nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
retCode = 1
|
||||||
|
end
|
||||||
|
return retCode, data
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:parseResponse(str)
|
||||||
|
local ok, errCode, desc
|
||||||
|
ok = str:match('"ok":(%w+)')
|
||||||
|
if ok == "false" then
|
||||||
|
errCode = tonumber(str:match('"error_code":(%d+)'))
|
||||||
|
if errCode then
|
||||||
|
desc = str:match('"description":"([%w%s%p_]+)"')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ok, errCode, desc
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:messageRequest(msg, textPattern)
|
||||||
|
local retVal = 1
|
||||||
|
local tgMsg = string.format(
|
||||||
|
textPattern, self.hostAlias, self.config.serviceConfig.instance, msg)
|
||||||
|
local url = string.format(
|
||||||
|
self.tgMsgURLpattern, self.tgAPIToken, self.tgChatId, self:escape(tgMsg))
|
||||||
|
|
||||||
|
local ok, errCode, desc
|
||||||
|
local retCode, data = self:httpRequest(url)
|
||||||
|
if data then
|
||||||
|
ok, errCode, desc = self:parseResponse(data)
|
||||||
|
end
|
||||||
|
if retCode == 0 and ok == "true" then
|
||||||
|
retVal = 0
|
||||||
|
self.syslog("info", string.format(
|
||||||
|
"%s: Message sent to chat %s", self.name, self.tgChatId))
|
||||||
|
else
|
||||||
|
if errCode == 400 or errCode == 406 then
|
||||||
|
retVal = 2
|
||||||
|
elseif (errCode == 401 or
|
||||||
|
errCode == 403 or
|
||||||
|
errCode == 404 or
|
||||||
|
errCode == 420) then
|
||||||
|
retVal = 3
|
||||||
|
end
|
||||||
|
if errCode and desc then
|
||||||
|
self.syslog("warning", string.format(
|
||||||
|
"%s: %s %s", self.name, tostring(errCode), tostring(desc)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return retVal
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:sendMessage(msg, textPattern)
|
||||||
|
local retVal = self:messageRequest(msg, textPattern)
|
||||||
|
if retVal == 0 then
|
||||||
|
self._msgBuffer = {}
|
||||||
|
elseif retVal == 2 then
|
||||||
|
self.syslog("err", string.format(
|
||||||
|
"%s: Server error (invalid API token or chat ID)", self.name))
|
||||||
|
else
|
||||||
|
self.syslog("err", string.format(
|
||||||
|
"%s: An error occured while sending message", self.name))
|
||||||
|
end
|
||||||
|
return retVal
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:run(currentStatus, lastStatus, timeDiff, timeNow, inetChecked)
|
||||||
|
if not self._enabled then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if currentStatus == 1 then
|
||||||
|
self._aliveCounter = 0
|
||||||
|
self._msgSentConnect = false
|
||||||
|
|
||||||
|
if not self._disconnected then
|
||||||
|
self._disconnected = true
|
||||||
|
self:appendNotice(string.format(
|
||||||
|
self.msgDisconnectPattern, os.date("%Y.%m.%d %H:%M:%S", os.time())))
|
||||||
|
end
|
||||||
|
if not self._msgSentDisconnect and (self.mode == 1 or self.mode == 2) then
|
||||||
|
if self._deadCounter >= self.deadPeriod then
|
||||||
|
self._msgSendCounter = 0
|
||||||
|
self._msgSentDisconnect = true
|
||||||
|
else
|
||||||
|
self._deadCounter = self._deadCounter + timeDiff
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self._connected = false
|
||||||
|
else
|
||||||
|
self._deadCounter = 0
|
||||||
|
self._msgSentDisconnect = false
|
||||||
|
|
||||||
|
if not self._connected then
|
||||||
|
self._connected = true
|
||||||
|
self:appendNotice(string.format(
|
||||||
|
self.msgConnectPattern, os.date("%Y.%m.%d %H:%M:%S", os.time())))
|
||||||
|
end
|
||||||
|
if not self._msgSentConnect and (self.mode == 0 or self.mode == 2) then
|
||||||
|
if self._aliveCounter >= self.alivePeriod then
|
||||||
|
self._msgSendCounter = 0
|
||||||
|
self._msgSentConnect = true
|
||||||
|
else
|
||||||
|
self._aliveCounter = self._aliveCounter + timeDiff
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self._disconnected = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if self._msgSendCounter < self.msgSendAttempts then
|
||||||
|
if self._msgTimeoutCounter >= self.msgSendTimeout then
|
||||||
|
if #self._msgBuffer > 0 then
|
||||||
|
local retVal = self:sendMessage(table.concat(self._msgBuffer, self.msgSeparator), self.msgTextPattern)
|
||||||
|
if retVal == 1 then
|
||||||
|
self._msgSendCounter = self._msgSendCounter + 1
|
||||||
|
else
|
||||||
|
self._msgSendCounter = self.msgSendAttempts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self._msgTimeoutCounter = 0
|
||||||
|
else
|
||||||
|
self._msgTimeoutCounter = self._msgTimeoutCounter + timeDiff
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self._msgTimeoutCounter = self.msgSendTimeout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:onExit()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return Module
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=internet-detector
|
PKG_NAME:=internet-detector
|
||||||
PKG_VERSION:=1.5.2
|
PKG_VERSION:=1.6.0
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/luci-app-internet-detector>
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ config instance 'internet'
|
|||||||
option mod_email_mode '0'
|
option mod_email_mode '0'
|
||||||
option mod_email_alive_period '0'
|
option mod_email_alive_period '0'
|
||||||
option mod_email_mail_security 'tls'
|
option mod_email_mail_security 'tls'
|
||||||
|
option mod_telegram_enabled '0'
|
||||||
|
option mod_telegram_message_at_startup '0'
|
||||||
|
option mod_telegram_mode '2'
|
||||||
|
option mod_telegram_dead_period '0'
|
||||||
|
option mod_telegram_alive_period '0'
|
||||||
option mod_user_scripts_enabled '0'
|
option mod_user_scripts_enabled '0'
|
||||||
option mod_user_scripts_alive_period '0'
|
option mod_user_scripts_alive_period '0'
|
||||||
option mod_user_scripts_up_script_attempts '1'
|
option mod_user_scripts_up_script_attempts '1'
|
||||||
|
|||||||
@@ -20,39 +20,69 @@ local Module = {
|
|||||||
port = 53,
|
port = 53,
|
||||||
runInterval = 600,
|
runInterval = 600,
|
||||||
runIntervalFailed = 60,
|
runIntervalFailed = 60,
|
||||||
runIntervalDNSFailed = 1,
|
runIntervalIPFailed = 1,
|
||||||
requestAttempts = 2,
|
requestAttempts = 2,
|
||||||
timeout = 3,
|
timeout = 3,
|
||||||
|
curlExec = "/usr/bin/curl",
|
||||||
|
curlParams = "-s",
|
||||||
providers = {
|
providers = {
|
||||||
opendns1 = {
|
opendns1 = {
|
||||||
name = "opendns1", host = "myip.opendns.com",
|
name = "opendns1", type = "dns", host = "myip.opendns.com",
|
||||||
server = "208.67.222.222", server6 = "2620:119:35::35",
|
server = "208.67.222.222", server6 = "2620:119:35::35",
|
||||||
port = 53, queryType = "A", queryType6 = "AAAA",
|
port = 53, queryType = "A", queryType6 = "AAAA",
|
||||||
},
|
},
|
||||||
opendns2 = {
|
opendns2 = {
|
||||||
name = "opendns2", host = "myip.opendns.com",
|
name = "opendns2", type = "dns", host = "myip.opendns.com",
|
||||||
server = "208.67.220.220", server6 = "2620:119:35::35",
|
server = "208.67.220.220", server6 = "2620:119:35::35",
|
||||||
port = 53, queryType = "A", queryType6 = "AAAA",
|
port = 53, queryType = "A", queryType6 = "AAAA",
|
||||||
},
|
},
|
||||||
opendns3 = {
|
opendns3 = {
|
||||||
name = "opendns3", host = "myip.opendns.com",
|
name = "opendns3", type = "dns", host = "myip.opendns.com",
|
||||||
server = "208.67.222.220", server6 = "2620:119:35::35",
|
server = "208.67.222.220", server6 = "2620:119:35::35",
|
||||||
port = 53, queryType = "A", queryType6 = "AAAA",
|
port = 53, queryType = "A", queryType6 = "AAAA",
|
||||||
},
|
},
|
||||||
opendns4 = {
|
opendns4 = {
|
||||||
name = "opendns4", host = "myip.opendns.com",
|
name = "opendns4", type = "dns", host = "myip.opendns.com",
|
||||||
server = "208.67.220.222", server6 = "2620:119:35::35",
|
server = "208.67.220.222", server6 = "2620:119:35::35",
|
||||||
port = 53, queryType = "A", queryType6 = "AAAA",
|
port = 53, queryType = "A", queryType6 = "AAAA",
|
||||||
},
|
},
|
||||||
akamai = {
|
google = {
|
||||||
name = "akamai", host = "whoami.akamai.net",
|
name = "google", type = "dns", host = "o-o.myaddr.l.google.com",
|
||||||
|
server = "ns1.google.com", server6 = "ns1.google.com",
|
||||||
|
port = 53, queryType = "TXT", queryType6 = "TXT",
|
||||||
|
},
|
||||||
|
akamai = {
|
||||||
|
name = "akamai", type = "dns", host = "whoami.akamai.net",
|
||||||
server = "ns1-1.akamaitech.net", server6 = "ns1-1.akamaitech.net",
|
server = "ns1-1.akamaitech.net", server6 = "ns1-1.akamaitech.net",
|
||||||
port = 53, queryType = "A", queryType6 = "AAAA",
|
port = 53, queryType = "A", queryType6 = "AAAA",
|
||||||
},
|
},
|
||||||
google = {
|
akamai_http = {
|
||||||
name = "google", host = "o-o.myaddr.l.google.com",
|
name = "akamai_http", type = "http", url = "http://whatismyip.akamai.com/",
|
||||||
server = "ns1.google.com", server6 = "ns1.google.com",
|
parseResponseFunc = nil,
|
||||||
port = 53, queryType = "TXT", queryType6 = "TXT",
|
},
|
||||||
|
amazonaws= {
|
||||||
|
name = "amazonaws", type = "http", url = "http://checkip.amazonaws.com/",
|
||||||
|
parseResponseFunc = nil,
|
||||||
|
},
|
||||||
|
wgetip= {
|
||||||
|
name = "wgetip", type = "http", url = "http://wgetip.com/",
|
||||||
|
parseResponseFunc = nil,
|
||||||
|
},
|
||||||
|
ifconfig= {
|
||||||
|
name = "ifconfig", type = "http", url = "http://ifconfig.me/",
|
||||||
|
parseResponseFunc = nil,
|
||||||
|
},
|
||||||
|
ipecho= {
|
||||||
|
name = "ipecho", type = "http", url = "http://ipecho.net/plain",
|
||||||
|
parseResponseFunc = nil,
|
||||||
|
},
|
||||||
|
canhazip= {
|
||||||
|
name = "canhazip", type = "http", url = "http://canhazip.com/",
|
||||||
|
parseResponseFunc = nil,
|
||||||
|
},
|
||||||
|
icanhazip = {
|
||||||
|
name = "icanhazip", type = "http", url = "http://icanhazip.com/",
|
||||||
|
parseResponseFunc = nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ipScript = "",
|
ipScript = "",
|
||||||
@@ -64,9 +94,10 @@ local Module = {
|
|||||||
_lastResolvedIp = nil,
|
_lastResolvedIp = nil,
|
||||||
_enabled = false,
|
_enabled = false,
|
||||||
_counter = 0,
|
_counter = 0,
|
||||||
_DNSFalseCounter = 0,
|
_IPFalseCounter = 0,
|
||||||
_interval = 600,
|
_interval = 600,
|
||||||
_DNSPacket = nil,
|
_DNSPacket = nil,
|
||||||
|
_requestIP = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
function Module:runIpScript()
|
function Module:runIpScript()
|
||||||
@@ -172,6 +203,7 @@ function Module:sendUDPMessage(message, server, port)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local ok, errMsg, errNum = socket.sendto(sock, message, saTable[1])
|
local ok, errMsg, errNum = socket.sendto(sock, message, saTable[1])
|
||||||
|
|
||||||
local response = {}
|
local response = {}
|
||||||
if ok then
|
if ok then
|
||||||
local ret, resp, errNum = socket.recvfrom(sock, 1024)
|
local ret, resp, errNum = socket.recvfrom(sock, 1024)
|
||||||
@@ -212,13 +244,10 @@ end
|
|||||||
function Module:parseParts(message, start, parts)
|
function Module:parseParts(message, start, parts)
|
||||||
local partStart = start + 2
|
local partStart = start + 2
|
||||||
local partLen = message:sub(start, start + 1)
|
local partLen = message:sub(start, start + 1)
|
||||||
|
|
||||||
if #partLen == 0 then
|
if #partLen == 0 then
|
||||||
return parts
|
return parts
|
||||||
end
|
end
|
||||||
|
|
||||||
local partEnd = partStart + (tonumber(partLen, 16) * 2)
|
local partEnd = partStart + (tonumber(partLen, 16) * 2)
|
||||||
|
|
||||||
parts[#parts + 1] = message:sub(partStart, partEnd - 1)
|
parts[#parts + 1] = message:sub(partStart, partEnd - 1)
|
||||||
if message:sub(partEnd, partEnd + 1) == "00" or partEnd > #message then
|
if message:sub(partEnd, partEnd + 1) == "00" or partEnd > #message then
|
||||||
return parts
|
return parts
|
||||||
@@ -240,6 +269,7 @@ function Module:decodeMessage(message)
|
|||||||
local ARCOUNT = message:sub(21, 24)
|
local ARCOUNT = message:sub(21, 24)
|
||||||
|
|
||||||
local questionSectionStarts = 25
|
local questionSectionStarts = 25
|
||||||
|
|
||||||
local questionParts = self:parseParts(message, questionSectionStarts, {})
|
local questionParts = self:parseParts(message, questionSectionStarts, {})
|
||||||
local qtypeStarts = questionSectionStarts + (#table.concat(questionParts)) + (#questionParts * 2) + 1
|
local qtypeStarts = questionSectionStarts + (#table.concat(questionParts)) + (#questionParts * 2) + 1
|
||||||
local qclassStarts = qtypeStarts + 4
|
local qclassStarts = qtypeStarts + 4
|
||||||
@@ -251,11 +281,11 @@ function Module:decodeMessage(message)
|
|||||||
if numAnswers > 0 then
|
if numAnswers > 0 then
|
||||||
for answerCount = 1, numAnswers do
|
for answerCount = 1, numAnswers do
|
||||||
if answerSectionStarts < #message then
|
if answerSectionStarts < #message then
|
||||||
local ATYPE = tonumber(
|
local ATYPE = tonumber(
|
||||||
message:sub(answerSectionStarts + 5, answerSectionStarts + 8), 16)
|
message:sub(answerSectionStarts + 5, answerSectionStarts + 8), 16)
|
||||||
local RDLENGTH = tonumber(
|
local RDLENGTH = tonumber(
|
||||||
message:sub(answerSectionStarts + 21, answerSectionStarts + 24), 16)
|
message:sub(answerSectionStarts + 21, answerSectionStarts + 24), 16)
|
||||||
local RDDATA = message:sub(
|
local RDDATA = message:sub(
|
||||||
answerSectionStarts + 25, answerSectionStarts + 24 + (RDLENGTH * 2))
|
answerSectionStarts + 25, answerSectionStarts + 24 + (RDLENGTH * 2))
|
||||||
local RDDATA_decoded = ""
|
local RDDATA_decoded = ""
|
||||||
|
|
||||||
@@ -290,26 +320,23 @@ function Module:decodeMessage(message)
|
|||||||
end
|
end
|
||||||
answerSectionStarts = answerSectionStarts + 24 + (RDLENGTH * 2)
|
answerSectionStarts = answerSectionStarts + 24 + (RDLENGTH * 2)
|
||||||
|
|
||||||
if RDDATA_decoded:match("^[a-f0-9.:]+$") then
|
if RDDATA_decoded:match("^[a-fA-F0-9.:]+$") then
|
||||||
retTable[#retTable + 1] = RDDATA_decoded
|
retTable[#retTable + 1] = RDDATA_decoded
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return retTable
|
return retTable
|
||||||
end
|
end
|
||||||
|
|
||||||
function Module:requestIP()
|
function Module:requestIPDNS()
|
||||||
local res
|
local res
|
||||||
local qtype = self._qtype and self._provider.queryType6 or self._provider.queryType
|
local qtype = self._qtype and self._provider.queryType6 or self._provider.queryType
|
||||||
local server = self._qtype and self._provider.server6 or self._provider.server
|
local server = self._qtype and self._provider.server6 or self._provider.server
|
||||||
local port = self._provider.port or self.port
|
local port = self._provider.port or self.port
|
||||||
|
|
||||||
if not self._DNSPacket then
|
if not self._DNSPacket then
|
||||||
self._DNSPacket = self:buildMessage(self._provider.host, qtype)
|
self._DNSPacket = self:buildMessage(self._provider.host, qtype)
|
||||||
end
|
end
|
||||||
|
|
||||||
local retCode, response = self:sendUDPMessage(self._DNSPacket, server, port)
|
local retCode, response = self:sendUDPMessage(self._DNSPacket, server, port)
|
||||||
if retCode == 0 and response then
|
if retCode == 0 and response then
|
||||||
local retTable = self:decodeMessage(response)
|
local retTable = self:decodeMessage(response)
|
||||||
@@ -320,7 +347,57 @@ function Module:requestIP()
|
|||||||
self.syslog("warning", string.format(
|
self.syslog("warning", string.format(
|
||||||
"%s: UDP error when requesting an IP address", self.name))
|
"%s: UDP error when requesting an IP address", self.name))
|
||||||
end
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:httpRequest(url)
|
||||||
|
local retCode = 1, data
|
||||||
|
local iface = ""
|
||||||
|
if self.config.serviceConfig.iface then
|
||||||
|
iface = " --interface " .. self.config.serviceConfig.iface
|
||||||
|
end
|
||||||
|
local fh = io.popen(string.format(
|
||||||
|
'%s%s --connect-timeout %s %s "%s"; printf "\n$?";', self.curlExec, iface, self.timeout, self.curlParams, url), "r")
|
||||||
|
if fh then
|
||||||
|
data = fh:read("*a")
|
||||||
|
fh:close()
|
||||||
|
local s, e = data:find("[0-9]+\n?$")
|
||||||
|
retCode = tonumber(data:sub(s))
|
||||||
|
data = data:sub(0, s - 2)
|
||||||
|
if not data or data == "" then
|
||||||
|
data = nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
retCode = 1
|
||||||
|
end
|
||||||
|
return retCode, data
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:parseHTTPResponse(data)
|
||||||
|
data = data:gsub("^[%s%c]+", ""):gsub("[%s%c]+$", "")
|
||||||
|
if data:match("^[a-fA-F0-9.:]+$") then
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module:requestIPHTTP()
|
||||||
|
local res
|
||||||
|
local url = self._provider.url
|
||||||
|
local parseResponseFunc = self._provider.parseResponseFunc
|
||||||
|
if url then
|
||||||
|
local retCode, data = self:httpRequest(url)
|
||||||
|
if retCode == 0 and data then
|
||||||
|
if type(parseResponseFunc) == "function" then
|
||||||
|
res = parseResponseFunc(data)
|
||||||
|
else
|
||||||
|
res = self:parseHTTPResponse(data)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.syslog("warning", string.format(
|
||||||
|
"%s: HTTP error when requesting an IP address", self.name))
|
||||||
|
end
|
||||||
|
end
|
||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -352,12 +429,28 @@ function Module:init(t)
|
|||||||
if t.qtype ~= nil then
|
if t.qtype ~= nil then
|
||||||
self._qtype = (tonumber(t.qtype) ~= 0)
|
self._qtype = (tonumber(t.qtype) ~= 0)
|
||||||
end
|
end
|
||||||
self._currentIp = nil
|
self._currentIp = nil
|
||||||
self._lastResolvedIp = nil
|
self._lastResolvedIp = nil
|
||||||
self._DNSPacket = nil
|
self._DNSPacket = nil
|
||||||
self._interval = self.runInterval
|
self._interval = self.runInterval
|
||||||
self._DNSFalseCounter = 0
|
self._IPFalseCounter = 0
|
||||||
self._enabled = true
|
self._enabled = true
|
||||||
|
if not self._provider then
|
||||||
|
self._enabled = false
|
||||||
|
else
|
||||||
|
if self._provider.url and not unistd.access(self.curlExec, "x") then
|
||||||
|
self._enabled = false
|
||||||
|
self.syslog("err", string.format(
|
||||||
|
"%s: %s is not available. You need to install curl.", self.name, self.curlExec))
|
||||||
|
end
|
||||||
|
if self._provider.type == "dns" then
|
||||||
|
self._requestIP = self.requestIPDNS
|
||||||
|
elseif self._provider.type == "http" then
|
||||||
|
self._requestIP = self.requestIPHTTP
|
||||||
|
else
|
||||||
|
self._enabled = false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Module:run(currentStatus, lastStatus, timeDiff, timeNow, inetChecked)
|
function Module:run(currentStatus, lastStatus, timeDiff, timeNow, inetChecked)
|
||||||
@@ -366,23 +459,20 @@ function Module:run(currentStatus, lastStatus, timeDiff, timeNow, inetChecked)
|
|||||||
end
|
end
|
||||||
if currentStatus == 0 then
|
if currentStatus == 0 then
|
||||||
if self._counter == 0 or self._counter >= self._interval or currentStatus ~= lastStatus then
|
if self._counter == 0 or self._counter >= self._interval or currentStatus ~= lastStatus then
|
||||||
|
local ip = self:_requestIP()
|
||||||
local ip = self:requestIP()
|
|
||||||
|
|
||||||
if not ip then
|
if not ip then
|
||||||
ip = ""
|
ip = ""
|
||||||
self._DNSFalseCounter = self._DNSFalseCounter + 1
|
self._IPFalseCounter = self._IPFalseCounter + 1
|
||||||
if self._DNSFalseCounter >= self.requestAttempts then
|
if self._IPFalseCounter >= self.requestAttempts then
|
||||||
self._interval = self.runIntervalFailed
|
self._interval = self.runIntervalFailed
|
||||||
self._DNSFalseCounter = 0
|
self._IPFalseCounter = 0
|
||||||
else
|
else
|
||||||
self._interval = self.runIntervalDNSFailed
|
self._interval = self.runIntervalIPFailed
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self._interval = self.runInterval
|
self._interval = self.runInterval
|
||||||
self._DNSFalseCounter = 0
|
self._IPFalseCounter = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
if ip ~= self._currentIp then
|
if ip ~= self._currentIp then
|
||||||
self.status = ip
|
self.status = ip
|
||||||
if ip ~= "" then
|
if ip ~= "" then
|
||||||
@@ -400,11 +490,11 @@ function Module:run(currentStatus, lastStatus, timeDiff, timeNow, inetChecked)
|
|||||||
self._counter = 0
|
self._counter = 0
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self._currentIp = nil
|
self._currentIp = nil
|
||||||
self.status = self._currentIp
|
self.status = self._currentIp
|
||||||
self._DNSFalseCounter = 0
|
self._IPFalseCounter = 0
|
||||||
self._counter = 0
|
self._counter = 0
|
||||||
self._interval = self.runInterval
|
self._interval = self.runInterval
|
||||||
end
|
end
|
||||||
self._counter = self._counter + timeDiff
|
self._counter = self._counter + timeDiff
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=luci-app-internet-detector
|
PKG_NAME:=luci-app-internet-detector
|
||||||
PKG_VERSION:=1.5.2
|
PKG_VERSION:=1.6.0
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
LUCI_TITLE:=LuCI support for internet-detector
|
LUCI_TITLE:=LuCI support for internet-detector
|
||||||
LUCI_DEPENDS:=+internet-detector
|
LUCI_DEPENDS:=+internet-detector
|
||||||
|
|||||||
@@ -134,6 +134,33 @@ var Timefield = ui.Textfield.extend({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var TextfieldButton = ui.Textfield.extend({
|
||||||
|
render() {
|
||||||
|
let frameEl = E('div', { 'id': this.options.id }),
|
||||||
|
inputEl = E('input', {
|
||||||
|
'id' : this.options.id ? 'widget.' + this.options.id : null,
|
||||||
|
'name' : this.options.name,
|
||||||
|
'type' : 'text',
|
||||||
|
'class' : 'cbi-input-text',
|
||||||
|
'readonly' : this.options.readonly ? '' : null,
|
||||||
|
'disabled' : this.options.disabled ? '' : null,
|
||||||
|
'maxlength' : this.options.maxlength,
|
||||||
|
'placeholder': this.options.placeholder,
|
||||||
|
'value' : this.value,
|
||||||
|
});
|
||||||
|
frameEl.appendChild(E('div', { 'class': 'control-group' }, [
|
||||||
|
inputEl,
|
||||||
|
E('button', {
|
||||||
|
'class' : `cbi-button cbi-button-${this.options.btnstyle || 'neutral'}`,
|
||||||
|
'title' : this.options.btntitle,
|
||||||
|
'aria-label': this.options.btntitle,
|
||||||
|
'click' : this.options.onclick,
|
||||||
|
}, this.options.btntext,)
|
||||||
|
]));
|
||||||
|
return this.bind(frameEl);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return view.extend({
|
return view.extend({
|
||||||
appName : 'internet-detector',
|
appName : 'internet-detector',
|
||||||
configDir : '/etc/internet-detector',
|
configDir : '/etc/internet-detector',
|
||||||
@@ -149,10 +176,13 @@ return view.extend({
|
|||||||
ledsPath : '/sys/class/leds',
|
ledsPath : '/sys/class/leds',
|
||||||
ledsPerInstance : 3,
|
ledsPerInstance : 3,
|
||||||
leds : [],
|
leds : [],
|
||||||
|
tgUpdatesURLPattern : 'https://api.telegram.org/bot%s/getUpdates',
|
||||||
mm : false,
|
mm : false,
|
||||||
mmInit : false,
|
mmInit : false,
|
||||||
email : false,
|
email : false,
|
||||||
emailExec : false,
|
emailExec : false,
|
||||||
|
telegram : false,
|
||||||
|
curlExec : false,
|
||||||
modRegularScriptNextRun: {},
|
modRegularScriptNextRun: {},
|
||||||
|
|
||||||
callInitStatus: rpc.declare({
|
callInitStatus: rpc.declare({
|
||||||
@@ -330,6 +360,61 @@ return view.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getTgChatIdHandler(ev, instance) {
|
||||||
|
ev.preventDefault();
|
||||||
|
let botToken;
|
||||||
|
let botTokenInput = document.getElementById(
|
||||||
|
'widget.cbid.%s.%s.mod_telegram_api_token'.format(this.appName, instance));
|
||||||
|
if(botTokenInput) {
|
||||||
|
botToken = botTokenInput.value;
|
||||||
|
};
|
||||||
|
if(!botTokenInput || !botToken) {
|
||||||
|
alert(_('Bot API token is missing!'));
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let apiURL = this.tgUpdatesURLPattern.format(botToken);
|
||||||
|
|
||||||
|
console.log(`Requesting chat ID: ${apiURL}`);
|
||||||
|
|
||||||
|
return fetch(apiURL).then(r => {
|
||||||
|
if(r.ok) {
|
||||||
|
r.json().then(j => {
|
||||||
|
let chats = [];
|
||||||
|
if(j.ok && j.result) {
|
||||||
|
j.result.forEach(i => {
|
||||||
|
if(i.message && i.message.chat && i.message.chat.id) {
|
||||||
|
if(!chats.includes(i.message.chat.id)) {
|
||||||
|
chats.push(i.message.chat.id);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
let tgChatIdInput = document.getElementById(
|
||||||
|
'widget.cbid.%s.%s.mod_telegram_chat_id'.format(this.appName, instance));
|
||||||
|
if(tgChatIdInput) {
|
||||||
|
if(chats.length == 0) {
|
||||||
|
alert(_('No messages available. Write something to the bot and try again.'));
|
||||||
|
} else {
|
||||||
|
tgChatIdInput.value = chats[chats.length - 1];
|
||||||
|
tgChatIdInput.focus();
|
||||||
|
tgChatIdInput.blur();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let status = r.status;
|
||||||
|
let errorString = `${_('Error')} ${r.status}.`;
|
||||||
|
if(status == 404) {
|
||||||
|
errorString += ` ${_('Incorrect bot token?')}`;
|
||||||
|
};
|
||||||
|
alert(errorString);
|
||||||
|
};
|
||||||
|
}).catch(e => {
|
||||||
|
alert(e.message);
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
CBITimeInput: form.Value.extend({
|
CBITimeInput: form.Value.extend({
|
||||||
__name__ : 'CBI.TimeInput',
|
__name__ : 'CBI.TimeInput',
|
||||||
|
|
||||||
@@ -354,6 +439,27 @@ return view.extend({
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
CBITextfieldButtonInput: form.Value.extend({
|
||||||
|
__name__ : 'CBI.TextfieldButtonInput',
|
||||||
|
|
||||||
|
renderWidget(section_id, option_index, cfgvalue) {
|
||||||
|
let value = (cfgvalue != null) ? cfgvalue : this.default,
|
||||||
|
widget = new TextfieldButton(value, {
|
||||||
|
id : this.cbid(section_id),
|
||||||
|
optional : this.optional || this.rmempty,
|
||||||
|
datatype : this.datatype,
|
||||||
|
placeholder: this.placeholder,
|
||||||
|
validate : L.bind(this.validate, this, section_id),
|
||||||
|
disabled : (this.readonly != null) ? this.readonly : this.map.readonly,
|
||||||
|
btntext : this.btntext,
|
||||||
|
btntitle : this.btntitle,
|
||||||
|
btnstyle : this.btnstyle,
|
||||||
|
onclick : this.onclick,
|
||||||
|
});
|
||||||
|
return widget.render();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
CBIBlockInetStatus: form.Value.extend({
|
CBIBlockInetStatus: form.Value.extend({
|
||||||
__name__ : 'CBI.BlockInetStatus',
|
__name__ : 'CBI.BlockInetStatus',
|
||||||
|
|
||||||
@@ -542,6 +648,12 @@ return view.extend({
|
|||||||
if(data[3].email_exec) {
|
if(data[3].email_exec) {
|
||||||
this.emailExec = true;
|
this.emailExec = true;
|
||||||
};
|
};
|
||||||
|
if(data[3].telegram) {
|
||||||
|
this.telegram = true;
|
||||||
|
};
|
||||||
|
if(data[3].curl_exec) {
|
||||||
|
this.curlExec = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
this.currentAppMode = uci.get(this.appName, 'config', 'mode');
|
this.currentAppMode = uci.get(this.appName, 'config', 'mode');
|
||||||
|
|
||||||
@@ -756,6 +868,9 @@ return view.extend({
|
|||||||
if(this.email) {
|
if(this.email) {
|
||||||
s.tab('email', _('Email notification'));
|
s.tab('email', _('Email notification'));
|
||||||
};
|
};
|
||||||
|
if(this.telegram) {
|
||||||
|
s.tab('telegram', _('Telegram notification'));
|
||||||
|
};
|
||||||
s.tab('user_scripts', _('User scripts'));
|
s.tab('user_scripts', _('User scripts'));
|
||||||
s.tab('regular_script', _('Regular script'));
|
s.tab('regular_script', _('Regular script'));
|
||||||
};
|
};
|
||||||
@@ -1081,16 +1196,27 @@ return view.extend({
|
|||||||
|
|
||||||
// provider
|
// provider
|
||||||
o = s.taboption('public_ip', form.ListValue,
|
o = s.taboption('public_ip', form.ListValue,
|
||||||
'mod_public_ip_provider', _('DNS provider'),
|
'mod_public_ip_provider', _('Provider'),
|
||||||
_('Service for determining the public IP address through DNS.')
|
_('Service for determining the public IP address.') + '<br />' +
|
||||||
|
((this.curlExec) ? '' :
|
||||||
|
_('To support HTTP services you need to install curl.'))
|
||||||
);
|
);
|
||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
o.value('opendns1');
|
o.value('opendns1', 'opendns1 (DNS)');
|
||||||
o.value('opendns2');
|
o.value('opendns2', 'opendns2 (DNS)');
|
||||||
o.value('opendns3');
|
o.value('opendns3', 'opendns3 (DNS)');
|
||||||
o.value('opendns4');
|
o.value('opendns4', 'opendns4 (DNS)');
|
||||||
o.value('akamai');
|
o.value('google', 'google (DNS)');
|
||||||
o.value('google');
|
o.value('akamai', 'akamai (DNS)');
|
||||||
|
if(this.curlExec) {
|
||||||
|
o.value('akamai_http', "akamai (HTTP)");
|
||||||
|
o.value('amazonaws', "amazonaws (HTTP)");
|
||||||
|
o.value('wgetip', "wgetip.com (HTTP)");
|
||||||
|
o.value('ifconfig', "ifconfig.me (HTTP)");
|
||||||
|
o.value('ipecho', "ipecho.net (HTTP)");
|
||||||
|
o.value('canhazip', "canhazip.com (HTTP)");
|
||||||
|
o.value('icanhazip', "icanhazip.com (HTTP)");
|
||||||
|
};
|
||||||
o.default = 'opendns1';
|
o.default = 'opendns1';
|
||||||
|
|
||||||
// ipv6
|
// ipv6
|
||||||
@@ -1102,6 +1228,12 @@ return view.extend({
|
|||||||
o.value('0', 'A (IPv4)');
|
o.value('0', 'A (IPv4)');
|
||||||
o.value('1', 'AAAA (IPv6)');
|
o.value('1', 'AAAA (IPv6)');
|
||||||
o.default = '0';
|
o.default = '0';
|
||||||
|
o.depends({ 'mod_public_ip_provider': 'opendns1' });
|
||||||
|
o.depends({ 'mod_public_ip_provider': 'opendns2' });
|
||||||
|
o.depends({ 'mod_public_ip_provider': 'opendns3' });
|
||||||
|
o.depends({ 'mod_public_ip_provider': 'opendns4' });
|
||||||
|
o.depends({ 'mod_public_ip_provider': 'google' });
|
||||||
|
o.depends({ 'mod_public_ip_provider': 'akamai' });
|
||||||
|
|
||||||
// interval
|
// interval
|
||||||
o = s.taboption('public_ip', form.ListValue,
|
o = s.taboption('public_ip', form.ListValue,
|
||||||
@@ -1290,6 +1422,103 @@ return view.extend({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Telegram notification
|
||||||
|
|
||||||
|
if(this.telegram) {
|
||||||
|
if(this.curlExec) {
|
||||||
|
o = s.taboption('telegram', form.DummyValue, '_dummy');
|
||||||
|
o.rawhtml = true;
|
||||||
|
o.default = '<div class="cbi-section-descr">' +
|
||||||
|
_('Telegram message will be sent when connected or disconnected from the Internet.') +
|
||||||
|
'<br />' +
|
||||||
|
_("You need to register a new %sTelegram bot%s. Then get the bot's API token and paste it into the <code>Bot token</code> field. After that, open a chat with the bot, write something (in the Telegram app) and you will be able to get the chat ID using the <code>ID</code> button.").format("<a href='https://core.telegram.org/bots#how-do-i-create-a-bot' target='_blank'>", '</a>') +
|
||||||
|
'</div>';
|
||||||
|
|
||||||
|
o.modalonly = true;
|
||||||
|
|
||||||
|
// enabled
|
||||||
|
o = s.taboption('telegram', form.Flag, 'mod_telegram_enabled',
|
||||||
|
_('Enable'));
|
||||||
|
o.rmempty = false;
|
||||||
|
o.modalonly = true;
|
||||||
|
|
||||||
|
// mode
|
||||||
|
o = s.taboption('telegram', form.ListValue,
|
||||||
|
'mod_telegram_mode', _('When message will be sent')
|
||||||
|
);
|
||||||
|
o.modalonly = true;
|
||||||
|
o.value(0, _('after connection'));
|
||||||
|
o.value(1, _('after disconnection'));
|
||||||
|
o.value(2, _('after connection or disconnection'));
|
||||||
|
o.default = '0';
|
||||||
|
|
||||||
|
// alive_period
|
||||||
|
o = s.taboption('telegram', this.CBITimeInput,
|
||||||
|
'mod_telegram_alive_period', _('Alive period'),
|
||||||
|
_('Period of time after connecting to the Internet before sending a message.')
|
||||||
|
);
|
||||||
|
o.rmempty = false;
|
||||||
|
o.modalonly = true;
|
||||||
|
o.depends({ 'mod_telegram_mode': '0' });
|
||||||
|
o.depends({ 'mod_telegram_mode': '2' });
|
||||||
|
o.default = '0';
|
||||||
|
|
||||||
|
// dead_period
|
||||||
|
o = s.taboption('telegram', this.CBITimeInput,
|
||||||
|
'mod_telegram_dead_period', _('Dead period'),
|
||||||
|
_('Period of time after disconnecting from Internet before sending a message.')
|
||||||
|
);
|
||||||
|
o.rmempty = false;
|
||||||
|
o.modalonly = true;
|
||||||
|
o.depends({ 'mod_telegram_mode': '1' });
|
||||||
|
o.depends({ 'mod_telegram_mode': '2' });
|
||||||
|
o.default = '0';
|
||||||
|
|
||||||
|
// host_alias
|
||||||
|
o = s.taboption('telegram', form.Value, 'mod_telegram_host_alias',
|
||||||
|
_('Host alias'),
|
||||||
|
_('Host identifier in messages. If not specified, hostname will be used.'));
|
||||||
|
o.modalonly = true;
|
||||||
|
|
||||||
|
// tg_api_token
|
||||||
|
o = s.taboption('telegram', form.Value,
|
||||||
|
'mod_telegram_api_token', _('Bot token'),
|
||||||
|
_('Telegram bot API token.'));
|
||||||
|
o.password = true;
|
||||||
|
o.modalonly = true;
|
||||||
|
|
||||||
|
// tg_chat_id
|
||||||
|
o = s.taboption('telegram', this.CBITextfieldButtonInput,
|
||||||
|
'mod_telegram_chat_id', _('Chat ID'),
|
||||||
|
_('ID of the Telegram chat to which messages will be sent.')
|
||||||
|
);
|
||||||
|
o.btntext = _('ID'),
|
||||||
|
o.btntitle = _('Request chat ID from bot API'),
|
||||||
|
o.btnstyle = 'action',
|
||||||
|
o.onclick = ui.createHandlerFn(this,
|
||||||
|
(ev) => this.getTgChatIdHandler(ev, s.section));
|
||||||
|
o.modalonly = true;
|
||||||
|
o.optional = false;
|
||||||
|
o.rmempty = false;
|
||||||
|
o.depends({ 'mod_telegram_api_token': /.+/ });
|
||||||
|
|
||||||
|
// message_at_startup
|
||||||
|
o = s.taboption('telegram', form.Flag, 'mod_telegram_message_at_startup',
|
||||||
|
_('On startup'),
|
||||||
|
_('Send message on service startup.')
|
||||||
|
);
|
||||||
|
o.rmempty = false;
|
||||||
|
o.modalonly = true;
|
||||||
|
} else {
|
||||||
|
o = s.taboption('telegram', form.DummyValue, '_dummy');
|
||||||
|
o.rawhtml = true;
|
||||||
|
o.default = '<label class="cbi-value-title"></label><div class="cbi-value-field"><em>' +
|
||||||
|
_('Curl is not available...') +
|
||||||
|
'</em></div>';
|
||||||
|
o.modalonly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// User scripts
|
// User scripts
|
||||||
|
|
||||||
o = s.taboption('user_scripts', form.DummyValue, '_dummy');
|
o = s.taboption('user_scripts', form.DummyValue, '_dummy');
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ msgid "Alive period"
|
|||||||
msgstr "Период после подключения"
|
msgstr "Период после подключения"
|
||||||
|
|
||||||
msgid "An email will be sent when connected or disconnected from the Internet."
|
msgid "An email will be sent when connected or disconnected from the Internet."
|
||||||
msgstr "Сообщение будет отправлено при подключении или отключении от Интернет."
|
msgstr "Сообщение будет отправлено на email при подключении или отключении от Интернет."
|
||||||
|
|
||||||
msgid "An error has occurred"
|
msgid "An error has occurred"
|
||||||
msgstr "Произошла ошибка"
|
msgstr "Произошла ошибка"
|
||||||
@@ -56,6 +56,15 @@ msgstr "Большой: 248 байт"
|
|||||||
msgid "Blink"
|
msgid "Blink"
|
||||||
msgstr "Мигание"
|
msgstr "Мигание"
|
||||||
|
|
||||||
|
msgid "Bot API token is missing!"
|
||||||
|
msgstr "Отсутствует API токен бота!"
|
||||||
|
|
||||||
|
msgid "Bot token"
|
||||||
|
msgstr "Токен бота"
|
||||||
|
|
||||||
|
msgid "ID чата"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Check type"
|
msgid "Check type"
|
||||||
msgstr "Тип проверки"
|
msgstr "Тип проверки"
|
||||||
|
|
||||||
@@ -80,6 +89,9 @@ msgstr "Таймаут соединения"
|
|||||||
msgid "Contents have been saved."
|
msgid "Contents have been saved."
|
||||||
msgstr "Содержимое сохранено."
|
msgstr "Содержимое сохранено."
|
||||||
|
|
||||||
|
msgid "Curl is not available..."
|
||||||
|
msgstr "Curl недоступен..."
|
||||||
|
|
||||||
msgid "Dead interval"
|
msgid "Dead interval"
|
||||||
msgstr "Интервал при отключении"
|
msgstr "Интервал при отключении"
|
||||||
|
|
||||||
@@ -113,9 +125,6 @@ msgstr "Закрыть"
|
|||||||
msgid "DNS query type"
|
msgid "DNS query type"
|
||||||
msgstr "Тип DNS-запроса"
|
msgstr "Тип DNS-запроса"
|
||||||
|
|
||||||
msgid "DNS provider"
|
|
||||||
msgstr "DNS провайдер"
|
|
||||||
|
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Изменить"
|
msgstr "Изменить"
|
||||||
|
|
||||||
@@ -152,6 +161,9 @@ msgstr "Включить public-ip-script"
|
|||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Включен"
|
msgstr "Включен"
|
||||||
|
|
||||||
|
msgid "Error"
|
||||||
|
msgstr "Ошибка"
|
||||||
|
|
||||||
msgid "Expecting:"
|
msgid "Expecting:"
|
||||||
msgstr "Ожидается:"
|
msgstr "Ожидается:"
|
||||||
|
|
||||||
@@ -180,7 +192,7 @@ msgid "Hosts"
|
|||||||
msgstr "Хосты"
|
msgstr "Хосты"
|
||||||
|
|
||||||
msgid "Hosts polling interval when the Internet is down."
|
msgid "Hosts polling interval when the Internet is down."
|
||||||
msgstr "Интервал опроса хостов если Интернет не доступен."
|
msgstr "Интервал опроса хостов если Интернет недоступен."
|
||||||
|
|
||||||
msgid "Hosts polling interval when the Internet is up."
|
msgid "Hosts polling interval when the Internet is up."
|
||||||
msgstr "Интервал опроса хостов если Интернет доступен."
|
msgstr "Интервал опроса хостов если Интернет доступен."
|
||||||
@@ -195,12 +207,18 @@ msgstr ""
|
|||||||
msgid "Huge: 1492 bytes"
|
msgid "Huge: 1492 bytes"
|
||||||
msgstr "Огромный: 1492 байта"
|
msgstr "Огромный: 1492 байта"
|
||||||
|
|
||||||
|
msgid "ID of the Telegram chat to which messages will be sent."
|
||||||
|
msgstr "ID чата Telegram в который будут отправлены сообщения."
|
||||||
|
|
||||||
msgid "ICMP-echo request (ping)"
|
msgid "ICMP-echo request (ping)"
|
||||||
msgstr "Запрос ICMP-echo (ping)"
|
msgstr "Запрос ICMP-echo (ping)"
|
||||||
|
|
||||||
msgid "ICMP packet data size"
|
msgid "ICMP packet data size"
|
||||||
msgstr "Размер данных ICMP-пакета"
|
msgstr "Размер данных ICMP-пакета"
|
||||||
|
|
||||||
|
msgid "Incorrect bot token?"
|
||||||
|
msgstr "Неправильный токен бота?"
|
||||||
|
|
||||||
msgid "Instances"
|
msgid "Instances"
|
||||||
msgstr "Экземпляры"
|
msgstr "Экземпляры"
|
||||||
|
|
||||||
@@ -250,7 +268,7 @@ msgid "Loading"
|
|||||||
msgstr "Загрузка"
|
msgstr "Загрузка"
|
||||||
|
|
||||||
msgid "Mailsend is not available..."
|
msgid "Mailsend is not available..."
|
||||||
msgstr "Mailsend не доступен..."
|
msgstr "Mailsend недоступен..."
|
||||||
|
|
||||||
msgid "Main settings"
|
msgid "Main settings"
|
||||||
msgstr "Основные настройки"
|
msgstr "Основные настройки"
|
||||||
@@ -280,7 +298,7 @@ msgid "Maximum timeout for waiting for a response from the host."
|
|||||||
msgstr "Максимальный таймаут ожидания ответа от хоста."
|
msgstr "Максимальный таймаут ожидания ответа от хоста."
|
||||||
|
|
||||||
msgid "ModemManager is not available..."
|
msgid "ModemManager is not available..."
|
||||||
msgstr "ModemManager не доступен..."
|
msgstr "ModemManager недоступен..."
|
||||||
|
|
||||||
msgid "Modem will be restarted when the Internet is disconnected."
|
msgid "Modem will be restarted when the Internet is disconnected."
|
||||||
msgstr "Модем будет перезапущен при отключении Интернет."
|
msgstr "Модем будет перезапущен при отключении Интернет."
|
||||||
@@ -314,6 +332,9 @@ msgstr "Следующий запуск"
|
|||||||
msgid "No <abbr title=\"Light Emitting Diode\">LED</abbr>s available..."
|
msgid "No <abbr title=\"Light Emitting Diode\">LED</abbr>s available..."
|
||||||
msgstr "Нет доступных <abbr title=\"Светодиод\">LED</abbr>..."
|
msgstr "Нет доступных <abbr title=\"Светодиод\">LED</abbr>..."
|
||||||
|
|
||||||
|
msgid "No messages available. Write something to the bot and try again."
|
||||||
|
msgstr "Нет доступных сообщений. Напишите что-нибудь боту и попробуйте ещё раз."
|
||||||
|
|
||||||
msgid "Not scheduled"
|
msgid "Not scheduled"
|
||||||
msgstr "Не запланирован"
|
msgstr "Не запланирован"
|
||||||
|
|
||||||
@@ -373,6 +394,9 @@ msgstr "Регулярный скрипт"
|
|||||||
msgid "Polling interval"
|
msgid "Polling interval"
|
||||||
msgstr "Интервал опроса"
|
msgstr "Интервал опроса"
|
||||||
|
|
||||||
|
msgid "Provider"
|
||||||
|
msgstr "Провайдер"
|
||||||
|
|
||||||
msgid "Public IP"
|
msgid "Public IP"
|
||||||
msgstr "Публичный IP"
|
msgstr "Публичный IP"
|
||||||
|
|
||||||
@@ -388,6 +412,9 @@ msgstr "Перезагрузка устройства если Интренет
|
|||||||
msgid "Recipient"
|
msgid "Recipient"
|
||||||
msgstr "Получатель"
|
msgstr "Получатель"
|
||||||
|
|
||||||
|
msgid "Request chat ID from bot API"
|
||||||
|
msgstr "Запросить ID чата через API бота"
|
||||||
|
|
||||||
msgid "Restart"
|
msgid "Restart"
|
||||||
msgstr "Перезапуск"
|
msgstr "Перезапуск"
|
||||||
|
|
||||||
@@ -463,8 +490,8 @@ msgstr "Не удалось выполнить действие службы \"%
|
|||||||
msgid "Service configuration"
|
msgid "Service configuration"
|
||||||
msgstr "Конфигурация службы"
|
msgstr "Конфигурация службы"
|
||||||
|
|
||||||
msgid "Service for determining the public IP address through DNS."
|
msgid "Service for determining the public IP address."
|
||||||
msgstr "Сервис для определения публичного IP адреса через DNS."
|
msgstr "Сервис для определения публичного IP адреса."
|
||||||
|
|
||||||
msgid "Service: detector always runs as a system service."
|
msgid "Service: detector always runs as a system service."
|
||||||
msgstr "Служба: детектор работает постоянно, как системная служба."
|
msgstr "Служба: детектор работает постоянно, как системная служба."
|
||||||
@@ -505,6 +532,12 @@ msgstr "TCP-порт"
|
|||||||
msgid "TCP port connection"
|
msgid "TCP port connection"
|
||||||
msgstr "Подключение к TCP-порту"
|
msgstr "Подключение к TCP-порту"
|
||||||
|
|
||||||
|
msgid "Telegram bot API token."
|
||||||
|
msgstr "API токен Telegram бота."
|
||||||
|
|
||||||
|
msgid "Telegram message will be sent when connected or disconnected from the Internet."
|
||||||
|
msgstr "Сообщение в Telegram будет отправлено при подключении или отключении от Интернет."
|
||||||
|
|
||||||
msgid "The type of record requested in the DNS query (if the service supports it)."
|
msgid "The type of record requested in the DNS query (if the service supports it)."
|
||||||
msgstr "Тип записи запрашиваемой в DNS-запросе (если сервис поддерживает)."
|
msgstr "Тип записи запрашиваемой в DNS-запросе (если сервис поддерживает)."
|
||||||
|
|
||||||
@@ -517,6 +550,9 @@ msgstr "Таймаут между остановкой и запуском се
|
|||||||
msgid "Timeout between stopping and starting a ModemManger interface when restarting."
|
msgid "Timeout between stopping and starting a ModemManger interface when restarting."
|
||||||
msgstr "Таймаут между остановкой и запуском интерфейса ModemManger при перезапуске."
|
msgstr "Таймаут между остановкой и запуском интерфейса ModemManger при перезапуске."
|
||||||
|
|
||||||
|
msgid "To support HTTP services you need to install curl."
|
||||||
|
msgstr "Для поддержки HTTP сервисов необходимо установить curl."
|
||||||
|
|
||||||
msgid "Type a time string"
|
msgid "Type a time string"
|
||||||
msgstr "Введите строку времени"
|
msgstr "Введите строку времени"
|
||||||
|
|
||||||
@@ -557,12 +593,20 @@ msgstr ""
|
|||||||
msgid "When email will be sent"
|
msgid "When email will be sent"
|
||||||
msgstr "Когда будет отправлено сообщение"
|
msgstr "Когда будет отправлено сообщение"
|
||||||
|
|
||||||
|
msgid "When message will be sent"
|
||||||
|
msgstr "Когда будет отправлено сообщение"
|
||||||
|
|
||||||
msgid "Windows: 32 bytes"
|
msgid "Windows: 32 bytes"
|
||||||
msgstr "Windows: 32 байта"
|
msgstr "Windows: 32 байта"
|
||||||
|
|
||||||
msgid "Write messages to the system log."
|
msgid "Write messages to the system log."
|
||||||
msgstr "Записывать сообщения в системный журнал."
|
msgstr "Записывать сообщения в системный журнал."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"You need to register a new %sTelegram bot%s. Then get the bot's API token and paste it into the <code>Bot token</code> field. After that, open a chat with the bot, write something (in the Telegram app) and you will be able to get the chat ID using the <code>ID</code> button."
|
||||||
|
msgstr ""
|
||||||
|
"Необходимо зарегистрировать новый %sTelegram бот%s. Затем получить API токен бота и вставить его в поле <code>Токен бота</code>. После этого, откройте чат с ботом, напишите что-нибудь (в приложении Telegram) и можно будет получить ID чата с помощью кнопки <code>ID</code>."
|
||||||
|
|
||||||
msgid "after connection"
|
msgid "after connection"
|
||||||
msgstr "после подключения"
|
msgstr "после подключения"
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,15 @@ msgstr ""
|
|||||||
msgid "Blink"
|
msgid "Blink"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Bot API token is missing!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Bot token"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Chat ID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Check type"
|
msgid "Check type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -68,6 +77,9 @@ msgstr ""
|
|||||||
msgid "Contents have been saved."
|
msgid "Contents have been saved."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Curl is not available..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Dead interval"
|
msgid "Dead interval"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -101,9 +113,6 @@ msgstr ""
|
|||||||
msgid "DNS query type"
|
msgid "DNS query type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "DNS provider"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -140,6 +149,9 @@ msgstr ""
|
|||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Expecting:"
|
msgid "Expecting:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -181,12 +193,18 @@ msgstr ""
|
|||||||
msgid "Huge: 1492 bytes"
|
msgid "Huge: 1492 bytes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ID of the Telegram chat to which messages will be sent."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ICMP-echo request (ping)"
|
msgid "ICMP-echo request (ping)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "ICMP packet data size"
|
msgid "ICMP packet data size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Incorrect bot token?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Instances"
|
msgid "Instances"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -289,6 +307,9 @@ msgstr ""
|
|||||||
msgid "No <abbr title=\"Light Emitting Diode\">LED</abbr>s available..."
|
msgid "No <abbr title=\"Light Emitting Diode\">LED</abbr>s available..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "No messages available. Write something to the bot and try again."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Not scheduled"
|
msgid "Not scheduled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -345,6 +366,9 @@ msgstr ""
|
|||||||
msgid "Polling interval"
|
msgid "Polling interval"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Provider"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Public IP"
|
msgid "Public IP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -360,6 +384,9 @@ msgstr ""
|
|||||||
msgid "Recipient"
|
msgid "Recipient"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Request chat ID from bot API"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Restart"
|
msgid "Restart"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -435,7 +462,7 @@ msgstr ""
|
|||||||
msgid "Service configuration"
|
msgid "Service configuration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Service for determining the public IP address through DNS."
|
msgid "Service for determining the public IP address."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Service: detector always runs as a system service."
|
msgid "Service: detector always runs as a system service."
|
||||||
@@ -477,6 +504,12 @@ msgstr ""
|
|||||||
msgid "TCP port connection"
|
msgid "TCP port connection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Telegram bot API token."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Telegram message will be sent when connected or disconnected from the Internet."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "The type of record requested in the DNS query (if the service supports it)."
|
msgid "The type of record requested in the DNS query (if the service supports it)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -489,6 +522,9 @@ msgstr ""
|
|||||||
msgid "Timeout between stopping and starting a ModemManger interface when restarting."
|
msgid "Timeout between stopping and starting a ModemManger interface when restarting."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "To support HTTP services you need to install curl."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Type a time string"
|
msgid "Type a time string"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -525,12 +561,19 @@ msgstr ""
|
|||||||
msgid "When email will be sent"
|
msgid "When email will be sent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "When message will be sent"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Windows: 32 bytes"
|
msgid "Windows: 32 bytes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Write messages to the system log."
|
msgid "Write messages to the system log."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"You need to register a new %sTelegram bot%s. Then get the bot's API token and paste it into the <code>Bot token</code> field. After that, open a chat with the bot, write something (in the Telegram app) and you will be able to get the chat ID using the <code>ID</code> button."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "after connection"
|
msgid "after connection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ local appName = "internet-detector"
|
|||||||
local appExec = "/usr/bin/internet-detector"
|
local appExec = "/usr/bin/internet-detector"
|
||||||
local mailsendExec = "/usr/bin/mailsend"
|
local mailsendExec = "/usr/bin/mailsend"
|
||||||
local modemManagerInit = "/etc/init.d/modemmanager"
|
local modemManagerInit = "/etc/init.d/modemmanager"
|
||||||
|
local curlExec = "/usr/bin/curl"
|
||||||
|
|
||||||
local InternetDetector = require(appName .. ".main")
|
local InternetDetector = require(appName .. ".main")
|
||||||
local uci = require("uci")
|
local uci = require("uci")
|
||||||
@@ -37,6 +38,16 @@ local function init()
|
|||||||
else
|
else
|
||||||
lines[#lines + 1] = '"email_mod":false'
|
lines[#lines + 1] = '"email_mod":false'
|
||||||
end
|
end
|
||||||
|
if prequire(appName .. ".modules.mod_telegram") then
|
||||||
|
lines[#lines + 1] = '"telegram":true'
|
||||||
|
else
|
||||||
|
lines[#lines + 1] = '"telegram":false'
|
||||||
|
end
|
||||||
|
if unistd.access(curlExec, "x") then
|
||||||
|
lines[#lines + 1] = '"curl_exec":true'
|
||||||
|
else
|
||||||
|
lines[#lines + 1] = '"curl_exec":false'
|
||||||
|
end
|
||||||
return string.format("{%s}", table.concat(lines, ","))
|
return string.format("{%s}", table.concat(lines, ","))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
BIN
screenshots/06.jpg
Normal file
BIN
screenshots/06.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 166 KiB |
Reference in New Issue
Block a user