summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrédéric Mangano-Tarumi <fmang@mg0.fr>2020-06-01 18:49:37 +0200
committerLukas Fleischer <lfleischer@archlinux.org>2021-02-20 17:24:30 +0100
commit5be07a8a9e9777d54cf7122be52aa0a7b1b51e14 (patch)
treea7a64f4f5bbe9e4555d1b358852fd2d92d7837b1
parentd4abe0b72d1215906806ee84474115961e79f7c0 (diff)
downloadaur-5be07a8a9e9777d54cf7122be52aa0a7b1b51e14.tar.gz
aur-5be07a8a9e9777d54cf7122be52aa0a7b1b51e14.tar.xz
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 <lfleischer@archlinux.org>
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--TESTING3
-rw-r--r--aurweb/asgi.py8
-rw-r--r--aurweb/spawn.py80
-rw-r--r--conf/config.defaults7
5 files changed, 86 insertions, 14 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 74784fce..f6260ebb 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -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-pytest-tap python-fastapi uvicorn nginx
test:
script:
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..5f30471a
--- /dev/null
+++ b/aurweb/asgi.py
@@ -0,0 +1,8 @@
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/hello/")
+async def hello():
+ return {"message": "Hello from FastAPI!"}
diff --git a/aurweb/spawn.py b/aurweb/spawn.py
index 5fa646b5..0506afa4 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 /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)
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])
+
+ print("{ruler}\n"
+ "Spawing PHP and FastAPI, then nginx as a reverse proxy.\n"
+ "Check out {aur_location}\n"
+ "Hit ^C to terminate everything.\n"
+ "{ruler}"
+ .format(ruler=("-" * os.get_terminal_size().columns),
+ aur_location=aurweb.config.get('options', 'aur_location')))
+
+ # 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