Files
any-hub/specs/002-fiber-single-proxy/spec.md
2025-11-14 12:11:44 +08:00

7.5 KiB
Raw Blame History

Feature Specification: HTTP 服务与单仓代理

Feature Branch: 002-fiber-single-proxy
Created: 2025-11-13
Status: Draft
Input: User description: "HTTP 服务与单仓代理 - 使用 Fiber 搭建 HTTP 服务,支持基于 Host 的路由到单一 Hub。 - 实现文件缓存模块读写、TTL 检查),完成命中/回源流程。 - 提供 Docker Hub/NPM 任一仓库的最小可用代理,并通过集成测试验证。"

宪法对齐v1.0.0

  • 保持“轻量、匿名、CLI 多仓代理”定位:不得引入 Web UI、账号体系或与代理无关的范围。
  • 方案必须基于 Go 1.25+ 单二进制,依赖仅限 Fiber、Viper、Logrus/Lumberjack 及必要标准库。
  • 所有行为由单一 config.toml 控制;若需新配置项,需在规范中说明字段、默认值与迁移策略。
  • 设计需维护缓存优先 + 流式传输路径,并描述命中/回源/失败时的日志与观测需求。
  • 验收必须包含配置解析、缓存读写、Host Header 绑定等测试与中文注释交付约束。

User Scenarios & Testing (mandatory)

User Story 1 - Host 路由下的单仓访问 (Priority: P1)

企业内开发者希望通过 docker.hub.localnpm.hub.local 这样的 Host 头访问本地代理,系统需要根据 Host 定位唯一 Hub并把请求透明转发至上游。

Why this priority: 没有稳定的 HTTP 入口和 Host 路由,就无法承载任何代理能力,是 Phase 1 的核心目标。

Independent Test: 启动 any-hub准备含单一 Hub 的配置,使用 curl -H "Host: docker.hub.local" http://127.0.0.1:5000/v2/_catalog,验证请求进入正确的 Handler 并记录结构化日志。

Acceptance Scenarios:

  1. Given 配置声明 Hub docker 监听端口 5000When 客户端携带 Host: docker.hub.local 访问,Then Fiber 将请求路由到 docker Hub并构造正确的上游 URL。
  2. Given 未声明的 HostWhen 客户端请求,Then 立即返回 404 并在日志中标记 host_unmapped

User Story 2 - 磁盘缓存与回源流程 (Priority: P1)

CI/CD 任务需要重复下载相同镜像或包,期望 any-hub 能在本地缓存结果:命中时直接返回,过期或未命中时回源并刷新缓存,同时保持流式传输。

Why this priority: 缓存是代理节省带宽与加速的唯一方式;缺失会让 Phase 1 成为普通转发层。

Independent Test: 使用集成测试模拟上游服务器,第一次请求写入缓存,第二次命中缓存并快速返回;设置 TTL 过期后触发 revalidate。

Acceptance Scenarios:

  1. Given 缓存文件存在且未过期,When 再次请求相同路径,Then 直接从磁盘流式返回,并记录 cache_hit=true
  2. Given 缓存过期,When 新请求到达,Then 先向上游发送带条件的请求;若上游 304则回退本地缓存若 200 则边回源边写磁盘与客户端。
  3. Given 回源失败或磁盘写入错误,Then 系统返回合理的 5xx 并记录 cache_hit=false 与错误原因。

User Story 3 - 最小 Docker/NPM 代理样例 (Priority: P2)

平台运维需要一份可运行的示例,让团队快速验证 Docker 或 NPM 仓库能通过 any-hub 获取常见资源,并在 CI 中运行端到端测试确保回源逻辑可靠。

Why this priority: 实际仓库样例可以验证配置、日志、缓存整体流程,也为后续多仓扩展提供可复制模板。

Independent Test: 提供 configs/docker.sample.tomlconfigs/npm.sample.toml,在集成测试中启动临时上游(可模拟 docker registry 或 npm registry通过 HTTP 调用完成一次拉取并校验缓存目录生成。

Acceptance Scenarios:

  1. Given 示例配置启用 Docker HubWhen 运行 quickstart 脚本,Then 可以从真实或模拟上游下载一个 manifest 并写入缓存目录。
  2. Given 示例配置选择 NPMWhen 执行 npm view foo 指向代理,Then CLI 能收到正确响应,日志显示命中/回源信息。

Edge Cases

  • 配置监听端口但 Host 头缺失或大小写异常:必须直接返回 404并在日志中记录 host_unmapped 字段,禁止回退默认 Hub。
  • 大文件下载中途中断:需要保证写入临时文件并在失败时清理,避免污染缓存。
  • TTL 设为 0永远回源或非常大需要解释行为并防止整数溢出。
  • 上游返回 4xx/5xx缓存不得写入同时应透传状态码。

Requirements (mandatory)

Functional Requirements

  • FR-001: 系统必须提供基于 Fiber 的 HTTP Server监听配置声明的端口并按照 HostHub 的映射路由所有请求。
  • FR-002: 对于匹配的 Hub请求路径、查询、方法、Headers 必须重新组装为上游 URL并保持匿名代理不注入用户标识
  • FR-003: 缓存模块必须在磁盘上以 StoragePath/<Hub>/<path> 结构保存内容并为每个条目维护元数据TTL、ETag/Last-Modified、写入时间
  • FR-004: 命中缓存时必须流式读取磁盘并返回;未命中或过期时需边回源边写入磁盘,并在完成前向客户端持续输出,避免全量加载内存。
  • FR-005: 系统必须支持条件请求:若缓存存在 ETag/Last-Modified回源时附带 If-None-Match/If-Modified-Since,收到 304 时回退缓存。
  • FR-006: 任一请求都要记录结构化日志字段hub、domain、cache_hit、upstream_status、elapsed_ms并在错误时附带原因。
  • FR-007: 提供至少一个 Docker 或 NPM 的示例配置与 quickstart 说明,包含端到端集成测试脚本,证明可从代理获取真实或模拟数据。
  • FR-008: 所有配置项端口、Host、TTL、缓存目录必须在 config.toml 中声明CLI 不引入新的隐式参数。

Key Entities (include if feature involves data)

  • HubRoute: 映射 Host/端口到具体上游信息,字段包括 Name, Domain, Port, Upstream, Proxy, CacheTTL
  • CacheEntry: 表示磁盘缓存文件与 .meta 元数据ETag、Last-Modified、StoredAt、Size、Checksum
  • ProxyRequest: 记录一次代理请求生命周期(原始 URL、Host、缓存命中状态、上游响应码、耗时
  • SampleConfig: 示例配置集合,用于定义 Docker/NPM Hub 所需的字段和默认值。

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: 针对同一资源的第二次请求延迟较首次下降 ≥70%,且日志显示 cache_hit=true
  • SC-002: Host 路由能在 100% 测试用例中将请求映射到正确 Hub未配置的 Host 返回 404误路由率为 0。
  • SC-003: 在示例配置下,端到端集成测试成功率达到 100%,并能在 2 分钟内完成一次 docker 或 npm 包的完整拉取。
  • SC-004: 缓存目录在异常情况下不产生损坏文件测试覆盖包括中断写入、上游错误、TTL 过期等至少 5 个边界场景。

Assumptions

  • Phase 1 仅需支持单一 Hub 路由;多 Hub 并行将在后续阶段扩展。
  • 上游仓库需支持 HTTP/HTTPS GET/HEAD暂不支持 WebSocket、Chunked 上传等复杂协议。
  • 示例代理默认指向公共 Docker Hub若网络受限可在 quickstart 中改为模拟上游。
  • 磁盘缓存容量和清理策略仍沿用全局配置,不在本次迭代扩展淘汰算法。

Clarifications

Session 2025-11-13

  • Q: Host 头缺失或未匹配时应如何处理? → A: 一律返回 404 并记录 host_unmapped,不允许回退默认 Hub。