This commit is contained in:
2025-01-13 14:04:52 +03:00
commit 83d031600e
13 changed files with 288 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
# created by virtualenv automatically
.idea
config/main_local.py
bin
lib
View File
Binary file not shown.
Binary file not shown.
+4
View File
@@ -0,0 +1,4 @@
pool = [
("demo-23", "3000"),
("demo-22", "3001")
]
+194
View File
@@ -0,0 +1,194 @@
"""Generic linux daemon base class for python 3.x."""
import sys, os, time, atexit, signal, logging
class Daemon:
"""A generic daemon class.
Usage: subclass the daemon class and override the run() method."""
def __init__(self, pidfile, error_log_file='/dev/null'):
self.logging = logging
self.logging.basicConfig(filename=error_log_file, filemode='w',
format='%(name)s - %(levelname)s - %(message)s\n')
self.logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
self.error_log_file = error_log_file
self.pidfile = pidfile
self.commands = {}
def __enter__(self):
self.base_commands()
self.reg_command()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
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))
self.logging.error('fork #1 failed: {0}\n'.format(err))
sys.exit(1)
# decouple from parent environment
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))
self.logging.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')
so = open(os.devnull, 'a+')
se = open(os.devnull, 'a+')
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
# write pidfile
atexit.register(self.delpid)
pid = str(os.getpid())
with open(self.pidfile, 'w+') as f:
f.write(pid + '\n')
def delpid(self):
os.remove(self.pidfile)
def start(self):
"""Start the daemon."""
self.logging.info("Start")
# Check for a pidfile to see if the daemon already runs
try:
with open(self.pidfile, 'r') as pf:
pid = int(pf.read().strip())
except IOError:
pid = None
if pid:
message = "pidfile {0} already exist. " + \
"Daemon already running?\n"
sys.stderr.write(message.format(self.pidfile))
self.logging.error(message.format(self.pidfile))
sys.exit(1)
# Start the daemon
self.daemonize()
self.run()
def stop(self):
"""Stop the daemon."""
self.logging.info("Stop")
# Get the pid from the pidfile
try:
with open(self.pidfile, 'r') as pf:
pid = int(pf.read().strip())
except IOError:
pid = None
if not pid:
message = "pidfile {0} does not exist. " + \
"Daemon not running?\n"
sys.stderr.write(message.format(self.pidfile))
self.logging.error(message.format(self.pidfile))
return # not an error in a restart
# Try killing the daemon process
try:
while 1:
os.kill(pid, signal.SIGTERM)
time.sleep(0.1)
except OSError as err:
e = str(err.args)
if e.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print(str(err.args))
sys.exit(1)
def restart(self):
"""Restart the daemon."""
self.logging.info("Restart")
self.stop()
self.start()
def status(self):
print("Status")
try:
with open(self.pidfile, 'r') as pf:
pid = int(pf.read().strip())
except IOError:
pid = None
if pid:
print("Process started, pid %d" % pid)
else:
print("Process is not running")
def console_stdout(self):
sys.stdout = sys.__stdout__
print(123)
def process_command(self):
if len(sys.argv) > 1:
command = sys.argv[1]
handler = self.get_command_handler(command)
if handler:
handler()
else:
print("Unknown command: %s" % command)
else:
print("usage: %s start|stop|restart|status" % sys.argv[0])
sys.exit(2)
def base_commands(self):
self.add_command('start', self.start)
self.add_command('stop', self.stop)
self.add_command('restart', self.restart)
self.add_command('status', self.status)
self.add_command('console_stdout', self.console_stdout)
def add_command(self, command, handler):
if command not in self.commands:
self.commands[command] = handler
def get_command_handler(self, command):
if command in self.commands:
return self.commands[command]
return None
def reg_command(self):
pass
def run(self):
"""You should override this method when you subclass Daemon.
It will be called after the process has been daemonized by
start() or restart()."""
View File
Binary file not shown.
Binary file not shown.
View File
+63
View File
@@ -0,0 +1,63 @@
from http.server import BaseHTTPRequestHandler, HTTPServer
from http.client import HTTPMessage
import requests
from config.main_local import pool
from daemon.SimpleDaemon import Daemon
hostName = "localhost"
serverPort = 9000
class FrontDemoDaemon(Daemon):
def run(self):
webServer = HTTPServer((hostName, serverPort), MyServer)
print(f"Server started http://{hostName}:{serverPort}")
try:
webServer.serve_forever()
except KeyboardInterrupt:
pass
webServer.server_close()
print("Http server stopped.")
class MyServer(BaseHTTPRequestHandler):
def do_GET(self):
host = get_host_from_headers(self.headers)
subdomain = get_subdomain(host)
port = get_port(subdomain)
url = 'http://localhost:{port}{path}'.format(path=self.path, port=port)
response = requests.get(url)
self.send_response(200)
self.send_header("Content-type", response.headers.get("Content-type"))
self.end_headers()
self.wfile.write(bytes(response.text, "utf-8"))
def get_host_from_headers(headers: HTTPMessage):
for item in headers.items():
if item[0] == "Host":
return item[1]
return None
def get_subdomain(host: str):
res = host.split(sep=".", maxsplit=-1)
if res[0]:
return res[0]
return None
def get_port(subdomain: str):
for item in pool:
if item[0] == subdomain:
return item[1]
return None
if __name__ == "__main__":
with FrontDemoDaemon('/tmp/front-demo-daemon.pid', error_log_file='/var/log/front-demo-daemon.txt') as front:
front.process_command()
+8
View File
@@ -0,0 +1,8 @@
home = /usr/bin
implementation = CPython
version_info = 3.10.12.final.0
virtualenv = 20.24.5
include-system-site-packages = false
base-prefix = /usr
base-exec-prefix = /usr
base-executable = /usr/bin/python3.10
+14
View File
@@ -0,0 +1,14 @@
blinker==1.9.0
certifi==2024.12.14
charset-normalizer==3.4.1
click==8.1.8
filelock==3.16.1
idna==3.10
itsdangerous==2.2.0
MarkupSafe==3.0.2
python-magic==0.4.27
requests==2.32.3
requests-file==2.1.0
tldextract==5.1.3
urllib3==2.3.0
Werkzeug==3.1.3