mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
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>
This commit is contained in:
parent
d4abe0b72d
commit
5be07a8a9e
5 changed files with 86 additions and 14 deletions
|
@ -11,7 +11,7 @@ before_script:
|
||||||
base-devel git gpgme protobuf pyalpm python-mysql-connector
|
base-devel git gpgme protobuf pyalpm python-mysql-connector
|
||||||
python-pygit2 python-srcinfo python-bleach python-markdown
|
python-pygit2 python-srcinfo python-bleach python-markdown
|
||||||
python-sqlalchemy python-alembic python-pytest python-werkzeug
|
python-sqlalchemy python-alembic python-pytest python-werkzeug
|
||||||
python-pytest-tap
|
python-pytest-tap python-fastapi uvicorn nginx
|
||||||
|
|
||||||
test:
|
test:
|
||||||
script:
|
script:
|
||||||
|
|
3
TESTING
3
TESTING
|
@ -12,7 +12,8 @@ INSTALL.
|
||||||
2) Install the necessary packages:
|
2) Install the necessary packages:
|
||||||
|
|
||||||
# pacman -S --needed php php-sqlite sqlite words fortune-mod \
|
# 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.
|
Ensure to enable the pdo_sqlite extension in php.ini.
|
||||||
|
|
||||||
|
|
8
aurweb/asgi.py
Normal file
8
aurweb/asgi.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/hello/")
|
||||||
|
async def hello():
|
||||||
|
return {"message": "Hello from FastAPI!"}
|
|
@ -10,8 +10,10 @@ configuration anyway.
|
||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
import argparse
|
import argparse
|
||||||
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
|
@ -20,6 +22,7 @@ import aurweb.schema
|
||||||
|
|
||||||
|
|
||||||
children = []
|
children = []
|
||||||
|
temporary_dir = None
|
||||||
verbosity = 0
|
verbosity = 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,10 +38,42 @@ class ProcessExceptions(Exception):
|
||||||
super().__init__("\n- ".join(messages))
|
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):
|
def spawn_child(args):
|
||||||
"""Open a subprocess and add it to the global state."""
|
"""Open a subprocess and add it to the global state."""
|
||||||
if verbosity >= 1:
|
if verbosity >= 1:
|
||||||
print(f"Spawning {args}", file=sys.stderr)
|
print(f":: Spawning {args}", file=sys.stderr)
|
||||||
children.append(subprocess.Popen(args))
|
children.append(subprocess.Popen(args))
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,10 +87,29 @@ def start():
|
||||||
if children:
|
if children:
|
||||||
return
|
return
|
||||||
atexit.register(stop)
|
atexit.register(stop)
|
||||||
aur_location = aurweb.config.get("options", "aur_location")
|
|
||||||
aur_location_parts = urllib.parse.urlsplit(aur_location)
|
print("{ruler}\n"
|
||||||
htmldir = aurweb.config.get("options", "htmldir")
|
"Spawing PHP and FastAPI, then nginx as a reverse proxy.\n"
|
||||||
spawn_child(["php", "-S", aur_location_parts.netloc, "-t", htmldir])
|
"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():
|
def stop():
|
||||||
|
@ -73,7 +127,7 @@ def stop():
|
||||||
try:
|
try:
|
||||||
p.terminate()
|
p.terminate()
|
||||||
if verbosity >= 1:
|
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:
|
except Exception as e:
|
||||||
exceptions.append(e)
|
exceptions.append(e)
|
||||||
for p in children:
|
for p in children:
|
||||||
|
@ -99,9 +153,11 @@ if __name__ == '__main__':
|
||||||
help='increase verbosity')
|
help='increase verbosity')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
verbosity = args.verbose
|
verbosity = args.verbose
|
||||||
start()
|
with tempfile.TemporaryDirectory(prefix="aurweb-") as tmpdirname:
|
||||||
try:
|
temporary_dir = tmpdirname
|
||||||
while True:
|
start()
|
||||||
time.sleep(60)
|
try:
|
||||||
except KeyboardInterrupt:
|
while True:
|
||||||
stop()
|
time.sleep(60)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
stop()
|
||||||
|
|
|
@ -41,9 +41,16 @@ cache = none
|
||||||
cache_pkginfo_ttl = 86400
|
cache_pkginfo_ttl = 86400
|
||||||
memcache_servers = 127.0.0.1:11211
|
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.
|
; Directory containing aurweb's PHP code, required by aurweb.spawn.
|
||||||
;htmldir = /path/to/web/html
|
;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]
|
[ratelimit]
|
||||||
request_limit = 4000
|
request_limit = 4000
|
||||||
window_length = 86400
|
window_length = 86400
|
||||||
|
|
Loading…
Add table
Reference in a new issue