This commit is contained in:
82
src/jiangchang_desktop_sdk/testing/host_api.py
Normal file
82
src/jiangchang_desktop_sdk/testing/host_api.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""匠厂 Host HTTP API 的 Python 轻封装。
|
||||
|
||||
使用 stdlib urllib,避免为 SDK 引入新运行时依赖。当前只暴露本模块
|
||||
真正需要的端点(健康探活、agent 列表),**不包含任何会话删除/会话
|
||||
文件系统操作**——测试侧要保持"只通过 UI 操作,不走底层接口"的原则,
|
||||
后续如需访问其他 host-api 端点请在此处按需添加读型方法。
|
||||
|
||||
Host API 默认端口:`13210`(见 jiangchang/electron/utils/config.ts 中 `CLAWX_HOST_API`)。
|
||||
可通过环境变量 ``CLAWX_PORT_CLAWX_HOST_API`` 或本类的 ``port`` 参数覆盖。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
DEFAULT_PORT = 13210
|
||||
DEFAULT_HOST = "127.0.0.1"
|
||||
|
||||
logger = logging.getLogger("jiangchang_desktop_sdk.testing.host_api")
|
||||
|
||||
|
||||
class HostAPIError(RuntimeError):
|
||||
"""Host API 调用失败(网络错误或非 2xx 响应)。"""
|
||||
|
||||
|
||||
class HostAPIClient:
|
||||
def __init__(
|
||||
self,
|
||||
host: str = DEFAULT_HOST,
|
||||
port: Optional[int] = None,
|
||||
timeout: float = 10.0,
|
||||
) -> None:
|
||||
self.host = host
|
||||
env_port = os.environ.get("CLAWX_PORT_CLAWX_HOST_API")
|
||||
self.port = port or (int(env_port) if env_port else DEFAULT_PORT)
|
||||
self.timeout = timeout
|
||||
|
||||
@property
|
||||
def base_url(self) -> str:
|
||||
return f"http://{self.host}:{self.port}"
|
||||
|
||||
def _request(self, method: str, path: str, body: Any = None) -> Any:
|
||||
url = f"{self.base_url}{path}"
|
||||
data = None
|
||||
headers = {"Accept": "application/json"}
|
||||
if body is not None:
|
||||
data = json.dumps(body).encode("utf-8")
|
||||
headers["Content-Type"] = "application/json"
|
||||
req = urllib.request.Request(url, data=data, method=method, headers=headers)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
|
||||
raw = resp.read().decode("utf-8")
|
||||
if not raw:
|
||||
return None
|
||||
try:
|
||||
return json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
return raw
|
||||
except urllib.error.HTTPError as exc:
|
||||
payload: Any
|
||||
try:
|
||||
payload = json.loads(exc.read().decode("utf-8"))
|
||||
except Exception: # noqa: BLE001
|
||||
payload = str(exc)
|
||||
raise HostAPIError(f"{method} {path} -> HTTP {exc.code}: {payload}") from exc
|
||||
except urllib.error.URLError as exc:
|
||||
raise HostAPIError(f"{method} {path} -> {exc}") from exc
|
||||
|
||||
def ping(self) -> bool:
|
||||
try:
|
||||
self.list_agents()
|
||||
return True
|
||||
except HostAPIError:
|
||||
return False
|
||||
|
||||
def list_agents(self) -> Dict[str, Any]:
|
||||
return self._request("GET", "/api/agents") or {}
|
||||
Reference in New Issue
Block a user