Implemented pagelet initialization.

This commit is contained in:
s3lph 2018-08-17 20:44:07 +02:00
parent fd90516125
commit 5bace1a3f8
4 changed files with 69 additions and 3 deletions

View file

@ -8,5 +8,5 @@ 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, pagelet_init
from .config import parse_config_file from .config import parse_config_file

View file

@ -1,7 +1,8 @@
from typing import Any, Callable, Dict, Tuple, Type, Union from typing import Any, Callable, Dict, List, Tuple, Type, Union
import logging import logging
import sys
import os import os
import socket import socket
import mimetypes import mimetypes
@ -38,6 +39,8 @@ _PAGELET_PATHS: Dict[str, Callable[[str, # HTTP method (GET, POST, ...)
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
]]] = dict() ]]] = dict()
# The pagelet initialization functions, to be executed upon startup
_PAGELET_INIT_FUNCTIONS: List[Callable[[Dict[str, str], logging.Logger], None]] = []
# Inactivity timeout for client sessions # Inactivity timeout for client sessions
_SESSION_TIMEOUT: int = 3600 _SESSION_TIMEOUT: int = 3600
@ -94,6 +97,28 @@ def pagelet(path: str):
return http_handler return http_handler
def pagelet_init(fun: Callable[[Dict[str, str], logging.Logger], None]):
"""
Annotate a function to act as a pagelet initialization function. The function will be called when the webserver is
started. The function should set up everything required for pagelets to operate correctly, e.g. providing default
values for configuration items, or performing database schema migrations.
Any exception thrown by an initialization function will cause the web server to seize operation. Multiple
initialization functions can be used.
The function must have the following signature:
(config: Dict[str, str], logger: logging.Logger) -> None
config: The mutable dictionary of variables read from the [Pagelets] section of the configuration file.
logger: The server's logger instance.
returns: Nothing.
:param fun: The function to annotate
"""
_PAGELET_INIT_FUNCTIONS.append(fun)
class MatematHTTPServer(HTTPServer): class MatematHTTPServer(HTTPServer):
""" """
A http.server.HTTPServer subclass that acts as a container for data that must be persistent between requests. A http.server.HTTPServer subclass that acts as a container for data that must be persistent between requests.
@ -184,8 +209,20 @@ class MatematWebserver(object):
def start(self) -> None: def start(self) -> None:
""" """
Start the web server. This call blocks while the server is running. Call all pagelet initialization functions and start the web server. This call blocks while the server is
running. If any exception is raised in the initialization phase, the program is terminated with a non-zero
exit code.
""" """
try:
# Run all pagelet initialization functions
for fun in _PAGELET_INIT_FUNCTIONS:
fun(self._httpd.pagelet_variables, self._httpd.logger)
except BaseException as e:
# If an error occurs, log it and terminate
self._httpd.logger.exception(e)
self._httpd.logger.critical('An initialization pagelet raised an error. Stopping.')
sys.exit(1)
# If pagelet initialization went fine, start the HTTP server
self._httpd.serve_forever() self._httpd.serve_forever()

View file

@ -4,6 +4,7 @@ This package contains the pagelet functions served by the Matemat software.
A new pagelet function must be imported here to be automatically loaded when the server is started. A new pagelet function must be imported here to be automatically loaded when the server is started.
""" """
from .initialization import initialization
from .main import main_page from .main import main_page
from .login import login_page from .login import login_page
from .logout import logout from .logout import logout

View file

@ -0,0 +1,28 @@
from typing import Dict
import logging
from matemat.webserver import pagelet_init
from matemat.db import MatematDatabase
@pagelet_init
def initialization(config: Dict[str, str],
logger: logging.Logger) -> None:
"""
The pagelet initialization function. Makes sure everything is ready for operation. If anything fails here, the web
server won't resume operation.
"""
# Set default values for missing config items
if 'InstanceName' not in config:
config['InstanceName'] = 'Matemat'
logger.warning('Property \'InstanceName\' not set, using \'Matemat\'')
if 'UploadDir' not in config:
config['UploadDir'] = './static/upload/'
logger.warning('Property \'UploadDir\' not set, using \'./static/upload/\'')
if 'DatabaseFile' not in config:
config['DatabaseFile'] = './matemat.db'
logger.warning('Property \'DatabaseFile\' not set, using \'./matemat.db\'')
with MatematDatabase(config['DatabaseFile']):
# Connect to the database to create it and perform any schema migrations
pass