From 36a369086d45b40c82c41201b5b2b73316e4830d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Dausseur?= Date: Wed, 26 Apr 2023 16:54:37 +0200 Subject: [PATCH] =?UTF-8?q?wip=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pyappengine/{appengine.py => __init__.py} | 0 .../{commands.py => appengine/__init__.py} | 181 ++++++++++++------ 2 files changed, 127 insertions(+), 54 deletions(-) rename src/pyappengine/{appengine.py => __init__.py} (100%) rename src/pyappengine/{commands.py => appengine/__init__.py} (67%) diff --git a/src/pyappengine/appengine.py b/src/pyappengine/__init__.py similarity index 100% rename from src/pyappengine/appengine.py rename to src/pyappengine/__init__.py diff --git a/src/pyappengine/commands.py b/src/pyappengine/appengine/__init__.py similarity index 67% rename from src/pyappengine/commands.py rename to src/pyappengine/appengine/__init__.py index a447c40..d912527 100644 --- a/src/pyappengine/commands.py +++ b/src/pyappengine/appengine/__init__.py @@ -1,58 +1,15 @@ +#!/usr/bin/python3 + +import os +from configparser import ConfigParser +import logging +from systemd import journal +import inspect +from importlib import import_module +from threading import Thread, Lock + import inspect from threading import Thread -from unicodedata import numeric - -def is_number(s): - try: - float(s) - return True - except ValueError: - pass - return False - -class Commands(Thread): - defmod = None - - def __init__(self, config, log): - super().__init__() - self.threaded = False - self.cmods = {} - self.config = config - self.log = log - self.stopped = False - self.nickname = None - if not (self.config is None): - self.nickname = self.config.get('nickname') - - def val_to_print(self, val, dig=1): - if isinstance(val, str): - return val - if isinstance(val, float): - f = '{:.' + str(int(dig)) + 'f}' - return f.format(val) - else: - return str(val) - - - def info(self, msg): - if self.log: - self.log.info(msg) - else: - print('info: '+msg) - - def debug(self, msg): - if self.log: - self.log.debug(msg) - else: - print('debug: '+msg) - - def warning(self, msg): - if self.log: - self.log.warning(msg) - else: - print('warning: '+msg)import inspect -from threading import Thread -from unicodedata import numeric def is_number(s): try: @@ -322,4 +279,120 @@ class Commands(Thread): if ret == '': ret = 'No command with this name...' - return ret \ No newline at end of file + return ret + +class CommandsLoader: + def __init__(self, config: ConfigParser, log: logging.Handler, modpath: str): + self.config = config + self.modpath = modpath + Commands.defmod = self.config['general'].get('default') + self.log = log + self.lock = Lock() + self._load_commands() + self._set_cmods() + self._load_dependencies() + + def _load_commands(self): + cmds = {} + with os.scandir(self.modpath) as it: + for entry in it: + if entry.name.startswith('cmds_') and entry.name.endswith('.py') and entry.is_file(): + obj = self._load_module(entry.name[:-3]) + if not obj is None: + nmod = obj.nickname + if nmod is None: + nmod = (entry.name[:-3])[5:] + cmds.update({nmod: obj}) + self.log.info('module "{}" loaded'.format(nmod)) + else: + self.log.error( + 'The module "{}" could not be loaded'.format(entry.name[:-3])) + self.cmods = cmds + + def _load_module(self, name): + module = import_module("."+name, 'commands') + members = inspect.getmembers(module, inspect.isclass) + conf = None + if name[5:] in self.config.sections(): + conf = self.config[name[5:]] + + obj = None + for n, c in members: + if issubclass(c, Commands) and (n != 'Commands'): + obj = c(conf, self.log) + obj.log = self.log + obj.lock = self.lock + break + + return obj + + def _set_cmods(self): + for k, v in self.cmods.items(): + v.cmods = self.cmods + + def _load_dependencies(self): + for k, v in self.cmods.items(): + if hasattr(v, "dependencies"): + for p in v.dependencies: + if p in self.cmods.keys(): + setattr(v, p, self.cmods[p]) + else: + self.log.error( + 'Dependency "{}" of module "{}" could not be satisfied'.format(p, k)) + + def start(self): + for k, v in self.cmods.items(): + if v.threaded: + v.start() + + def join(self): + for k, v in self.cmods.items(): + if v.threaded: + v.join() + + +class AppEngine: + def __init__(self, app_name: str, conf_file : str="", log_file: str="", debug: bool=False) -> None: + self.app_name = app_name + self.conf = ConfigParser() + if conf_file != '': + self.parse_config(conf_file) + self.def_log(log_file) + + if debug: + self.log.setLevel(logging.DEBUG) + else: + self.log.setLevel(logging.WARNING) + + def parse_config(self, cf: str): + if os.path.exists(cf) and os.path.isfile(cf): + self.conf.read(cf) + else: + raise Exception('Configuration file not found') + + def def_log(self, log_file): + self.log = logging.getLogger(self.app_name) + if log_file != '': + fname = log_file + is_writeable = False + + if not os.path.isabs(fname): + fname = os.path.join(os.getcwd(), fname) + + if os.access(os.path.dirname(fname), os.W_OK): + is_writeable = True + + if is_writeable: + self.log.addHandler(logging.FileHandler(fname)) + else: + self.log.addHandler(journal.JournalHandler()) + self.log.error('No write permissions: "{}"'.format(fname)) + + else: + self.log.addHandler(journal.JournalHandler()) + + + def exec(self, modpath: str=""): + cl = CommandsLoader(self.conf, self.log, modpath) + cl.start() + cl.join()