Commit 5be07a8a authored by Frédéric Mangano-Tarumi's avatar Frédéric Mangano-Tarumi Committed by Lukas Fleischer
Browse files

aurweb.spawn: Integrate FastAPI and nginx

aurweb.spawn used to launch only PHP’s built-in server. Now it spawns a
dummy FastAPI application too. Since both stacks spawn their own HTTP
server, aurweb.spawn also spawns nginx as a reverse proxy to mount them
under the same base URL, defined by aur_location in the configuration.

Signed-off-by: Lukas Fleischer's avatarLukas Fleischer <>
parent d4abe0b7
......@@ -11,7 +11,7 @@ before_script:
base-devel git gpgme protobuf pyalpm python-mysql-connector
python-pygit2 python-srcinfo python-bleach python-markdown
python-sqlalchemy python-alembic python-pytest python-werkzeug
python-pytest-tap python-fastapi uvicorn nginx
......@@ -12,7 +12,8 @@ INSTALL.
2) Install the necessary packages:
# pacman -S --needed php php-sqlite sqlite words fortune-mod \
python python-sqlalchemy python-alembic
python python-sqlalchemy python-alembic \
python-fastapi uvicorn nginx
Ensure to enable the pdo_sqlite extension in php.ini.
from fastapi import FastAPI
app = FastAPI()
async def hello():
return {"message": "Hello from FastAPI!"}
......@@ -10,8 +10,10 @@ configuration anyway.
import atexit
import argparse
import os
import subprocess
import sys
import tempfile
import time
import urllib
......@@ -20,6 +22,7 @@ import aurweb.schema
children = []
temporary_dir = None
verbosity = 0
......@@ -35,10 +38,42 @@ class ProcessExceptions(Exception):
super().__init__("\n- ".join(messages))
def generate_nginx_config():
Generate an nginx configuration based on aurweb's configuration.
The file is generated under `temporary_dir`.
Returns the path to the created configuration file.
aur_location = aurweb.config.get("options", "aur_location")
aur_location_parts = urllib.parse.urlsplit(aur_location)
config_path = os.path.join(temporary_dir, "nginx.conf")
config = open(config_path, "w")
# We double nginx's braces because they conflict with Python's f-strings.
events {{}}
daemon off;
error_log /dev/stderr info;
pid {os.path.join(temporary_dir, "")};
http {{
access_log /dev/stdout;
server {{
listen {aur_location_parts.netloc};
location / {{
proxy_pass http://{aurweb.config.get("php", "bind_address")};
location /hello {{
proxy_pass http://{aurweb.config.get("fastapi", "bind_address")};
return config_path
def spawn_child(args):
"""Open a subprocess and add it to the global state."""
if verbosity >= 1:
print(f"Spawning {args}", file=sys.stderr)
print(f":: Spawning {args}", file=sys.stderr)
......@@ -52,10 +87,29 @@ def start():
if children:
aur_location = aurweb.config.get("options", "aur_location")
aur_location_parts = urllib.parse.urlsplit(aur_location)
htmldir = aurweb.config.get("options", "htmldir")
spawn_child(["php", "-S", aur_location_parts.netloc, "-t", htmldir])
"Spawing PHP and FastAPI, then nginx as a reverse proxy.\n"
"Check out {aur_location}\n"
"Hit ^C to terminate everything.\n"
.format(ruler=("-" * os.get_terminal_size().columns),
aur_location=aurweb.config.get('options', 'aur_location')))
php_address = aurweb.config.get("php", "bind_address")
htmldir = aurweb.config.get("php", "htmldir")
spawn_child(["php", "-S", php_address, "-t", htmldir])
# FastAPI
host, port = aurweb.config.get("fastapi", "bind_address").rsplit(":", 1)
spawn_child(["python", "-m", "uvicorn",
"--host", host,
"--port", port,
# nginx
spawn_child(["nginx", "-p", temporary_dir, "-c", generate_nginx_config()])
def stop():
......@@ -73,7 +127,7 @@ def stop():
if verbosity >= 1:
print(f"Sent SIGTERM to {p.args}", file=sys.stderr)
print(f":: Sent SIGTERM to {p.args}", file=sys.stderr)
except Exception as e:
for p in children:
......@@ -99,9 +153,11 @@ if __name__ == '__main__':
help='increase verbosity')
args = parser.parse_args()
verbosity = args.verbose
while True:
except KeyboardInterrupt:
with tempfile.TemporaryDirectory(prefix="aurweb-") as tmpdirname:
temporary_dir = tmpdirname
while True:
except KeyboardInterrupt:
......@@ -41,9 +41,16 @@ cache = none
cache_pkginfo_ttl = 86400
memcache_servers =
; Address PHP should bind when spawned in development mode by aurweb.spawn.
bind_address =
; Directory containing aurweb's PHP code, required by aurweb.spawn.
;htmldir = /path/to/web/html
; Address uvicorn should bind when spawned in development mode by aurweb.spawn.
bind_address =
request_limit = 4000
window_length = 86400
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment