Reworked and cleaned up config file integration.

This commit is contained in:
s3lph 2018-07-13 00:14:48 +02:00
parent a52f09fc58
commit 2dd57dcfd6
9 changed files with 63 additions and 48 deletions

View file

@ -1,4 +1,2 @@
__version__ = '2.0' __version__ = '2.0'
from .config import parse_config_file

View file

@ -3,7 +3,7 @@ from typing import Any, Dict
import sys import sys
from matemat import parse_config_file from matemat.webserver import parse_config_file
if __name__ == '__main__': if __name__ == '__main__':
# Those imports are actually needed, as they implicitly register pagelets. # Those imports are actually needed, as they implicitly register pagelets.

View file

@ -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

View file

@ -9,3 +9,4 @@ server will attempt to serve the request with a static resource in a previously
from .requestargs import RequestArgument, RequestArguments from .requestargs import RequestArgument, RequestArguments
from .responses import PageletResponse, RedirectResponse, TemplateResponse from .responses import PageletResponse, RedirectResponse, TemplateResponse
from .httpd import MatematWebserver, HttpHandler, pagelet from .httpd import MatematWebserver, HttpHandler, pagelet
from .config import parse_config_file

View file

@ -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

View file

@ -57,7 +57,8 @@ def pagelet(path: str):
path: str, path: str,
args: RequestArguments, args: RequestArguments,
session_vars: Dict[str, Any], session_vars: Dict[str, Any],
headers: Dict[str, str]) headers: Dict[str, str],
config: Dict[str, str])
-> Union[bytes, str, Tuple[int, str]] -> Union[bytes, str, Tuple[int, str]]
method: The HTTP method (GET, POST) that was used. 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). 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. 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. 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: returns: One of the following:
- A HTTP Response body as str or bytes - A HTTP Response body as str or bytes
- A PageletResponse class instance: An instance of (a subclass of) - A PageletResponse class instance: An instance of (a subclass of)
@ -104,17 +106,15 @@ class MatematHTTPServer(HTTPServer):
handler: Type[BaseHTTPRequestHandler], handler: Type[BaseHTTPRequestHandler],
staticroot: str, staticroot: str,
templateroot: str, templateroot: str,
dbpath: str, pagelet_variables: Dict[str, str],
pagelet_arguments: Dict[str, str],
bind_and_activate: bool = True) -> None: bind_and_activate: bool = True) -> None:
super().__init__(server_address, handler, bind_and_activate) super().__init__(server_address, handler, bind_and_activate)
# Resolve webroot directory and database file # Resolve webroot directory
self.webroot = os.path.abspath(staticroot) self.webroot = os.path.abspath(staticroot)
self.database_file = os.path.abspath(dbpath)
# Set up session vars dict # Set up session vars dict
self.session_vars: Dict[str, Tuple[datetime, Dict[str, Any]]] = dict() self.session_vars: Dict[str, Tuple[datetime, Dict[str, Any]]] = dict()
# Set up pagelet arguments dict # Set up pagelet arguments dict
self.pagelet_arguments = pagelet_arguments self.pagelet_variables = pagelet_variables
# Set up the Jinja2 environment # Set up the Jinja2 environment
self.jinja_env: jinja2.Environment = jinja2.Environment( self.jinja_env: jinja2.Environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.abspath(templateroot)) loader=jinja2.FileSystemLoader(os.path.abspath(templateroot))
@ -141,8 +141,7 @@ class MatematWebserver(object):
port: int, port: int,
staticroot: str, staticroot: str,
templateroot: str, templateroot: str,
dbpath: str, pagelet_variables: Dict[str, str]) -> None:
pagelet_arguments: Dict[str, str]) -> None:
""" """
Instantiate a MatematWebserver. Instantiate a MatematWebserver.
@ -150,14 +149,14 @@ class MatematWebserver(object):
:param port: The TCP port to listen on. :param port: The TCP port to listen on.
:param staticroot: Path to the static webroot directory. :param staticroot: Path to the static webroot directory.
:param templateroot: Path to the Jinja2 templates root 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 # IPv4 address detection heuristic
if ':' not in listen and '.' in listen: if ':' not in listen and '.' in listen:
# Rewrite IPv4 address to IPv6-mapped form # Rewrite IPv4 address to IPv6-mapped form
listen = f'::ffff:{listen}' listen = f'::ffff:{listen}'
# Create the http server # 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: def start(self) -> None:
""" """
@ -296,14 +295,13 @@ class HttpHandler(BaseHTTPRequestHandler):
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Cache-Control': 'no-cache' 'Cache-Control': 'no-cache'
} }
print(self.server.pagelet_arguments)
# Call the pagelet function # Call the pagelet function
pagelet_res = _PAGELET_PATHS[path](method, pagelet_res = _PAGELET_PATHS[path](method,
path, path,
args, args,
self.session_vars, self.session_vars,
headers, headers,
self.server.pagelet_arguments) self.server.pagelet_variables)
# Parse the pagelet's return value, vielding a HTTP status code and a response body # Parse the pagelet's return value, vielding a HTTP status code and a response body
hsc, data = self._parse_pagelet_result(pagelet_res, headers) hsc, data = self._parse_pagelet_result(pagelet_res, headers)
# Send the HTTP status code # Send the HTTP status code

View file

@ -18,7 +18,7 @@ def login_page(method: str,
if 'user' in session_vars: if 'user' in session_vars:
return RedirectResponse('/') return RedirectResponse('/')
if method == 'GET': if method == 'GET':
return TemplateResponse('login.html', setupname=config['name']) return TemplateResponse('login.html', setupname=config['InstanceName'])
elif method == 'POST': elif method == 'POST':
with MatematDatabase(config['DatabaseFile']) as db: with MatematDatabase(config['DatabaseFile']) as db:
try: try:

View file

@ -18,7 +18,7 @@ def main_page(method: str,
if 'user' in session_vars: if 'user' in session_vars:
user: User = session_vars['user'] user: User = session_vars['user']
products = db.list_products() 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: else:
users = db.list_users() users = db.list_users()
return TemplateResponse('main.html', list=users, setupname=config['name']) return TemplateResponse('main.html', list=users, setupname=config['InstanceName'])

View file

@ -22,7 +22,7 @@ def touchkey_page(method: str,
if method == 'GET': if method == 'GET':
return TemplateResponse('touchkey.html', return TemplateResponse('touchkey.html',
username=str(args.username) if 'username' in args else None, username=str(args.username) if 'username' in args else None,
setupname=config['name']) setupname=config['InstanceName'])
elif method == 'POST': elif method == 'POST':
with MatematDatabase(config['DatabaseFile']) as db: with MatematDatabase(config['DatabaseFile']) as db:
try: try: