Files
clan-core/pkgs/clan-cli/clan_cli/webui/server.py
2023-09-27 09:47:50 +00:00

93 lines
2.4 KiB
Python

import argparse
import logging
import subprocess
import time
import urllib.request
import webbrowser
from contextlib import ExitStack, contextmanager
from pathlib import Path
from threading import Thread
from typing import Iterator
# XXX: can we dynamically load this using nix develop?
from uvicorn import run
log = logging.getLogger(__name__)
def defer_open_browser(base_url: str) -> None:
for i in range(5):
try:
urllib.request.urlopen(base_url + "/health")
break
except OSError:
time.sleep(i)
webbrowser.open(base_url)
@contextmanager
def spawn_node_dev_server(host: str, port: int) -> Iterator[None]:
log.info("Starting node dev server...")
path = Path(__file__).parent.parent.parent.parent / "ui"
with subprocess.Popen(
[
"direnv",
"exec",
path,
"npm",
"run",
"dev",
"--",
"--hostname",
host,
"--port",
str(port),
],
cwd=path,
) as proc:
try:
yield
finally:
proc.terminate()
def start_server(args: argparse.Namespace) -> None:
with ExitStack() as stack:
headers: list[tuple[str, str]] = []
if args.dev:
stack.enter_context(spawn_node_dev_server(args.dev_host, args.dev_port))
open_url = f"http://{args.dev_host}:{args.dev_port}"
host = args.dev_host
if ":" in host:
host = f"[{host}]"
headers = [
# (
# "Access-Control-Allow-Origin",
# f"http://{host}:{args.dev_port}",
# ),
# (
# "Access-Control-Allow-Methods",
# "DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT"
# ),
# (
# "Allow",
# "DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT"
# )
]
else:
open_url = f"http://[{args.host}]:{args.port}"
if not args.no_open:
Thread(target=defer_open_browser, args=(open_url,)).start()
run(
"clan_cli.webui.app:app",
host=args.host,
port=args.port,
log_level=args.log_level,
reload=args.reload,
access_log=args.log_level == "debug",
headers=headers,
)