83 lines
8.7 KiB
Markdown
83 lines
8.7 KiB
Markdown
# 宿主机浏览器控制面
|
||
|
||
> 当前实现说明,基于已同步的 `main@7e3808cf4ce453b3583079680a3b59ca2ed64ad4`。单节点 native browser + Xvfb 已实现;真实平台、代理、LAN 和多节点能力仍以[验证文档](../native-browser-verification.md)为准。业务范围以 [plan01](../plan01.md) 为准,部署步骤见[部署说明](../deployment.md)。
|
||
|
||
## 技术选型
|
||
|
||
- 前端:React 19 + Vite 8 + Refine + shadcn/ui + Tailwind CSS,图标 RemixIcon;项目自有 Layout 与 HashRouter。
|
||
- 控制面:Go、Fiber v3、Viper、Logrus、Cobra。控制面编排浏览器 gateway、环境、账号、任务和审计,不直接启动浏览器。
|
||
- 浏览器 gateway:Python 3.12+ 标准库 HTTP/进程/文件/socket 能力;以非 root `systemctl --user` 服务运行,在宿主机管理 Xvfb、native/fingerprint browser、Profile、CDP、代理和运行代次。
|
||
- 数据:PostgreSQL 保存网关登记、环境绑定、运行实例、清理状态、租约、账号、任务、结果和审计。浏览器可执行文件、默认版本和路径映射属于 gateway 宿主机配置,不进入 control-plane 管理数据。
|
||
- 部署:Compose 只提供控制面和 PostgreSQL;gateway 与 Xvfb 在宿主机运行。控制面在 Compose 中通过 `host.docker.internal:8081` 访问 gateway,裸机运行使用 `127.0.0.1:8081`。
|
||
|
||
## 调用链与职责
|
||
|
||
```text
|
||
React ── /api/* (Basic Auth) ──> control-plane ──> PostgreSQL
|
||
│
|
||
└─ /v1/browsers (Bearer token)
|
||
└─ host-native browser gateway
|
||
├─ Xvfb display
|
||
├─ fingerprint browser + Profile
|
||
├─ CDP endpoint
|
||
└─ loopback proxy / event stream
|
||
```
|
||
|
||
控制面是业务事实源,gateway 是本机浏览器资源事实源。gateway 不接受任意 Profile 路径、不暴露通用 CDP、不创建 Docker 资源;Profile 由 gateway 根据 `profile_id` 映射到 gateway 自己管理的目录。
|
||
|
||
## 生命周期契约
|
||
|
||
生命周期操作都必须带当前 `binding_version`,并在需要时带 `runtime_id`、`network_id` 和 `runtime_instance_id`。服务端以 alias 串行化操作,拿锁后重新读取账号、环境、版本和出口。
|
||
|
||
| 接口/动作 | 当前行为与失败语义 |
|
||
| --- | --- |
|
||
| `POST /api/browsers` | 接收 `alias`、`name`、`gateway`、`fingerprint`、`account_id`、`network_exit_id`。账号必须满足授权/暂停规则,指定出口必须健康。先保存环境和稳定 binding,再向 gateway 创建停止态 runtime;失败保留环境、operation 和清理状态,不伪造成功。
|
||
| `GET /api/browsers`、`GET /api/browsers/{alias}` | 返回数据库状态与 gateway 可达时的 runtime 快照,包括 `node_id`、generation、ready、运行状态、cleanup 状态和失败原因。不可达、版本缺失、Profile 占用和待清理均保持可见;读取不把未知状态改成 stopped。 |
|
||
| `POST /api/browsers/{alias}/start` | 重新核对账号、Profile、出口和 binding。匹配的 ready runtime 可复用;缺失或不匹配时按当前 binding 创建新代次并激活。必需代理失败时不得直连。 |
|
||
| `POST /api/browsers/{alias}/stop` | 以当前 generation 停止浏览器、Xvfb、代理和订阅,并记录独立 cleanup 状态。结果未知、强杀或清理失败返回可见失败/待清理状态,而不是请求发出即成功。 |
|
||
| `POST /api/browsers/{alias}/rebind` | 接收有效 `network_exit_id`,要求没有执行中的 runtime-use 或业务任务;成功后递增 binding version。空值切直连不通过此接口隐式完成。 |
|
||
| `DELETE /api/browsers/{alias}` | 回收当前 runtime 和本次临时资源,保留环境、稳定 binding、账号 Profile、正式结果和长期监听。旧 generation 的迟到清理不会触碰 successor。 |
|
||
|
||
每个 runtime 独立拥有:`runtime_id`、`runtime_instance_id`、`generation`、`node_id`、owner、Profile、display、CDP 端口、loopback proxy 端口、browser/Xvfb unit、日志目录和 cleanup 状态。runtime 结束后,任务目录按结果语义清理;正式素材和结果目录不由通用 runtime 清理逻辑删除。
|
||
|
||
## 网关与 Profile
|
||
|
||
- `GET/POST /api/gateways` 注册稳定 gateway endpoint、node name 和令牌;gateway `/v1/info` 返回稳定 `node_id`、默认运行时和能力。浏览器安装、默认版本及可选路径映射只由 gateway 宿主机配置,control-plane 不提供版本登记或升级入口。
|
||
- 创建环境只绑定账号、gateway、指纹和网络出口;gateway 创建 runtime 时使用自己的默认浏览器配置。当前目标只调度单 gateway,不执行跨机迁移。
|
||
- `profile_id` 由控制面绑定账号和环境,gateway 只接受已登记的标识并生成目录。Profile 目录权限为 owner-only;同一 Profile 的第二个 runtime 在资源锁阶段拒绝。
|
||
- 每个执行使用独立的 `.runs/<execution_id>` 目录和不可变 token。业务结果引用相对 work root 的正式产物;路径穿越、绝对路径、跨 work 目录和临时文件均拒绝。
|
||
|
||
## generation 与 runtime-use lease
|
||
|
||
- 激活 runtime 时保存 owner、node、binding version、runtime/network ID 和 runtime instance ID。所有 gateway 写操作核对这些值;旧代次收到迟到请求时返回冲突,不删除 successor。
|
||
- 业务任务和长期监听不共享“环境存在”这一隐含占用。`runtime_use_lease` 默认 60 秒,20 秒续租;任务、素材处理、平台读取、会话历史和监听均显式 acquire/renew/release。
|
||
- lease 续租失败会取消使用上下文并保留失败原因;释放操作幂等。gateway 重启后先按 runtime instance 恢复或标记 cleanup pending,再允许新 lease。
|
||
- 采集 task lease 与合法长期监听 lease 分开;监听重连会核对 node/generation/binding,事件去重和 UID 冷却仍由 creator 数据层负责。
|
||
|
||
## 代理边界
|
||
|
||
控制面只把经过校验的出口配置交给 gateway。gateway 代理绑定 `127.0.0.1` 动态端口,并以 alias、binding version、runtime/network generation 绑定;代理恢复或移除失败必须可见。必需代理启动失败时不切换直连,不把不确定的写结果转换成成功。
|
||
|
||
出口凭据只存在于控制面单次请求和 gateway 内存代理,不能进入 URL、日志、数据库、浏览器命令行或 API 响应。代理检查、重启恢复和清理均按当前 generation fence。
|
||
|
||
## 非 root 与系统边界
|
||
|
||
- gateway 由宿主机非 root 用户的 `systemctl --user` 服务运行;Xvfb、browser 和 Profile 的 unit 都属于该用户。
|
||
- native gateway 不读取 Docker socket,不创建/删除浏览器 container、image、volume 或 network,也不保留 Docker fallback。
|
||
- 启动命令拒绝 `--no-sandbox` 等越权参数;无法满足 sandbox、磁盘、路径、端口、权限或版本条件时直接失败并记录原因。
|
||
- `/healthz` 用于存活;其它 gateway API 使用 Bearer token。控制面继续按现有部署策略提供 Basic Auth;本目标不新增 RBAC。
|
||
|
||
## 运行与恢复
|
||
|
||
使用[部署说明](../deployment.md)中的变量和命令。首次部署时在 gateway 宿主机配置已安装的浏览器和 Xvfb,再以 `scripts/install-native-browser-gateway.sh` 安装 gateway user service,随后在控制面注册 gateway、账号和出口。
|
||
|
||
启动、停止和回收分别写 requested/finished operation;gateway 不可达、返回未知、cleanup pending 和 Profile 被占用都在页面和 API 显示。gateway 重启只恢复仍匹配当前代次的 runtime;机器重启不自动恢复已过期短任务。控制面后台 heartbeat 续租 running runtime 并调和 cleanup,读取列表不会用轮询伪装业务事件监听。
|
||
|
||
## 阶段 A 与 Creator 业务边界
|
||
|
||
阶段 A 账号、凭据引用、确认、任务和审计继续由 PostgreSQL 持久化。账号身份在每次写操作前由 gateway 返回的实际 UID 与已授权 `platform_account_key` 核对;Cookie、密码、token 和 provider reference 不回显。
|
||
|
||
Creator 采集流程使用独立 runtime-use lease:登录二维码、身份核对、抖音读取、评论/私信历史、素材下载、音频提取和指标处理完成后才释放浏览器使用权。结果保存与资源清理分开记录;结果未知时保留执行目录和证据,不能重复写入或删除可能仍被引用的素材。
|
||
|
||
当前仍需真实账号、真实代理和人工 LAN 验收的项目见[验证记录](../evidence/native-browser-verification-2026-09-18.md)。多节点、A/B、跨机故障恢复和性能对比明确移出本目标。
|