mirror of
https://github.com/gSpotx2f/luci-app-internet-detector.git
synced 2025-12-08 12:36:49 +03:00
Compare commits
22 Commits
v0.2(depre
...
v0.6(depre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
642265b96d | ||
|
|
312294aeef | ||
|
|
f81cfc930f | ||
|
|
78067be67f | ||
|
|
5b5db26919 | ||
|
|
e19d2bc61b | ||
|
|
a22e48e786 | ||
|
|
7a879809c7 | ||
|
|
cb4ddc4062 | ||
|
|
4f89925348 | ||
|
|
97496366a7 | ||
|
|
4a46ac1f4c | ||
|
|
80845f6c3d | ||
|
|
ab0a2bce86 | ||
|
|
6fb2cf8a5e | ||
|
|
438c99bf35 | ||
|
|
29eb4e8a71 | ||
|
|
54f13984a3 | ||
|
|
a554668306 | ||
|
|
a0a495267b | ||
|
|
8d5022cdfd | ||
|
|
a008297225 |
214
LICENSE
214
LICENSE
@@ -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.
|
||||||
|
|||||||
18
Makefile
18
Makefile
@@ -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
|
|
||||||
51
README.md
51
README.md
@@ -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.
|
||||||
|

|
||||||
|
- 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:
|
||||||
|
|
||||||

|

|
||||||
|

|
||||||
|
|||||||
@@ -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);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
59
internet-detector/Makefile
Normal file
59
internet-detector/Makefile
Normal 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)))
|
||||||
52
internet-detector/files/etc/config/internet-detector
Normal file
52
internet-detector/files/etc/config/internet-detector
Normal 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'
|
||||||
19
internet-detector/files/etc/init.d/internet-detector
Executable file
19
internet-detector/files/etc/init.d/internet-detector
Executable 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
|
||||||
|
}
|
||||||
1
internet-detector/files/etc/internet-detector/down-script
Executable file
1
internet-detector/files/etc/internet-detector/down-script
Executable file
@@ -0,0 +1 @@
|
|||||||
|
# Shell commands to run when disconnected from the Internet
|
||||||
1
internet-detector/files/etc/internet-detector/up-script
Executable file
1
internet-detector/files/etc/internet-detector/up-script
Executable file
@@ -0,0 +1 @@
|
|||||||
|
# Shell commands that run when connected to the Internet
|
||||||
555
internet-detector/files/usr/bin/internet-detector
Executable file
555
internet-detector/files/usr/bin/internet-detector
Executable 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)
|
||||||
139
internet-detector/files/usr/lib/internet-detector/mod_email.lua
Normal file
139
internet-detector/files/usr/lib/internet-detector/mod_email.lua
Normal 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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
15
luci-app-internet-detector/Makefile
Normal file
15
luci-app-internet-detector/Makefile
Normal 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
@@ -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);
|
||||||
|
},
|
||||||
|
});
|
||||||
477
luci-app-internet-detector/po/ru/internet-detector.po
Normal file
477
luci-app-internet-detector/po/ru/internet-detector.po
Normal 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"
|
||||||
441
luci-app-internet-detector/po/templates/internet-detector.pot
Normal file
441
luci-app-internet-detector/po/templates/internet-detector.pot
Normal 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 ""
|
||||||
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -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 "Интернет отключен"
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
msgid ""
|
|
||||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
|
||||||
|
|
||||||
msgid "Internet"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Internet connected"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Internet disconnected"
|
|
||||||
msgstr ""
|
|
||||||
@@ -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
BIN
screenshots/02.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
BIN
screenshots/internet-led.jpg
Normal file
BIN
screenshots/internet-led.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
Reference in New Issue
Block a user