lafay 7fa2431a4a
All checks were successful
Build Updates Server / build (push) Successful in 1m1s
Build Updates Server / build-docker (push) Successful in 36m50s
feat(api): enhance public APK endpoint to return semantic version from OTA bundle
The PublicLatestAPK endpoint now reads the expoConfig.json from the OTA bundle
to extract the actual semantic version (expo.version) instead of returning
the runtimeVersion as the version name. Falls back to runtimeVersion if
expoConfig.json is not available.
2026-06-17 20:06:07 +08:00

Expo Updates Server (Go)

这个目录是 expo-updates-server 的 Go 版本实现,目标是:

  • 保持客户端接口兼容:GET /api/manifestGET /api/assets
  • 增加便于上传和 CI 的管理接口:/admin/publish/admin/rollback/admin/releases

运行

cd expo-updates-server-go
go run ./cmd/server

默认监听 :3001,可通过环境变量覆盖:

  • PORT:默认 3001
  • HOSTNAME:默认 http://localhost:3001,用于拼接 assets URL
  • UPDATES_ROOT:默认 updates
  • PRIVATE_KEY_PATH:可选;若客户端请求 expo-expect-signature,必须配置
  • ADMIN_TOKEN:管理接口 Bearer Token

示例(复用现有 expo-updates-server/updates

cd expo-updates-server-go
PORT=3001 \
HOSTNAME=http://localhost:3001 \
UPDATES_ROOT=../expo-updates-server/updates \
PRIVATE_KEY_PATH=../expo-updates-server/code-signing-keys/private-key.pem \
ADMIN_TOKEN=dev-token \
go run ./cmd/server

生产环境建议将 HOSTNAME 配置为:

https://updates.littlelan.cn

兼容接口

  • GET /api/manifest
    • 支持 expo-platformexpo-runtime-versionexpo-protocol-version
    • 支持 rollBackToEmbeddednoUpdateAvailable
    • 支持 expo-expect-signature
  • GET /api/assets?asset=...&runtimeVersion=...&platform=...

APK 管理接口(公开)

获取最新 APK 版本信息

GET /api/apk/latest

返回最新 APK 的版本信息,用于客户端检查更新。

{
  "runtimeVersion": "1.0.11",
  "versionName": "1.0.11",
  "size": 52428800,
  "downloadUrl": "https://updates.littlelan.cn/api/apk/download?runtimeVersion=1.0.11",
  "createdAt": "2026-03-26T00:00:00Z"
}

下载 APK

GET /api/apk/download?runtimeVersion=<runtimeVersion>

下载指定版本的 APK 文件。

管理接口(上传/CI

1) 发布 zip

POST /admin/publish?runtimeVersion=<rv>&platform=<ios|android>

  • HeaderAuthorization: Bearer <ADMIN_TOKEN>
  • Bodyexpo export 产物 zipzip 根目录需包含 metadata.json
curl -X POST \
  "https://updates.littlelan.cn/admin/publish?runtimeVersion=2&platform=ios" \
  -H "Authorization: Bearer dev-token" \
  -H "Content-Type: application/zip" \
  --data-binary @dist.zip

2) 创建回滚标记

POST /admin/rollback

curl -X POST "https://updates.littlelan.cn/admin/rollback" \
  -H "Authorization: Bearer dev-token" \
  -H "Content-Type: application/json" \
  -d '{"runtimeVersion":"2","platform":"ios"}'

3) 查看发布列表

GET /admin/releases?runtimeVersion=2

curl "https://updates.littlelan.cn/admin/releases?runtimeVersion=2" \
  -H "Authorization: Bearer dev-token"

4) 上传 APK

POST /admin/apk/upload?runtimeVersion=<runtimeVersion>

  • HeaderAuthorization: Bearer <ADMIN_TOKEN>
  • Content-Typeapplication/vnd.android.package-archiveapplication/octet-stream
  • BodyAPK 二进制文件
curl -X POST \
  "https://updates.littlelan.cn/admin/apk/upload?runtimeVersion=1.0.11" \
  -H "Authorization: Bearer dev-token" \
  -H "Content-Type: application/vnd.android.package-archive" \
  --data-binary @app-release.apk

CI 示例思路

  1. 在客户端跑 npx expo export
  2. 打包 dist 为 zip
  3. 调用 /admin/publish

可直接参考根目录新增工作流:.github/workflows/go-updates-server-ci.yml

CI/CD

项目使用 Gitea Actions 进行持续集成和部署:

Build Workflow (.gitea/workflows/build.yml)

  • 触发条件push 到 master/main 分支,或 PR
  • 步骤:
    1. 编译 Go 二进制文件
    2. 构建 Docker 镜像
    3. 推送到私有镜像仓库 code.littlelan.cn/carrot_bbs/updates-server

Deploy Workflow (.gitea/workflows/deploy.yml)

  • 触发条件PR 合并到 master/main或手动触发
  • 步骤:
    1. SSH 到服务器
    2. 拉取最新镜像
    3. 重启容器

所需 Secrets

  • GIT_USERNAME - Gitea 用户名
  • GIT_TOKEN - Gitea Token用于推送镜像
  • SERVER_PASSWORD - 服务器 SSH 密码
  • UPDATES_ADMIN_TOKEN - 管理接口 Token

Docker 打包与运行

1) 构建镜像并导出 tar

expo-updates-server-go 目录执行:

./build-docker-tar.sh

可指定 tag

./build-docker-tar.sh 20260309-ota

执行后会生成:

  • 镜像:carrot-bbs-updates-server:<tag>
  • tarcarrot-bbs-updates-server-<tag>.tar

2) 运行容器(挂载更新目录和密钥)

docker run -d \
  --name carrot-bbs-updates-server \
  -p 3001:3001 \
  -e PORT=3001 \
  -e HOSTNAME=https://updates.littlelan.cn \
  -e UPDATES_ROOT=/data/updates \
  -e PRIVATE_KEY_PATH=/data/privatekey.pem \
  -e ADMIN_TOKEN=dev-token \
  -v /opt/carrot-bbs/updates:/data/updates \
  -v /opt/carrot-bbs/keys/privatekey.pem:/data/privatekey.pem:ro \
  carrot-bbs-updates-server:latest
Description
No description provided
Readme 57 KiB
Languages
Go 97%
Shell 1.9%
Dockerfile 1.1%