aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorneodarz <neodarz@neodarz.net>2019-09-28 19:30:41 +0200
committerneodarz <neodarz@neodarz.net>2019-09-28 19:30:41 +0200
commitd70390197ee3e06ee1fecbc14d1ed48ba4040c94 (patch)
tree325267c8d64ed2d7282d1d3166b0a651b9594ddc
downloadpykeepalive-master.tar.xz
pykeepalive-master.zip
Initial commitHEADmaster
-rw-r--r--.gitignore131
-rw-r--r--README.md7
-rw-r--r--commands.py91
-rw-r--r--config.py24
-rw-r--r--file.py8
-rw-r--r--log.py20
-rw-r--r--pykeepalive.py42
-rw-r--r--tools.py37
8 files changed, 360 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..01495c0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,131 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# Vim tmp file
+.pykeepalive.py.swp
+
+# Log file
+log.txt
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..64f40cd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,7 @@
+# PyKeepAlive
+
+Rewrite of
+["openwrt-lte-keep-alive"](https://github.com/mchsk/openwrt-lte-keep-alive)
+for fun, do the same.
+
+It ping my server and a FDN DNS server, it can be changes in `config.py`.
diff --git a/commands.py b/commands.py
new file mode 100644
index 0000000..6ddb940
--- /dev/null
+++ b/commands.py
@@ -0,0 +1,91 @@
+#/bin/python3
+
+import sys
+
+import tailhead
+
+import platform
+import subprocess
+
+import datetime, time
+
+import json
+
+def _make_gen(reader):
+ b = reader(1024 * 1024)
+ while b:
+ yield b
+ b = reader(1024*1024)
+
+def file_len(filename):
+ """ More opti than wc on turis """
+ f = open(filename, 'rb')
+ f_gen = _make_gen(f.raw.read)
+ return sum( buf.count(b'\n') for buf in f_gen )
+
+def multi_ping(hosts, interface):
+ """
+ Returns True if host (list of str) responds to a ping request.
+ Remember that a host may not respond to a ping (ICMP) request even if the host name is valid.
+ """
+
+ # Option for the number of packets as a function of
+ count = '-n' if platform.system().lower()=='windows' else '-c'
+ source = '-S' if platform.system().lower()=='windows' else '-I'
+
+ if type(hosts) is list:
+ procs = []
+ for host in hosts:
+ command = ['ping', count, '1', source, interface, host]
+ proc = subprocess.Popen(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+ procs.append(proc)
+
+ procs_done = []
+ while True:
+ for proc in procs:
+ if proc.poll() is not None:
+ procs_done.append(proc.poll())
+ procs.pop(procs.index(proc))
+ if len(procs) == 0:
+ #print("o")
+ break
+ time.sleep(1)
+
+ if 0 in procs_done:
+ return 0
+ else:
+ return 1
+
+ else:
+ print("fuck you host must be a list")
+ sys.exit()
+
+
+def log_write(status):
+ with open(LOG_PATH_FILE, 'a') as f:
+ f.write("{} {}\n".format(tools.date(), status))
+
+def uqmi_current_settings():
+ command = ['uqmi', '-d', '/dev/cdc-wdm0', '--get-current-settings']
+ proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ datas = json.loads(proc.stdout)
+ return datas["ipv4"]["ip"], datas["ipv4"]["gateway"], datas["ipv4"]["subnet"]
+
+def ifconfig_update(interface, ip, subnet):
+ command = ['ifconfig', interface, ip, 'netmask', subnet, 'up']
+ proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+def route_update(gateway):
+ command = ['route', 'add', 'default', 'gw', gateway]
+ proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+def tail(file, lines):
+ return tailhead.tail(open(file, 'rb'), lines)
+
+
+def date():
+ # Calculate the offset taking into account daylight saving time
+ utc_offset_sec = time.altzone if time.localtime().tm_isdst else time.timezone
+ utc_offset = datetime.timedelta(seconds=-utc_offset_sec)
+ return datetime.datetime.now().replace(tzinfo=datetime.timezone(offset=utc_offset)).isoformat()
+
diff --git a/config.py b/config.py
new file mode 100644
index 0000000..c9cc4dc
--- /dev/null
+++ b/config.py
@@ -0,0 +1,24 @@
+#/bin/python3
+
+import os
+import sys
+from pathlib import Path, PurePath
+
+import tools
+import commands
+
+DIR=os.path.dirname(os.path.abspath( __file__ ))
+LOG_FILE=PurePath("log.txt")
+LOG_PATH_FILE=Path(DIR / LOG_FILE)
+if not os.path.exists(LOG_PATH_FILE):
+ os.mknod(LOG_PATH_FILE)
+
+OFFLINE_COUNT=tools.offline_counts(LOG_PATH_FILE)
+OFFLINE_COUNT_TRESHOLD=4
+
+LINES_MAX=11000
+LINES_MIN=6000
+LINES_COUNT=commands.file_len(LOG_PATH_FILE)
+
+HOSTS = ["80.67.169.12", "neodarz.net"]
+INTERFACE = "wwan0"
diff --git a/file.py b/file.py
new file mode 100644
index 0000000..efad937
--- /dev/null
+++ b/file.py
@@ -0,0 +1,8 @@
+#/bin/python3
+
+from config import *
+import commands
+
+def log_write(status):
+ with open(LOG_PATH_FILE, 'a') as f:
+ f.write("{} {}\n".format(commands.date(), status))
diff --git a/log.py b/log.py
new file mode 100644
index 0000000..a4ff80c
--- /dev/null
+++ b/log.py
@@ -0,0 +1,20 @@
+#/bin/python3
+
+import platform
+import subprocess
+
+from config import *
+import commands
+
+def tail_log():
+ if commands.file_len(LOG_PATH_FILE) > LINES_MAX:
+ if platform.system().lower()=='windows':
+ datas = commands.tail(LOG_PATH_FILE, LINES_MIN)
+ with open(LOG_PATH_FILE, "wb") as f:
+ f.write(b' \n'.join(datas))
+ else:
+ command = ["tail", "-"+str(LINES_MIN), str(LOG_PATH_FILE)]
+ proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ datas = proc.stdout.decode('utf-8')
+ with open(LOG_PATH_FILE, "w") as f:
+ f.write("".join(datas))
diff --git a/pykeepalive.py b/pykeepalive.py
new file mode 100644
index 0000000..e4d54af
--- /dev/null
+++ b/pykeepalive.py
@@ -0,0 +1,42 @@
+#/bin/python3
+
+import sys, time
+import tailhead
+
+from config import *
+
+import tools
+import commands
+import file
+import log
+
+if len(sys.argv) == 1:
+ log.tail_log()
+ if commands.multi_ping(HOSTS, INTERFACE) == 0:
+ file.log_write("ONLINE")
+ else:
+ print("Ooops, we're offline!")
+ file.log_write("OFFLINE >> RESETING INTERFACE [{}]".format(INTERFACE))
+ print(">> Reseting interface [{}]...".format(INTERFACE))
+ ip, gateway, subnet = commands.uqmi_current_settings()
+ commands.ifconfig_update(INTERFACE, ip, subnet)
+ commands.route_update(gateway)
+elif len(sys.argv) == 2:
+ if sys.argv[1] == "tail":
+ log.tail_log()
+ for line in tailhead.follow_path(LOG_PATH_FILE):
+ if line is not None:
+ print(tools.status_color(line))
+ else:
+ time.sleep(1)
+ elif sys.argv[1] == "cat":
+ log.tail_log()
+ with open(LOG_PATH_FILE) as f:
+ for line in f:
+ print(tools.status_color(line), end="")
+ else:
+ tools.show_help()
+else:
+ tools.show_help()
+
+
diff --git a/tools.py b/tools.py
new file mode 100644
index 0000000..862f15d
--- /dev/null
+++ b/tools.py
@@ -0,0 +1,37 @@
+#/bin/python3
+
+import sys
+import re
+import colorama
+from termcolor import colored
+colorama.init()
+
+from collections import Counter
+
+import commands
+
+def offline_counts(file):
+ counts = Counter()
+ for sentence in commands.tail(file, 4):
+ counts.update(word.strip('.,?!"\'').upper() for word in sentence.decode('utf-8').split())
+ return counts["OFFLINE"]
+
+def show_help():
+ print("{} [command]".format(sys.argv[0]))
+ print("{} Check internet status, log status in file and, if\n {}needed, restart interface.".format(sys.argv[0], " " * len(sys. argv[0])))
+ print("{} tail Follow log file like tail command".format(sys.argv[0]))
+ print("{} cat Like cat command".format(sys.argv[0]))
+
+offline = re.compile(r'.*OFFLINE.*', re.IGNORECASE)
+online = re.compile(r'.*ONLINE.*', re.IGNORECASE)
+
+def status_color(str_line):
+ if type(str_line) is bytes:
+ str_line = str_line.decode('utf-8')
+ if offline.search(str_line):
+ return colored(str_line, 'red')
+ elif online.search(str_line):
+ return colored(str_line, 'green')
+ else:
+ return str_line
+