"""Local IPC transport for browser-cli client commands.""" from __future__ import annotations import asyncio import socket from collections.abc import Callable from multiprocessing.connection import Client as PipeClient from browser_cli.framing import async_recv_exact as framing_async_recv_exact from browser_cli.framing import async_recv_frame, async_send_frame, frame from browser_cli.platform import is_windows from browser_cli.remote.transport import _recv_all async def async_recv_exact(reader: asyncio.StreamReader, n: int) -> bytes | None: try: return await framing_async_recv_exact(reader, n, allow_eof=True) except ConnectionError: return None async def async_recv_all(reader: asyncio.StreamReader) -> bytes | None: try: return await async_recv_frame(reader, allow_eof=True) except ConnectionError: return None async def async_send_all(writer: asyncio.StreamWriter, data: bytes) -> None: await async_send_frame(writer, data) def send_local_sync(profile: str | None, payload: bytes, resolve_socket: Callable[[str | None], str]) -> bytes | None: sock_path = resolve_socket(profile) if is_windows(): with PipeClient(sock_path, family="AF_PIPE") as conn: conn.send_bytes(payload) return conn.recv_bytes() with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock: sock.connect(sock_path) sock.sendall(frame(payload)) return _recv_all(sock) async def send_local_async(profile: str | None, payload: bytes, resolve_socket: Callable[[str | None], str]) -> bytes | None: sock_path = await asyncio.to_thread(resolve_socket, profile) if is_windows(): return await _send_windows_pipe_async(sock_path, payload) return await _send_local_unix_async(sock_path, payload) async def _send_local_unix_async(sock_path: str, payload: bytes) -> bytes | None: reader, writer = await asyncio.open_unix_connection(sock_path) try: await async_send_all(writer, payload) return await async_recv_all(reader) finally: writer.close() try: await writer.wait_closed() except Exception: pass async def _send_windows_pipe_async(sock_path: str, payload: bytes) -> bytes: def _roundtrip(): with PipeClient(sock_path, family="AF_PIPE") as conn: conn.send_bytes(payload) return conn.recv_bytes() return await asyncio.to_thread(_roundtrip)