Made an application for supporting sustainable local businesses in San Pancho.
Never really got completed, but it has some useful Svelte components for maps that we can reuse.
http://greenspots.dctrl.space
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
78 lines
2.5 KiB
78 lines
2.5 KiB
""" |
|
Application Dispatcher |
|
====================== |
|
|
|
This middleware creates a single WSGI application that dispatches to |
|
multiple other WSGI applications mounted at different URL paths. |
|
|
|
A common example is writing a Single Page Application, where you have a |
|
backend API and a frontend written in JavaScript that does the routing |
|
in the browser rather than requesting different pages from the server. |
|
The frontend is a single HTML and JS file that should be served for any |
|
path besides "/api". |
|
|
|
This example dispatches to an API app under "/api", an admin app |
|
under "/admin", and an app that serves frontend files for all other |
|
requests:: |
|
|
|
app = DispatcherMiddleware(serve_frontend, { |
|
'/api': api_app, |
|
'/admin': admin_app, |
|
}) |
|
|
|
In production, you might instead handle this at the HTTP server level, |
|
serving files or proxying to application servers based on location. The |
|
API and admin apps would each be deployed with a separate WSGI server, |
|
and the static files would be served directly by the HTTP server. |
|
|
|
.. autoclass:: DispatcherMiddleware |
|
|
|
:copyright: 2007 Pallets |
|
:license: BSD-3-Clause |
|
""" |
|
import typing as t |
|
|
|
if t.TYPE_CHECKING: |
|
from _typeshed.wsgi import StartResponse |
|
from _typeshed.wsgi import WSGIApplication |
|
from _typeshed.wsgi import WSGIEnvironment |
|
|
|
|
|
class DispatcherMiddleware: |
|
"""Combine multiple applications as a single WSGI application. |
|
Requests are dispatched to an application based on the path it is |
|
mounted under. |
|
|
|
:param app: The WSGI application to dispatch to if the request |
|
doesn't match a mounted path. |
|
:param mounts: Maps path prefixes to applications for dispatching. |
|
""" |
|
|
|
def __init__( |
|
self, |
|
app: "WSGIApplication", |
|
mounts: t.Optional[t.Dict[str, "WSGIApplication"]] = None, |
|
) -> None: |
|
self.app = app |
|
self.mounts = mounts or {} |
|
|
|
def __call__( |
|
self, environ: "WSGIEnvironment", start_response: "StartResponse" |
|
) -> t.Iterable[bytes]: |
|
script = environ.get("PATH_INFO", "") |
|
path_info = "" |
|
|
|
while "/" in script: |
|
if script in self.mounts: |
|
app = self.mounts[script] |
|
break |
|
|
|
script, last_item = script.rsplit("/", 1) |
|
path_info = f"/{last_item}{path_info}" |
|
else: |
|
app = self.mounts.get(script, self.app) |
|
|
|
original_script_name = environ.get("SCRIPT_NAME", "") |
|
environ["SCRIPT_NAME"] = original_script_name + script |
|
environ["PATH_INFO"] = path_info |
|
return app(environ, start_response)
|
|
|