First, horrible config file support.

This commit is contained in:
s3lph 2018-07-11 22:06:06 +02:00
parent 2347908381
commit a52f09fc58
10 changed files with 86 additions and 28 deletions

1
.gitignore vendored
View file

@ -9,3 +9,4 @@
*.sqlite3 *.sqlite3
*.db *.db
**/matemat.conf

View file

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

View file

@ -1,16 +1,23 @@
from typing import Any, Dict
import sys import sys
from matemat 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.
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from matemat.webserver.pagelets import * from matemat.webserver.pagelets import *
from matemat.webserver import MatematWebserver from matemat.webserver import MatematWebserver
# Read HTTP port from command line # Use config file name from command line, if present
port: int = 8080 configfile: str = '/etc/matemat.conf'
if len(sys.argv) > 1: 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 # Start the web server
MatematWebserver(port=port).start() MatematWebserver(**config).start()

29
matemat/config.py Normal file
View file

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

View file

@ -34,7 +34,8 @@ _PAGELET_PATHS: Dict[str, Callable[[str, # HTTP method (GET, POST, ...)
str, # Request path str, # Request path
RequestArguments, # HTTP Request arguments RequestArguments, # HTTP Request arguments
Dict[str, Any], # Session vars 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 Union[ # Return type: either a response body, or a redirect
bytes, str, # Response body: will assign HTTP/1.0 200 OK bytes, str, # Response body: will assign HTTP/1.0 200 OK
PageletResponse, # A generic response PageletResponse, # A generic response
@ -77,6 +78,7 @@ def pagelet(path: str):
str, str,
RequestArguments, RequestArguments,
Dict[str, Any], Dict[str, Any],
Dict[str, str],
Dict[str, str]], Dict[str, str]],
Union[ Union[
bytes, str, bytes, str,
@ -102,12 +104,17 @@ class MatematHTTPServer(HTTPServer):
handler: Type[BaseHTTPRequestHandler], handler: Type[BaseHTTPRequestHandler],
staticroot: str, staticroot: str,
templateroot: str, templateroot: str,
dbpath: 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 # Resolve webroot directory and database file
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
self.pagelet_arguments = pagelet_arguments
# 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))
@ -130,10 +137,12 @@ class MatematWebserver(object):
""" """
def __init__(self, def __init__(self,
listen: str = '::', listen: str,
port: int = 80, port: int,
staticroot: str = './static', staticroot: str,
templateroot: str = './templates') -> None: templateroot: str,
dbpath: str,
pagelet_arguments: Dict[str, str]) -> None:
""" """
Instantiate a MatematWebserver. Instantiate a MatematWebserver.
@ -141,16 +150,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.
""" """
if len(listen) == 0:
# Empty string should be interpreted as all addresses
listen = '::'
# 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) self._httpd = MatematHTTPServer((listen, port), HttpHandler, staticroot, templateroot, dbpath, pagelet_arguments)
def start(self) -> None: def start(self) -> None:
""" """
@ -289,8 +296,14 @@ 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, 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 # 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

@ -12,14 +12,15 @@ def login_page(method: 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, PageletResponse]: -> Union[bytes, str, PageletResponse]:
if 'user' in session_vars: if 'user' in session_vars:
return RedirectResponse('/') return RedirectResponse('/')
if method == 'GET': if method == 'GET':
return TemplateResponse('login.html') return TemplateResponse('login.html', setupname=config['name'])
elif method == 'POST': elif method == 'POST':
with MatematDatabase('test.db') as db: with MatematDatabase(config['DatabaseFile']) as db:
try: try:
user: User = db.login(str(args.username), str(args.password)) user: User = db.login(str(args.username), str(args.password))
except AuthenticationError: except AuthenticationError:

View file

@ -9,7 +9,8 @@ def logout(method: 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, PageletResponse]: -> Union[bytes, str, PageletResponse]:
if 'user' in session_vars: if 'user' in session_vars:
del session_vars['user'] del session_vars['user']

View file

@ -11,13 +11,14 @@ def main_page(method: 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, PageletResponse]: -> Union[bytes, str, PageletResponse]:
with MatematDatabase('test.db') as db: with MatematDatabase(config['DatabaseFile']) as db:
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) return TemplateResponse('main.html', user=user, list=products, setupname=config['name'])
else: else:
users = db.list_users() users = db.list_users()
return TemplateResponse('main.html', list=users) return TemplateResponse('main.html', list=users, setupname=config['name'])

View file

@ -14,14 +14,17 @@ def touchkey_page(method: 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, PageletResponse]: -> Union[bytes, str, PageletResponse]:
if 'user' in session_vars: if 'user' in session_vars:
return RedirectResponse('/') return RedirectResponse('/')
if method == 'GET': 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': elif method == 'POST':
with MatematDatabase('test.db') as db: with MatematDatabase(config['DatabaseFile']) as db:
try: try:
user: User = db.login(str(args.username), touchkey=str(args.touchkey)) user: User = db.login(str(args.username), touchkey=str(args.touchkey))
except AuthenticationError: except AuthenticationError:

View file

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Matemat</title> <title>{{ setupname }}</title>
<style> <style>
body { body {
color: #f0f0f0; color: #f0f0f0;
@ -10,7 +10,7 @@
</style> </style>
</head> </head>
<body> <body>
<h1>Matemat {{__version__}}</h1> <h1>{{ setupname }}</h1>
{% block main %} {% block main %}
{% endblock %} {% endblock %}
</body> </body>