云服务推送

This commit is contained in:
not-like-juvenile
2026-02-27 16:02:44 +08:00
parent 065f12b16a
commit 427010f7db
16 changed files with 2144 additions and 5 deletions

View File

@@ -81,6 +81,220 @@ UNIPUSH 集成注意事项
- 文档:[server/PUSH_SERVER_README.md](server/PUSH_SERVER_README.md)
- 代码:[server/push-server.js](server/push-server.js)
自动化部署(可选)
- 本仓库新增了一个打包并可选上传云函数的脚本:`server/tools/deploy-cloudfunc.js`,会把
`uniCloud-alipay/cloudfunctions/testUnipush2` 打包到 `server/dist/testUnipush2.zip`
- 使用前请在 `server` 目录安装依赖:
```bash
cd server
npm install archiver node-fetch form-data
```
- 本地打包(只生成 zip
```bash
node server/tools/deploy-cloudfunc.js
```
- 如果你有云平台的上传 URL可直接上传脚本会读取 `CLOUD_UPLOAD_URL` 与 `CLOUD_UPLOAD_TOKEN` 环境变量,或使用 `--upload <URL>` 参数):
```bash
export CLOUD_UPLOAD_URL='https://your-cloud-upload-api'
export CLOUD_UPLOAD_TOKEN='xxxxx'
node server/tools/deploy-cloudfunc.js --upload
```
- 我也添加了一个 GitHub Actions 模板(.github/workflows/deploy-cloudfunc.yml可在仓库的 `main` 分支 push 时自动打包并上传(需要在 Actions Secrets 中配置 `CLOUD_UPLOAD_URL` 与 `CLOUD_UPLOAD_TOKEN`)。
CI / 自动化 说明
- 已提供 GitHub Actions workflow: [.github/workflows/deploy-cloudfunc.yml](.github/workflows/deploy-cloudfunc.yml)。支持可选步骤:上传 -> 触发部署 API -> 调用云函数做 smoke test。
- 推荐在仓库 Secrets 中添加(根据你云厂商调整):
- `CLOUD_UPLOAD_URL` : 上传 zip 的 HTTP endpointupload 接口)
- `CLOUD_UPLOAD_TOKEN` : 上传接口的 Bearer token
- `CLOUD_DEPLOY_API` : (可选)触发云函数部署/发布的 API
- `CLOUD_DEPLOY_TOKEN` : (可选)部署 API 的 token
- `CLOUD_FUNC_URL` : (可选)已部署云函数的外网 URLCI 将对其执行一次 smoke 测试
- `PUSH_TOKEN` : (可选)云函数鉴权 token用于 smoke 测试
- `TEST_DEVICE_CID` : (可选)用于 CI smoke 测试的设备 CID
- 我也添加了本地 helper 脚本:`server/tools/ci-deploy.ps1`,可在本地执行相同流程(打包 -> 上传 -> 触发 -> 调用)。
如果需要,我可以:
- 把 adapter 的请求体精确匹配你现有成功的 uni-push curl请把 curl 发来);或
- 为通知添加重试/记录字段并实现简单重试机制。
自动部署成功示例
-----------------
下面是一个你实际执行并确认成功的示例,便于复制到文档或在团队内复现:
- 启用自动部署并设置 tokenPowerShell 示例):
```powershell
$env:AUTO_DEPLOY_ON_START='true'
$env:DEPLOY_BEARER='your-secret' # 请使用真实随机 token 暂无
$env:CLOUD_UPLOAD_URL='https://env-00jy5x5oy9zd.dev-hz.cloudbasefunction.cn/test'
$env:CLOUD_UPLOAD_TOKEN='upload-token' # 如果上传需要鉴权
$env:AUTO_DEPLOY_ARGS='--upload' # 可选:将 --upload 传给 deploy 脚本
node push-server.js
```
- 预期控制台输出(已在你的环境中观察到):
```
Push server listening on http://0.0.0.0:7301
ENV: UNI_PUSH_URL= https://restapi.getui.com/v2/...
Auto-deploy: spawning node D:\...\server\tools\deploy-cloudfunc.js
[auto-deploy stdout] 打包目录: D:\...\uniCloud-alipay\cloudfunctions\testUnipush2
[auto-deploy stdout] 打包完成 -> D:\...\server\dist\testUnipush2.zip (1324 bytes)
[auto-deploy stdout] 上传到: https://env-00jy5x5oy9zd.dev-hz.cloudbasefunction.cn/test
[auto-deploy stdout] 上传响应: 200 {"data":{...},"errCode":0,"errMsg":"success"}
Auto-deploy process exited with code=0 signal=null
```
- 说明:
- `errCode:0` / `errMsg: "success"` 表示云平台已接收并下发(上线)该云函数包。具体字段会随云厂商略有不同,请以返回的 `errCode` / `errMsg` 或 `status` 为准。
- 若你需要进一步验证云函数可用性,请用 `curl` 或 `Invoke-RestMethod` 调用返回的云函数 URL 做一次 smoke test见上文的“直接调用云函数smoke test”示例
安全提醒:自动部署具有上传并触发发布的能力,请仅在受控环境或 CI 中启用,并把 `DEPLOY_BEARER` / `CLOUD_UPLOAD_TOKEN` 等密钥放入 CI Secrets 或受限的环境变量中。
快速上手(最小环境变量)
- 如果你只是想快速上传并通过云函数下发一次推送,最小只需设置两个环境变量并运行打包脚本:
PowerShell 示例:
```powershell
$env:CLOUD_UPLOAD_URL='https://env-00jy5x5oy9zd.dev-hz.cloudbasefunction.cn/test'
$env:UNI_PUSH_APPID='__UNI__9462CA7'
node tools\deploy-cloudfunc.js --upload
```
说明:设置 `CLOUD_UPLOAD_URL` 与 `UNI_PUSH_APPID` 后,运行 `deploy-cloudfunc.js` 会把 `uniCloud-alipay/cloudfunctions/testUnipush2` 打包并上传到该地址,上传成功后云平台会返回已下发/上线的结果,从而完成推送通路的测试。
**用户整合指南(一步到位)**
下面把之前讨论过的流程与命令整合成一个可复用的清单,便于在本地或 CI 中自动化执行:
- 先决条件:在 `server` 目录下有 `tools/deploy-cloudfunc.js`,并且已安装依赖 `archiver node-fetch form-data`。
1) 本地打包并上传(最小)
PowerShell
```powershell
cd D:\叶\桌面文件\hfkj_mall\mall\server
npm install archiver node-fetch form-data
$env:CLOUD_UPLOAD_URL='https://env-00jy5x5oy9zd.dev-hz.cloudbasefunction.cn/test'
$env:UNI_PUSH_APPID='__UNI__9462CA7'
node tools\deploy-cloudfunc.js --upload
```
说明:这两条环境变量(`CLOUD_UPLOAD_URL` + `UNI_PUSH_APPID`)在多数场景下已足够完成上传并让云平台下发推送;上传成功时脚本会打印上传后的 URL 与平台响应(检查返回的 `errCode` / `data` 字段以确认)。
2) 直接调用云函数smoke test
PowerShell使用 `curl.exe` 保持与 Linux curl 行为一致):
```powershell
curl.exe -X POST "https://env-.../test" `
-H "Content-Type: application/json" `
-d "{\"token\":\"<PUSH_TOKEN>\",\"push_clientid\":\"<DEVICE_CID>\",\"title\":\"测试\",\"content\":\"hi\",\"payload\":{}}"
```
或用 PowerShell 原生:
```powershell
$body = @{ token = '<PUSH_TOKEN>'; push_clientid = '<DEVICE_CID>'; title='测试'; content='hi'; payload=@{} } | ConvertTo-Json
Invoke-RestMethod -Method Post -Uri 'https://env-.../test' -ContentType 'application/json' -Body $body
```
3) 本地辅助脚本(整合流程)
- 已添加 `server/tools/ci-deploy.ps1`,支持:打包、上传、触发部署 API、调用云函数做 smoke test。用法示例
```powershell
# 只打包
.\server\tools\ci-deploy.ps1 -Pack
# 打包并上传并触发部署
.\server\tools\ci-deploy.ps1 -Pack -UploadUrl 'https://your-upload' -UploadToken 'token' -DeployApi 'https://your-deploy-api' -DeployToken 'token'
# 打包并上传然后调用云函数做 smoke test
.\server\tools\ci-deploy.ps1 -Pack -UploadUrl 'https://your-upload' -UploadToken 'token' -FuncInvokeUrl 'https://env-.../test' -PushToken 'xxx' -TestCid 'device-cid'
```
4) CIGitHub Actions
- workflow: `.github/workflows/deploy-cloudfunc.yml` 已包含:打包 -> 上传 ->(可选)触发部署 API ->(可选)调用云函数做 smoke test。
- 建议在 Actions Secrets 中添加:
- `CLOUD_UPLOAD_URL`(必需用于上传)
- `CLOUD_UPLOAD_TOKEN`(上传 token
- `CLOUD_DEPLOY_API` / `CLOUD_DEPLOY_TOKEN`(可选,用于触发厂商部署)
- `CLOUD_FUNC_URL` / `PUSH_TOKEN` / `TEST_DEVICE_CID`(可选,用于 smoke test
5) 后端直接单推(如果你愿意绕过云函数)
- 启动 `push-server`(示例):
```powershell
cd D:\叶\桌面文件\hfkj_mall\mall\server
npm install
SUPA_URL='http://rest:3000' SERVICE_ROLE_KEY='PASTE_SERVICE_ROLE_KEY' node push-server.js
```
- 直接按 CID 发送(跳过 DB
```powershell
curl.exe -X POST "http://localhost:7301/api/v1/push/send" -H "Content-Type: application/json" -d "{\"cids\":[\"<DEVICE_CID>\"],\"notification\":{\"title\":\"hi\",\"body\":\"msg\"}}"
```
注意与安全建议
- `uniCloud.uploadFile` 可以把 zip 存到云端存储(返回 `fileID`),但不会自动部署为云函数;若要自动部署需要调用云厂商的部署/发布 API或使用厂商控制台/CLI
- 保管好 `CLOUD_UPLOAD_TOKEN`、`CLOUD_DEPLOY_TOKEN`、`SERVICE_ROLE_KEY` 等机密,放到 CI Secrets 或安全环境变量中,不要硬编码在仓库。
- 上传后若要确认运行状态,请查看云平台函数控制台或调用厂商的状态/日志接口CI 的 smoke test 能快速验证下发路径是否通顺。
如果你希望,我可以把上面示例中的 `curl` 调用替换成你厂商的部署 API 或把 `ci-deploy.ps1` 改为更严格的错误处理与日志输出。
部署服务文件说明
----------------
以下两个文件用于让后端通过一个 HTTP 接口自动完成云函数的打包、上传、触发部署与可选的 smoke-test
- `server/tools/deploy-cloudfunc-service.js`
- 目的封装打包zip、上传、触发部署 API、调用云函数smoke-test的通用函数便于从后端代码调用或在 CI 中复用。
- 主要导出:`deployCloudFunction(options)`,接收的 `options` 支持字段:
- `uploadUrl`(必需或由环境变量提供):上传 zip 的 HTTP endpoint。
- `uploadToken`:上传接口的 Bearer token可选
- `uniAppId`:可附加到上传请求的 appId可选
- `deployApi` / `deployToken`:如果需要调用厂商的部署/发布 API可指定可选
- `funcInvokeUrl` / `pushToken` / `testCid`:若提供,将在上传/部署后调用该云函数进行 smoke-test可选
- 返回值:一个对象,包含 `packed`(打包信息)、`uploaded`(上传响应)、`deployed`(触发部署 API 的响应)和 `invoked`smoke-test 调用响应)四部分,便于在后端记录和判断各个阶段的结果。
- `server/routes/deploy.js`
- 目的:提供一个 Express 路由 `/api/v1/deploy-cloudfunc`,让后端或 CI 通过一次 HTTP POST 调用完成上面封装的流程。
- 请求体示例JSON
```json
{
"uploadUrl":"https://your-upload-endpoint",
"uploadToken":"<UPLOAD_TOKEN>",
"uniAppId":"__UNI__9462CA7",
"deployApi":"https://your-deploy-api",
"deployToken":"<DEPLOY_TOKEN>",
"funcInvokeUrl":"https://env-.../test",
"pushToken":"<PUSH_TOKEN>",
"testCid":"<DEVICE_CID>"
}
```
- 行为:路由优先使用请求体中的字段;若缺失则回落使用环境变量(例如 `CLOUD_UPLOAD_URL`、`CLOUD_UPLOAD_TOKEN`、`UNI_PUSH_APPID`、`CLOUD_DEPLOY_API`、`CLOUD_DEPLOY_TOKEN`、`CLOUD_FUNC_URL`、`PUSH_TOKEN`、`TEST_DEVICE_CID`)。
- 返回JSON 格式,包含 `result` 对象(见 `deployCloudFunction` 的返回结构)。
安全与接入建议
- 强烈建议只在内网或受保护的管理接口上暴露该路由,或在请求中加入鉴权头(例如 `Authorization: Bearer <ADMIN_TOKEN>`)并在服务端验证。此接口具有上传并触发部署的能力,若未保护将导致安全风险。
- 如果你需要,我可以:
- 把路由自动挂载到 `server/push-server.js`(并添加简单的 token 验证);或
- 增强 `deploy-cloudfunc-service.js` 的错误日志与重试策略,或把上传/部署调用改写成你云厂商的精确 API 参数格式。
异步 Consumer已实现说明
---------------------------------
- 目的:从数据库 `express_notifications` 拉取待发送的消息pending解耦写入与下发流程保证可重试、可审计与可运维。
- 实现位置:`server/push-server.js`(已新增 consumer 逻辑)。
- 启用:设置环境变量 `ENABLE_CONSUMER=true`(或 `CONSUMER_ENABLED=true`),可选配置轮询间隔 `CONSUMER_POLL_MS`(默认 2000 ms
- 关键环境变量:`SUPA_URL`、`SUPA_KEY`Supabase REST、`CLOUD_FUNC_URL`(云函数 invoke URL、`PUSH_TOKEN`(云函数鉴权)。
- 行为摘要:
- 轮询 `express_notifications`status_code IS NULL并选取记录
- 通过带过滤的 PATCH 抢占(将 `status_code` 设为 `processing`)以避免并发重复处理;
- 查询目标设备(`push_devices`),对每个 `cid` 构造 event 并 POST 到 `CLOUD_FUNC_URL`(若未配置则回退到 `UNI_PUSH_URL` 适配器);
- 根据调用结果回写 `express_notifications.status_code` 为 `success` / `failed` / `no-targets`。
- 限制与扩展点:当前 consumer 依赖 Supabase REST尚未在 DB 中新增 `retry_count`/`last_error` 字段(建议在迁移中加入以支持指数退避与重试);为保证高可用建议配合 `FOR UPDATE SKIP LOCKED` 或 Supabase Realtime 优化并发策略。
文档实践
---------------------------------
- 变更策略:今后每次由自动化工具或我生成/修改后端代码时,将同步把该变更的作用、配置项与启用方法记录到本文件(`server/PUSH_SERVER_README.md`)或对应 workflow 文档中,确保运行/运维人员能直接查阅到最新说明。