Files
simplex-chat/scripts/relay/entrypoint.py

106 lines
3.2 KiB
Python
Executable File

#!/usr/bin/env python3
"""Save the relay address on first start, then exec the relay.
The address is printed only when it is created, and is not stored in the
database in its displayed form, so it is captured from the relay's output.
"""
import os
import shlex
import subprocess
import sys
BIN = "simplex-chat-relay"
WEB_ROOT = "/var/www/relay-web-channels"
ADDR_FILE = "/out/relay-address.txt"
CAPTURE_TIMEOUT = 180 # seconds
DEFAULT_RTS_OPTS = "-N -F1.2 -A16m -I0.01 -Iw15"
DEFAULT_POOL_SIZE = "4" # the binary defaults to a single connection
DEFAULT_QUEUE_SIZE = "65536"
def require(name):
value = os.environ.get(name)
if not value:
sys.exit(f"{name} is required")
return value
def rts_args():
"""RELAY_RTS_OPTS holds bare options; the +RTS/-RTS markers are added here."""
opts = [
o
for o in shlex.split(os.environ.get("RELAY_RTS_OPTS") or DEFAULT_RTS_OPTS)
if o not in ("+RTS", "-RTS")
]
return ["+RTS", *opts, "-RTS"] if opts else []
def find_address(text):
for token in text.split():
if token.startswith("https://") or token.startswith("simplex:"):
return token
return None
def capture_address(oneshot):
"""Create the address if needed and save it. Runs before the relay starts."""
cmd = oneshot + ["--create-schema", "-t", "0", "-e", "/sa"]
try:
out = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
errors="replace",
timeout=CAPTURE_TIMEOUT,
).stdout
except subprocess.TimeoutExpired as exc:
out = exc.stdout or ""
sys.stdout.write(out)
sys.stdout.flush()
address = find_address(out)
if address:
with open(ADDR_FILE, "w") as f:
f.write(address + "\n")
else:
sys.stderr.write("entrypoint: relay address not captured; will retry next start\n")
def main():
name = require("RELAY_NAME")
domain = require("RELAY_WEB_DOMAIN")
conn = require("DB_CONN")
image_file = os.environ.get("RELAY_IMAGE_FILE")
os.makedirs(f"{WEB_ROOT}/channel", exist_ok=True)
os.makedirs("/out", exist_ok=True)
common = [BIN, "--relay", "--headless", "--user-display-name", name]
# Only applied when the address is created, which the one-shot below does.
address_server = os.environ.get("RELAY_ADDRESS_SERVER")
if address_server:
common += ["--relay-address-server", address_server]
# The image is applied only when the profile is created.
if not os.path.exists(ADDR_FILE):
oneshot = common + (["--user-image-file", image_file] if image_file else []) + ["-d", conn]
capture_address(oneshot)
relay = common + [
"--relay-web-domain", domain,
"--relay-web-dir", f"{WEB_ROOT}/channel",
"--relay-web-cors-file", f"{WEB_ROOT}/cors.conf",
"--relay-web-interval", "30",
"-d", conn,
"--create-schema",
"--pool-size", os.environ.get("RELAY_POOL_SIZE") or DEFAULT_POOL_SIZE,
"--queue-size", os.environ.get("RELAY_QUEUE_SIZE") or DEFAULT_QUEUE_SIZE,
] + rts_args()
os.execvp(relay[0], relay)
if __name__ == "__main__":
main()