From 77e545d0fea7d000fd0ec77436b24562b419580d Mon Sep 17 00:00:00 2001 From: simonmicro Date: Fri, 9 Dec 2022 19:37:18 +0100 Subject: [PATCH] Removed Etrigan support --- .gitignore | 1 - docs/Getting Started.md | 4 - py-kms/Etrigan.py | 609 ---------------------------------------- py-kms/pykms_Server.py | 134 ++------- 4 files changed, 16 insertions(+), 732 deletions(-) delete mode 100644 py-kms/Etrigan.py diff --git a/.gitignore b/.gitignore index 874f86a..6f4050f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ pykms_logserver.log* pykms_logclient.log* pykms_database.db* -etrigan.log* # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/docs/Getting Started.md b/docs/Getting Started.md index 6669c26..129a674 100644 --- a/docs/Getting Started.md +++ b/docs/Getting Started.md @@ -91,10 +91,6 @@ Check syntax with `sudo systemd-analyze verify py3-kms.service`, correct file pe start the daemon `sudo systemctl start py3-kms.service` and view its status `sudo systemctl status py3-kms.service`. Check if daemon is correctly running with `cat /pykms_logserver.log`. Finally a few generic commands useful for interact with your daemon [here](https://linoxide.com/linux-how-to/enable-disable-services-ubuntu-systemd-upstart/). -### Etrigan (deprecated) -You can run py-kms daemonized (via [Etrigan](https://github.com/SystemRage/Etrigan)) using a command like `python3 pykms_Server.py etrigan start` and stop it with `python3 pykms_Server.py etrigan stop`. With Etrigan you have another -way to launch py-kms GUI (specially suitable if you're using a virtualenv), so `python3 pykms_Server.py etrigan start -g` and stop the GUI with `python3 pykms_Server.py etrigan stop` (or interact with the `EXIT` button). - ### Upstart (deprecated) If you are running a Linux distro using `upstart` (deprecated), create the file: `sudo nano /etc/init/py3-kms.conf`, then add the following (change it where needed) and save: ``` diff --git a/py-kms/Etrigan.py b/py-kms/Etrigan.py deleted file mode 100644 index c9cf193..0000000 --- a/py-kms/Etrigan.py +++ /dev/null @@ -1,609 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import atexit -import errno -import os -import sys -import time -import signal -import logging -import argparse -from collections.abc import Sequence - -__version__ = "0.1" -__license__ = "MIT License" -__author__ = u"Matteo ℱan " -__copyright__ = "© Copyright 2020" -__url__ = "https://github.com/SystemRage/Etrigan" -__description__ = "Etrigan: a python daemonizer that rocks." - - -class Etrigan(object): - """ - Daemonizer based on double-fork method - -------------------------------------- - Each option can be passed as a keyword argument or modified by assigning - to an attribute on the instance: - - jasonblood = Etrigan(pidfile, - argument_example_1 = foo, - argument_example_2 = bar) - - that is equivalent to: - - jasonblood = Etrigan(pidfile) - jasonblood.argument_example_1 = foo - jasonblood.argument_example_2 = bar - - Object constructor expects always `pidfile` argument. - `pidfile` - Path to the pidfile. - - The following other options are defined: - `stdin` - `stdout` - `stderr` - :Default: `os.devnull` - File objects used as the new file for the standard I/O streams - `sys.stdin`, `sys.stdout`, and `sys.stderr` respectively. - - `funcs_to_daemonize` - :Default: `[]` - Define a list of your custom functions - which will be executed after daemonization. - If None, you have to subclass Etrigan `run` method. - Note that these functions can return elements that will be - added to Etrigan object (`etrigan_add` list) so the other subsequent - ones can reuse them for further processing. - You only have to provide indexes of `etrigan_add` list, - (an int (example: 2) for single index or a string (example: '1:4') for slices) - as first returning element. - - `want_quit` - :Default: `False` - If `True`, runs Etrigan `quit_on_start` or `quit_on_stop` - lists of your custom functions at the end of `start` or `stop` operations. - These can return elements as `funcs_to_daemonize`. - - `logfile` - :Default: `None` - Path to the output log file. - - `loglevel` - :Default: `None` - Set the log level of logging messages. - - `mute` - :Default: `False` - Disable all stdout and stderr messages (before double forking). - - `pause_loop` - :Default: `None` - Seconds of pause between the calling, in an infinite loop, - of every function in `funcs_to_daemonize` list. - If `-1`, no pause between the calling, in an infinite loop, - of every function in `funcs_to_daemonize` list. - If `None`, only one run (no infinite loop) of functions in - `funcs_to_daemonize` list, without pause. - """ - - def __init__(self, pidfile, - stdin = os.devnull, stdout = os.devnull, stderr = os.devnull, - funcs_to_daemonize = [], want_quit = False, - logfile = None, loglevel = None, - mute = False, pause_loop = None): - - self.pidfile = pidfile - self.funcs_to_daemonize = funcs_to_daemonize - self.stdin = stdin - self.stdout = stdout - self.stderr = stderr - self.logfile = logfile - self.loglevel = loglevel - self.mute = mute - self.want_quit = want_quit - self.pause_loop = pause_loop - # internal only. - self.homedir = '/' - self.umask = 0o22 - self.etrigan_restart, self.etrigan_reload = (False for _ in range(2)) - self.etrigan_alive = True - self.etrigan_add = [] - self.etrigan_index = None - # seconds of pause between stop and start during the restart of the daemon. - self.pause_restart = 5 - # when terminate a process, seconds to wait until kill the process with signal. - # self.pause_kill = 3 - - # create logfile. - self.setup_files() - - def handle_terminate(self, signum, frame): - if os.path.exists(self.pidfile): - self.etrigan_alive = False - # eventually run quit (on stop) function/s. - if self.want_quit: - if not isinstance(self.quit_on_stop, (list, tuple)): - self.quit_on_stop = [self.quit_on_stop] - self.execute(self.quit_on_stop) - # then always run quit standard. - self.quit_standard() - else: - self.view(self.logdaemon.error, self.emit_error, "Failed to stop the daemon process: can't find PIDFILE '%s'" %self.pidfile) - sys.exit(0) - - def handle_reload(self, signum, frame): - self.etrigan_reload = True - - def setup_files(self): - self.pidfile = os.path.abspath(self.pidfile) - - if self.logfile is not None: - self.logdaemon = logging.getLogger('logdaemon') - self.logdaemon.setLevel(self.loglevel) - - filehandler = logging.FileHandler(self.logfile) - filehandler.setLevel(self.loglevel) - formatter = logging.Formatter(fmt = '[%(asctime)s] [%(levelname)8s] --- %(message)s', - datefmt = '%Y-%m-%d %H:%M:%S') - filehandler.setFormatter(formatter) - self.logdaemon.addHandler(filehandler) - else: - nullhandler = logging.NullHandler() - self.logdaemon.addHandler(nullhandler) - - def emit_error(self, message, to_exit = True): - """ Print an error message to STDERR. """ - if not self.mute: - sys.stderr.write(message + '\n') - sys.stderr.flush() - if to_exit: - sys.exit(1) - - def emit_message(self, message, to_exit = False): - """ Print a message to STDOUT. """ - if not self.mute: - sys.stdout.write(message + '\n') - sys.stdout.flush() - if to_exit: - sys.exit(0) - - def view(self, logobj, emitobj, msg, **kwargs): - options = {'to_exit' : False, - 'silent' : False - } - options.update(kwargs) - - if logobj: - logobj(msg) - if emitobj: - if not options['silent']: - emitobj(msg, to_exit = options['to_exit']) - - def daemonize(self): - """ - Double-forks the process to daemonize the script. - see Stevens' "Advanced Programming in the UNIX Environment" for details (ISBN 0201563177) - http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 - """ - self.view(self.logdaemon.debug, None, "Attempting to daemonize the process...") - - # First fork. - self.fork(msg = "First fork") - # Decouple from parent environment. - self.detach() - # Second fork. - self.fork(msg = "Second fork") - # Write the PID file. - self.create_pidfile() - self.view(self.logdaemon.info, self.emit_message, "The daemon process has started.") - # Redirect standard file descriptors. - sys.stdout.flush() - sys.stderr.flush() - self.attach('stdin', mode = 'r') - self.attach('stdout', mode = 'a+') - - try: - self.attach('stderr', mode = 'a+', buffering = 0) - except ValueError: - # Python 3 can't have unbuffered text I/O. - self.attach('stderr', mode = 'a+', buffering = 1) - - # Handle signals. - signal.signal(signal.SIGINT, self.handle_terminate) - signal.signal(signal.SIGTERM, self.handle_terminate) - signal.signal(signal.SIGHUP, self.handle_reload) - #signal.signal(signal.SIGKILL....) - - def fork(self, msg): - try: - pid = os.fork() - if pid > 0: - self.view(self.logdaemon.debug, None, msg + " success with PID %d." %pid) - # Exit from parent. - sys.exit(0) - except Exception as e: - msg += " failed: %s." %str(e) - self.view(self.logdaemon.error, self.emit_error, msg) - - def detach(self): - # cd to root for a guarenteed working dir. - try: - os.chdir(self.homedir) - except Exception as e: - msg = "Unable to change working directory: %s." %str(e) - self.view(self.logdaemon.error, self.emit_error, msg) - - # clear the session id to clear the controlling tty. - pid = os.setsid() - if pid == -1: - sys.exit(1) - - # set the umask so we have access to all files created by the daemon. - try: - os.umask(self.umask) - except Exception as e: - msg = "Unable to change file creation mask: %s." %str(e) - self.view(self.logdaemon.error, self.emit_error, msg) - - def attach(self, name, mode, buffering = -1): - with open(getattr(self, name), mode, buffering) as stream: - os.dup2(stream.fileno(), getattr(sys, name).fileno()) - - def checkfile(self, path, typearg, typefile): - filename = os.path.basename(path) - pathname = os.path.dirname(path) - if not os.path.isdir(pathname): - msg = "argument %s: invalid directory: '%s'. Exiting..." %(typearg, pathname) - self.view(self.logdaemon.error, self.emit_error, msg) - elif not filename.lower().endswith(typefile): - msg = "argument %s: not a %s file, invalid extension: '%s'. Exiting..." %(typearg, typefile, filename) - self.view(self.logdaemon.error, self.emit_error, msg) - - def create_pidfile(self): - atexit.register(self.delete_pidfile) - pid = os.getpid() - try: - with open(self.pidfile, 'w+') as pf: - pf.write("%s\n" %pid) - self.view(self.logdaemon.debug, None, "PID %d written to '%s'." %(pid, self.pidfile)) - except Exception as e: - msg = "Unable to write PID to PIDFILE '%s': %s" %(self.pidfile, str(e)) - self.view(self.logdaemon.error, self.emit_error, msg) - - def delete_pidfile(self, pid): - # Remove the PID file. - try: - os.remove(self.pidfile) - self.view(self.logdaemon.debug, None, "Removing PIDFILE '%s' with PID %d." %(self.pidfile, pid)) - except Exception as e: - if e.errno != errno.ENOENT: - self.view(self.logdaemon.error, self.emit_error, str(e)) - - def get_pidfile(self): - # Get the PID from the PID file. - if self.pidfile is None: - return None - if not os.path.isfile(self.pidfile): - return None - - try: - with open(self.pidfile, 'r') as pf: - pid = int(pf.read().strip()) - self.view(self.logdaemon.debug, None, "Found PID %d in PIDFILE '%s'" %(pid, self.pidfile)) - except Exception as e: - self.view(self.logdaemon.warning, None, "Empty or broken PIDFILE") - pid = None - - def pid_exists(pid): - # psutil _psposix.py. - if pid == 0: - return True - try: - os.kill(pid, 0) - except OSError as e: - if e.errno == errno.ESRCH: - return False - elif e.errno == errno.EPERM: - return True - else: - self.view(self.logdaemon.error, self.emit_error, str(e)) - else: - return True - - if pid is not None and pid_exists(pid): - return pid - else: - # Remove the stale PID file. - self.delete_pidfile(pid) - return None - - def start(self): - """ Start the daemon. """ - self.view(self.logdaemon.info, self.emit_message, "Starting the daemon process...", silent = self.etrigan_restart) - - # Check for a PID file to see if the Daemon is already running. - pid = self.get_pidfile() - if pid is not None: - msg = "A previous daemon process with PIDFILE '%s' already exists. Daemon already running ?" %self.pidfile - self.view(self.logdaemon.warning, self.emit_error, msg, to_exit = False) - return - - # Daemonize the main process. - self.daemonize() - # Start a infinitive loop that periodically runs `funcs_to_daemonize`. - self.loop() - # eventualy run quit (on start) function/s. - if self.want_quit: - if not isinstance(self.quit_on_start, (list, tuple)): - self.quit_on_start = [self.quit_on_start] - self.execute(self.quit_on_start) - - def stop(self): - """ Stop the daemon. """ - self.view(None, self.emit_message, "Stopping the daemon process...", silent = self.etrigan_restart) - - self.logdaemon.disabled = True - pid = self.get_pidfile() - self.logdaemon.disabled = False - if not pid: - # Just to be sure. A ValueError might occur - # if the PIDFILE is empty but does actually exist. - if os.path.exists(self.pidfile): - self.delete_pidfile(pid) - - msg = "Can't find the daemon process with PIDFILE '%s'. Daemon not running ?" %self.pidfile - self.view(self.logdaemon.warning, self.emit_error, msg, to_exit = False) - return - - # Try to kill the daemon process. - try: - while True: - os.kill(pid, signal.SIGTERM) - time.sleep(0.1) - except Exception as e: - if (e.errno != errno.ESRCH): - self.view(self.logdaemon.error, self.emit_error, "Failed to stop the daemon process: %s" %str(e)) - else: - self.view(None, self.emit_message, "The daemon process has ended correctly.", silent = self.etrigan_restart) - - def restart(self): - """ Restart the daemon. """ - self.view(self.logdaemon.info, self.emit_message, "Restarting the daemon process...") - self.etrigan_restart = True - self.stop() - if self.pause_restart: - time.sleep(self.pause_restart) - self.etrigan_alive = True - self.start() - - def reload(self): - pass - - def status(self): - """ Get status of the daemon. """ - self.view(self.logdaemon.info, self.emit_message, "Viewing the daemon process status...") - - if self.pidfile is None: - self.view(self.logdaemon.error, self.emit_error, "Cannot get the status of daemon without PIDFILE.") - - pid = self.get_pidfile() - if pid is None: - self.view(self.logdaemon.info, self.emit_message, "The daemon process is not running.", to_exit = True) - else: - try: - with open("/proc/%d/status" %pid, 'r') as pf: - pass - self.view(self.logdaemon.info, self.emit_message, "The daemon process is running.", to_exit = True) - except Exception as e: - msg = "There is not a process with the PIDFILE '%s': %s" %(self.pidfile, str(e)) - self.view(self.logdaemon.error, self.emit_error, msg) - - def flatten(self, alistoflists, ltypes = Sequence): - # https://stackoverflow.com/questions/2158395/flatten-an-irregular-list-of-lists/2158532#2158532 - alistoflists = list(alistoflists) - while alistoflists: - while alistoflists and isinstance(alistoflists[0], ltypes): - alistoflists[0:1] = alistoflists[0] - if alistoflists: yield alistoflists.pop(0) - - def exclude(self, func): - from inspect import getargspec - args = getargspec(func) - if callable(func): - try: - args[0].pop(0) - except IndexError: - pass - return args - else: - self.view(self.logdaemon.error, self.emit_error, "Not a function.") - return - - def execute(self, some_functions): - returned = None - if isinstance(some_functions, (list, tuple)): - for func in some_functions: - l_req = len(self.exclude(func)[0]) - - if l_req == 0: - returned = func() - else: - l_add = len(self.etrigan_add) - if l_req > l_add: - self.view(self.logdaemon.error, self.emit_error, - "Can't evaluate function: given %s, required %s." %(l_add, l_req)) - return - else: - arguments = self.etrigan_add[self.etrigan_index] - l_args = (len(arguments) if isinstance(arguments, list) else 1) - if (l_args > l_req) or (l_args < l_req): - self.view(self.logdaemon.error, self.emit_error, - "Can't evaluate function: given %s, required %s." %(l_args, l_req)) - return - else: - if isinstance(arguments, list): - returned = func(*arguments) - else: - returned = func(arguments) - - if returned: - if isinstance(returned, (list, tuple)): - if isinstance(returned[0], int): - self.etrigan_index = returned[0] - else: - self.etrigan_index = slice(*map(int, returned[0].split(':'))) - if returned[1:] != []: - self.etrigan_add.append(returned[1:]) - self.etrigan_add = list(self.flatten(self.etrigan_add)) - else: - self.view(self.logdaemon.error, self.emit_error, "Function should return list or tuple.") - returned = None - else: - if some_functions is None: - self.run() - - def loop(self): - try: - if self.pause_loop is None: - # one-shot. - self.execute(self.funcs_to_daemonize) - else: - if self.pause_loop >= 0: - # infinite with pause. - time.sleep(self.pause_loop) - while self.etrigan_alive: - self.execute(self.funcs_to_daemonize) - time.sleep(self.pause_loop) - elif self.pause_loop == -1: - # infinite without pause. - while self.etrigan_alive: - self.execute(self.funcs_to_daemonize) - except Exception as e: - msg = "The daemon process start method failed: %s" %str(e) - self.view(self.logdaemon.error, self.emit_error, msg) - - def quit_standard(self): - self.view(self.logdaemon.info, None, "Stopping the daemon process...") - self.delete_pidfile(self.get_pidfile()) - self.view(self.logdaemon.info, None, "The daemon process has ended correctly.") - - def quit_on_start(self): - """ - Override this method when you subclass Daemon. - """ - self.quit_standard() - - def quit_on_stop(self): - """ - Override this method when you subclass Daemon. - """ - pass - - def run(self): - """ - Override this method when you subclass Daemon. - It will be called after the process has been - daemonized by start() or restart(). - """ - pass - -#----------------------------------------------------------------------------------------------------------------------------------------------------------- - -class JasonBlood(Etrigan): - def run(self): - jasonblood_func() - -def jasonblood_func(): - with open(os.path.join('.', 'etrigan_test.txt'), 'a') as file: - file.write("Yarva Demonicus Etrigan " + time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()) + '\n') - -def Etrigan_parser(parser = None): - if parser is None: - # create a new parser. - parser = argparse.ArgumentParser(description = __description__, epilog = __version__) - if not parser.add_help: - # create help argument. - parser.add_argument("-h", "--help", action = "help", help = "show this help message and exit") - - # attach to an existent parser. - parser.add_argument("operation", action = "store", choices = ["start", "stop", "restart", "status", "reload"], - help = "Select an operation for daemon.", type = str) - parser.add_argument("--etrigan-pid", - action = "store", dest = "etriganpid", default = "/tmp/etrigan.pid", - help = "Choose a pidfile path. Default is \"/tmp/etrigan.pid\".", type = str) #'/var/run/etrigan.pid' - parser.add_argument("--etrigan-log", - action = "store", dest = "etriganlog", default = os.path.join('.', "etrigan.log"), - help = "Use this option to choose an output log file; for not logging don't select it. Default is \"etrigan.log\".", type = str) - parser.add_argument("--etrigan-lev", - action = "store", dest = "etriganlev", default = "DEBUG", - choices = ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"], - help = "Use this option to set a log level. Default is \"DEBUG\".", type = str) - parser.add_argument("--etrigan-mute", - action = "store_const", dest = 'etriganmute', const = True, default = False, - help = "Disable all stdout and stderr messages.") - return parser - -class Etrigan_check(object): - def emit_opt_err(self, msg): - print(msg) - sys.exit(1) - - def checkfile(self, path, typearg, typefile): - filename, extension = os.path.splitext(path) - pathname = os.path.dirname(path) - if not os.path.isdir(pathname): - msg = "argument `%s`: invalid directory: '%s'. Exiting..." %(typearg, pathname) - self.emit_opt_err(msg) - elif not extension == typefile: - msg = "argument `%s`: not a %s file, invalid extension: '%s'. Exiting..." %(typearg, typefile, extension) - self.emit_opt_err(msg) - - def checkfunction(self, funcs, booleans): - if not isinstance(funcs, (list, tuple)): - if funcs is not None: - msg = "argument `funcs_to_daemonize`: provide list, tuple or None" - self.emit_opt_err(msg) - - for elem in booleans: - if not type(elem) == bool: - msg = "argument `want_quit`: not a boolean." - self.emit_opt_err(msg) - -def Etrigan_job(type_oper, daemon_obj): - Etrigan_check().checkfunction(daemon_obj.funcs_to_daemonize, - [daemon_obj.want_quit]) - if type_oper == "start": - daemon_obj.start() - elif type_oper == "stop": - daemon_obj.stop() - elif type_oper == "restart": - daemon_obj.restart() - elif type_oper == "status": - daemon_obj.status() - elif type_oper == "reload": - daemon_obj.reload() - sys.exit(0) - -def main(): - # Parse arguments. - parser = Etrigan_parser() - args = vars(parser.parse_args()) - # Check arguments. - Etrigan_check().checkfile(args['etriganpid'], '--etrigan-pid', '.pid') - Etrigan_check().checkfile(args['etriganlog'], '--etrigan-log', '.log') - - # Setup daemon. - jasonblood_1 = Etrigan(pidfile = args['etriganpid'], logfile = args['etriganlog'], loglevel = args['etriganlev'], - mute = args['etriganmute'], - funcs_to_daemonize = [jasonblood_func], pause_loop = 5) - -## jasonblood_2 = JasonBlood(pidfile = args['etriganpid'], logfile = args['etriganlog'], loglevel = args['etriganlev'], -## mute = args['etriganmute'], -## funcs_to_daemonize = None, pause_loop = 5) - # Do job. - Etrigan_job(args['operation'], jasonblood_1) - -if __name__ == '__main__': - main() diff --git a/py-kms/pykms_Server.py b/py-kms/pykms_Server.py index 9d244de..80e549e 100755 --- a/py-kms/pykms_Server.py +++ b/py-kms/pykms_Server.py @@ -23,7 +23,6 @@ from pykms_Misc import check_setup, check_lcid, check_dir, check_other from pykms_Misc import KmsParser, KmsParserException, KmsParserHelp from pykms_Misc import kms_parser_get, kms_parser_check_optionals, kms_parser_check_positionals, kms_parser_check_connect from pykms_Format import enco, deco, pretty_printer, justify -from Etrigan import Etrigan, Etrigan_parser, Etrigan_check, Etrigan_job from pykms_Connect import MultipleListener srv_version = "py-kms_2020-10-01" @@ -256,15 +255,6 @@ def server_options(): server_parser.add_argument("-h", "--help", action = "help", help = "show this help message and exit") - ## Daemon (Etrigan) parsing. - daemon_parser = KmsParser(description = "daemon options inherited from Etrigan", add_help = False) - daemon_subparser = daemon_parser.add_subparsers(dest = "mode") - - etrigan_parser = daemon_subparser.add_parser("etrigan", add_help = False) - etrigan_parser.add_argument("-g", "--gui", action = "store_const", dest = 'gui', const = True, default = False, - help = "Enable py-kms GUI usage.") - etrigan_parser = Etrigan_parser(parser = etrigan_parser) - ## Connection parsing. connection_parser = KmsParser(description = "connect options", add_help = False) connection_subparser = connection_parser.add_subparsers(dest = "mode") @@ -284,16 +274,14 @@ def server_options(): # Run help. if any(arg in ["-h", "--help"] for arg in userarg): - KmsParserHelp().printer(parsers = [server_parser, (daemon_parser, etrigan_parser), - (connection_parser, connect_parser)]) + KmsParserHelp().printer(parsers = [server_parser, (connection_parser, connect_parser)]) # Get stored arguments. pykmssrv_zeroarg, pykmssrv_onearg = kms_parser_get(server_parser) - etrigan_zeroarg, etrigan_onearg = kms_parser_get(etrigan_parser) connect_zeroarg, connect_onearg = kms_parser_get(connect_parser) - subdict = {'etrigan' : (etrigan_zeroarg, etrigan_onearg, daemon_parser.parse_args), - 'connect' : (connect_zeroarg, connect_onearg, connection_parser.parse_args) - } + subdict = { + 'connect' : (connect_zeroarg, connect_onearg, connection_parser.parse_args) + } subpars = list(subdict.keys()) pykmssrv_zeroarg += subpars # add subparsers @@ -309,14 +297,7 @@ def server_options(): if subindx: # Set `daemon options` and/or `connect options` for server dict config. # example cases: - # 1 python3 pykms_Server.py [1.2.3.4] [1234] [--pykms_optionals] etrigan daemon_positional [--daemon_optionals] \ - # connect [--connect_optionals] - # - # 2 python3 pykms_Server.py [1.2.3.4] [1234] [--pykms_optionals] connect [--connect_optionals] etrigan \ - # daemon_positional [--daemon_optionals] - # - # 3 python3 pykms_Server.py [1.2.3.4] [1234] [--pykms_optionals] etrigan daemon_positional [--daemon_optionals] - # 4 python3 pykms_Server.py [1.2.3.4] [1234] [--pykms_optionals] connect [--connect_optionals] + # 1 python3 pykms_Server.py [1.2.3.4] [1234] [--pykms_optionals] connect [--connect_optionals] first = subindx[0][0] # initial. kms_parser_check_optionals(userarg[0 : first], pykmssrv_zeroarg, pykmssrv_onearg, exclude_opt_len = exclude_kms) @@ -338,7 +319,7 @@ def server_options(): else: # Update `pykms options` for server dict config. # example case: - # 5 python3 pykms_Server.py [1.2.3.4] [1234] [--pykms_optionals] + # 2 python3 pykms_Server.py [1.2.3.4] [1234] [--pykms_optionals] kms_parser_check_optionals(userarg, pykmssrv_zeroarg, pykmssrv_onearg, exclude_opt_len = exclude_kms) kms_parser_check_positionals(srv_config, server_parser.parse_args) @@ -347,63 +328,6 @@ def server_options(): except KmsParserException as e: pretty_printer(put_text = "{reverse}{red}{bold}%s. Exiting...{end}" %str(e), to_exit = True) -class Etrigan_Check(Etrigan_check): - def emit_opt_err(self, msg): - pretty_printer(put_text = "{reverse}{red}{bold}%s{end}" %msg, to_exit = True) - -class Etrigan(Etrigan): - def emit_message(self, message, to_exit = False): - if not self.mute: - pretty_printer(put_text = "{reverse}{green}{bold}%s{end}" %message) - if to_exit: - sys.exit(0) - - def emit_error(self, message, to_exit = True): - if not self.mute: - pretty_printer(put_text = "{reverse}{red}{bold}%s{end}" %message, to_exit = True) - -def server_daemon(): - if 'etrigan' in srv_config.values(): - path = os.path.join(gettempdir(), 'pykms_config.pickle') - - if srv_config['operation'] in ['stop', 'restart', 'status'] and len(sys.argv[1:]) > 2: - pretty_printer(put_text = "{reverse}{red}{bold}too much arguments with etrigan '%s'. Exiting...{end}" %srv_config['operation'], - to_exit = True) - - # Check file arguments. - Etrigan_Check().checkfile(srv_config['etriganpid'], '--etrigan-pid', '.pid') - Etrigan_Check().checkfile(srv_config['etriganlog'], '--etrigan-log', '.log') - - if srv_config['gui']: - pass - else: - if srv_config['operation'] == 'start': - with open(path, 'wb') as file: - pickle.dump(srv_config, file, protocol = pickle.HIGHEST_PROTOCOL) - elif srv_config['operation'] in ['stop', 'status', 'restart']: - with open(path, 'rb') as file: - old_srv_config = pickle.load(file) - old_srv_config = {x: old_srv_config[x] for x in old_srv_config if x not in ['operation']} - srv_config.update(old_srv_config) - - serverdaemon = Etrigan(srv_config['etriganpid'], - logfile = srv_config['etriganlog'], loglevel = srv_config['etriganlev'], - mute = srv_config['etriganmute'], pause_loop = None) - - if srv_config['operation'] in ['start', 'restart']: - serverdaemon.want_quit = True - if srv_config['gui']: - serverdaemon.funcs_to_daemonize = [server_with_gui] - else: - server_without_gui = ServerWithoutGui() - serverdaemon.funcs_to_daemonize = [server_without_gui.start, server_without_gui.join] - indx_for_clean = lambda: (0, ) - serverdaemon.quit_on_stop = [indx_for_clean, server_without_gui.clean] - elif srv_config['operation'] == 'stop': - os.remove(path) - - Etrigan_job(srv_config['operation'], serverdaemon) - def server_check(): # Setup and some checks. check_setup(srv_config, srv_options, loggersrv, where = "srv") @@ -543,35 +467,15 @@ def server_main_terminal(): server_check() serverthread.checked = True - if 'etrigan' not in srv_config.values(): - # (without GUI) and (without daemon). - # Run threaded server. - serverqueue.put('start') - # Wait to finish. - try: - while serverthread.is_alive(): - serverthread.join(timeout = 0.5) - except (KeyboardInterrupt, SystemExit): - server_terminate(serverthread, exit_server = True, exit_thread = True) - else: - # (with or without GUI) and (with daemon) - # Setup daemon (eventually). - pretty_printer(log_obj = loggersrv.warning, put_text = "{reverse}{yellow}{bold}Etrigan support is deprecated and will be removed in the future!{end}") - server_daemon() - -def server_with_gui(): - import pykms_GuiBase - - pretty_printer(log_obj = loggersrv.warning, put_text = "{reverse}{yellow}{bold}Etrigan GUI support is deprecated and will be removed in the future!{end}") - - root = pykms_GuiBase.KmsGui() - root.title(pykms_GuiBase.gui_description + ' (' + pykms_GuiBase.gui_version + ')') - root.mainloop() - -def server_main_no_terminal(): - # Run tkinter GUI. - # (with GUI) and (without daemon). - server_with_gui() + # (without GUI) and (without daemon). + # Run threaded server. + serverqueue.put('start') + # Wait to finish. + try: + while serverthread.is_alive(): + serverthread.join(timeout = 0.5) + except (KeyboardInterrupt, SystemExit): + server_terminate(serverthread, exit_server = True, exit_thread = True) class kmsServerHandler(socketserver.BaseRequestHandler): def setup(self): @@ -636,10 +540,4 @@ serverthread.daemon = True serverthread.start() if __name__ == "__main__": - if sys.stdout.isatty(): - server_main_terminal() - else: - try: - server_main_no_terminal() - except: - server_main_terminal() + server_main_terminal()