refactor: reorganize client transport and extension internals
- Split client, native, remote, serve, markdown, and SDK internals into focused packages with direct imports. - Move local and remote transport framing/protocol helpers behind clearer module boundaries. - Break up the extension injected DOM logic into a separate content dispatch bundle and dedicated content modules. - Add explicit client handling for passive remote discovery without noisy PQ warnings. - Keep behavior covered with updated unit, integration, and extension tests.
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user