From 2dd57dcfd698033ab0e3f484d6ffa1a89d30d551 Mon Sep 17 00:00:00 2001 From: s3lph Date: Fri, 13 Jul 2018 00:14:48 +0200 Subject: [PATCH] Reworked and cleaned up config file integration. --- matemat/__init__.py | 2 -- matemat/__main__.py | 2 +- matemat/config.py | 29 ---------------- matemat/webserver/__init__.py | 1 + matemat/webserver/config.py | 47 ++++++++++++++++++++++++++ matemat/webserver/httpd.py | 22 ++++++------ matemat/webserver/pagelets/login.py | 2 +- matemat/webserver/pagelets/main.py | 4 +-- matemat/webserver/pagelets/touchkey.py | 2 +- 9 files changed, 63 insertions(+), 48 deletions(-) delete mode 100644 matemat/config.py create mode 100644 matemat/webserver/config.py diff --git a/matemat/__init__.py b/matemat/__init__.py index 2d3934d..a3332a5 100644 --- a/matemat/__init__.py +++ b/matemat/__init__.py @@ -1,4 +1,2 @@ __version__ = '2.0' - -from .config import parse_config_file diff --git a/matemat/__main__.py b/matemat/__main__.py index cc69d4a..b461855 100644 --- a/matemat/__main__.py +++ b/matemat/__main__.py @@ -3,7 +3,7 @@ from typing import Any, Dict import sys -from matemat import parse_config_file +from matemat.webserver import parse_config_file if __name__ == '__main__': # Those imports are actually needed, as they implicitly register pagelets. diff --git a/matemat/config.py b/matemat/config.py deleted file mode 100644 index 48963dd..0000000 --- a/matemat/config.py +++ /dev/null @@ -1,29 +0,0 @@ - -from typing import Any, Dict - -from configparser import ConfigParser, NoSectionError - - -def parse_config_file(path: str) -> Dict[str, Any]: - config: Dict[str, Any] = dict() - - parser: ConfigParser = ConfigParser() - parser.read(path, 'utf-8') - if 'Matemat' not in parser.sections(): - raise NoSectionError(f'Section "matemat" missing in file {path}') - config['listen'] = parser['Matemat'].get('Address', '::') - config['port'] = int(parser['Matemat'].get('Port', '8080')) - config['dbpath'] = parser['Matemat'].get('DatabaseFile', '/var/matemat/db/matemat.sqlite3') - config['staticroot'] = parser['Matemat'].get('StaticPath', '/var/matemat/static/') - config['templateroot'] = parser['Matemat'].get('TemplatePath', '/var/matemat/templates/') - - config['pagelet_arguments']: Dict[str, str] = dict() - config['pagelet_arguments']['DatabaseFile'] = config['dbpath'] - config['pagelet_arguments']['StaticPath'] = config['staticroot'] - config['pagelet_arguments']['TemplatePath'] = config['templateroot'] - - if 'Pagelets' in parser.sections(): - for k, v in parser['Pagelets'].items(): - config['pagelet_arguments'][k] = v - - return config diff --git a/matemat/webserver/__init__.py b/matemat/webserver/__init__.py index 6059687..bf3f2f8 100644 --- a/matemat/webserver/__init__.py +++ b/matemat/webserver/__init__.py @@ -9,3 +9,4 @@ server will attempt to serve the request with a static resource in a previously from .requestargs import RequestArgument, RequestArguments from .responses import PageletResponse, RedirectResponse, TemplateResponse from .httpd import MatematWebserver, HttpHandler, pagelet +from .config import parse_config_file diff --git a/matemat/webserver/config.py b/matemat/webserver/config.py new file mode 100644 index 0000000..c220adc --- /dev/null +++ b/matemat/webserver/config.py @@ -0,0 +1,47 @@ + +from typing import Any, Dict + +from configparser import ConfigParser + + +def parse_config_file(path: str) -> Dict[str, Any]: + """ + Parse the configuration file at the given path. + + :param path: The config file to parse. + :return: A dictionary containing the parsed configuration. + """ + # Set up default values + config: Dict[str, Any] = { + # Address to listen on + 'listen': '::', + # TCP port to listen on + 'port': 80, + # Root directory of statically served content + 'staticroot': '/var/matemat/static', + # Root directory of Jinja2 templates + 'templateroot': '/var/matemat/templates', + # Variables passed to pagelets + 'pagelet_variables': dict() + } + + # Initialize the config parser + parser: ConfigParser = ConfigParser() + # Replace the original option transformation by a string constructor to preserve the case of config keys + parser.optionxform = str + # Read the configuration file + parser.read(path, 'utf-8') + + # Read values from the [Matemat] section, if present, falling back to default values + if 'Matemat' in parser.sections(): + config['listen'] = parser['Matemat'].get('Address', config['listen']) + config['port'] = int(parser['Matemat'].get('Port', config['port'])) + config['staticroot'] = parser['Matemat'].get('StaticPath', config['staticroot']) + config['templateroot'] = parser['Matemat'].get('TemplatePath', config['templateroot']) + + # Read all values from the [Pagelets] section, if present. These values are passed to pagelet functions + if 'Pagelets' in parser.sections(): + for k, v in parser['Pagelets'].items(): + config['pagelet_variables'][k] = v + + return config diff --git a/matemat/webserver/httpd.py b/matemat/webserver/httpd.py index c3a35c6..2d5194d 100644 --- a/matemat/webserver/httpd.py +++ b/matemat/webserver/httpd.py @@ -57,7 +57,8 @@ def pagelet(path: str): path: str, args: RequestArguments, session_vars: Dict[str, Any], - headers: Dict[str, str]) + headers: Dict[str, str], + config: Dict[str, str]) -> Union[bytes, str, Tuple[int, str]] method: The HTTP method (GET, POST) that was used. @@ -65,6 +66,7 @@ def pagelet(path: str): args: The arguments that were passed with the request (as GET or POST arguments). session_vars: The session storage. May be read from and written to. headers: The dictionary of HTTP response headers. Add headers you wish to send with the response. + config: The dictionary of variables read from the [Pagelets] section of the configuration file. returns: One of the following: - A HTTP Response body as str or bytes - A PageletResponse class instance: An instance of (a subclass of) @@ -104,17 +106,15 @@ class MatematHTTPServer(HTTPServer): handler: Type[BaseHTTPRequestHandler], staticroot: str, templateroot: str, - dbpath: str, - pagelet_arguments: Dict[str, str], + pagelet_variables: Dict[str, str], bind_and_activate: bool = True) -> None: super().__init__(server_address, handler, bind_and_activate) - # Resolve webroot directory and database file + # Resolve webroot directory self.webroot = os.path.abspath(staticroot) - self.database_file = os.path.abspath(dbpath) # Set up session vars dict self.session_vars: Dict[str, Tuple[datetime, Dict[str, Any]]] = dict() # Set up pagelet arguments dict - self.pagelet_arguments = pagelet_arguments + self.pagelet_variables = pagelet_variables # Set up the Jinja2 environment self.jinja_env: jinja2.Environment = jinja2.Environment( loader=jinja2.FileSystemLoader(os.path.abspath(templateroot)) @@ -141,8 +141,7 @@ class MatematWebserver(object): port: int, staticroot: str, templateroot: str, - dbpath: str, - pagelet_arguments: Dict[str, str]) -> None: + pagelet_variables: Dict[str, str]) -> None: """ Instantiate a MatematWebserver. @@ -150,14 +149,14 @@ class MatematWebserver(object): :param port: The TCP port to listen on. :param staticroot: Path to the static webroot directory. :param templateroot: Path to the Jinja2 templates root directory. - :param dbpath: Path to the database file. + :param pagelet_variables: Dictionary of variables to pass to pagelet functions. """ # IPv4 address detection heuristic if ':' not in listen and '.' in listen: # Rewrite IPv4 address to IPv6-mapped form listen = f'::ffff:{listen}' # Create the http server - self._httpd = MatematHTTPServer((listen, port), HttpHandler, staticroot, templateroot, dbpath, pagelet_arguments) + self._httpd = MatematHTTPServer((listen, port), HttpHandler, staticroot, templateroot, pagelet_variables) def start(self) -> None: """ @@ -296,14 +295,13 @@ class HttpHandler(BaseHTTPRequestHandler): 'Content-Type': 'text/html', 'Cache-Control': 'no-cache' } - print(self.server.pagelet_arguments) # Call the pagelet function pagelet_res = _PAGELET_PATHS[path](method, path, args, self.session_vars, headers, - self.server.pagelet_arguments) + self.server.pagelet_variables) # Parse the pagelet's return value, vielding a HTTP status code and a response body hsc, data = self._parse_pagelet_result(pagelet_res, headers) # Send the HTTP status code diff --git a/matemat/webserver/pagelets/login.py b/matemat/webserver/pagelets/login.py index a36dda2..e956795 100644 --- a/matemat/webserver/pagelets/login.py +++ b/matemat/webserver/pagelets/login.py @@ -18,7 +18,7 @@ def login_page(method: str, if 'user' in session_vars: return RedirectResponse('/') if method == 'GET': - return TemplateResponse('login.html', setupname=config['name']) + return TemplateResponse('login.html', setupname=config['InstanceName']) elif method == 'POST': with MatematDatabase(config['DatabaseFile']) as db: try: diff --git a/matemat/webserver/pagelets/main.py b/matemat/webserver/pagelets/main.py index 534cf61..b96364d 100644 --- a/matemat/webserver/pagelets/main.py +++ b/matemat/webserver/pagelets/main.py @@ -18,7 +18,7 @@ def main_page(method: str, if 'user' in session_vars: user: User = session_vars['user'] products = db.list_products() - return TemplateResponse('main.html', user=user, list=products, setupname=config['name']) + return TemplateResponse('main.html', user=user, list=products, setupname=config['InstanceName']) else: users = db.list_users() - return TemplateResponse('main.html', list=users, setupname=config['name']) + return TemplateResponse('main.html', list=users, setupname=config['InstanceName']) diff --git a/matemat/webserver/pagelets/touchkey.py b/matemat/webserver/pagelets/touchkey.py index 26c481e..2470ffd 100644 --- a/matemat/webserver/pagelets/touchkey.py +++ b/matemat/webserver/pagelets/touchkey.py @@ -22,7 +22,7 @@ def touchkey_page(method: str, if method == 'GET': return TemplateResponse('touchkey.html', username=str(args.username) if 'username' in args else None, - setupname=config['name']) + setupname=config['InstanceName']) elif method == 'POST': with MatematDatabase(config['DatabaseFile']) as db: try: