allow to ask for remote host profiles and save token on first connection for later use
This commit is contained in:
+82
-11
@@ -21,6 +21,7 @@ from typing import Any
|
||||
from browser_cli.platform import endpoint_for_alias, is_windows, registry_path
|
||||
|
||||
REGISTRY_PATH = registry_path()
|
||||
REMOTE_REGISTRY_PATH = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "browser-cli" / "remotes.json"
|
||||
|
||||
|
||||
class BrowserNotConnected(Exception):
|
||||
@@ -32,6 +33,8 @@ class BrowserTarget:
|
||||
profile: str
|
||||
display_name: str
|
||||
socket_path: str
|
||||
remote: str | None = None
|
||||
token: str | None = None
|
||||
|
||||
|
||||
def _active_endpoints(reg: dict) -> dict:
|
||||
@@ -47,17 +50,85 @@ def display_browser_name(profile_name: str, sock_path: str) -> str:
|
||||
return Path(sock_path).stem or profile_name
|
||||
|
||||
|
||||
def active_browser_targets() -> list[BrowserTarget]:
|
||||
if not REGISTRY_PATH.exists():
|
||||
return []
|
||||
def _load_remotes() -> dict[str, dict[str, str]]:
|
||||
if not REMOTE_REGISTRY_PATH.exists():
|
||||
return {}
|
||||
try:
|
||||
reg = json.loads(REGISTRY_PATH.read_text())
|
||||
data = json.loads(REMOTE_REGISTRY_PATH.read_text(encoding="utf-8"))
|
||||
except Exception:
|
||||
return []
|
||||
return [
|
||||
BrowserTarget(profile=profile, display_name=display_browser_name(profile, sock_path), socket_path=sock_path)
|
||||
for profile, sock_path in _active_endpoints(reg).items()
|
||||
]
|
||||
return {}
|
||||
if not isinstance(data, dict):
|
||||
return {}
|
||||
return {str(endpoint): cfg for endpoint, cfg in data.items() if isinstance(cfg, dict)}
|
||||
|
||||
|
||||
def save_remote_token(endpoint: str, token: str | None) -> None:
|
||||
"""Persist the auth token for a remote endpoint used by this client."""
|
||||
if not endpoint or not token:
|
||||
return
|
||||
remotes = _load_remotes()
|
||||
current = remotes.get(endpoint, {})
|
||||
current["token"] = token
|
||||
remotes[endpoint] = current
|
||||
REMOTE_REGISTRY_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
REMOTE_REGISTRY_PATH.write_text(json.dumps(remotes, indent=2, sort_keys=True), encoding="utf-8")
|
||||
try:
|
||||
REMOTE_REGISTRY_PATH.chmod(0o600)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def token_for_remote(endpoint: str | None) -> str | None:
|
||||
if not endpoint:
|
||||
return None
|
||||
cfg = _load_remotes().get(endpoint) or {}
|
||||
token = cfg.get("token")
|
||||
return str(token) if token else None
|
||||
|
||||
|
||||
def _remote_display_name(endpoint: str, profile_name: str, display_name: str) -> str:
|
||||
host, sep, port = endpoint.rpartition(":")
|
||||
remote_name = host if sep and port == "8765" else endpoint
|
||||
return f"{remote_name}:{display_name or profile_name}"
|
||||
|
||||
|
||||
def _remote_browser_targets() -> list[BrowserTarget]:
|
||||
targets: list[BrowserTarget] = []
|
||||
for endpoint, cfg in _load_remotes().items():
|
||||
token = str(cfg.get("token") or "") or None
|
||||
try:
|
||||
remote_targets = send_command("browser-cli.targets", remote=endpoint, token=token)
|
||||
except (BrowserNotConnected, RuntimeError):
|
||||
continue
|
||||
for item in remote_targets or []:
|
||||
profile = str(item.get("profile") or "default")
|
||||
display = str(item.get("displayName") or profile)
|
||||
targets.append(
|
||||
BrowserTarget(
|
||||
profile=profile,
|
||||
display_name=_remote_display_name(endpoint, profile, display),
|
||||
socket_path="",
|
||||
remote=endpoint,
|
||||
token=token,
|
||||
)
|
||||
)
|
||||
return targets
|
||||
|
||||
|
||||
def active_browser_targets(*, include_remotes: bool = True) -> list[BrowserTarget]:
|
||||
targets: list[BrowserTarget] = []
|
||||
if REGISTRY_PATH.exists():
|
||||
try:
|
||||
reg = json.loads(REGISTRY_PATH.read_text())
|
||||
except Exception:
|
||||
reg = {}
|
||||
targets.extend(
|
||||
BrowserTarget(profile=profile, display_name=display_browser_name(profile, sock_path), socket_path=sock_path)
|
||||
for profile, sock_path in _active_endpoints(reg).items()
|
||||
)
|
||||
if include_remotes:
|
||||
targets.extend(_remote_browser_targets())
|
||||
return targets
|
||||
|
||||
|
||||
def _resolve_socket(profile: str | None = None) -> str:
|
||||
@@ -76,7 +147,7 @@ def _resolve_socket(profile: str | None = None) -> str:
|
||||
|
||||
# Auto-detect: error when multiple browser instances are active
|
||||
try:
|
||||
active = active_browser_targets()
|
||||
active = active_browser_targets(include_remotes=False)
|
||||
if len(active) > 1:
|
||||
aliases = [target.profile for target in active]
|
||||
examples = "\n".join(f" browser-cli --browser {a} ..." for a in aliases)
|
||||
@@ -101,7 +172,7 @@ def _resolve_socket(profile: str | None = None) -> str:
|
||||
def send_command(command: str, args: dict | None = None, profile: str | None = None, remote: str | None = None, token: str | None = None) -> Any:
|
||||
"""Send a command to the browser and return the response data."""
|
||||
remote_endpoint = remote or os.environ.get("BROWSER_CLI_REMOTE")
|
||||
resolved_token = token or os.environ.get("BROWSER_CLI_TOKEN")
|
||||
resolved_token = token or os.environ.get("BROWSER_CLI_TOKEN") or token_for_remote(remote_endpoint)
|
||||
msg = {
|
||||
"id": str(uuid.uuid4()),
|
||||
"command": command,
|
||||
|
||||
Reference in New Issue
Block a user