Files
sehuatang/PROJECT_ARCHITECTURE.md
2026-03-18 00:28:14 +08:00

17 KiB
Raw Permalink Blame History

涩花塘磁力助手 - 项目架构与部署说明

更新时间2026-03-14
说明:本文档描述当前项目的整体架构、核心数据流、缓存策略、云同步设计、线上部署信息(不包含任何敏感凭据),以及当前已知问题与优化方向。


1. 项目概览

本项目由两部分组成:

  1. Chrome 扩展端
    负责在涩花塘论坛页面中:

    • 识别列表页 / 帖子页
    • 批量抓取帖子与磁力链接
    • 本地缓存帖子、范围快照、页快照、磁力结果
    • 展示搜索结果、缓存总览、收藏夹、云同步入口
  2. 云端共享缓存服务
    负责:

    • 共享线程缓存shared thread cache
    • 共享范围缓存shared coverage cache
    • 共享页缓存shared page cache
    • 覆盖规划coverage planning
    • 私有保险柜vault
    • 账号注册 / 登录 / 鉴权

2. 目录结构

扩展端根目录

  • manifest.jsonChrome 扩展清单MV3
  • content.js:内容脚本,挂载 UI、执行抓取、合并缓存、结果展示
  • background.jsService Worker负责 IndexedDB、本地状态、云接口、跨页请求
  • popup.html / popup.js:扩展独立云同步中心 + 快捷复制入口

服务端目录

  • server/package.json:服务端依赖与脚本
  • server/src/index.jsFastify 入口
  • server/src/config.js:环境变量配置
  • server/src/db.jsMySQL 连接池
  • server/src/redis.jsRedis 连接与 JSON 缓存
  • server/src/crypto.jsAES-GCM 加密与哈希
  • server/src/auth.js:认证辅助逻辑
  • server/src/routes/auth.js:注册 / 登录 / me / logout
  • server/src/routes/vault.js:私有保险柜 push / pull
  • server/src/routes/shared-cache.js:共享缓存查找 / 写入 / coverage planning
  • server/sql/001_init.sql:数据库初始化表结构

3. 扩展端架构

3.1 页面层content.js

content.js 负责:

  • 判断当前页面是:
    • 列表页forumdisplay / forum-x-y.html / normalthread tbody
    • 帖子页thread-xxx / tid=xxx
  • 创建浮动面板 UI
  • 管理:
    • 关键词搜索
    • 页码范围
    • 速度模式
    • 结果列表
    • 收藏页
    • 缓存页
    • 云同步页入口
  • 调用后台:
    • 读取 / 保存本地缓存
    • 读取 / 保存进度状态
    • 触发云同步相关动作

3.2 后台层background.js

background.js 是当前项目的核心调度层,负责:

  • IndexedDB 缓存存取
  • 云缓存接口调用
  • 共享缓存 planning 调用
  • 上传抑制hash 去重 + TTL 节流)
  • 本地历史缓存回填到云端
  • 私有保险柜加解密
  • 云账号登录状态维护

3.3 本地存储层

当前本地存储分三类:

  1. IndexedDB结构化缓存

    • threads
    • coverages
    • pageCoverages
  2. chrome.storage.local扩展私有存储

    • 收藏夹
    • 搜索历史
    • 云同步状态
    • 上传元数据去重表
    • 进度状态
  3. 运行时内存态

    • 当前抓取状态
    • session backup 临时状态

4. 服务端架构

4.1 服务端职责

云服务现在不仅是“存数据”,还承担:

  • 共享缓存存储
  • 去重写入
  • coverage planning
  • Redis 缓存 planning 结果
  • 账号认证
  • 私有保险柜同步

4.2 路由职责

认证

  • POST /api/auth/register
  • POST /api/auth/login
  • GET /api/auth/me
  • POST /api/auth/logout

私有保险柜

  • POST /api/vault/push
  • POST /api/vault/pull

共享缓存

  • POST /api/shared-cache/threads/lookup
  • POST /api/shared-cache/threads/upsert
  • POST /api/shared-cache/coverages/lookup
  • POST /api/shared-cache/coverages/upsert
  • POST /api/shared-cache/pages/lookup
  • POST /api/shared-cache/pages/upsert
  • POST /api/shared-cache/coverages/plan

健康检查

  • GET /health
  • GET /ready

5. 本地缓存模型

5.1 threads

存储唯一帖子级信息:

  • forumKey
  • threadKey
  • url
  • title
  • lastSeenAt
  • magnets
  • lastMagnetSyncAt

特点:

  • 同一板块 + 同一帖子只保留一份
  • 线程磁链缓存优先从这里命中

5.2 coverages

存储范围级快照:

  • forumKey
  • startPage
  • endPage
  • strategy
  • frontRefreshPages
  • threadKeys

特点:

  • 表示某个页范围对应的帖子集合
  • 用于 exact coverage / shifted coverage / 历史 coverage 碎片复用

5.3 pageCoverages

存储页级快照:

  • forumKey
  • page
  • threadKeys

特点:

  • 用来组装连续页块
  • 当前大范围命中优化的重要基础

6. 云端缓存模型

6.1 共享线程缓存 shared_thread_cache

  • 唯一键:(forum_key, thread_key)
  • 数据库存储加密AES-GCM
  • 用于跨用户复用帖子级磁链结果

6.2 共享范围缓存 shared_coverage_cache

  • 唯一键:(forum_key, start_page, end_page, strategy)
  • 用于整段范围的覆盖规划

6.3 共享页缓存 shared_page_cache

  • 唯一键:(forum_key, page)
  • 用于连续页块拼装

6.4 私有保险柜 vault_items

  • 用户级密文存储
  • 当前用于:
    • 收藏夹
    • 搜索历史
    • UI 设置
    • 进度状态

7. 抓取流程(当前实际运行路径)

7.1 点击“开始获取”后的流程

  1. 读取页码范围 / 关键词 / 速度配置
  2. 构建 searchContext
  3. 显示:
    • 正在规划缓存:检查本地缓存 / 云端规划 / 复用块...
  4. 调用 getCachedCoveragePlan(...)
  5. 依次判断:
    • exact coverage
    • assembled page coverage
    • 服务端 planning
    • cachedBlocks
    • shiftedCoverage
  6. 对缺口区间执行 live 抓取
  7. 结果与缓存合并后,再写回本地与云端

7.2 实际搜索执行路径

主要函数:

  • fetchFromPage(...)
  • fetchLivePageRange(...)
  • processCachedThreadBatch(...)
  • applyCachedMagnetHits(...)

8. 去重与上传抑制策略

8.1 本地去重

  • 线程去重:normalizeCachedThreads()
  • 磁链去重:normalizeMagnetList()
  • coverage 合并去重:mergeCoverageThreads()
  • coverage 保存前合并:mergeCoverageThreadLists()

8.2 云端去重

数据库唯一索引 + ON DUPLICATE KEY UPDATE

8.3 上传抑制

本地维护 upload meta

  • threads
  • coverages
  • pages

每类记录:

  • payloadHash
  • lastUploadedAt

TTL

  • 线程10 分钟
  • 30 分钟
  • 范围60 分钟

作用:

  • 降低重复上传
  • 降低重复加密
  • 降低数据库写入压力

9. 当前“智能更新”逻辑

已实现

  1. front refresh从第一页开始时可刷新前段
  2. shiftedCoverage 复用
  3. page cache block 复用
  4. intersecting coverage fragments 复用
  5. 服务端 coverage planning
  6. Redis 缓存 planning 结果

当前仍不够理想的点

  1. thread cache 很多,但未完全反向沉淀成 page/coverage 索引
    这会导致“明明有很多历史线程缓存,但大范围规划不够聪明”。

  2. coverage 合并仍然偏保守
    少量前页更新后,虽然已经补了历史 coverage 合并,但仍建议继续增强“旧帖保留连续性”。

  3. 前段刷新策略仍是经验型策略
    当前已从“固定刷新前 20 页”改为“前面没有缓存覆盖才刷新”,但仍属于启发式策略。

  4. 启动前规划仍然是同步等待
    现在已经加了状态提示,但未来可以做:

    • 本地快速规划优先
    • 云端规划异步补充

10. 线上部署信息(不含敏感凭据)

服务器基础信息

  • 公网 IP47.238.173.98
  • 域名:s.52oai.com
  • 系统CentOS 7当前会话已确认
  • 部署方式Nginx + PM2 + Node.js + MySQL + Redis
  • 面板宝塔面板BT Panel

当前服务端组成

  • Nginx反向代理入口
  • Node 服务:magnet-cloud-cache
  • PM2进程守护
  • MySQL主数据存储
  • Rediscoverage planning 结果缓存

线上访问入口

  • https://s.52oai.com/health
  • https://s.52oai.com/ready

Redis 状态

当前已验证:

  • Redis 可连接
  • 可写入/读取 JSON
  • coverage planning key 已落库

11. 当前安全边界

已完成的安全改造

  1. 云同步登录/注册 UI 已迁移到扩展独立页面
  2. 收藏/搜索历史已迁移到扩展私有存储
  3. session 进度备份已不再依赖页面 sessionStorage
  4. shared-cache 写接口已加写入令牌鉴权
  5. shared-cache 已避免旧写覆盖新写

仍建议后续加强

  1. vaultKeyBase64 改为 session-only
  2. auth/vault/shared-cache 更细粒度限流
  3. 服务端请求体大小再收紧
  4. 共享缓存写审计日志

12. 当前最值得继续优化的方向

P1 - 正确性优先

  1. thread cache 反向沉淀成 page/coverage 索引
    这是目前提升“大范围缓存命中率”的最高价值项。

  2. coverage 合并策略继续增强
    尤其是前段少量更新后,历史旧帖不应被挤出当前范围搜索。

  3. 规划器结果可观测化
    建议增加 debug summary

    • 命中 exact coverage
    • 命中 page blocks 数
    • 命中 intersecting coverage 数
    • 实际缺口页数

P2 - 性能优先

  1. 本地快速规划优先,云端 planning 异步补充
  2. planning 结果本地短时缓存
  3. 回填队列分批化

12.1 当前抓取合并 / 去重 / 智能更新逻辑复盘

一、当前逻辑里已经做对的部分

  1. 线程级去重已经明确

    • 本地通过 threadKey 去重
    • 云端通过 (forum_key, thread_key) 唯一约束去重
  2. 磁链级去重已经明确

    • 本地通过 normalizeMagnetList() 去重
    • 云端共享缓存目前按线程保存,磁链集合在单线程内部去重
  3. coverage 规划已经从“只看精确范围”进化为多层来源
    当前 getCachedCoveragePlan() 已经综合:

    • exact coverage
    • assembled page coverage
    • 服务端 planning
    • cachedBlocks页块
    • intersecting coverages相交范围碎片
    • shiftedCoverage
  4. 上传抑制已经开始发挥作用

    • thread/page/coverage 都有 upload meta
    • hash + TTL 可以减少重复上云

二、当前逻辑不够理想的核心点

1. 线程缓存与页/范围索引仍然是“半脱节”

这是目前最关键的问题:

  • threads 里可能已经积累了大量帖子与磁链
  • 但这些历史数据没有系统性地回灌成:
    • pageCoverages
    • coverages

结果就是:

看起来缓存很多,但真正能参与“大范围规划”的缓存块不够多。

2. 智能更新仍然偏启发式,而不是差异驱动

当前 front refresh / shiftedCoverage 还是基于:

  • 从第 1 页开始时,倾向刷新前段
  • 历史范围快照的最近性

但它缺少真正的:

  • 基于“帖子是否变化”的差异判断
  • 基于线程游标 / 内容指纹 / 页指纹 的更新模型

3. coverage 合并虽然已经补强,但仍然不够结构化

当前已经补了:

  • 保存新 coverage 前,合并历史相交 coverage 的线程

但这个策略仍是:

  • 按线程集合合并
  • 不是按“真实页结构”或“线程页位置偏移”合并

所以在论坛前段轻微更新时,仍可能出现:

  • 范围快照连续性不足
  • 旧帖可见性波动

4. 服务端 planning 已加入,但仍然是“辅助规划器”

现在服务端已经能返回:

  • exactCoverage
  • cachedBlocks
  • shiftedCoverage

但扩展端仍保留了大量本地规划逻辑,导致:

  • 本地规划与服务端规划并存
  • 逻辑复杂度上升
  • 调试成本高

三、当前最值得优先继续优化的技术方向

A. threads -> pageCoverages / coverages 反向沉淀

这是正确性和命中率的第一优先级优化。

目标:

  • 当系统手里已经有大量 thread cache 时
  • 能定期 / 按需将其重建为:
    • page coverage block
    • coverage fragment

收益:

  • “缓存明明很多却命中不上”的问题会明显缓解

B. 引入“线程或页面指纹”作为智能更新依据

例如:

  • 页面线程列表 hash
  • 范围线程集合 hash
  • 线程集合版本号

这样 front refresh 就能从“经验刷新”变成:

  • 先比对指纹
  • 只有前段真的变化才刷新

C. 最终把 planning 统一到服务端主导

建议目标不是“双规划器”,而是:

  • 服务端负责 coverage planning
  • 扩展端只负责执行计划
  • 本地逻辑只保留兜底回退

这样架构会明显更稳。

P3 - 运维优先

  1. 共享缓存保留策略 / 归档策略
  2. 写入审计与异常监控
  3. 密钥轮换机制

13. 当前版本的整体评价

已经具备的能力

  • 本地线程 / 范围 / 页缓存
  • 云端共享缓存
  • 私有保险柜
  • 上传抑制与 TTL 节流
  • coverage planning + Redis planning cache
  • 扩展端 UI / 云同步中心 / 收藏 / 搜索历史

当前最核心的短板

缓存数据已经很多,但“如何把这些缓存组织成最优复用计划”仍然不够强。

也就是说,当前系统最难的不是“存缓存”,而是:

把已有缓存规划成正确、完整、连续的搜索路径


14. 文档使用建议

如果后续你继续迭代项目,建议把本文档当成:

  1. 新人接手说明
  2. 线上部署说明
  3. 缓存/同步逻辑总览
  4. 后续重构路线图

15. 敏感信息说明

本文档不记录以下信息:

  • SSH 密码
  • MySQL 密码
  • write token
  • 加密密钥
  • .env 明文内容

这些信息应只保留在安全的部署环境与秘密管理系统中。


16. Chrome 分发与更新能力边界

结合当前平台限制和架构评估,下面是真实可行不可行的边界。

16.1 对普通 Chrome 用户,不可直接做到的事

以下能力在普通非企业托管 Chrome 中,不现实或不受支持

  1. 从网站自动把扩展装进 Chrome
  2. 通过主页密码后,静默安装 CRX
  3. 普通用户使用自托管 CRX 自动更新

也就是说:

s.52oai.com 可以做“分发引导页”,但不能真正实现“输密码后自动装到 Chrome 里”。

16.2 最现实的分发方式

对于普通用户,最推荐:

  1. 发布到 Chrome Web Store建议 unlisted
  2. s.52oai.com 做密码门禁页
  3. 门禁通过后展示:
    • CWS 安装链接
    • 安装说明
    • 使用说明

这样可以获得:

  • 官方安装路径
  • Chrome 自动更新
  • 最低用户支持成本

16.3 自托管更新什么时候才成立

只有在以下场景,自托管更新才是现实方案:

  • 企业托管 Chrome
  • 管理员通过策略安装
  • 使用企业设备 / 组织统一管理浏览器

这不是普通公网用户场景。

16.4 当前项目建议的分发策略

如果未来要正式分发,推荐顺序:

  1. Chrome Web Store最好 Unlisted
  2. s.52oai.com 做密码门禁与引导页
  3. 扩展内做“最低支持版本”检查
  4. 如果版本太低,则提示用户去商店更新

16.5 站点密码的真实作用

主页密码(例如 123456)只能充当:

  • 引导门槛
  • 简单访问控制
  • 降低无关访问

但它不能视为真正安全边界。真正的权限控制仍然必须放在:

  • 后端账号系统
  • API 鉴权
  • 服务端授权逻辑

16. Chrome 分发与更新能力边界(部署到主页的现实约束)

16.1 对普通 Chrome 用户,不能直接做到的事

对于普通、非企业托管的 Chrome 用户,当前不支持:

  1. s.52oai.com 网页直接自动安装扩展
  2. 从自有网站静默安装 CRX
  3. 对普通用户使用自托管 CRX 做自动更新

也就是说:

网站可以做“入口页 / 密码门禁页 / 引导页”,但不能真正代替 Chrome 官方安装渠道完成自动安装。

16.2 对普通用户最现实的方案

最可行方案是:

  1. 发布到 Chrome Web Store建议 Unlisted
  2. s.52oai.com 作为密码门禁页
  3. 输入密码后展示:
    • Chrome Web Store 安装链接
    • 使用说明
    • 更新说明

这样可以获得:

  • 标准安装体验
  • Chrome 自动更新
  • 最低的用户支持成本

16.3 自托管自动更新什么时候可行

只有在:

  • 企业托管 Chrome
  • 管理员策略安装
  • 受管设备/受管浏览器环境

这种情况下,自托管 CRX + update manifest 才是现实路径。

16.4 当前项目推荐的分发模式

推荐顺序:

  1. Chrome Web StoreUnlisted 作为主分发渠道
  2. s.52oai.com 做密码门禁 + 安装引导页
  3. 扩展内调用服务端 /ext/config(后续可实现)检查最低支持版本
  4. 如果版本过低,提示用户跳转到商店升级

16.5 密码门禁的真实作用

密码门禁只能起到:

  • 隐藏安装入口
  • 控制谁能看到链接

但它不能视为真正的安全边界。真正的权限控制必须放在:

  • 后端账号体系
  • API token / 登录态
  • 服务器侧权限判断