github.com/qiniu/go-sdk/v7@v7.27.0/AGENTS.md (about)

     1  # 七牛云 Go SDK — 开发维护指南
     2  
     3  七牛云官方 Go SDK,模块路径 `github.com/qiniu/go-sdk/v7`,Go 1.22+,MIT 许可。
     4  
     5  本文档面向 SDK 维护者和贡献者,帮助理解项目结构、架构模式和开发流程。
     6  SDK 的 API 使用说明请参考各包的 `doc.go` 文件和 `examples/` 目录。
     7  
     8  ## 项目结构
     9  
    10  ### 顶层包
    11  
    12  | 包 | 职责 |
    13  |---|------|
    14  | `auth` | 认证凭证(AK/SK)、HMAC-SHA1 签名、上传凭证、回调验证 |
    15  | `storage` | 对象存储 v1:表单上传、分片上传、Bucket/对象管理、数据处理(pfop) |
    16  | `storagev2` | 对象存储 v2:类型化 API、自动区域检测、连接池、重试、Provider/Interface 模式 |
    17  | `cdn` | CDN 加速:刷新、预取、流量/带宽查询、时间戳防盗链 |
    18  | `pili` | 直播云:流管理、域名管理、推拉流地址生成 |
    19  | `rtc` | 实时音视频:应用管理、房间 Token、用户管理 |
    20  | `sms` | 短信:发送短信、签名/模板管理 |
    21  | `linking` | IoT 设备联网:设备管理、密钥、录像片段 |
    22  | `qvs` | 视频监控(QVS):GB/T 28181 设备接入、空间/设备/流管理 |
    23  | `iam` | 身份与访问管理:用户、组、策略 CRUD(生成代码) |
    24  | `media` | 多媒体处理:Pfop 触发/Prefop 查询(生成代码) |
    25  | `audit` | 审计日志:日志查询(生成代码) |
    26  | `sandbox` | 沙箱环境:创建/管理沙箱、文件操作、命令执行、PTY 终端 |
    27  | `client` | 底层 HTTP 客户端:请求签名、JSON/表单序列化、错误解析 |
    28  | `conf` | 全局配置:SDK 版本号(`conf.Version`)、User-Agent 设置 |
    29  | `reqid` | 请求 ID:通过 Context 传递 X-Reqid |
    30  
    31  ### internal 包
    32  
    33  | 包 | 职责 |
    34  |---|------|
    35  | `internal/api-generator` | 代码生成器:读取 YAML API 规范生成类型化 Go 代码 |
    36  | `internal/clientv2` | HTTP 客户端 v2:拦截器链模式、认证注入、重试、防劫持 |
    37  | `internal/cache` | 通用缓存 |
    38  | `internal/hostprovider` | 主机地址提供者 |
    39  | `internal/freezer` | 主机冻结/降级 |
    40  | `internal/context` | Context 兼容层 |
    41  | `internal/env` | 环境变量读取 |
    42  | `internal/log` | 内部日志 |
    43  | `internal/uplog` | 上传日志 |
    44  | `internal/io` | IO 工具 |
    45  | `internal/dialer` | 网络拨号 |
    46  | `internal/configfile` | 配置文件读取 |
    47  
    48  ### storagev2 子包
    49  
    50  | 包 | 职责 |
    51  |---|------|
    52  | `storagev2/apis` | 低级 API 客户端,所有方法由代码生成器生成 |
    53  | `storagev2/apistest` | API mock/测试辅助 |
    54  | `storagev2/credentials` | 凭证管理(Provider 接口) |
    55  | `storagev2/http_client` | HTTP 客户端选项、拦截器集成 |
    56  | `storagev2/region` | 区域信息(RegionsProvider 接口) |
    57  | `storagev2/uploader` | 上传管理器(自动选择上传方式) |
    58  | `storagev2/downloader` | 下载管理器 |
    59  | `storagev2/objects` | 对象管理(流式 API) |
    60  | `storagev2/uptoken` | 上传凭证(PutPolicy → Signer) |
    61  | `storagev2/backoff` | 重试退避策略 |
    62  | `storagev2/chooser` | 主机选择器 |
    63  | `storagev2/resolver` | 域名解析器 |
    64  | `storagev2/retrier` | 重试器 |
    65  | `storagev2/defaults` | 默认配置值 |
    66  | `storagev2/errors` | 类型化错误 |
    67  | `storagev2/uplog` | 上传日志 |
    68  | `storagev2/internal` | storagev2 内部实现 |
    69  
    70  ### 其他目录
    71  
    72  | 目录 | 说明 |
    73  |------|------|
    74  | `api-specs/` | API 规范(git submodule),包含 storage、iam、media、audit、sandbox 的 YAML/OpenAPI 定义 |
    75  | `examples/` | 各功能的使用示例,每个示例是独立子目录(独立 `main` 包) |
    76  
    77  ## 核心架构模式
    78  
    79  ### Manager 模式(storage v1)
    80  
    81  v1 的对象存储使用 Manager 模式,每个功能域对应一个 Manager 结构体:
    82  
    83  - `storage.BucketManager` — Bucket 和对象管理
    84  - `storage.FormUploader` / `storage.ResumeUploader` — 上传
    85  - `storage.OperationManager` — 数据处理
    86  
    87  构造方式统一为 `New*(mac, &cfg)` 或 `New*(&cfg)`,通过 `auth.Credentials` 传递认证信息。
    88  
    89  ### Provider/Interface 模式(storagev2)
    90  
    91  v2 通过接口抽象实现可插拔:
    92  
    93  - `credentials.CredentialsProvider` — 凭证提供者
    94  - `region.RegionsProvider` — 区域信息提供者
    95  - `chooser.Chooser` — 主机选择策略
    96  - `resolver.Resolver` — 域名解析
    97  - `retrier.Retrier` — 重试策略
    98  - `backoff.Backoff` — 退避策略
    99  
   100  所有组件通过 `http_client.Options` 注入,支持自定义替换。
   101  
   102  ### Interceptor 拦截器链(internal/clientv2)
   103  
   104  HTTP 请求通过拦截器链处理,拦截器按优先级排序(数字越小优先级越高):
   105  
   106  ```
   107  RetryHosts(200) → RetrySimple(300) → Uplog(310) → BufferResponse(320)
   108    → SetHeader(400) → Normal(500) → Auth(600) → AntiHijacking(700) → Debug(800)
   109  ```
   110  
   111  核心接口:
   112  
   113  ```go
   114  type Interceptor interface {
   115      Priority() InterceptorPriority
   116      Intercept(req *http.Request, handler Handler) (*http.Response, error)
   117  }
   118  ```
   119  
   120  ### Context 传递认证
   121  
   122  storage v1 通过函数参数传递 `auth.Credentials`,storagev2 通过 `http_client.Options` 结构体传递。`reqid` 包提供 Context 传递请求 ID 的机制(`X-Reqid` 头)。
   123  
   124  ### 双版本共存
   125  
   126  `storage`(v1)和 `storagev2`(v2)并行维护:
   127  - v1:稳定的对外 API,Manager 模式,手写代码
   128  - v2:新一代 API,Provider/Interface 模式,代码生成 + 手写
   129  - 两者共享 `auth`、`client`、`conf`、`reqid` 等基础包
   130  - 新功能优先在 v2 实现,v1 仅做维护性修改
   131  
   132  ## 代码生成
   133  
   134  ### API 代码生成(make generate)
   135  
   136  `internal/api-generator` 读取 `api-specs/` 中的 YAML 规范,生成类型化 Go 代码:
   137  
   138  ```
   139  api-specs/<service>/*.yml  →  internal/api-generator  →  <service>/apis/*.go
   140  ```
   141  
   142  涉及的包及 `//go:generate` 指令:
   143  - `storagev2/` → `storagev2/apis/`(struct: Storage)
   144  - `iam/` → `iam/apis/`(struct: IAM)
   145  - `media/` → `media/apis/`(struct: Media)
   146  - `audit/` → `audit/apis/`(struct: Audit)
   147  
   148  运行命令:
   149  
   150  ```bash
   151  make generate   # 运行所有 go generate 并格式化代码
   152  ```
   153  
   154  ### Sandbox 代码生成(make generate-sandbox)
   155  
   156  sandbox 使用不同的生成工具链:
   157  
   158  - **控制面 API**:`oapi-codegen`(OpenAPI → Go)→ `sandbox/internal/apis/`
   159  - **envd HTTP API**:`oapi-codegen` → `sandbox/internal/envdapi/`
   160  - **envd ConnectRPC**:`buf` + `protoc-gen-go` + `protoc-gen-connect-go` → `sandbox/internal/envdapi/`
   161  
   162  运行命令:
   163  
   164  ```bash
   165  make generate-sandbox   # 需要安装 buf、protoc-gen-go、protoc-gen-connect-go
   166  ```
   167  
   168  ### 生成代码标记
   169  
   170  所有生成的代码文件首行包含如下标记之一:
   171  
   172  - `// THIS FILE IS GENERATED BY api-generator, DO NOT EDIT DIRECTLY!`
   173  - `// Code generated by protoc-gen-go. DO NOT EDIT.`
   174  - `// Code generated by protoc-gen-connect-go. DO NOT EDIT.`
   175  - `// Code generated by github.com/oapi-codegen/oapi-codegen/v2 ... DO NOT EDIT.`
   176  
   177  **绝对不要手动修改这些文件**,如需修改请更新对应的 API 规范后重新生成。
   178  
   179  ## 编码规范
   180  
   181  ### 格式化
   182  
   183  - 使用 `gofmt -s` 格式化代码(CI 会检查)
   184  - `make generate` 会自动运行 `gofmt -w .` 和 `gofumpt -w .`
   185  
   186  ### 静态检查
   187  
   188  - 使用 `staticcheck`(CI 会检查)
   189  - 运行:`make staticcheck`
   190  
   191  ### 注释规范
   192  
   193  - 注释默认使用**中文**
   194  - 导出的 API、函数、类型、常量、变量必须添加注释
   195  - 注释以被注释的标识符名称开头(符合 Go 官方 godoc 规范)
   196  - 包级别注释写在 `doc.go` 的 `package` 声明之前
   197  
   198  ### 命名规范
   199  
   200  - 构造函数使用 `New*()` 或 `New*Ex()` 命名
   201  - 错误类型:根包使用 `client.ErrorInfo`(Code + Err + Reqid),storagev2 使用 `storagev2/errors` 包
   202  
   203  ### 错误处理
   204  
   205  - 错误使用 Go 标准的 `fmt.Errorf("context: %w", err)` 包装
   206  - 使用 `errors.Is()` / `errors.As()` 判断错误类型
   207  
   208  ## 测试规范
   209  
   210  ### Build Tags
   211  
   212  测试文件必须添加 build tag:
   213  
   214  ```go
   215  //go:build unit
   216  
   217  package xxx_test
   218  ```
   219  
   220  - `unit` — 单元测试,不依赖外部服务
   221  - `integration` — 集成测试,需要七牛账号和网络
   222  
   223  ### Makefile 测试命令
   224  
   225  | 命令 | 说明 |
   226  |------|------|
   227  | `make unittest` | 运行单元测试(提交前必须通过) |
   228  | `make integrationtest` | 运行集成测试(需要环境变量配置) |
   229  | `make test` | 运行所有测试 |
   230  
   231  所有测试命令排除 `examples/` 和 `sms/` 目录。
   232  
   233  ### 测试实践
   234  
   235  - 使用 `testify/assert` 进行断言
   236  - 推荐使用表驱动测试
   237  - mock 测试可参考 `storagev2/apistest` 包
   238  
   239  ## CI 流程
   240  
   241  CI 在 push 和 pull_request 时触发(`.github/workflows/ci-test.yml`):
   242  
   243  ### Linux(主要检查)
   244  
   245  Go 1.22 + stable 两个版本矩阵:
   246  
   247  1. **gofmt 检查**(仅 stable):`gofmt -s -l .` 检查未格式化文件
   248  2. **staticcheck**(仅 stable):`make staticcheck`
   249  3. **编译 examples**(仅 stable):`go build ./examples/...`
   250  4. **单元测试**(两个版本):`make unittest`
   251  
   252  ### Windows / macOS
   253  
   254  Linux 通过后依次运行,仅执行 `make unittest`(stable 版本)。
   255  
   256  ### 版本检查
   257  
   258  发布 tag 时(`.github/workflows/version-check.yml`),检查以下三处版本号一致:
   259  
   260  - `CHANGELOG.md` 包含 `## <version>`
   261  - `README.md` 包含 `require github.com/qiniu/go-sdk/v7 v<version>`
   262  - `conf/conf.go` 包含 `const Version = "<version>"`
   263  
   264  ## 开发工作流
   265  
   266  ### 环境准备
   267  
   268  ```bash
   269  # 初始化 api-specs submodule
   270  git submodule update --init --recursive
   271  
   272  # 验证当前状态
   273  make unittest
   274  make staticcheck
   275  ```
   276  
   277  ### 日常开发
   278  
   279  1. 确保分支基于最新 master:`git fetch upstream && git rebase upstream/master`
   280  2. 修改代码前先运行 `make unittest` 确认当前状态
   281  3. 修改 API 规范后运行 `make generate` 或 `make generate-sandbox`
   282  4. 提交前运行 `make unittest` 和 `make staticcheck` 确保通过
   283  5. 代码格式化:`gofmt -s -w .`
   284  
   285  ### 修改生成代码的正确流程
   286  
   287  1. 更新 `api-specs/` 中对应的 YAML 规范(如需)
   288  2. 运行 `make generate`(或 `make generate-sandbox`)
   289  3. 检查生成结果,确认无误后提交规范和生成代码
   290  
   291  ### 测试与验证
   292  
   293  实现新功能或修复 bug 时,应同时提供单元测试和集成测试。对于涉及幂等、重试等逻辑的接口,单元测试用 mock 覆盖边界条件,集成测试用真实凭证验证端到端行为。
   294  
   295  #### 运行规则
   296  
   297  ```bash
   298  # 单测(提交前必须通过)
   299  make unittest
   300  
   301  # 特定包的单测
   302  go test -tags=unit -count=1 -v ./sandbox/
   303  
   304  # 集成测试(需要 .env 文件)
   305  set -a && source sandbox/.env && set +a && go test -tags=integration -count=1 -v ./sandbox/
   306  ```
   307  
   308  #### 环境变量 `.env` 文件
   309  
   310  `sandbox/.env` 用于集成测试和示例程序的环境变量配置:
   311  
   312  ```
   313  QINIU_API_KEY=          # 七牛 API Key(必填)
   314  QINIU_SANDBOX_API_URL=  # API 端点(可选,默认 https://cn-yangzhou-1-sandbox.qiniuapi.com)
   315  SANDBOX_RETRY_MAX=      # 可重试 API 的最大重试次数(可选,默认 5,设为 0 禁用重试)
   316  ```
   317  
   318  使用方式:
   319  
   320  ```bash
   321  cd sandbox/
   322  set -a && source .env && set +a
   323  # 后续 go test / go run 命令可直接读取环境变量
   324  ```
   325  
   326  #### 运行示例
   327  
   328  ```bash
   329  # 需要先 source sandbox/.env
   330  go run ./examples/sandbox_idempotency_retry/
   331  ```
   332  
   333  ## 重要约定
   334  
   335  1. **不要手动修改生成代码** — 带 `DO NOT EDIT DIRECTLY` 标记的文件由代码生成器维护
   336  2. **不要删除 sms 测试排除** — Makefile 中 `egrep -v 'examples|sms'` 是有意为之
   337  3. **examples 是独立子目录** — 每个示例是独立的 `main` 包,编译方式为 `go build ./examples/...`
   338  4. **版本号三处同步** — 发布时确保 `conf/conf.go`、`CHANGELOG.md`、`README.md` 版本一致
   339  5. **api-specs 是 git submodule** — 更新规范需要在 submodule 中操作
   340  6. **保持双版本兼容** — storage v1 和 storagev2 v2 并行维护,不要在 v1 中引入 v2 的依赖