diff --git a/pkgs/clan-cli/clan_cli/__init__.py b/pkgs/clan-cli/clan_cli/__init__.py index 49771ad1..432e041d 100644 --- a/pkgs/clan-cli/clan_cli/__init__.py +++ b/pkgs/clan-cli/clan_cli/__init__.py @@ -3,7 +3,7 @@ import sys from types import ModuleType from typing import Optional -from . import config, create, machines, secrets, vms, webui +from . import config, create, join, machines, secrets, vms, webui from .errors import ClanError from .ssh import cli as ssh_cli @@ -30,6 +30,9 @@ def create_parser(prog: Optional[str] = None) -> argparse.ArgumentParser: ) create.register_parser(parser_create) + parser_join = subparsers.add_parser("join", help="join a remote clan") + join.register_parser(parser_join) + parser_config = subparsers.add_parser("config", help="set nixos configuration") config.register_parser(parser_config) diff --git a/pkgs/clan-cli/clan_cli/join/__init__.py b/pkgs/clan-cli/clan_cli/join/__init__.py new file mode 100644 index 00000000..7b96d085 --- /dev/null +++ b/pkgs/clan-cli/clan_cli/join/__init__.py @@ -0,0 +1,35 @@ +# !/usr/bin/env python3 +import argparse +import subprocess +import urllib +from typing import Optional + + +def join(args: argparse.Namespace) -> None: + # start webui in background + uri = args.flake_uri.removeprefix("clan://") + subprocess.run( + ["clan", "webui", f"/join?flake={urllib.parse.quote_plus(uri)}"], + # stdout=sys.stdout, + # stderr=sys.stderr, + ) + print(f"joined clan {args.flake_uri}") + + +# takes a (sub)parser and configures it +def register_parser( + parser: Optional[argparse.ArgumentParser], +) -> None: + if parser is None: + parser = argparse.ArgumentParser( + description="join a remote clan", + ) + + # inject callback function to process the input later + parser.set_defaults(func=join) + + parser.add_argument( + "flake_uri", + help="flake uri to join", + type=str, + ) diff --git a/pkgs/clan-cli/clan_cli/webui/__init__.py b/pkgs/clan-cli/clan_cli/webui/__init__.py index ca71979e..de2f5ae3 100644 --- a/pkgs/clan-cli/clan_cli/webui/__init__.py +++ b/pkgs/clan-cli/clan_cli/webui/__init__.py @@ -19,7 +19,9 @@ def fastapi_is_not_installed(_: argparse.Namespace) -> NoReturn: def register_parser(parser: argparse.ArgumentParser) -> None: parser.add_argument("--port", type=int, default=2979, help="Port to listen on") - parser.add_argument("--host", type=str, default="::1", help="Host to listen on") + parser.add_argument( + "--host", type=str, default="localhost", help="Host to listen on" + ) parser.add_argument( "--no-open", action="store_true", help="Don't open the browser", default=False ) @@ -46,6 +48,14 @@ def register_parser(parser: argparse.ArgumentParser) -> None: choices=["critical", "error", "warning", "info", "debug", "trace"], ) + parser.add_argument( + "sub_url", + type=str, + default="/", + nargs="?", + help="Sub url to open in the browser", + ) + # Set the args.func variable in args if start_server is None: parser.set_defaults(func=fastapi_is_not_installed) diff --git a/pkgs/clan-cli/clan_cli/webui/server.py b/pkgs/clan-cli/clan_cli/webui/server.py index 27f80b7b..6d7857ec 100644 --- a/pkgs/clan-cli/clan_cli/webui/server.py +++ b/pkgs/clan-cli/clan_cli/webui/server.py @@ -20,7 +20,7 @@ from clan_cli.errors import ClanError log = logging.getLogger(__name__) -def open_browser(base_url: str) -> None: +def open_browser(base_url: str, sub_url: str) -> None: with tempfile.TemporaryDirectory() as tmpdir: for i in range(5): try: @@ -28,7 +28,8 @@ def open_browser(base_url: str) -> None: break except OSError: time.sleep(i) - proc = _open_browser(base_url, tmpdir) + url = f"{base_url}/{sub_url.removeprefix('/')}" + proc = _open_browser(url, tmpdir) try: proc.wait() print("Browser closed") @@ -38,7 +39,7 @@ def open_browser(base_url: str) -> None: proc.wait() -def _open_browser(base_url: str, tmpdir: str) -> subprocess.Popen: +def _open_browser(url: str, tmpdir: str) -> subprocess.Popen: for browser in ("firefox", "iceweasel", "iceape", "seamonkey"): if shutil.which(browser): cmd = [ @@ -48,13 +49,13 @@ def _open_browser(base_url: str, tmpdir: str) -> subprocess.Popen: "--new-instance", "--profile", tmpdir, - base_url, + 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}"]) + return subprocess.Popen([browser, f"--app={url}"]) raise ClanError("No browser found") @@ -90,7 +91,7 @@ def start_server(args: argparse.Namespace) -> None: 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}" + base_url = f"http://{args.dev_host}:{args.dev_port}" host = args.dev_host if ":" in host: host = f"[{host}]" @@ -109,10 +110,10 @@ def start_server(args: argparse.Namespace) -> None: # ) ] else: - open_url = f"http://[{args.host}]:{args.port}" + base_url = f"http://{args.host}:{args.port}" if not args.no_open: - Thread(target=open_browser, args=(open_url,)).start() + Thread(target=open_browser, args=(base_url, args.sub_url)).start() uvicorn.run( "clan_cli.webui.app:app", diff --git a/pkgs/clan-cli/default.nix b/pkgs/clan-cli/default.nix index 68cc8f98..d81b9f36 100644 --- a/pkgs/clan-cli/default.nix +++ b/pkgs/clan-cli/default.nix @@ -171,7 +171,7 @@ python3.pkgs.buildPythonApplication { desktopItems = [ (makeDesktopItem { name = "clan"; - exec = "clan"; + exec = "clan join %u"; desktopName = "CLan Manager"; startupWMClass = "clan"; mimeTypes = [ "x-scheme-handler/clan" ];