generated from Luis/nextjs-python-web-template
126 lines
3.4 KiB
Python
126 lines
3.4 KiB
Python
import argparse
|
|
import logging
|
|
import os
|
|
import shutil
|
|
import signal
|
|
import subprocess
|
|
import tempfile
|
|
import time
|
|
import urllib.request
|
|
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?
|
|
import uvicorn
|
|
|
|
from clan_cli.errors import ClanError
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def open_browser(base_url: str) -> None:
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
for i in range(5):
|
|
try:
|
|
urllib.request.urlopen(base_url + "/health")
|
|
break
|
|
except OSError:
|
|
time.sleep(i)
|
|
proc = _open_browser(base_url, tmpdir)
|
|
try:
|
|
proc.wait()
|
|
print("Browser closed")
|
|
os.kill(os.getpid(), signal.SIGINT)
|
|
finally:
|
|
proc.kill()
|
|
proc.wait()
|
|
|
|
|
|
def _open_browser(base_url: str, tmpdir: str) -> subprocess.Popen:
|
|
for browser in ("firefox", "iceweasel", "iceape", "seamonkey"):
|
|
if shutil.which(browser):
|
|
cmd = [
|
|
browser,
|
|
"-kiosk",
|
|
"-private-window",
|
|
"--new-instance",
|
|
"--profile",
|
|
tmpdir,
|
|
base_url,
|
|
]
|
|
print(" ".join(cmd))
|
|
return subprocess.Popen(cmd)
|
|
for browser in ("chromium", "chromium-browser", "google-chrome", "chrome"):
|
|
if shutil.which(browser):
|
|
return subprocess.Popen([browser, f"--app={base_url}"])
|
|
raise ClanError("No browser found")
|
|
|
|
|
|
@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=open_browser, args=(open_url,)).start()
|
|
|
|
uvicorn.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,
|
|
)
|