一句话描述:一个围绕浏览器指纹、代理池、浏览器实例和自建 stealth 浏览器运行时构建的浏览器环境编排仓库。
服务对象:上层账号/会话编排系统、浏览器实例调度逻辑、开发与测试人员。
所属模块:浏览器环境编排与自动化执行。
- 指纹生成与校验:
fingerprint/生成国家维度的确定性浏览器指纹,并校验平台、GPU、时区、语言、屏幕与网络一致性。 - 代理池管理:
proxy/维护代理状态、绑定关系、健康检查,并支持 Bright Data、Oxylabs、Mock 适配器。 - 浏览器实例管理:
instance/负责端口分配、进程拉起、实例持久化、CDP 连接与生命周期管理。 - 浏览器运行时接入:
cloakbrowser/目前封装兼容 CloakBrowser 的浏览器启动与 CDP 接入;目标是逐步切换到自建 Chromium-based stealth 浏览器产物。
| 维度 | 结果 |
|---|---|
| 主要语言 | Go |
| 主要运行形态 | Go 库包 |
| 外部依赖 | 浏览器产物、代理商服务、PostgreSQL 风格存储 |
| 当前架构 | 模块化单仓库,偏库层/适配层设计 |
| 当前范围 | 指纹、实例、代理、浏览器运行时发现,以及浏览器内核专项规划 |
- 默认浏览器引擎:实例服务当前默认走 CloakBrowser-compatible runtime。
- 开发回退:仅在显式设置
BROWSER_ENGINE=local-chrome时回退到本地 Chrome。 - 二进制解析顺序:优先读取
CLOAKBROWSER_PATH/BROWSER_BINARY,否则再尝试resources/cloakbrowser/artifacts.json和打包后 app-relative 的浏览器产物路径。 - 诊断入口:设置页可查看当前激活引擎,以及每个指纹字段在运行时的注入覆盖状态。
| 路径 | 说明 |
|---|---|
fingerprint/ |
指纹数据结构、国家配置、生成器、校验器 |
proxy/ |
代理实体、Provider 接口、适配器、健康检查、存储 |
instance/ |
浏览器实例模型、进程管理、CDP 通信、端口分配、存储 |
cloakbrowser/ |
浏览器运行时客户端封装(当前兼容 CloakBrowser,目标切换自建产物) |
resources/cloakbrowser/ |
浏览器产物清单与后续打包入口 |
docs/ |
项目文档与测试指南 |
resources/ |
补充资源文件 |
screenshots/ |
历史截图与快照输出 |
- 仓库当前没有完整业务域 HTTP Controller/REST API 实现,对外能力仍以 Go 包导出方法与 Wails 命令为主。
- 仓库当前已经有
go.mod,可直接运行go test ./...与go build ./...。 instance/store.go显示存在browser_instances表,但仓库内没有完整 schema 文件。- 主模块 import path 已切换到
github.com/tmos/fingerbrower,但proxy/adapter/中仍保留少量上游github.com/tmos/facebook/internal/proxy引用,需要后续统一。 - 仓库当前活动文档集只保留与指纹浏览器产品本身直接相关的内容;旧的 TMOS/TikTok 业务文档已移出活动文档集。
- PRD
- 架构覆盖报告
- 模块说明:MOD-01 指纹引擎
- 模块说明:MOD-02 实例管理
- 模块说明:MOD-03 IP 池
- 浏览器源码构建与运行时发现架构
- 浏览器内核专项技术设计
- 开发计划总览
- 后端开发计划:MOD-01 指纹引擎
- 后端开发计划:MOD-02 实例管理
- 后端开发计划:MOD-03 IP 池
- 浏览器源码构建改进方案
- 浏览器内核专项开发计划
- 单元测试指南
- 集成测试指南
- E2E 测试指南
- Mock 策略
核心原则:每个功能只在一个地方实现。
- 同一接口/方法不要在多个包中重复实现
- 如果需要在多个地方使用同一逻辑,将其提取为共享接口或工具函数
- 禁止复制粘贴代码,即使"只是一点点"
示例:
// 错误:重复实现同一接口
type InstanceService struct {
manager browserRuntimeManager
// ... 自己实现了 GetCDPClient
}
type instanceManager struct {
store Store
processMgr *ProcessManager
// ... 又实现了一个 GetCDPClient
}
// 正确:委托模式,InstanceService 使用 InstanceManager
type InstanceService struct {
mgr InstanceManager // 委托给 instance 包
}
func (s *InstanceService) GetCDPClient(ctx context.Context, id string) (CDPClientInterface, error) {
return s.mgr.GetCDPClient(ctx, id) // 委托
}- 修改代码前先确认该代码的实际调用路径(不要只改"看起来像"的地方)
- 通过日志、进程检查等手段验证修改是否生效
- 彻底杀灭旧进程后再启动新进程
- Go 编译缓存可能需要手动清理:
go clean -cache