7.4 KiB
WalletMan 后端对接文档
前端集成见 walletman前端对接.md
1. 架构
Android 宿主 ◄── HTTP / WS ──► walletman (:16000 或反代) ◄── 代理 TCP ──► 钱包 API
◄── FCM data ──► Firebase
| 链路 | 用途 |
|---|---|
| HTTP REST | 登录、绑钱包、查流水等业务 |
WebSocket /ws |
设备注册、TCP 代理、心跳 |
| FCM data | WS 断线拉活、token 过期重绑 |
clientId:设备唯一 ID,WS 注册 key + FCM 目标 key,须与 App DeviceInfo.getUniqueIdSync() 一致。
2. 启动与配置
cd servers/walletman/cmd/server
go run . -tls android
- 默认监听
:16000 - 测试页:
http://localhost:16000/test/index.html - 钱包持久化:
cmd/wallets.json
FCM 服务账号(二选一):
servers/walletman/cmd/server/config/fcm-service-account.json
或环境变量 FCM_SERVICE_ACCOUNT=/path/to/json。须与宿主 App 的 google-services.json 同一 Firebase 项目。
3. 通用约定
响应格式:
{ "success": true, "message": "说明", "data": {} }
需登录接口请求头:
Content-Type: application/json
X-User-ID: 10000
4. HTTP 接口
POST /login
// req
{ "username": "test123", "password": "123456" }
// data
{ "userId": 10000, "userToken": "10000" }
POST /register
Token 模式绑钱包 / 静默重绑落库。
{
"walletType": "paytm",
"params": {
"type": "paytm",
"token": "...",
"refreshToken": "...",
"mobile": "9876543210",
"deviceId": "...",
"chType": "ipay",
"chVersion": "3"
}
}
// data
{ "walletId": "paytm_9876543210", "walletType": "paytm" }
walletId = {walletType}_{phone}。
支持的 walletType(见 walletman.GetAllWalletTypes()):
| walletType | 说明 |
|---|---|
paytm |
Paytm Personal(ipay AIDL) |
phonepe |
PhonePe Personal(ipay AIDL) |
mobikwik |
Mobikwik Personal |
freecharge |
Freecharge Personal |
amazonpay |
Amazon Pay Personal |
paytm business |
Paytm Business |
phonepe business |
PhonePe Business |
googlepay business |
Google Pay Business |
bharatpe business |
BharatPe Business |
各类型 params 字段以对应 *_personal.go / *_business.go 及前端 Bind 组件为准。
POST /request-otp / POST /verify-otp
OTP 绑钱包。重绑场景若钱包已存在,会复用已有 params(保留 deviceId 等),见 requestOTPHTTP。
GET /wallets
{
"wallets": [{
"id": "paytm_9876543210",
"walletType": "paytm",
"phone": "9876543210",
"upi": "xxx@paytm",
"status": "active",
"otpMode": false
}]
}
status=inactive 且 otpMode=false 时,可能触发 FCM 重绑(见 §6)。
POST /fcm/register
{ "clientId": "设备ID", "fcmToken": "..." }
与 WS register.data.fcmToken 等价,均写入 FCM token 存储。
POST /fcm/send-wake
{ "clientId": "xxx" }
// 或
{ "userId": 10000 }
下发 wake_proxy,客户端重连 WS。
POST /fcm/send-rebind
{
"walletId": "paytm_9876543210",
"walletType": "paytm",
"phone": "9876543210",
"retry": false,
"notify": true
}
| 字段 | 说明 |
|---|---|
clientId |
可省略,按 wallet owner 查 GetFcmClientID |
retry |
传给客户端;phonepe 类型服务端会强制 retry=true |
notify |
true 时在 data 中带 msg 文案;客户端 AIDL 失败才本地弹通知 |
GET /fcm/clients
已注册 FCM 的 clientId 列表。
POST /wallet/set-status
手动改钱包状态;设为 inactive 时会 maybeNotifyWalletRebind。
5. WebSocket /ws
URL:ws://host:16000/ws 或 wss://host/ws(反代)
客户端 → 服务端
register(连接后立即发送)
{
"type": "register",
"messageId": "register_1700000000000",
"clientId": "设备ID",
"data": { "userId": 10000, "fcmToken": "可选" }
}
- 绑定
clientId → Client userManager.SetProxy(userId, clientId, ...)- 同 clientId 新连接踢旧连接
ping(建议 10s)
{ "type": "ping", "messageId": "ping_xxx" }
proxyReady / proxyData / proxyClose
| type | 说明 |
|---|---|
| proxyReady | TCP 已连 host:port |
| proxyData | data.data = base64 |
| proxyClose | 结束本次代理 |
服务端 → 客户端
proxyRequest
{
"type": "proxyRequest",
"messageId": "req_1700000000000",
"data": { "host": "api.phonepe.com", "port": 443 }
}
443 端口在服务端侧做 TLS,再 HTTP/2 转发。
服务端行为
| 事件 | 行为 |
|---|---|
| WS 断开 | cleanupClient → sendFcmWake(clientId) |
| 45s 无活动 | 心跳超时清理 + wake |
| 代理时 client 离线 | requestProxy 失败 → wake |
| 钱包 API 出网 | proxyRoundTripper → requestProxy |
代码入口:websocket_handler.go、proxy.go、fcm.go。
6. FCM 下发
重绑走 data-only(不发 FCM notification 块),文案放在 data.msg,由客户端决定何时弹本地通知。
| data key | 说明 |
|---|---|
msg |
通知文案(notify=true 时有值) |
cmd |
wake_proxy | rebind_wallet |
params |
JSON 字符串 |
wake_proxy
{ "cmd": "wake_proxy", "params": "{}" }
rebind_wallet
{
"cmd": "rebind_wallet",
"msg": "Paytm 已过期,点我自动重绑",
"params": "{\"walletId\":\"paytm_9876543210\",\"walletType\":\"paytm\",\"phone\":\"9876543210\",\"retry\":false,\"tryGtkAnyway\":false}"
}
params 字段:
| 字段 | 说明 |
|---|---|
walletId |
钱包 ID |
walletType |
钱包类型 |
phone |
手机号 |
retry |
PhonePe 是否走 gtk 重试;phonepe 类型服务端默认 true |
tryGtkAnyway |
客户端扩展,当前服务端固定 false |
自动触发
POST /wallet/set-status设为 inactive →maybeNotifyWalletRebind(..., retry=false)- 拉流水后 token 失效变 inactive →
persistWalletIfChanged→ phonepe 且 inactiveCount>1 时retry=true
条件:GetOTPMode()==false 且 GetStatus()==inactive。
发送实现
sendFcmToClient → FCM HTTP v1 projects/{id}/messages:send。
7. 时序
代理请求
walletman HTTP 出网
→ GetProxyClientID(userId)
→ requestProxy(clientId, host, 443)
→ WS proxyRequest → 等 proxyReady
→ 双向 proxyData
断线拉活
WS cleanupClient
→ sendFcmWake(clientId)
→ 客户端 wakeFromPrefs → 重连 WS register
重绑
inactive 检测 / POST /fcm/send-rebind
→ FCM rebind_wallet(data.msg + params)
→ 客户端静默 AIDL → registerWallet → POST /register
→ 失败 → 客户端本地通知 → 用户点击 → JS handler 打开 Bind
8. 调试
| 方式 | 说明 |
|---|---|
http://localhost:16000/test/index.html |
发 wake / rebind、看 WS |
GET /fcm/clients |
已注册设备 |
POST /fcm/send-wake |
手动拉活 |
POST /fcm/send-rebind |
手动重绑 |
| 现象 | 排查 |
|---|---|
| FCM send failed | 服务账号路径、project_id |
| no FCM token for clientId | App 未 POST /fcm/register 且 WS 未带 fcmToken |
| Client not connected | WS 未连;先发 wake |
| 重绑发了客户端无反应 | Firebase 项目是否与 App 一致;logcat ProxyFcmService |