22 Commits

Author SHA1 Message Date
gSpot
642265b96d luci-app-internet-detector: Fixes for dark style 2023-03-27 01:20:03 +03:00
gSpot
312294aeef luci-app-internet-detector: CSS fixes 2022-09-20 16:21:25 +03:00
gSpot
f81cfc930f New module: mod_public_ip 2022-08-13 17:17:45 +03:00
gSpot
78067be67f luci-app-internet-detector: Minor fixes 2022-05-26 18:56:10 +03:00
gSpot
5b5db26919 luci-app-internet-detector: Minor fixes 2022-05-24 04:54:29 +03:00
gSpot
e19d2bc61b Fixed typos 2022-02-24 18:42:33 +03:00
gSpot
a22e48e786 Minor fixes 2022-02-20 18:39:11 +03:00
gSpot
7a879809c7 luci-app-internet-detector fixes for 21.02.2 2022-02-19 18:50:13 +03:00
gSpot
cb4ddc4062 v0.5. New modules, refactoring 2022-02-06 17:17:02 +03:00
gSpot
4f89925348 README.md 2021-12-21 21:00:49 +03:00
gSpot
97496366a7 JS improvements 2021-12-21 17:12:48 +03:00
gSpot
4a46ac1f4c Fixed syslog 2021-12-20 20:54:20 +03:00
gSpot
80845f6c3d Minor fixes 2021-12-20 19:37:58 +03:00
gSpot
ab0a2bce86 Fixed internet-detector/Makefile 2021-12-17 16:59:23 +03:00
gSpot
6fb2cf8a5e Fixed syslog 2021-12-12 17:05:45 +03:00
gSpot
438c99bf35 JS fixes 2021-12-09 17:22:07 +03:00
gSpot
29eb4e8a71 v0.4. Daemon modules, LED control 2021-12-08 20:58:14 +03:00
gSpot
54f13984a3 Changes for OpenWrt 21.02 2021-12-05 18:58:48 +03:00
gSpot
a554668306 Moving packages 2021-12-03 22:16:18 +03:00
gSpot
a0a495267b README 2021-12-01 19:35:26 +03:00
gSpot
8d5022cdfd Fixed init status 2021-11-03 19:11:15 +03:00
gSpot
a008297225 v0.3. Internet detector daemon 2021-10-31 20:07:17 +03:00
32 changed files with 3807 additions and 145 deletions

214
LICENSE
View File

@@ -1,21 +1,201 @@
MIT License Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Copyright (c) 2020 gSpotx2f TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Permission is hereby granted, free of charge, to any person obtaining a copy 1. Definitions.
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all "License" shall mean the terms and conditions for use, reproduction,
copies or substantial portions of the Software. and distribution as defined by Sections 1 through 9 of this document.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR "Licensor" shall mean the copyright owner or entity authorized by
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, the copyright owner that is granting the License.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER "Legal Entity" shall mean the union of the acting entity and all
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, other entities that control, are controlled by, or are under common
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE control with that entity. For the purposes of this definition,
SOFTWARE. "control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,18 +0,0 @@
#
# Copyright (C) 2020 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
#
# This is free software, licensed under the MIT License.
#
include $(TOPDIR)/rules.mk
PKG_VERSION:=0.2
PKG_RELEASE:=1
LUCI_TITLE:=Internet detector for the LuCI status page
LUCI_DEPENDS:=+luci-mod-admin-full
LUCI_PKGARCH:=all
PKG_LICENSE:=MIT
include ../../luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@@ -1,21 +1,48 @@
# luci-app-internet-detector # Internet detector for OpenWrt.
Internet detector for the LuCI status page (OpenWrt webUI). Internet-detector is an application for checking the availability of the Internet. Performs periodic connections to a known public host (8.8.8.8, 1.1.1.1) and determines the actual Internet availability.
OpenWrt >= 19.07. **OpenWrt** >= 19.07.
**Installation notes:** **Dependences:** lua, luci-lib-nixio, libuci-lua.
wget --no-check-certificate -O /tmp/luci-app-internet-detector_0.2-1_all.ipk https://github.com/gSpotx2f/luci-app-internet-detector/raw/master/packages/19.07/luci-app-internet-detector_0.2-1_all.ipk **Features:**
opkg install /tmp/luci-app-internet-detector_0.2-1_all.ipk - It can run continuously as a system service or only in an open web interface.
rm /tmp/luci-app-internet-detector_0.2-1_all.ipk - Checking the availability of a host using ping or by connecting via TCP to a specified port.
- LED indication of Internet availability.
![](https://github.com/gSpotx2f/luci-app-internet-detector/blob/master/screenshots/internet-led.jpg)
- 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.
- The daemon is written entirely in Lua using the nixio library.
## Installation notes
**OpenWrt >= 21.02:**
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
opkg install /tmp/internet-detector_0.6-0_all.ipk
rm /tmp/internet-detector_0.6-0_all.ipk
/etc/init.d/internet-detector start
/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
opkg install /tmp/luci-app-internet-detector_0.6-1_all.ipk
rm /tmp/luci-app-internet-detector_0.6-1_all.ipk
/etc/init.d/rpcd restart /etc/init.d/rpcd restart
**i18n-ru:** Email notification:
wget --no-check-certificate -O /tmp/luci-i18n-internet-detector-ru_0.2-1_all.ipk https://github.com/gSpotx2f/luci-app-internet-detector/raw/master/packages/19.07/luci-i18n-internet-detector-ru_0.2-1_all.ipk opkg install mailsend
opkg install /tmp/luci-i18n-internet-detector-ru_0.2-1_all.ipk
rm /tmp/luci-i18n-internet-detector-ru_0.2-1_all.ipk
**Screenshots:** 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
opkg install /tmp/luci-i18n-internet-detector-ru_0.6-1_all.ipk
rm /tmp/luci-i18n-internet-detector-ru_0.6-1_all.ipk
**[OpenWrt 19.07](https://github.com/gSpotx2f/luci-app-internet-detector/tree/19.07)**
## Screenshots:
![](https://github.com/gSpotx2f/luci-app-internet-detector/blob/master/screenshots/01.jpg) ![](https://github.com/gSpotx2f/luci-app-internet-detector/blob/master/screenshots/01.jpg)
![](https://github.com/gSpotx2f/luci-app-internet-detector/blob/master/screenshots/02.jpg)

View File

@@ -1,56 +0,0 @@
'use strict';
'require fs';
return L.Class.extend({
title: _('Internet'),
hosts: [
'8.8.8.8',
'2a00:1450:4010:c05::71',
'1.1.1.1',
'2606:4700::6811:b055',
//'8.8.4.4',
//'2a00:1450:4010:c09::66',
],
checkInterval: 6, // 5 x 6 = 30 sec.
load: async function() {
window.internetDetectorCounter = ('internetDetectorCounter' in window) ?
++window.internetDetectorCounter : 0;
if(!('internetDetectorState' in window)) {
window.internetDetectorState = 1;
};
if(window.internetDetectorState === 0 &&
window.internetDetectorCounter % this.checkInterval) {
return;
};
for(let host of this.hosts) {
await fs.exec('/bin/ping', [ '-c', '1', '-W', '1', host ]).then(res => {
window.internetDetectorState = res.code;
}).catch(e => {});
if(window.internetDetectorState === 0) {
break;
};
};
},
render: function() {
let internetStatus = E('span', { 'class': 'label' });
if(window.internetDetectorState === 0) {
internetStatus.style.background = '#46a546';
internetStatus.textContent = _('Internet connected');
} else {
internetStatus.textContent = _('Internet disconnected');
};
return E('div', {
'class': 'cbi-section',
'style': 'margin-bottom:1em',
}, internetStatus);
},
});

View File

@@ -0,0 +1,59 @@
#
# (с) 2021 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
#
include $(TOPDIR)/rules.mk
PKG_NAME:=internet-detector
PKG_VERSION:=0.6
PKG_RELEASE:=0
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:=Internet detector
URL:=https://github.com/gSpotx2f/luci-app-internet-detector
PKGARCH:=all
DEPENDS:=+lua +luci-lib-nixio +libuci-lua
endef
define Package/$(PKG_NAME)/description
Internet-detector is a small daemon
for checking Internet availability.
Written in Lua using the nixio library.
endef
define Package/$(PKG_NAME)/conffiles
/etc/config/internet-detector
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/etc/config/internet-detector $(1)/etc/config/internet-detector
$(INSTALL_DIR) $(1)/etc/internet-detector
$(INSTALL_BIN) ./files/etc/internet-detector/down-script $(1)/etc/internet-detector/down-script
$(INSTALL_BIN) ./files/etc/internet-detector/up-script $(1)/etc/internet-detector/up-script
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/etc/init.d/internet-detector $(1)/etc/init.d/internet-detector
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) ./files/usr/bin/internet-detector $(1)/usr/bin/internet-detector
$(INSTALL_DIR) $(1)/usr/lib/internet-detector
$(INSTALL_DATA) ./files/usr/lib/internet-detector/mod_email.lua $(1)/usr/lib/internet-detector/mod_email.lua
$(INSTALL_DATA) ./files/usr/lib/internet-detector/mod_public_ip.lua $(1)/usr/lib/internet-detector/mod_public_ip.lua
$(INSTALL_DATA) ./files/usr/lib/internet-detector/mod_led_control.lua $(1)/usr/lib/internet-detector/mod_led_control.lua
$(INSTALL_DATA) ./files/usr/lib/internet-detector/mod_modem_restart.lua $(1)/usr/lib/internet-detector/mod_modem_restart.lua
$(INSTALL_DATA) ./files/usr/lib/internet-detector/mod_network_restart.lua $(1)/usr/lib/internet-detector/mod_network_restart.lua
$(INSTALL_DATA) ./files/usr/lib/internet-detector/mod_reboot.lua $(1)/usr/lib/internet-detector/mod_reboot.lua
$(INSTALL_DATA) ./files/usr/lib/internet-detector/mod_user_scripts.lua $(1)/usr/lib/internet-detector/mod_user_scripts.lua
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -0,0 +1,52 @@
config main 'config'
option mode '2'
list hosts '8.8.8.8'
list hosts '1.1.1.1'
option check_type '0'
option tcp_port '53'
option ui_interval_up '6'
option ui_interval_down '1'
option ui_connection_attempts '1'
option ui_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'
option enabled '0'
config module 'mod_reboot'
option enabled '0'
option dead_period '3600'
option force_reboot_delay '300'
config module 'mod_network_restart'
option enabled '0'
option dead_period '900'
option attempts '1'
option restart_timeout '0'
config module 'mod_modem_restart'
option enabled '0'
option dead_period '600'
option any_band '0'
config module 'mod_public_ip'
option enabled '0'
option provider 'opendns1'
option interval '600'
option timeout '3'
config module 'mod_email'
option enabled '0'
option alive_period '0'
option mail_smtp 'smtp.gmail.com'
option mail_smtp_port '587'
option mail_security 'tls'
config module 'mod_user_scripts'
option enabled '0'
option alive_period '0'
option dead_period '0'

View File

@@ -0,0 +1,19 @@
#!/bin/sh /etc/rc.common
START=97
STOP=01
ID="/usr/bin/internet-detector"
start() {
$ID
}
stop() {
$ID stop
}
restart() {
stop
start
}

View File

@@ -0,0 +1 @@
# Shell commands to run when disconnected from the Internet

View File

@@ -0,0 +1 @@
# Shell commands that run when connected to the Internet

View File

@@ -0,0 +1,555 @@
#!/usr/bin/env lua
--[[
Internet detector daemon for OpenWrt.
Dependences:
lua
luci-lib-nixio
libuci-lua
(с) 2021 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
local function prequire(package)
local retVal, pkg = pcall(require, package)
return retVal and pkg
end
local nixio = prequire("nixio")
if not nixio then
error("You need to install nixio...")
end
local uci = prequire("uci")
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 fh = io.open(filePath, "w")
if fh then
fh:setvbuf("no")
fh:write(string.format("%s\n", str))
fh:close()
retValue = true
end
return retValue
end
local function readValueFromFile(filePath)
local retValue
local fh = io.open(filePath, "r")
if fh then
retValue = fh:read("*l")
fh:close()
end
return retValue
end
local function statusJson(inet, t)
local lines = { [1] = string.format('"inet":%d', inet) }
if t then
for k, v in pairs(t) do
lines[#lines + 1] = string.format('"%s":"%s"', k, v)
end
end
return "{" .. table.concat(lines, ",") .. "}"
end
local function writeLogMessage(level, msg)
if Config.enableLogger then
nixio.syslog(level, msg)
end
end
local function loadModules()
package.path = string.format("%s;%s/?.lua", package.path, Config.modulesDir)
Config.modules = {}
uciCursor:foreach(
Config.appName,
"module",
function(s)
local mod_name = s[".name"]
if mod_name and s.enabled == "1" then
local m = prequire(mod_name)
if m then
m.config = Config
m.syslog = writeLogMessage
m.writeValue = writeValueToFile
m.readValue = readValueFromFile
m:init(s)
Config.modules[#Config.modules + 1] = m
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
local function pingHost(host)
local ping = string.format(
"%s %s -W %d -s %d%s %s > /dev/null 2>&1",
Config.pingCmd,
Config.pingParams,
Config.connectionTimeout,
Config.pingPacketSize,
Config.iface and (" -I " .. Config.iface) or "",
host
)
local retCode = os.execute(ping)
-- Debug
if Config.debug then
io.stdout:write(string.format(
"--- Ping ---\ntime = %s\n%s\nretCode = %s\n", os.time(), ping, retCode)
)
io.stdout:flush()
end
return retCode
end
local function TCPConnectionToHost(host, port)
local retCode = 1
local addrInfo = nixio.getaddrinfo(host, "any")
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 Config.debug then
local sockAddr, sockPort = socket:getsockname()
local peerAddr, peerPort = socket:getpeername()
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",
os.time(),
Config.connectionTimeout,
tostring(Config.iface),
host,
port or Config.tcpPort,
tostring(sockAddr),
tostring(sockPort),
tostring(peerAddr),
tostring(peerPort),
tostring(success))
)
io.stdout:flush()
end
socket:close()
retCode = success and 0 or 1
end
end
return retCode
end
local function checkHosts()
local checkFunc = (Config.checkType == 1) and pingHost or TCPConnectionToHost
local retCode = 1
for k, v in ipairs(Config.parsedHosts) do
for i = 1, Config.connectionAttempts do
if checkFunc(v.addr, v.port) == 0 then
retCode = 0
break
end
end
if retCode == 0 then
break
end
end
return retCode
end
local function main()
local lastStatus, currentStatus, timeNow, timeDiff, lastTime
local interval = Config.intervalUp
local counter = 0
while true do
if counter == 0 or counter >= interval then
currentStatus = checkHosts()
if not nixio.fs.access(Config.statusFile, "r") then
writeValueToFile(Config.statusFile, statusJson(currentStatus))
end
if currentStatus == 0 then
interval = Config.intervalUp
if lastStatus ~= nil and currentStatus ~= lastStatus then
writeValueToFile(Config.statusFile, statusJson(currentStatus))
writeLogMessage("notice", "Internet connected")
end
else
interval = Config.intervalDown
if lastStatus ~= nil and currentStatus ~= lastStatus then
writeValueToFile(Config.statusFile, statusJson(currentStatus))
writeLogMessage("notice", "Internet disconnected")
end
end
counter = 0
end
timeDiff = 0
for _, e in ipairs(Config.modules) do
timeNow = nixio.sysinfo().uptime
if lastTime then
timeDiff = timeDiff + timeNow - lastTime
else
timeDiff = 1
end
lastTime = timeNow
e:run(currentStatus, lastStatus, timeDiff)
end
local modulesStatus = {}
for k, v in ipairs(Config.modules) do
if v.status ~= nil then
modulesStatus[v.name] = v.status
end
end
if next(modulesStatus) then
writeValueToFile(Config.statusFile, statusJson(currentStatus, modulesStatus))
end
lastStatus = currentStatus
nixio.nanosleep(1)
counter = counter + 1
end
end
local function removeProcessFiles()
os.remove(Config.pidFile)
os.remove(Config.statusFile)
end
local function status()
if nixio.fs.access(Config.pidFile, "r") then
return "running"
else
return "stoped"
end
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
return inetStat
end
local function stop()
local pidValue
if Config.enableLogger then
nixio.openlog(Config.appName)
end
if nixio.fs.access(Config.pidFile, "r") then
pidValue = readValueFromFile(Config.pidFile)
if pidValue then
local success
for i = 0, 10 do
success = nixio.kill(tonumber(pidValue), 15)
if success then
break
end
end
if not success then
io.stderr:write(string.format('No such process: "%s"\n', pidValue))
end
writeLogMessage("info", string.format("[%s] stoped", pidValue))
removeProcessFiles()
end
end
if not pidValue then
io.stderr:write(
string.format('PID file "%s" does not exist. %s not running?\n',
Config.pidFile, Config.appName))
end
if Config.enableLogger then
nixio.closelog()
end
end
local function preRun()
-- Exit if internet-detector mode != 2(Service)
if Config.mode ~= 2 then
io.stderr:write(string.format('Start failed, mode != 2\n', Config.appName))
os.exit(0)
end
if nixio.fs.access(Config.pidFile, "r") then
io.stderr:write(
string.format('PID file "%s" already exist. %s already running?\n',
Config.pidFile, Config.appName))
return false
end
return true
end
local function run()
local pidValue = nixio.getpid()
writeValueToFile(Config.pidFile, pidValue)
if Config.enableLogger then
nixio.openlog(Config.appName, "pid")
end
writeLogMessage("info", "started")
loadModules()
-- Loaded modules
local modules = {}
for _, v in ipairs(Config.modules) do
modules[#modules + 1] = string.format("%s", v.name)
end
if #modules > 0 then
writeLogMessage(
"info", string.format("Loaded modules: %s", table.concat(modules, ", "))
)
end
-- Debug
if Config.debug then
local function inspectTable()
local tables = {}, f
f = function(t, prefix)
tables[t] = true
for k, v in pairs(t) do
io.stdout:write(string.format(
"%s%s = %s\n", prefix, k, tostring(v))
)
if type(v) == "table" and not tables[v] then
f(v, string.format("%s%s.", prefix, k))
end
end
end
return f
end
io.stdout:write("--- Config ---\n")
inspectTable()(Config, "Config.")
io.stdout:flush()
end
main()
if Config.enableLogger then
nixio.closelog()
end
end
local function noDaemon()
if not preRun() then
return
end
run()
end
local function daemon(debug)
if not preRun() then
return
end
-- UNIX double fork
if nixio.fork() == 0 then
nixio.setsid()
if nixio.fork() == 0 then
nixio.chdir("/")
nixio.umask(0)
local output = "/dev/null"
if debug then
output = Config.debugLog
Config.debug = true
end
io.stdout:flush()
io.stderr:flush()
nixio.dup(io.open("/dev/null", "r"), io.stdin)
nixio.dup(io.open(output, "a+"), io.stdout)
nixio.dup(io.open(output, "a+"), io.stderr)
run()
end
os.exit(0)
end
os.exit(0)
end
local function restart()
stop()
daemon()
end
-- Main section
parseHosts()
local function help()
return string.format(
"Usage: %s [start|stop|restart|no-daemon|debug|status|inet-status|inet-status-json|poll [<attempts num>] [<timeout sec>]|--help]",
arg[0]
)
end
local helpArgs = { ["-h"] = true, ["--help"] = true, ["help"] = true }
if arg[1] == "start" or #arg == 0 then
daemon()
elseif arg[1] == "no-daemon" then
noDaemon()
elseif arg[1] == "debug" then
daemon(true)
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
print(poll(attempts, timeout))
elseif helpArgs[arg[1]] then
print(help())
else
print(help())
os.exit(1)
end
os.exit(0)

View File

@@ -0,0 +1,139 @@
--[[
Dependences:
mailsend
--]]
local nixio = require("nixio")
local Module = {
name = "mod_email",
config = {},
syslog = function(level, msg) return true end,
writeValue = function(filePath, str) return false end,
readValue = function(filePath) return nil end,
alivePeriod = 0,
hostAlias = "OpenWrt",
mta = "/usr/bin/mailsend",
mailRecipient = "email@gmail.com",
mailSender = "email@gmail.com",
mailUser = "email@gmail.com",
mailPassword = "password",
mailSmtp = "smtp.gmail.com",
mailSmtpPort = '587',
mailSecurity = "tls",
status = nil,
_enabled = false,
_aliveCounter = 0,
_msgSent = true,
_disconnected = true,
_lastDisconnection = nil,
_lastConnection = nil,
}
function Module:init(t)
self.alivePeriod = tonumber(t.alive_period)
if t.host_alias then
self.hostAlias = t.host_alias
else
self.hostAlias = self.config.hostname
end
self.mailRecipient = t.mail_recipient
self.mailSender = t.mail_sender
self.mailUser = t.mail_user
self.mailPassword = t.mail_password
self.mailSmtp = t.mail_smtp
self.mailSmtpPort = t.mail_smtp_port
self.mailSecurity = t.mail_security
if nixio.fs.access(self.mta, "x") then
self._enabled = true
else
self._enabled = false
self.syslog("warning", string.format("%s: %s is not available", self.name, self.mta))
end
if (not self.mailRecipient or
not self.mailSender or
not self.mailUser or
not self.mailPassword or
not self.mailSmtp or
not self.mailSmtpPort) then
self._enabled = false
self.syslog("warning", string.format(
"%s: Insufficient data to connect to the SMTP server", self.name))
end
end
function Module:sendMessage(msg)
local verboseArg = ""
-- Debug
if self.config.debug then
verboseArg = " -v"
io.stdout:write("--- mod_email ---\n")
io.stdout:flush()
end
local securityArgs = "-starttls -auth-login"
if self.mailSecurity == "ssl" then
securityArgs = "-ssl -auth"
end
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"',
self.mta, verboseArg, securityArgs, self.mailSmtp, self.mailSmtpPort,
self.mailUser, self.mailPassword, self.mailSender, self.mailRecipient,
string.format("%s notification", self.hostAlias),
string.format("%s:\n%s", self.hostAlias, msg))
if os.execute(mtaCmd) ~= 0 then
self.syslog("err", string.format(
"%s: An error occured while sending message", self.name))
else
self.syslog("info", string.format(
"%s: Message sent to %s", self.name, self.mailRecipient))
end
end
function Module:run(currentStatus, lastStatus, timeDiff)
if not self._enabled then
return
end
if currentStatus == 1 then
self._aliveCounter = 0
self._msgSent = false
self._lastConnection = nil
if not self._disconnected then
self._disconnected = true
if not self._lastDisconnection then
self._lastDisconnection = os.date("%Y.%m.%d %H:%M:%S", os.time())
end
end
else
if not self._msgSent then
if not self._lastConnection then
self._lastConnection = os.date("%Y.%m.%d %H:%M:%S", os.time())
end
if self._aliveCounter >= self.alivePeriod then
local message = {}
if self._lastDisconnection then
message[#message + 1] = string.format(
"Internet disconnected: %s", self._lastDisconnection)
self._lastDisconnection = nil
end
if self._lastConnection then
message[#message + 1] = string.format(
"Internet connected: %s", self._lastConnection)
self:sendMessage(table.concat(message, ", "))
self._msgSent = true
end
else
self._aliveCounter = self._aliveCounter + timeDiff
end
end
self._disconnected = false
end
end
return Module

View File

@@ -0,0 +1,91 @@
local nixio = require("nixio")
local Module = {
name = "mod_led_control",
config = {},
syslog = function(level, msg) return true end,
writeValue = function(filePath, str) return false end,
readValue = function(filePath) return nil end,
runInterval = 5,
sysLedsDir = "/sys/class/leds",
ledName = nil,
status = nil,
_enabled = false,
_ledDir = nil,
_ledMaxBrightnessFile = nil,
_ledBrightnessFile = nil,
_ledMaxBrightness = nil,
_counter = 0,
}
function Module:resetLeds()
local dir = nixio.fs.dir(self.sysLedsDir)
if not dir then
return
end
for led in dir do
local brightness = string.format("%s/%s/brightness", self.sysLedsDir, led)
if nixio.fs.access(brightness, "w") then
self.writeValue(brightness, 0)
end
end
end
function Module:init(t)
self.ledName = t.led_name
if not self.ledName then
return
end
self._ledDir = string.format("%s/%s", self.sysLedsDir, self.ledName)
self._ledMaxBrightnessFile = string.format("%s/max_brightness", self._ledDir)
self._ledBrightnessFile = string.format("%s/brightness", self._ledDir)
self._ledMaxBrightness = self.readValue(self._ledMaxBrightnessFile) or 1
if (not nixio.fs.access(self._ledDir, "r") or
not nixio.fs.access(self._ledBrightnessFile, "r", "w")) then
self._enabled = false
self.syslog("warning", string.format("%s: LED '%s' is not available", self.name, self.ledName))
else
self._enabled = true
-- Reset all LEDs
--self:resetLeds()
end
end
function Module:getCurrentState()
local state = self.readValue(self._ledBrightnessFile)
if state and tonumber(state) > 0 then
return tonumber(state)
end
end
function Module:on()
self.writeValue(self._ledBrightnessFile, self._ledMaxBrightness)
end
function Module:off()
self.writeValue(self._ledBrightnessFile, 0)
end
function Module:run(currentStatus, lastStatus, timeDiff)
if not self._enabled then
return
end
if self._counter == 0 or self._counter >= self.runInterval or currentStatus ~= lastStatus then
if currentStatus == 0 then
if not self:getCurrentState() then
self:on()
end
else
if self:getCurrentState() then
self:off()
end
end
self._counter = 0
end
self._counter = self._counter + timeDiff
end
return Module

View File

@@ -0,0 +1,85 @@
--[[
Dependences:
modemmanager
--]]
local nixio = require("nixio")
local Module = {
name = "mod_modem_restart",
config = {},
syslog = function(level, msg) return true end,
writeValue = function(filePath, str) return false end,
readValue = function(filePath) return nil end,
mmcli = "/usr/bin/mmcli",
mmInit = "/etc/init.d/modemmanager",
deadPeriod = 0,
iface = nil,
anyBand = false,
status = nil,
_enabled = false,
_deadCounter = 0,
_restarted = false,
}
function Module:toggleIface(flag)
return os.execute(
string.format("%s %s", (flag and "/sbin/ifup" or "/sbin/ifdown"), self.iface)
)
end
function Module:restartMM()
if self.anyBand then
self.syslog("info", string.format(
"%s: resetting current-bands to 'any'", self.name))
os.execute(string.format("%s -m any --set-current-bands=any", self.mmcli))
end
self.syslog("info", string.format("%s: reconnecting modem", self.name))
os.execute(string.format("%s restart", self.mmInit))
if self.iface then
self.syslog("info", string.format(
"%s: restarting network interface '%s'", self.name, self.iface))
self:toggleIface(false)
self:toggleIface(true)
end
end
function Module:init(t)
self.deadPeriod = tonumber(t.dead_period)
self.iface = t.iface
self.anyBand = (tonumber(t.any_band) ~= 0)
if not nixio.fs.access(self.mmcli, "x") then
self.anyBand = false
end
if nixio.fs.access(self.mmInit, "x") then
self._enabled = true
else
self._enabled = false
self.syslog("warning", string.format(
"%s: modemmanager service is not available", self.name))
end
end
function Module:run(currentStatus, lastStatus, timeDiff)
if not self._enabled then
return
end
if currentStatus == 1 then
if not self._restarted then
if self._deadCounter >= self.deadPeriod then
self:restartMM()
self._restarted = true
else
self._deadCounter = self._deadCounter + timeDiff
end
end
else
self._deadCounter = 0
self._restarted = false
end
end
return Module

View File

@@ -0,0 +1,92 @@
local nixio = require("nixio")
local Module = {
name = "mod_network_restart",
config = {},
syslog = function(level, msg) return true end,
writeValue = function(filePath, str) return false end,
readValue = function(filePath) return nil end,
iface = false,
attempts = 0,
deadPeriod = 0,
restartTimeout = 0,
status = nil,
_attemptsCounter = 0,
_deadCounter = 0,
}
function Module:toggleFunc(flag)
return
end
function Module:toggleDevice(flag)
local ip = "/sbin/ip"
if nixio.fs.access(ip, "x") then
return os.execute(
string.format("%s link set dev %s %s", ip, self.iface, (flag and "up" or "down"))
)
end
end
function Module:toggleIface(flag)
return os.execute(
string.format("%s %s", (flag and "/sbin/ifup" or "/sbin/ifdown"), self.iface)
)
end
function Module:ifaceUp()
self:toggleFunc(true)
end
function Module:ifaceDown()
self:toggleFunc(false)
end
function Module:networkRestart()
return os.execute("/etc/init.d/network restart")
end
function Module:init(t)
local iface = t.iface
if iface then
self.iface = iface
if self.iface:match("^@") then
self.iface = self.iface:gsub("^@", "")
self.toggleFunc = self.toggleIface
else
self.toggleFunc = self.toggleDevice
end
end
self.attempts = tonumber(t.attempts)
self.deadPeriod = tonumber(t.dead_period)
self.restartTimeout = tonumber(t.restart_timeout)
end
function Module:run(currentStatus, lastStatus, timeDiff)
if currentStatus == 1 then
if self.attempts == 0 or self._attemptsCounter < self.attempts then
if self._deadCounter >= self.deadPeriod then
if self.iface then
self.syslog("info", string.format(
"%s: restarting network interface '%s'", self.name, self.iface))
self:ifaceDown()
nixio.nanosleep(self.restartTimeout)
self:ifaceUp()
else
self.syslog("info", string.format("%s: restarting network", self.name))
self:networkRestart()
end
self._deadCounter = 0
self._attemptsCounter = self._attemptsCounter + 1
else
self._deadCounter = self._deadCounter + timeDiff
end
end
else
self._attemptsCounter = 0
self._deadCounter = 0
end
end
return Module

View File

@@ -0,0 +1,139 @@
local nixio = require("nixio")
local Module = {
name = "mod_public_ip",
config = {},
syslog = function(level, msg) return true end,
writeValue = function(filePath, str) return false end,
readValue = function(filePath) return nil end,
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,
_provider = nil,
_nslookupCmd = nil,
_currentIp = nil,
_enabled = false,
_counter = 0,
}
function Module:parseA(str)
res = str:match("Name:%s+" .. self._provider.host .. "\nAddress:%s+[%w.:]+")
if res then
return res:match("[%w.:]+$")
end
end
function Module:parseGoogle(str)
res = str:match(self._provider.host .. '%s+text%s+=%s+"[%w.:]+"')
if res then
return res:gsub('"', ''):match("[%w.:]+$")
end
end
function Module:resolveIP()
local res
local fh = io.popen(self._nslookupCmd, "r")
if fh then
output = fh:read("*a")
fh:close()
if self._provider.name == "google" then
res = self:parseGoogle(output)
else
res = self:parseA(output)
end
else
self.syslog("err", string.format(
"%s: Nslookup call failed (%s)", self.name, self.nslookup))
end
return res or "Undefined"
end
function Module:init(t)
if t.interval then
self.runInterval = tonumber(t.interval)
end
if t.timeout then
self.timeout = tonumber(t.timeout)
end
if t.provider then
self._provider = self.providers[t.provider]
else
self._provider = self.providers.opendns1
end
if not nixio.fs.access(self.nslookup, "x") then
self._enabled = false
self.syslog(
"warning",
string.format("%s: '%s' does not exists", self.name, self.nslookup)
)
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
function Module:run(currentStatus, lastStatus, timeDiff)
if not self._enabled then
return
end
if currentStatus == 0 then
if self._counter == 0 or self._counter >= self.runInterval or currentStatus ~= lastStatus then
local ip = self:resolveIP()
if ip ~= self._currentIp then
self.status = ip
self.syslog(
"notice",
string.format("%s: public IP address %s", self.name, ip)
)
else
self.status = nil
end
self._currentIp = ip
self._counter = 0
else
self.status = nil
end
else
self.status = nil
self._currentIp = nil
self._counter = 0
end
self._counter = self._counter + timeDiff
end
return Module

View File

@@ -0,0 +1,47 @@
local nixio = require("nixio")
local Module = {
name = "mod_reboot",
config = {},
syslog = function(level, msg) return true end,
writeValue = function(filePath, str) return false end,
readValue = function(filePath) return nil end,
deadPeriod = 0,
forceRebootDelay = 0,
status = nil,
_deadCounter = 0,
}
function Module:rebootDevice()
self.syslog("warning", string.format("%s: reboot", self.name))
os.execute("/sbin/reboot &")
if self.forceRebootDelay > 0 then
nixio.nanosleep(self.forceRebootDelay)
self.syslog("warning", string.format("%s: force reboot", self.name))
self.writeValue("/proc/sys/kernel/sysrq", "1")
self.writeValue("/proc/sysrq-trigger", "b")
end
end
function Module:init(t)
self.deadPeriod = tonumber(t.dead_period)
self.forceRebootDelay = tonumber(t.force_reboot_delay)
end
function Module:run(currentStatus, lastStatus, timeDiff)
if currentStatus == 1 then
if self._deadCounter >= self.deadPeriod then
self:rebootDevice()
self._deadCounter = 0
else
self._deadCounter = self._deadCounter + timeDiff
end
else
self._deadCounter = 0
end
end
return Module

View File

@@ -0,0 +1,64 @@
local nixio = require("nixio")
local Module = {
name = "mod_user_scripts",
config = {},
syslog = function(level, msg) return true end,
writeValue = function(filePath, str) return false end,
readValue = function(filePath) return nil end,
deadPeriod = 0,
alivePeriod = 0,
upScript = "",
downScript = "",
status = nil,
_deadCounter = 0,
_aliveCounter = 0,
_upScriptExecuted = true,
_downScriptExecuted = true,
}
function Module:runExternalScript(scriptPath)
if nixio.fs.access(scriptPath, "x") then
os.execute(string.format('/bin/sh -c "%s" &', scriptPath))
end
end
function Module:init(t)
self.deadPeriod = tonumber(t.dead_period)
self.alivePeriod = tonumber(t.alive_period)
if self.config.configDir then
self.upScript = string.format("%s/up-script", self.config.configDir)
self.downScript = string.format("%s/down-script", self.config.configDir)
end
end
function Module:run(currentStatus, lastStatus, timeDiff)
if currentStatus == 1 then
self._aliveCounter = 0
self._downScriptExecuted = false
if not self._upScriptExecuted then
if self._deadCounter >= self.deadPeriod then
self:runExternalScript(self.downScript)
self._upScriptExecuted = true
else
self._deadCounter = self._deadCounter + timeDiff
end
end
else
self._deadCounter = 0
self._upScriptExecuted = false
if not self._downScriptExecuted then
if self._aliveCounter >= self.alivePeriod then
self:runExternalScript(self.upScript)
self._downScriptExecuted = true
else
self._aliveCounter = self._aliveCounter + timeDiff
end
end
end
end
return Module

View File

@@ -0,0 +1,15 @@
#
# (с) 2021 gSpot (https://github.com/gSpotx2f/luci-app-internet-detector)
#
include $(TOPDIR)/rules.mk
PKG_VERSION:=0.6-1
LUCI_TITLE:=LuCI support for internet-detector
LUCI_DEPENDS:=+internet-detector
LUCI_PKGARCH:=all
#include ../../luci.mk
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,118 @@
'use strict';
'require baseclass';
'require fs';
'require uci';
document.head.append(E('style', {'type': 'text/css'},
`
:root {
--app-id-font-color: #fff;
--app-id-connected-color: #2ea256;
--app-id-disconnected-color: #ff4e54;
--app-id-undefined-color: #8a8a8a;
}
:root[data-darkmode="true"] {
--app-id-connected-color: #005F20;
--app-id-disconnected-color: #a93734;
--app-id-undefined-color: #4d4d4d;
}
.id-connected {
background-color: var(--app-id-connected-color) !important;
color: var(--app-id-font-color) !important;
}
.id-disconnected {
background-color: var(--app-id-disconnected-color) !important;
color: var(--app-id-font-color) !important;
}
.id-undefined {
background-color: var(--app-id-undefined-color) !important;
color: var(--app-id-font-color) !important;
}
`));
return baseclass.extend({
title : _('Internet'),
appName : 'internet-detector',
execPath : '/usr/bin/internet-detector',
inetStatus : null,
publicIp : null,
inetStatusFromJson: function(res) {
let curInetStatus = null;
let curPubIp = null;
if(res.code === 0) {
try {
let json = JSON.parse(res.stdout.trim());
curInetStatus = json.inet;
curPubIp = json.mod_public_ip;
} catch(e) {};
};
return [ curInetStatus, curPubIp ];
},
load: async function() {
if(!(
'uiCheckIntervalUp' in window &&
'uiCheckIntervalDown' in window &&
'currentAppMode' in window
)) {
await uci.load(this.appName).then(data => {
window.uiCheckIntervalUp = Number(uci.get(this.appName, 'config', 'ui_interval_up'));
window.uiCheckIntervalDown = Number(uci.get(this.appName, 'config', 'ui_interval_down'));
window.currentAppMode = uci.get(this.appName, 'config', 'mode');
}).catch(e => {});
};
if(window.currentAppMode === '1' || window.currentAppMode === '2') {
window.internetDetectorCounter = ('internetDetectorCounter' in window) ?
++window.internetDetectorCounter : 0;
if(!('internetDetectorState' in window)) {
window.internetDetectorState = 2;
};
if(window.currentAppMode === '1' && (
(window.internetDetectorState === 0 && window.internetDetectorCounter % window.uiCheckIntervalUp) ||
(window.internetDetectorState === 1 && window.internetDetectorCounter % window.uiCheckIntervalDown)
)) {
return;
};
window.internetDetectorCounter = 0;
return L.resolveDefault(fs.exec(this.execPath, [ 'inet-status-json' ]), null);
}
else {
window.internetDetectorState = 2;
};
},
render: function(data) {
if(window.currentAppMode === '0') {
return
};
if(data) {
[ window.internetDetectorState, this.publicIp ] = this.inetStatusFromJson(data);
};
let internetStatus = E('span', { 'class': 'label' });
if(window.internetDetectorState === 0) {
internetStatus.textContent = _('Connected') + (this.publicIp ? ' | %s: %s'.format(_('Public IP'), _(this.publicIp)) : '');
internetStatus.className = "label id-connected";
}
else if(window.internetDetectorState === 1) {
internetStatus.textContent = _('Disconnected');
internetStatus.className = "label id-disconnected";
}
else {
internetStatus.textContent = _('Undefined');
internetStatus.className = "label id-undefined";
};
return E('div', {
'class': 'cbi-section',
'style': 'margin-bottom:1em',
}, internetStatus);
},
});

View File

@@ -0,0 +1,477 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.4.2\n"
"Last-Translator: \n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? "
"1 : 2);\n"
"Language: ru\n"
msgid "<abbr title=\"Light Emitting Diode\">LED</abbr> Name"
msgstr "Имя <abbr title=\"Светодиод\">LED</abbr>"
msgid "<abbr title=\"Light Emitting Diode\">LED</abbr> control"
msgstr "Управление <abbr title=\"Светодиод\">LED</abbr>"
msgid ""
"<abbr title=\"Light Emitting Diode\">LED</abbr> is on when Internet is "
"available."
msgstr "<abbr title=\"Светодиод\">LED</abbr> включен если Интернет доступен."
msgid "Alive interval"
msgstr "Интервал при подключении"
msgid "Alive period"
msgstr "Период после подключения"
msgid ""
"An email will be sent when the internet connection is restored after being "
"disconnected."
msgstr "Сообщение будет отправлено при восстановлении соединения с Интернет после отключения."
msgid "An error has occurred"
msgstr "Произошла ошибка"
msgid "Big: 248 bytes"
msgstr "Большой: 248 байт"
msgid "Check type"
msgstr "Тип проверки"
msgid "Checking Internet availability."
msgstr "Проверка доступности Интернет."
msgid "Checking the real public IP address."
msgstr "Проверка реального публичного IP адреса."
msgid "Command failed"
msgstr "Команда не выполнена"
msgid "Connected"
msgstr "Подключен"
msgid "Connection attempts"
msgstr "Попытки подключения"
msgid "Connection timeout"
msgstr "Таймаут соединения"
msgid "Contents have been saved."
msgstr "Содержимое сохранено."
msgid "Dead interval"
msgstr "Интервал при отключении"
msgid "Dead period"
msgstr "Период после отключения"
msgid "Default port value for TCP connections."
msgstr "Стандартное значение порта для TCP-подключений."
msgid "Device will be rebooted when the Internet is disconnected."
msgstr "Устройство будет перезагружено при отключении Интернет."
msgid "Disable forced reboot"
msgstr "Отключить принудительную перезагрузку"
msgid "Disabled"
msgstr "Отключен"
msgid "Disabled: detector is completely off."
msgstr "Отключен: детектор полностью выключен."
msgid "Disconnected"
msgstr "Отключен"
msgid "Dismiss"
msgstr "Закрыть"
msgid "DNS provider"
msgstr "DNS провайдер"
msgid "Edit"
msgstr "Изменить"
msgid "Edit down-script"
msgstr "Изменить down-script"
msgid "Edit up-script"
msgstr "Изменить up-script"
msgid "Email notification"
msgstr "Уведомление по email"
msgid "Email address of the recipient."
msgstr "Email-адрес получателя."
msgid "Email address of the sender."
msgstr "Email-адрес отправителя."
msgid "Enable"
msgstr "Включить"
msgid "Enable logging"
msgstr "Включить запись событий в лог"
msgid "Enabled"
msgstr "Включен"
msgid "Expecting:"
msgstr "Ожидается:"
msgid "Public IP"
msgstr "Публичный IP"
msgid "Public IP address"
msgstr "Публичный IP адрес"
msgid "Failed to get %s init status: %s"
msgstr "Не удалось получить статус инициализации %s: %s"
msgid "Forced reboot delay"
msgstr "Задержка принудительной перезагрузки"
msgid "Host alias"
msgstr "Псевдоним хоста"
msgid "Host availability check type."
msgstr "Тип проверки доступности хоста."
msgid "Host identifier in messages. If not specified, hostname will be used."
msgstr "Идентификатор хоста в сообщениях. Если не указан, будет использовано имя хоста."
msgid "Hostname/IP address of the SMTP server."
msgstr "Имя хоста/IP-адрес SMTP-сервера."
msgid "Hosts"
msgstr "Хосты"
msgid "Hosts polling interval when the Internet is down."
msgstr "Интервал опроса хостов если Интернет не доступен."
msgid "Hosts polling interval when the Internet is up."
msgstr "Интервал опроса хостов если Интернет доступен."
msgid ""
"Hosts to check Internet availability. Hosts are polled (in list order) until "
"at least one of them responds."
msgstr ""
"Хосты для проверки доступности Интернет. Хосты опрашиваются (в порядке "
"списка) до тех пор, пока хотя бы один из них не ответит."
msgid "Huge: 1492 bytes"
msgstr "Огромный: 1492 байта"
msgid "Interface"
msgstr "Интерфейс"
msgid "Internet"
msgstr "Интернет"
msgid "Internet Detector"
msgstr "Интернет-детектор"
msgid "Internet detector mode"
msgstr "Режим интернет-детектора"
msgid "Internet status"
msgstr "Статус Интернет"
msgid "Interval between IP address requests."
msgstr "Интервал между запросами IP адреса."
msgid "Jumbo: 9000 bytes"
msgstr "Гигантский: 9000 байт"
msgid "LED control"
msgstr "Управление LED"
msgid "Loading"
msgstr "Загрузка"
msgid ""
"Longest period of time after connecting to Internet before \"up-script\" "
"runs."
msgstr ""
"Максимальный промежуток времени после подключения к Интернет перед запуском "
"\"up-script\"."
msgid ""
"Longest period of time after connecting to the Internet before sending a "
"message."
msgstr "Максимальный промежуток времени после отключения Интернет перед отправкой сообщения."
msgid ""
"Longest period of time after disconnecting from Internet before \"down-script"
"\" runs."
msgstr ""
"Максимальный промежуток времени после отключения Интернет перед запуском "
"\"down-script\"."
msgid "Longest period of time without Internet access before modem restart."
msgstr ""
"Максимальное время отсутствия доступа в Интренет перед перезапуском модема."
msgid "Longest period of time without Internet access before network restart."
msgstr ""
"Максимальное время отсутствия доступа в Интренет перед перезапуском сети."
msgid ""
"Longest period of time without Internet access until the device is rebooted."
msgstr ""
"Максимальное время отсутствия доступа в Интренет перед перезагрузкой "
"устройства."
msgid "Mailsend is not available..."
msgstr "Mailsend недоступен..."
msgid "Main settings"
msgstr "Основные настройки"
msgid "Maximum number of attempts to connect to each host."
msgstr "Максимальное количество попыток подключения к каждому хосту."
msgid ""
"Maximum number of network restart attempts before Internet access is "
"available."
msgstr ""
"Максимальное количество попыток перезапуска сети до появления доступа в "
"Интренет."
msgid "Maximum timeout for waiting for a response from the host."
msgstr "Максимальный таймаут ожидания ответа от хоста."
msgid "Modem will be restarted when the Internet is disconnected."
msgstr "Модем будет перезапущен при отключении Интернет."
msgid "ModemManager is not available..."
msgstr "ModemManager недоступен..."
msgid ""
"ModemManger interface. If specified, it will be restarted after restarting "
"ModemManager."
msgstr ""
"Интерфейс ModemManager. Если задан, то будет перезапущен после перезапуска "
"ModemManger."
msgid ""
"Network interface for Internet access. If not specified, the default "
"interface is used."
msgstr ""
"Сетевой интерфейс для доступа в Интернет. Если не указан, используется "
"интерфейс по умолчанию."
msgid ""
"Network interface to restart. If not specified, then the network service is restarted."
msgstr ""
"Сетевой интерфейс для перезапуска. Если не задан, то будет перезапущена сетевая "
"служба."
msgid "Network will be restarted when the Internet is disconnected."
msgstr "Сеть будет перезапущена при отключении Интернет."
msgid "No <abbr title=\"Light Emitting Diode\">LED</abbr>s available..."
msgstr "Нет доступных <abbr title=\"Светодиод\">LED</abbr>..."
msgid "One of the following:"
msgstr "Одно из следующих значений:"
msgid "Password"
msgstr "Пароль"
msgid "Password for SMTP authentication."
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"
msgstr "Интервал опроса"
msgid "Reboot device"
msgstr "Перезагрузка устройства"
msgid "Recipient"
msgstr "Получатель"
msgid "Restart"
msgstr "Перезапуск"
msgid "Restart attempts"
msgstr "Попытки перезапуска"
msgid "Restart modem"
msgstr "Перезапуск модема"
msgid "Restart network"
msgstr "Перезапуск сети"
msgid "Restart service"
msgstr "Перезапуск службы"
msgid "Restart timeout"
msgstr "Таймаут перезапуска"
msgid "Run service at startup"
msgstr "Запуск службы при старте"
msgid "Running"
msgstr "Выполняется"
msgid "SMTP server"
msgstr "SMTP-сервер"
msgid "SMTP server port"
msgstr "Порт SMTP-сервера"
msgid "SSL: SMTP over SSL."
msgstr "SSL: SMTP поверх SSL."
msgid "Save"
msgstr "Сохранить"
msgid "Security"
msgstr "Безопасность"
msgid "Sender"
msgstr "Отправитель"
msgid "Server response timeout"
msgstr "Таймаут ответа сервера"
msgid "Service"
msgstr "Служба"
msgid "Service action failed \"%s %s\": %s"
msgstr "Не удалось выполнить действие службы \"%s %s\": %s"
msgid "Service configuration"
msgstr "Конфигурация службы"
msgid "Service for determining the public IP address through DNS."
msgstr "Сервис для определения публичного IP адреса через DNS."
msgid "Service modules"
msgstr "Модули службы"
msgid "Service: detector always runs as a system service."
msgstr "Служба: детектор работает постоянно, как системная служба."
msgid "Set the modem to be allowed to use any band."
msgstr "Разрешить модему использование любой частоты."
msgid "Shell commands that run when connected to the Internet."
msgstr "Команды shell выполняемые при подключении к Интернет."
msgid "Shell commands to run when connected or disconnected from the Internet."
msgstr "Команды shell выполняемые при подключении или отключении Интернет."
msgid "Shell commands to run when disconnected from the Internet."
msgstr "Команды shell выполняемые при отключении от Интернет."
msgid "Small: 1 byte"
msgstr "Маленький: 1 байт"
msgid "Standard: 56 bytes"
msgstr "Стандартный: 56 байт"
msgid "Stopped"
msgstr "Остановлена"
msgid "TCP port"
msgstr "TCP-порт"
msgid "TCP port connection"
msgstr "Подключение к TCP-порту"
msgid "TLS: use STARTTLS if the server supports it."
msgstr "TLS: использовать STARTTLS если сервер поддерживает."
msgid "Timeout between stopping and starting the interface."
msgstr "Таймаут между остановкой и запуском интерфейса."
msgid "Type a time string"
msgstr "Введите строку времени"
msgid "UI detector configuration"
msgstr "Конфигурация UI детектора"
msgid "Unable to read the contents"
msgstr "Невозможно прочитать содержимое"
msgid "Unable to save the contents"
msgstr "Невозможно сохранить содержимое"
msgid "Undefined"
msgstr "Неопределён"
msgid "Unlock modem bands"
msgstr "Освободить частоты модема"
msgid "User"
msgstr "Пользователь"
msgid "User scripts"
msgstr "Пользовательские скрипты"
msgid "Username for SMTP authentication."
msgstr "Имя пользователя для SMTP-аутентификации."
msgid "Waiting for a reboot to complete before performing a forced reboot."
msgstr ""
"Ожидание завершения перезагрузки перед выполнением принудительной "
"перезагрузки."
msgid "Web UI only"
msgstr "Только web-интерфейс"
msgid "Web UI only: detector works only when the Web UI is open (UI detector)."
msgstr ""
"Только web-интерфейс: детектор работает только в web-интерфейсе (UI "
"детектор)."
msgid "Windows: 32 bytes"
msgstr "Windows: 32 байта"
msgid "Write messages to the system log."
msgstr "Записывать сообщения в системный журнал."
msgid "down-script"
msgstr "down-script"
msgid "hour"
msgstr "час"
msgid "hours"
msgstr "часы"
msgid "min"
msgstr "мин"
msgid "minutes"
msgstr "минуты"
msgid "sec"
msgstr "сек"
msgid "seconds"
msgstr "секунды"
msgid "up-script"
msgstr "up-script"

View File

@@ -0,0 +1,441 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "<abbr title=\"Light Emitting Diode\">LED</abbr> Name"
msgstr ""
msgid "<abbr title=\"Light Emitting Diode\">LED</abbr> control"
msgstr ""
msgid ""
"<abbr title=\"Light Emitting Diode\">LED</abbr> is on when Internet is "
"available."
msgstr ""
msgid "Alive interval"
msgstr ""
msgid "Alive period"
msgstr ""
msgid ""
"An email will be sent when the internet connection is restored after being "
"disconnected."
msgstr ""
msgid "An error has occurred"
msgstr ""
msgid "Big: 248 bytes"
msgstr ""
msgid "Check type"
msgstr ""
msgid "Checking Internet availability."
msgstr ""
msgid "Checking the real public IP address."
msgstr ""
msgid "Command failed"
msgstr ""
msgid "Connected"
msgstr ""
msgid "Connection attempts"
msgstr ""
msgid "Connection timeout"
msgstr ""
msgid "Contents have been saved."
msgstr ""
msgid "Dead interval"
msgstr ""
msgid "Dead period"
msgstr ""
msgid "Default port value for TCP connections."
msgstr ""
msgid "Device will be rebooted when the Internet is disconnected."
msgstr ""
msgid "Disable forced reboot"
msgstr ""
msgid "Disabled"
msgstr ""
msgid "Disabled: detector is completely off."
msgstr ""
msgid "Disconnected"
msgstr ""
msgid "Dismiss"
msgstr ""
msgid "DNS provider"
msgstr ""
msgid "Edit"
msgstr ""
msgid "Edit down-script"
msgstr ""
msgid "Edit up-script"
msgstr ""
msgid "Email notification"
msgstr ""
msgid "Email address of the recipient."
msgstr ""
msgid "Email address of the sender."
msgstr ""
msgid "Enable"
msgstr ""
msgid "Enable logging"
msgstr ""
msgid "Enabled"
msgstr ""
msgid "Expecting:"
msgstr ""
msgid "Public IP"
msgstr ""
msgid "Public IP address"
msgstr ""
msgid "Failed to get %s init status: %s"
msgstr ""
msgid "Forced reboot delay"
msgstr ""
msgid "Host alias"
msgstr ""
msgid "Host availability check type."
msgstr ""
msgid "Host identifier in messages. If not specified, hostname will be used."
msgstr ""
msgid "Hostname/IP address of the SMTP server."
msgstr ""
msgid "Hosts"
msgstr ""
msgid "Hosts polling interval when the Internet is down."
msgstr ""
msgid "Hosts polling interval when the Internet is up."
msgstr ""
msgid ""
"Hosts to check Internet availability. Hosts are polled (in list order) until "
"at least one of them responds."
msgstr ""
msgid "Huge: 1492 bytes"
msgstr ""
msgid "Interface"
msgstr ""
msgid "Internet"
msgstr ""
msgid "Internet Detector"
msgstr ""
msgid "Internet detector mode"
msgstr ""
msgid "Internet status"
msgstr ""
msgid "Interval between IP address requests."
msgstr ""
msgid "Jumbo: 9000 bytes"
msgstr ""
msgid "LED control"
msgstr ""
msgid "Loading"
msgstr ""
msgid ""
"Longest period of time after connecting to Internet before \"up-script\" "
"runs."
msgstr ""
msgid ""
"Longest period of time after connecting to the Internet before sending a "
"message."
msgstr ""
msgid ""
"Longest period of time after disconnecting from Internet before \"down-script"
"\" runs."
msgstr ""
msgid "Longest period of time without Internet access before modem restart."
msgstr ""
msgid "Longest period of time without Internet access before network restart."
msgstr ""
msgid ""
"Longest period of time without Internet access until the device is rebooted."
msgstr ""
msgid "Mailsend is not available..."
msgstr ""
msgid "Main settings"
msgstr ""
msgid "Maximum number of attempts to connect to each host."
msgstr ""
msgid ""
"Maximum number of network restart attempts before Internet access is "
"available."
msgstr ""
msgid "Maximum timeout for waiting for a response from the host."
msgstr ""
msgid "Modem will be restarted when the Internet is disconnected."
msgstr ""
msgid "ModemManager is not available..."
msgstr ""
msgid ""
"ModemManger interface. If specified, it will be restarted after restarting "
"ModemManager."
msgstr ""
msgid ""
"Network interface for Internet access. If not specified, the default "
"interface is used."
msgstr ""
msgid ""
"Network interface to restart. If not specified, then the network service is restarted."
msgstr ""
msgid "Network will be restarted when the Internet is disconnected."
msgstr ""
msgid "No <abbr title=\"Light Emitting Diode\">LED</abbr>s available..."
msgstr ""
msgid "One of the following:"
msgstr ""
msgid "Password"
msgstr ""
msgid "Password for SMTP authentication."
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"
msgstr ""
msgid "Reboot device"
msgstr ""
msgid "Recipient"
msgstr ""
msgid "Restart"
msgstr ""
msgid "Restart attempts"
msgstr ""
msgid "Restart modem"
msgstr ""
msgid "Restart network"
msgstr ""
msgid "Restart service"
msgstr ""
msgid "Restart timeout"
msgstr ""
msgid "Run service at startup"
msgstr ""
msgid "Running"
msgstr ""
msgid "SMTP server"
msgstr ""
msgid "SMTP server port"
msgstr ""
msgid "SSL: SMTP over SSL."
msgstr ""
msgid "Save"
msgstr ""
msgid "Security"
msgstr ""
msgid "Sender"
msgstr ""
msgid "Server response timeout"
msgstr ""
msgid "Service"
msgstr ""
msgid "Service action failed \"%s %s\": %s"
msgstr ""
msgid "Service configuration"
msgstr ""
msgid "Service for determining the public IP address through DNS."
msgstr ""
msgid "Service modules"
msgstr ""
msgid "Service: detector always runs as a system service."
msgstr ""
msgid "Set the modem to be allowed to use any band."
msgstr ""
msgid "Shell commands that run when connected to the Internet."
msgstr ""
msgid "Shell commands to run when connected or disconnected from the Internet."
msgstr ""
msgid "Shell commands to run when disconnected from the Internet."
msgstr ""
msgid "Small: 1 byte"
msgstr ""
msgid "Standard: 56 bytes"
msgstr ""
msgid "Stopped"
msgstr ""
msgid "TCP port"
msgstr ""
msgid "TCP port connection"
msgstr ""
msgid "TLS: use STARTTLS if the server supports it."
msgstr ""
msgid "Timeout between stopping and starting the interface."
msgstr ""
msgid "Type a time string"
msgstr ""
msgid "UI detector configuration"
msgstr ""
msgid "Unable to read the contents"
msgstr ""
msgid "Unable to save the contents"
msgstr ""
msgid "Undefined"
msgstr ""
msgid "Unlock modem bands"
msgstr ""
msgid "User"
msgstr ""
msgid "User scripts"
msgstr ""
msgid "Username for SMTP authentication."
msgstr ""
msgid "Waiting for a reboot to complete before performing a forced reboot."
msgstr ""
msgid "Web UI only"
msgstr ""
msgid "Web UI only: detector works only when the Web UI is open (UI detector)."
msgstr ""
msgid "Windows: 32 bytes"
msgstr ""
msgid "Write messages to the system log."
msgstr ""
msgid "down-script"
msgstr ""
msgid "hour"
msgstr ""
msgid "hours"
msgstr ""
msgid "min"
msgstr ""
msgid "minutes"
msgstr ""
msgid "sec"
msgstr ""
msgid "seconds"
msgstr ""
msgid "up-script"
msgstr ""

View File

@@ -0,0 +1,17 @@
{
"admin/services/internet-detector": {
"title": "Internet Detector",
"order": 80,
"action": {
"type": "view",
"path": "internet-detector"
},
"depends": {
"acl": [ "luci-app-internet-detector" ],
"fs": {
"/usr/bin/internet-detector": "executable"
},
"uci": { "internet-detector": true }
}
}
}

View File

@@ -0,0 +1,25 @@
{
"luci-app-internet-detector": {
"description": "Grant access to internet-detector procedures",
"read": {
"file": {
"/sys/class/leds": [ "list" ],
"/etc/internet-detector/up-script": [ "read" ],
"/etc/internet-detector/down-script": [ "read" ],
"/usr/bin/internet-detector*": [ "exec" ],
"/usr/bin/mailsend": [ "exec" ]
},
"uci": [ "internet-detector" ],
"ubus": {
"luci": [ "getInitList", "setInitAction" ]
}
},
"write": {
"file": {
"/etc/internet-detector/up-script": [ "write" ],
"/etc/internet-detector/down-script": [ "write" ]
},
"uci": [ "internet-detector" ]
}
}
}

View File

@@ -1,21 +0,0 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ru\n"
"X-Generator: Poedit 2.0.6\n"
msgid "Internet"
msgstr "Интернет"
msgid "Internet connected"
msgstr "Интернет подключен"
msgid "Internet disconnected"
msgstr "Интернет отключен"

View File

@@ -1,11 +0,0 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "Internet"
msgstr ""
msgid "Internet connected"
msgstr ""
msgid "Internet disconnected"
msgstr ""

View File

@@ -1,10 +0,0 @@
{
"luci-app-internet-detector": {
"description": "Grant access to internet-detector procedures",
"read": {
"file": {
"/bin/ping -c 1 -W 1 [a-z0-9:.]*": [ "exec" ]
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 233 KiB

BIN
screenshots/02.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB