From 83d031600e7f8ba9595e061b484a5c536f866fc6 Mon Sep 17 00:00:00 2001 From: Kavalar Date: Mon, 13 Jan 2025 14:04:52 +0300 Subject: [PATCH] first --- .gitignore | 5 + config/__init__.py | 0 config/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 141 bytes config/__pycache__/main_local.cpython-310.pyc | Bin 0 -> 192 bytes config/main_example.py | 4 + daemon/SimpleDaemon.py | 194 ++++++++++++++++++ daemon/__init__.py | 0 .../__pycache__/SimpleDaemon.cpython-310.pyc | Bin 0 -> 5667 bytes daemon/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 141 bytes front-demo-daemon.txt | 0 main.py | 63 ++++++ pyvenv.cfg | 8 + requirements.txt | 14 ++ 13 files changed, 288 insertions(+) create mode 100644 .gitignore create mode 100644 config/__init__.py create mode 100644 config/__pycache__/__init__.cpython-310.pyc create mode 100644 config/__pycache__/main_local.cpython-310.pyc create mode 100644 config/main_example.py create mode 100644 daemon/SimpleDaemon.py create mode 100644 daemon/__init__.py create mode 100644 daemon/__pycache__/SimpleDaemon.cpython-310.pyc create mode 100644 daemon/__pycache__/__init__.cpython-310.pyc create mode 100644 front-demo-daemon.txt create mode 100644 main.py create mode 100644 pyvenv.cfg create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fc5796c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# created by virtualenv automatically +.idea +config/main_local.py +bin +lib diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/config/__pycache__/__init__.cpython-310.pyc b/config/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f065b15b6a6adad696ba703bc7ab8d2c2082ca90 GIT binary patch literal 141 zcmd1j<>g`k0=^F|=^*+sh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o6v2KQ}ccGf}@h zzbIS3pt2+*KTkicC_k?xJ|#6bUq3lNFD)}&KR!M)FS8^*Uaz3?7Kcr4eoARhsvXFr KVkRKL!Tg`k0{0Is>DEB{F^Gc(44TZEOjYbDsk!;O zM#i^Tj13G75CTSE0Yg7c##<}}`T0338H!kd`oY96BmLael*~l^^8BJ~{esGpjQl+P zw4(gHl6a75`pNluX_@Kzxrv#1@j3a)i8*=&mA5!-a`RJ4b5iXXL2h9K5=@Ltj2!;} DxxFrr literal 0 HcmV?d00001 diff --git a/config/main_example.py b/config/main_example.py new file mode 100644 index 0000000..505e255 --- /dev/null +++ b/config/main_example.py @@ -0,0 +1,4 @@ +pool = [ + ("demo-23", "3000"), + ("demo-22", "3001") +] \ No newline at end of file diff --git a/daemon/SimpleDaemon.py b/daemon/SimpleDaemon.py new file mode 100644 index 0000000..fb8bc33 --- /dev/null +++ b/daemon/SimpleDaemon.py @@ -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().""" diff --git a/daemon/__init__.py b/daemon/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/daemon/__pycache__/SimpleDaemon.cpython-310.pyc b/daemon/__pycache__/SimpleDaemon.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bf01adba151523b317196f0e1e1409791a6d28d4 GIT binary patch literal 5667 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 J2}rOo001%OAFu!b literal 0 HcmV?d00001 diff --git a/front-demo-daemon.txt b/front-demo-daemon.txt new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/main.py new file mode 100644 index 0000000..4ca3260 --- /dev/null +++ b/main.py @@ -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() diff --git a/pyvenv.cfg b/pyvenv.cfg new file mode 100644 index 0000000..2889eea --- /dev/null +++ b/pyvenv.cfg @@ -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 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3702b8c --- /dev/null +++ b/requirements.txt @@ -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