144 lines
6.0 KiB
Markdown
144 lines
6.0 KiB
Markdown
# DHT 元数据搜索服务开发约定
|
|
|
|
## 项目目标
|
|
|
|
本项目用于持续或间歇地从 BitTorrent DHT 网络发现 infohash 获取元数据并提供本地全文搜索和高性能过滤能力
|
|
|
|
基础 DHT 协议和抓取能力保留在 `src/crawler` 中
|
|
|
|
面向最终用户运行的服务代码统一放在 `src/search` 中
|
|
|
|
Web 前端代码统一放在 `src/web` 中
|
|
|
|
## 技术方案
|
|
|
|
- Tokio 负责异步任务调度网络任务和有界队列
|
|
- RocksDB 负责权威数据持久化精确去重抓取状态和索引状态
|
|
- Tantivy 负责可重建的全文搜索过滤排序和结果聚合
|
|
- Axum 负责 HTTP 搜索接口详情接口和运行状态接口
|
|
- BLAKE3 负责计算规范化内容结构指纹
|
|
- Serde 负责配置领域对象和接口数据的序列化
|
|
- Tracing 负责结构化日志和故障定位
|
|
- SQLite 负责有保留上限的运行诊断历史且不得成为业务权威数据源
|
|
|
|
RocksDB 是唯一权威数据源
|
|
|
|
Tantivy 索引必须能够从 RocksDB 完整重建
|
|
|
|
## 数据处理流程
|
|
|
|
1. DHT 采集器发现 infohash
|
|
2. 内存近期缓存过滤高频重复
|
|
3. RocksDB 精确判断 infohash 是否已处理
|
|
4. 未处理的 infohash 进入有界 Metadata 下载队列
|
|
5. Metadata 完成校验和规范化后计算内容指纹
|
|
6. 使用 RocksDB WriteBatch 原子保存元数据去重映射和待索引状态
|
|
7. 后台索引任务批量写入 Tantivy
|
|
8. Tantivy 提交成功后将记录状态更新为已索引
|
|
9. Axum 只通过搜索和存储抽象读取数据
|
|
|
|
所有任务队列必须有明确容量并在队列满时产生背压
|
|
|
|
禁止通过无限队列维持表面吞吐
|
|
|
|
## 去重规则
|
|
|
|
第一层以 infohash 做精确去重并阻止相同 Metadata 被重复下载
|
|
|
|
第二层根据规范化文件路径和文件大小计算 content key 将不同 infohash 的相同内容聚合展示
|
|
|
|
模糊名称相似度只用于搜索结果聚合不得直接删除数据
|
|
|
|
Bloom Filter 只能作为前置加速结构不得作为最终去重依据
|
|
|
|
再次发现已有 infohash 时只更新最后发现时间和发现次数
|
|
|
|
## 持久化和恢复
|
|
|
|
程序必须支持间歇运行和跨重启恢复
|
|
|
|
正常关闭时先停止接收新任务再排空或持久化队列最后提交搜索索引
|
|
|
|
异常退出后依靠 RocksDB WAL 恢复已提交数据
|
|
|
|
每条搜索文档必须具有待索引和已索引状态以便启动后补建索引
|
|
|
|
内存队列不得成为任何权威状态的唯一保存位置
|
|
|
|
数据目录必须通过配置指定且不得依赖当前工作目录
|
|
|
|
## 代码边界
|
|
|
|
- `crawler` 只负责协调 DHT 事件和 Metadata 下载
|
|
- `domain` 只定义领域模型规范化规则和内容指纹
|
|
- `storage` 只负责 RocksDB 数据布局原子写入查询和恢复
|
|
- `search` 只负责 Tantivy schema 文档转换索引和查询
|
|
- `api` 只负责 HTTP 协议参数校验和响应转换
|
|
- `config` 只负责读取校验和暴露配置
|
|
- `diagnostics` 只负责采集聚合和查询可删除的运行指标历史
|
|
- `telemetry` 只负责日志指标和运行观测
|
|
- `shutdown` 只负责关闭信号和优雅退出协调
|
|
|
|
模块之间通过明确的数据结构和 trait 通信不得跨层直接访问内部实现
|
|
|
|
配置文件只是配置 DTO 的持久化适配器
|
|
|
|
用户配置 DTO 运行时解析结果和配置存储实现必须保持独立边界
|
|
|
|
配置更新必须先完整校验再通过同目录临时文件同步和原子替换保存
|
|
|
|
配置接口必须使用修订号阻止并发请求静默覆盖且不得假装未实际支持的在线热更新
|
|
|
|
领域层不得直接依赖 `dht-crawler` 的回调或传输 DTO
|
|
|
|
## 组合和文件边界
|
|
|
|
- trait 只用于存储搜索网络回调等真实替换边界 不创建只有一个调用方的抽象基类或通用 Service 层
|
|
- 应用入口只负责构造依赖启动任务选择退出原因和按顺序关闭 不承载 worker 循环和指标格式化
|
|
- 每个长期任务独立拥有状态和取消令牌 通过明确句柄组合 不共享可变全局状态
|
|
- 领域文件按 infohash Metadata 接纳内容聚合和种子状态演进划分 不按接口页面或数据库字段重复定义模型
|
|
- 搜索 schema 查询条件文档映射索引执行分别维护 Tantivy 细节不得泄漏到 API 层
|
|
- 基准和工具代码同样遵守职责拆分 不因不进入主服务而集中到单个大文件
|
|
- 文件长度不是机械拆分标准 单一状态机或单一 adapter 可以集中维护 强拆会产生私有状态穿透时应保持内聚
|
|
- 删除没有调用方的预留模块 新扩展在产生真实行为时再创建文件
|
|
|
|
测试分层位置默认验证命令和依赖规则统一记录在根目录 `README.md`
|
|
|
|
## 资源约束
|
|
|
|
- Metadata 下载并发必须可配置
|
|
- 单个 Metadata 大小文件数量和路径长度必须有限制
|
|
- RocksDB 写入使用批处理并明确控制 block cache
|
|
- Tantivy 写入使用批量提交并明确控制 IndexWriter 内存预算
|
|
- 日志不得输出完整 Metadata 或大文件列表
|
|
- 长期运行的集合必须有容量上限过期规则或磁盘持久化方案
|
|
- 诊断历史必须使用独立 SQLite 数据库并通过采样降级和保留策略限制增长
|
|
|
|
## 开发规则
|
|
|
|
新业务代码写入 `src/search`
|
|
|
|
项目阶段任务完成状态和验收标准统一维护在根目录 `TODOS.md`
|
|
|
|
需求实现或技术决策发生变化时必须同步更新 `TODOS.md`
|
|
|
|
`src/crawler` 只接受可复用的 DHT 基础能力不得包含数据库搜索接口或部署逻辑
|
|
|
|
每个 Rust 文件顶部必须使用中文行注释描述该文件的功能边界且注释行尾不添加标点
|
|
|
|
新增行为必须包含与风险相称的测试
|
|
|
|
开发阶段修改持久化 key 或编码格式时经用户明确授权可以清理测试数据重新开始 正式格式冻结后必须提供兼容或迁移方案
|
|
|
|
不得把 `opencodes` 下的参考项目纳入 workspace 或修改其内容
|
|
|
|
## 构建准备
|
|
|
|
应用骨架默认不启用 RocksDB 原生构建
|
|
|
|
实现存储层时通过 `rocksdb-storage` feature 启用 RocksDB
|
|
|
|
Windows 构建 RocksDB 前需要安装 LLVM 并确保 `LIBCLANG_PATH` 指向包含 `libclang.dll` 的目录
|
|
|
|
启用后的检查命令为 `cargo check -p dht-search --features rocksdb-storage`
|