From a52f09fc58b9078eed02e24aa08a9d77bc8afba4 Mon Sep 17 00:00:00 2001 From: s3lph Date: Wed, 11 Jul 2018 22:06:06 +0200 Subject: [PATCH] First, horrible config file support. --- .gitignore | 1 + matemat/__init__.py | 2 ++ matemat/__main__.py | 15 ++++++++--- matemat/config.py | 29 +++++++++++++++++++++ matemat/webserver/httpd.py | 35 ++++++++++++++++++-------- matemat/webserver/pagelets/login.py | 7 +++--- matemat/webserver/pagelets/logout.py | 3 ++- matemat/webserver/pagelets/main.py | 9 ++++--- matemat/webserver/pagelets/touchkey.py | 9 ++++--- templates/base.html | 4 +-- 10 files changed, 86 insertions(+), 28 deletions(-) create mode 100644 matemat/config.py diff --git a/.gitignore b/.gitignore index cca262e..fef1fd9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ *.sqlite3 *.db +**/matemat.conf diff --git a/matemat/__init__.py b/matemat/__init__.py index a3332a5..2d3934d 100644 --- a/matemat/__init__.py +++ b/matemat/__init__.py @@ -1,2 +1,4 @@ __version__ = '2.0' + +from .config import parse_config_file diff --git a/matemat/__main__.py b/matemat/__main__.py index 9654b64..cc69d4a 100644 --- a/matemat/__main__.py +++ b/matemat/__main__.py @@ -1,16 +1,23 @@ +from typing import Any, Dict + import sys +from matemat import parse_config_file + if __name__ == '__main__': # Those imports are actually needed, as they implicitly register pagelets. # noinspection PyUnresolvedReferences from matemat.webserver.pagelets import * from matemat.webserver import MatematWebserver - # Read HTTP port from command line - port: int = 8080 + # Use config file name from command line, if present + configfile: str = '/etc/matemat.conf' if len(sys.argv) > 1: - port = int(sys.argv[1]) + configfile = sys.argv[1] + + # Parse the config file + config: Dict[str, Any] = parse_config_file(configfile) # Start the web server - MatematWebserver(port=port).start() + MatematWebserver(**config).start() diff --git a/matemat/config.py b/matemat/config.py new file mode 100644 index 0000000..48963dd --- /dev/null +++ b/matemat/config.py @@ -0,0 +1,29 @@ + +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/httpd.py b/matemat/webserver/httpd.py index 41866de..c3a35c6 100644 --- a/matemat/webserver/httpd.py +++ b/matemat/webserver/httpd.py @@ -34,7 +34,8 @@ _PAGELET_PATHS: Dict[str, Callable[[str, # HTTP method (GET, POST, ...) str, # Request path RequestArguments, # HTTP Request arguments Dict[str, Any], # Session vars - Dict[str, str]], # Response headers + Dict[str, str], # Response headers + Dict[str, str]], # Items from the [Pagelets] section in the config file Union[ # Return type: either a response body, or a redirect bytes, str, # Response body: will assign HTTP/1.0 200 OK PageletResponse, # A generic response @@ -77,6 +78,7 @@ def pagelet(path: str): str, RequestArguments, Dict[str, Any], + Dict[str, str], Dict[str, str]], Union[ bytes, str, @@ -102,12 +104,17 @@ class MatematHTTPServer(HTTPServer): handler: Type[BaseHTTPRequestHandler], staticroot: str, templateroot: str, + dbpath: str, + pagelet_arguments: Dict[str, str], bind_and_activate: bool = True) -> None: super().__init__(server_address, handler, bind_and_activate) - # Resolve webroot directory + # Resolve webroot directory and database file 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 # Set up the Jinja2 environment self.jinja_env: jinja2.Environment = jinja2.Environment( loader=jinja2.FileSystemLoader(os.path.abspath(templateroot)) @@ -130,10 +137,12 @@ class MatematWebserver(object): """ def __init__(self, - listen: str = '::', - port: int = 80, - staticroot: str = './static', - templateroot: str = './templates') -> None: + listen: str, + port: int, + staticroot: str, + templateroot: str, + dbpath: str, + pagelet_arguments: Dict[str, str]) -> None: """ Instantiate a MatematWebserver. @@ -141,16 +150,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. """ - if len(listen) == 0: - # Empty string should be interpreted as all addresses - listen = '::' # 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) + self._httpd = MatematHTTPServer((listen, port), HttpHandler, staticroot, templateroot, dbpath, pagelet_arguments) def start(self) -> None: """ @@ -289,8 +296,14 @@ 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) + pagelet_res = _PAGELET_PATHS[path](method, + path, + args, + self.session_vars, + headers, + self.server.pagelet_arguments) # 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 6ef9a9c..a36dda2 100644 --- a/matemat/webserver/pagelets/login.py +++ b/matemat/webserver/pagelets/login.py @@ -12,14 +12,15 @@ def login_page(method: 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, PageletResponse]: if 'user' in session_vars: return RedirectResponse('/') if method == 'GET': - return TemplateResponse('login.html') + return TemplateResponse('login.html', setupname=config['name']) elif method == 'POST': - with MatematDatabase('test.db') as db: + with MatematDatabase(config['DatabaseFile']) as db: try: user: User = db.login(str(args.username), str(args.password)) except AuthenticationError: diff --git a/matemat/webserver/pagelets/logout.py b/matemat/webserver/pagelets/logout.py index cbd7cad..4e18258 100644 --- a/matemat/webserver/pagelets/logout.py +++ b/matemat/webserver/pagelets/logout.py @@ -9,7 +9,8 @@ def logout(method: 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, PageletResponse]: if 'user' in session_vars: del session_vars['user'] diff --git a/matemat/webserver/pagelets/main.py b/matemat/webserver/pagelets/main.py index be0bd60..534cf61 100644 --- a/matemat/webserver/pagelets/main.py +++ b/matemat/webserver/pagelets/main.py @@ -11,13 +11,14 @@ def main_page(method: 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, PageletResponse]: - with MatematDatabase('test.db') as db: + with MatematDatabase(config['DatabaseFile']) as db: if 'user' in session_vars: user: User = session_vars['user'] products = db.list_products() - return TemplateResponse('main.html', user=user, list=products) + return TemplateResponse('main.html', user=user, list=products, setupname=config['name']) else: users = db.list_users() - return TemplateResponse('main.html', list=users) + return TemplateResponse('main.html', list=users, setupname=config['name']) diff --git a/matemat/webserver/pagelets/touchkey.py b/matemat/webserver/pagelets/touchkey.py index 2b81c89..26c481e 100644 --- a/matemat/webserver/pagelets/touchkey.py +++ b/matemat/webserver/pagelets/touchkey.py @@ -14,14 +14,17 @@ def touchkey_page(method: 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, PageletResponse]: if 'user' in session_vars: return RedirectResponse('/') if method == 'GET': - return TemplateResponse('touchkey.html', username=str(args.username) if 'username' in args else None) + return TemplateResponse('touchkey.html', + username=str(args.username) if 'username' in args else None, + setupname=config['name']) elif method == 'POST': - with MatematDatabase('test.db') as db: + with MatematDatabase(config['DatabaseFile']) as db: try: user: User = db.login(str(args.username), touchkey=str(args.touchkey)) except AuthenticationError: diff --git a/templates/base.html b/templates/base.html index 1ddd113..5bae28f 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,7 +1,7 @@ - Matemat + {{ setupname }} -

Matemat {{__version__}}

+

{{ setupname }}

{% block main %} {% endblock %}