Files
doodle-store/packages/asset-sync/README.md
T

108 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 本地备份同步七牛
独立 Node.js 脚本项目,使用官方 qiniu SDK 7.15.2。入口命令在 doodle-store 根目录执行。只复制本地文件到已存在的七牛空间,不创建空间、不删除/覆盖远端对象、不修改数据库或业务 URL。
## 配置
已生成本机 `packages/asset-sync/.env`,源目录配置为:
```dotenv
SOURCE_DIR=/Users/joey-xd/sites/doodle/doodle-assets/cloud_backup
QINIU_AK=
QINIU_SK=
QINIU_BUCKET=
QINIU_REGION=
QINIU_KEY_PREFIX=doodle/
QINIU_PUBLIC_DOMAIN=
SYNC_CONCURRENCY=3
SYNC_RETRIES=2
SYNC_MAX_FILE_BYTES=67108864
```
填写本地 `.env` 即可,不要将 AK/SK 写到小程序、Git、命令参数或聊天中。该文件被 Git 忽略,并以 0600 权限保存。新机器可从 `.env.example` 复制;相对 SOURCE_DIR 以配置文件目录为基准,运行目录不影响源路径。进程环境变量优先于文件配置。
| 配置 | 说明 |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| SOURCE_DIR | 本地备份根目录,工具只读 |
| QINIU_AK / QINIU_SK | 七牛服务端 AccessKey / SecretKey,仅正式同步要求 |
| QINIU_BUCKET | 所有资源共用的公开空间:图片、头像、字体、JSON 等 |
| QINIU_REGION | 可留空自动查询;固定区域时使用七牛 region ID,如 z0、z1、z2、na0、as0 |
| QINIU_KEY_PREFIX | 对象前缀;默认 doodle/,空串为原相对路径 |
| QINIU_PUBLIC_DOMAIN | 可选 HTTPS origin,例如 https://cdn.example.com;不含 /doodle 等路径,仅用于生成报告中的公共 URL,不证明域名已经绑定该空间 |
| SYNC_CONCURRENCY | 并发文件数,1~10,默认 3 |
| SYNC_RETRIES | 瞬时错误额外重试次数,0~5,默认 2 |
| SYNC_MAX_FILE_BYTES | 每个文件读取内存的大小限制,默认 64 MiB |
空间必须已存在且有权查询和上传。执行前读取空间设置,核对目标空间实际 private=0,工具不会自动调整 ACL。头像与其他资源使用同一个 QINIU_BUCKET,无需配置私有空间。
## 使用
```bash
# 查看用法
pnpm assets:sync --help
# 默认预演全部文件,不调用七牛接口,也不要求 AK/SK
pnpm assets:sync
# 只预演题型预览图
pnpm assets:sync --only assets/previews
# 填写 .env 后,先同步 51 张预览
pnpm assets:sync --apply --only assets/previews
# 可选择多个目录
pnpm assets:sync --apply --only assets/fonts --only assets/materials
# 全部同步,含头像,均使用 QINIU_BUCKET 公开空间
pnpm assets:sync --apply
# 自定义配置文件/报告;报告文件不能已存在,也不能位于源备份内
pnpm assets:sync --env /绝对路径/.env.sync --report /绝对路径/report.json
```
`--only` 按目录前缀或精确文件路径筛选,不是 glob;`--dry-run` 可显式声明预演,与 `--apply` 互斥。通过默认预演确认清单后,再添加 --apply 上传。文件缺失、损坏 JSON、超限文件、软链接及无法识别的预览/头像图片会停止预检。
## 对象路径和同步行为
默认映射:
```text
assets/previews/math/number-find.jpg
→ 公共 bucket : doodle/assets/previews/math/number-find.jpg
user-avatars/<文件名>.png
→ 同一公共 bucket : doodle/user-avatars/<文件名>.png
```
头像保留 `user-avatars/` 相对路径,与预览等资源共用公开空间。配置 QINIU_PUBLIC_DOMAIN 后,报告也会生成头像的公开地址。工具不根据文件名推断用户身份,用户归属仍需在后续绑定时核实。
1. 扫描源目录,忽略隐藏文件,记录实际 MIME、字节数、SHA-256 与七牛 ETag;不修改源文件。
2. 正式执行时重新读取并核对本地摘要,使用该次读取的 Buffer 上传,避免核对后源文件被修改。
3. 远端不存在时,用指定 bucket:key 的 insertOnly=1 凭证上传,仅允许新增,启用 SDK CRC 校验和 HTTPS。
4. 远端同 key 且 ETag/大小一致:跳过并标记已核对。不同内容:报告 conflict,保留原远端文件;需要新版本时选择新的前缀/key。
5. 上传完成再次 stat,对比远端 ETag/大小;不是仅凭“请求成功”就记完成。
6. 瞬时网络错误、429、5xx 有限重试,鉴权错误和冲突不盲目重试。上传已成功但响应丢失时,重试遇到 614 后回查摘要恢复。
7. 任一文件失败或冲突时命令退出码为 1,其余文件结果仍写入报告。中断后重新运行同一命令,会重新检查远端并跳过已完成对象;未提供分片级断点续传。
校验方式是七牛内容 ETag 和大小,不等同于从 CDN 下载全部文件后比较 SHA-256。SHA-256 是本地备份摘要,报告明确记录 verifiedBy=qiniu-etag-and-size。不会自动刷新 CDN 或替换同名对象。
## 报告与后续接入
默认报告写 `packages/asset-sync/reports/<时间>-<随机ID>.json`,目录被 Git 和格式化工具忽略,文件权限 0600;含源相对路径、目标 bucket/key、MIME、大小、摘要、状态和有限错误码。不包含 AK、SK、上传凭证、签名链接或 SDK 原始异常。中断时报告可能未写完,以重新运行后的远端校验为准。
主要状态:planned(预演)、uploaded(上传并核对)、skipped(已有同内容)、conflict(同名异内容)、failed、not_attempted(全批配置/权限预检未通过)。常见全批错误:CREDENTIALS_REQUIRED、BUCKET_REQUIRED、BUCKET_VISIBILITY_MISMATCH。上传用户需有 bucketInfo、stat、upload 所需权限。
这次只做文件同步。同步成功后仍需按报告映射更新新后端 assets(保持现有 ID 并回填 bucket/key/MIME/摘要、status=ready)、字体配置、用户头像绑定及首页 JSON 内的 cloud 引用。content/page-config.json 当前会原样复制,不会自动转换嵌套链接;原云上传和定时任务也不会自动切换到七牛。
## 验证与当前预演
```bash
pnpm assets:test
pnpm check
```
测试使用临时本地文件和模拟七牛接口,覆盖配置、ETag 边界、头像同空间映射、预演无网络、首次上传、重复跳过、冲突保护、重试、响应丢失恢复、源文件变化、校验失败、凭据脱敏及 CLI 报告权限。没有使用真实 AK/SK 或执行真实上传。
本地备份预演:62 个文件,共 3,568,778 字节;其中题型预览 51、头像 7、字体 1、素材 1、首页配置 1、demo 1。该数量为本地预演结果,不代表已上传。
实现依据:[七牛官方 Node.js SDK](https://developer.qiniu.com/kodo/sdk/nodejs)、[七牛上传策略](https://developer.qiniu.com/kodo/manual/put-policy)。