# Expo Updates Server (Go) 这个目录是 `expo-updates-server` 的 Go 版本实现,目标是: - 保持客户端接口兼容:`GET /api/manifest`、`GET /api/assets` - 增加便于上传和 CI 的管理接口:`/admin/publish`、`/admin/rollback`、`/admin/releases` ## 运行 ```bash 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`): ```bash 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` 配置为: ```text https://updates.littlelan.cn ``` ## 兼容接口 - `GET /api/manifest` - 支持 `expo-platform`、`expo-runtime-version`、`expo-protocol-version` - 支持 `rollBackToEmbedded`、`noUpdateAvailable` - 支持 `expo-expect-signature` - `GET /api/assets?asset=...&runtimeVersion=...&platform=...` ## APK 管理接口(公开) ### 获取最新 APK 版本信息 `GET /api/apk/latest` 返回最新 APK 的版本信息,用于客户端检查更新。 ```json { "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=` 下载指定版本的 APK 文件。 ## 管理接口(上传/CI) ### 1) 发布 zip `POST /admin/publish?runtimeVersion=&platform=` - Header:`Authorization: Bearer ` - Body:`expo export` 产物 zip(zip 根目录需包含 `metadata.json`) ```bash 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` ```bash 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` ```bash curl "https://updates.littlelan.cn/admin/releases?runtimeVersion=2" \ -H "Authorization: Bearer dev-token" ``` ### 4) 上传 APK `POST /admin/apk/upload?runtimeVersion=` - Header:`Authorization: Bearer ` - Content-Type:`application/vnd.android.package-archive` 或 `application/octet-stream` - Body:APK 二进制文件 ```bash 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` 目录执行: ```bash ./build-docker-tar.sh ``` 可指定 tag: ```bash ./build-docker-tar.sh 20260309-ota ``` 执行后会生成: - 镜像:`carrot-bbs-updates-server:` - tar:`carrot-bbs-updates-server-.tar` ### 2) 运行容器(挂载更新目录和密钥) ```bash 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 ```