102 lines
2.6 KiB
Python
102 lines
2.6 KiB
Python
import logging
|
|
from http import HTTPStatus
|
|
|
|
|
|
from . import exceptions
|
|
from . import configuration
|
|
from . import hooks
|
|
from . import web
|
|
|
|
class Application(web.SiteCompositionPiece):
|
|
|
|
"""
|
|
Class for the main app object.
|
|
Holds configuration, routing and rendering utilities.
|
|
This classes `__call__` function is the WSGI entrypoint.
|
|
"""
|
|
|
|
root = ''
|
|
absolute_root = '/'
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__()
|
|
self.debug = True
|
|
|
|
self._booted = False
|
|
configuration.config.load(self)
|
|
|
|
# add handlers only to top-level logger, see:
|
|
# https://docs.python.org/3.8/library/logging.html#logging.Logger.propagate
|
|
self.logger.addHandler(logging.FileHandler(f'{self.project_path}/ooze.log'))
|
|
self.logger.addHandler(logging.StreamHandler())
|
|
|
|
# register new app in Appoxy singleton so submodules can access the
|
|
# app object without having a depenceny on the module instantiating
|
|
# it (which would be code in the project using Ooze).
|
|
from . import appoxy
|
|
appoxy.app.set_app(self)
|
|
|
|
def __call__(self, environ, start_response):
|
|
|
|
"""
|
|
WSGI entrypoint
|
|
"""
|
|
|
|
if not self._booted:
|
|
self.boot()
|
|
|
|
request = self.request_class(self, environ)
|
|
|
|
try:
|
|
response = self.handle_request(request)
|
|
|
|
except exceptions.HTTPException as e:
|
|
|
|
response = self.response_class(request)
|
|
response.status = e.status
|
|
response.body = e.safe_message
|
|
|
|
self.logger.warn(f"Encountered HTTPException: {e}")
|
|
|
|
except exceptions.SafeException as e:
|
|
|
|
response = self.response_class(request)
|
|
response.status = HTTPStatus(500)
|
|
response.body = e.safe_message
|
|
|
|
self.logger.warn(f"Encountered SafeException: {e}")
|
|
|
|
except Exception as e:
|
|
|
|
if self.debug:
|
|
raise e
|
|
|
|
response = self.response_class(request)
|
|
response.status = HTTPStatus(500)
|
|
response.body = 'Oops!'
|
|
|
|
self.logger.error(f"Encountered unplanned exception: {e}")
|
|
|
|
start_response(
|
|
f"{response.status.numerator} {response.status.name}",
|
|
response.headers_wsgi()
|
|
)
|
|
|
|
return response.body_wsgi()
|
|
|
|
def install(self):
|
|
|
|
self.logger.debug("Running install functions…")
|
|
|
|
hooks.call('install', self)
|
|
|
|
def boot(self):
|
|
|
|
self.logger.debug("Running boot functions…")
|
|
|
|
hooks.call('boot', self)
|
|
|
|
self._booted = True
|
|
self.logger.debug("All booted up.")
|