[PATCH] aurweb.spawn: Integrate FastAPI and nginx
Frédéric Mangano-Tarumi
fmang at mg0.fr
Sat May 30 17:41:07 UTC 2020
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.
---
TESTING | 3 +-
aurweb/asgi.py | 8 +++++
aurweb/spawn.py | 80 +++++++++++++++++++++++++++++++++++++-------
conf/config.defaults | 7 ++++
4 files changed, 85 insertions(+), 13 deletions(-)
create mode 100644 aurweb/asgi.py
diff --git a/TESTING b/TESTING
index a5e08cb8..31e3bcbd 100644
--- a/TESTING
+++ b/TESTING
@@ -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.
diff --git a/aurweb/asgi.py b/aurweb/asgi.py
new file mode 100644
index 00000000..8d3deedc
--- /dev/null
+++ b/aurweb/asgi.py
@@ -0,0 +1,8 @@
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+ at app.get("/sso/")
+async def hello():
+ return {"message": "Hello from FastAPI!"}
diff --git a/aurweb/spawn.py b/aurweb/spawn.py
index 5fa646b5..df6a2ed5 100644
--- a/aurweb/spawn.py
+++ b/aurweb/spawn.py
@@ -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.
+ config.write(f"""
+ events {{}}
+ daemon off;
+ error_log /dev/stderr info;
+ pid {os.path.join(temporary_dir, "nginx.pid")};
+ http {{
+ access_log /dev/stdout;
+ server {{
+ listen {aur_location_parts.netloc};
+ location / {{
+ proxy_pass http://{aurweb.config.get("php", "bind_address")};
+ }}
+ location /sso {{
+ 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)
children.append(subprocess.Popen(args))
@@ -52,10 +87,29 @@ def start():
if children:
return
atexit.register(stop)
- 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])
+
+ # Friendly message
+ ruler = "-" * os.get_terminal_size().columns
+ print(ruler)
+ print("Spawing PHP and FastAPI, then nginx as a reverse proxy.")
+ print("Check out " + aurweb.config.get("options", "aur_location"))
+ print("Hit ^C to terminate everything.")
+ print(ruler)
+
+ # PHP
+ 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,
+ "aurweb.asgi:app"])
+
+ # nginx
+ spawn_child(["nginx", "-p", temporary_dir, "-c", generate_nginx_config()])
def stop():
@@ -73,7 +127,7 @@ def stop():
try:
p.terminate()
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:
exceptions.append(e)
for p in children:
@@ -99,9 +153,11 @@ if __name__ == '__main__':
help='increase verbosity')
args = parser.parse_args()
verbosity = args.verbose
- start()
- try:
- while True:
- time.sleep(60)
- except KeyboardInterrupt:
- stop()
+ with tempfile.TemporaryDirectory(prefix="aurweb-") as tmpdirname:
+ temporary_dir = tmpdirname
+ start()
+ try:
+ while True:
+ time.sleep(60)
+ except KeyboardInterrupt:
+ stop()
diff --git a/conf/config.defaults b/conf/config.defaults
index 86fe765c..ed495168 100644
--- a/conf/config.defaults
+++ b/conf/config.defaults
@@ -41,9 +41,16 @@ cache = none
cache_pkginfo_ttl = 86400
memcache_servers = 127.0.0.1:11211
+[php]
+; Address PHP should bind when spawned in development mode by aurweb.spawn.
+bind_address = 127.0.0.1:8081
; Directory containing aurweb's PHP code, required by aurweb.spawn.
;htmldir = /path/to/web/html
+[fastapi]
+; Address uvicorn should bind when spawned in development mode by aurweb.spawn.
+bind_address = 127.0.0.1:8082
+
[ratelimit]
request_limit = 4000
window_length = 86400
--
2.26.2
More information about the aur-dev
mailing list