Refactoring, Cleanups and prepared a new directory structure

This commit is contained in:
Johannes Findeisen 2021-12-27 21:04:49 +01:00
commit 3966cd0e0f
12 changed files with 54 additions and 19 deletions

View file

@ -61,6 +61,8 @@ Edit config.json to your needs.
TODO
For now there is only the file uplink.sql which will create the tables in your MariaDB/MySQL database.
The file is under files/uplink.sql
## Usage
./uplink [-c | -d | -f] ./config.json
@ -98,10 +100,9 @@ There will be a Gtk+ frontend to uplink at some time but this project is at a ve
- A lot... :)
- Make all config vars as ARGS and vice versa. ARGS have higher priority. Chain: default -> config -> ARGS.
- Bring back SQLite support.
- Switch to ORM (peewee, sqlalchemy?) to support PostgreSQL, MariaDB/MySQL, SQLite and more.
- Switch to ORM (peewee, sqlalchemy?) to support PostgreSQL, MariaDB/MySQL, SQLite and maybe more databases.
- Gtk+/urwid frontend for visualizing the collected data. wxGlade?
- A tool to generate reports for showing to your uplink provider.
- Always keep platform independence in mind but not if uplink looses nice features on Linux.
- Implement a speedtest feature to regularly run speedtest but independent to uptime checks with different interval.
- A small embedded webserver to view what is going on.
- Real file based logging

1
__init__.py Normal file
View file

@ -0,0 +1 @@
from uplink import Uplink

0
bin/.gitkeep Normal file
View file

1
bin/__init__.py Normal file
View file

@ -0,0 +1 @@
import ../uplink/uplink

0
files/.gitkeep Normal file
View file

0
uplink.playground.py → files/uplink.playground.py Normal file → Executable file
View file

View file

@ -35,8 +35,8 @@ from uplink.uplink import Uplink
__version__ = "0.5.0-development"
# TODO: CHECK ALL ERROR HANDLING!!!
# TODO: IDEA: Implement a small webserver inline to get statistics and graphs over the network? Or maybe better as a
# separate daemon
# TODO: IDEA: Implement a small webserver inline to get statistics and graphs over the network?
# Or maybe better as a separate daemon
# TODO: Make use of more args passed to the script
# TODO: Implement a speedtest that will also run regularly but in an individual interval
@ -79,7 +79,7 @@ def parse_args():
help="maximum number of logfiles in rotation (default: 5)")
parser.add_argument("-m", "--logsize", default=10485760, type=int,
help="maximum logfile size in bytes (default: 10485760)")
help="maximum logfile size in bytes (default: 1048576)")
parser.add_argument("-s", "--stdout", default=False, dest="stdout", action="store_true",
help="log to stdout")
@ -127,7 +127,6 @@ def main():
root_logger.setLevel(args.loglevel)
# TODO: Cleanup config.json and only define what really is needed
config_path = args.config
try:
with open(config_path, 'r', encoding='utf-8') as configfile:
@ -162,7 +161,7 @@ def main():
t.start()
try:
time.sleep(config["interval"])
except KeyboardInterrupt as err:
except KeyboardInterrupt:
logger.info(str("uplink: program terminated by user!"))
sys.exit(0)
else:

View file

@ -1,5 +0,0 @@
"""
uplink
library for the uplink project
"""

View file

@ -1,4 +1,6 @@
"""
Generic linux daemon base class for python 3.x.
Original Source:
https://web.archive.org/web/20131017130434/http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
https://web.archive.org/web/20131017130434/http://www.jejik.com/files/examples/daemon3x.py
@ -9,40 +11,57 @@ https://franklingu.github.io/programming/2016/03/01/creating-daemon-process-pyth
https://dpbl.wordpress.com/2017/02/12/a-tutorial-on-python-daemon/
"""
from logging import getLogger
import sys
import os
import time
import atexit
import signal
logger = getLogger(__name__)
# TODO: Check why pid files are not being deleted when sending the TERM signal
class Daemon:
"""
A generic daemon class.
Usage: subclass the daemon class and override the run() method.
"""
def __init__(self, pid_file):
self.pid_file = pid_file
def daemonize(self):
"""
Deamonize class. UNIX double fork mechanism.
"""
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError as err:
sys.stderr.write('fork #1 failed: {0}\n'.format(err))
logger.error('fork #1 failed: {0}\n'.format(err))
sys.exit(1)
# decouple from parent environme
os.chdir('/')
os.setsid()
os.umask(0)
# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError as err:
sys.stderr.write('fork #2 failed: {0}\n'.format(err))
logger.error('fork #2 failed: {0}\n'.format(err))
sys.exit(1)
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = open(os.devnull, 'r')
@ -53,6 +72,7 @@ class Daemon:
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
# write pidfile
atexit.register(self.del_pid)
pid = str(os.getpid())
@ -63,6 +83,11 @@ class Daemon:
os.remove(self.pid_file)
def start(self):
"""
Start the daemon.
"""
# Check for a pidfile to see if the daemon already runs
try:
with open(self.pid_file, 'r') as pf:
pid = int(pf.read().strip())
@ -71,13 +96,19 @@ class Daemon:
if pid:
message = "pid_file {0} already exist. Daemon already running?\n"
sys.stderr.write(message.format(self.pid_file))
logger.error(message.format(self.pid_file))
sys.exit(1)
# Start the daemon
self.daemonize()
self.run()
def stop(self):
"""
Stop the daemon.
"""
# Get the pid from the pidfile
try:
with open(self.pid_file, 'r') as pf:
pid = int(pf.read().strip())
@ -86,9 +117,11 @@ class Daemon:
if not pid:
message = "pid_file {0} does not exist. Daemon not running?\n"
sys.stderr.write(message.format(self.pid_file))
logger.error(message.format(self.pid_file))
# not an error in a restart
return
# Try killing the daemon process
try:
while 1:
os.kill(pid, signal.SIGTERM)
@ -99,14 +132,19 @@ class Daemon:
if os.path.exists(self.pid_file):
os.remove(self.pid_file)
else:
print(str(err.args))
logger.error(str(err.args))
sys.exit(1)
def restart(self):
"""
Restart the daemon.
"""
self.stop()
self.start()
def run(self):
"""Override this method when you subclass Daemon.
"""
Override this method when you subclass Daemon.
It will be called after the process has been daemonized by
start() or restart()."""
start() or restart().
"""