1.ws优化bet.win订阅
This commit is contained in:
@@ -760,7 +760,7 @@
|
||||
以下与代码 `app/process/GameWebSocketServer.php`、`config/process.php`、`app/common/library/admin/WebSocketConfigHelper.php` 一致,**文档此前未写明的条件**在此补齐:
|
||||
|
||||
- **独立进程**:需在运行环境中启动 Webman 自定义进程 **`gameWebSocketServer`**(见 `config/process.php`),默认监听 **`H5_WEBSOCKET_LISTEN`**(缺省为 `websocket://0.0.0.0:3131`)。未启动进程则客户端无法建连或立刻断线。
|
||||
- **连接 URL**:优先使用环境变量 **`H5_WEBSOCKET_URL`**(完整 `ws://` / `wss://` 地址,建议带路径,如 `.env-example` 所示)。未配置时,后台 **`GET /admin/test.GameCurrentStatus/wsConfig`**(及游戏实时页同类接口)会通过 `WebSocketConfigHelper` 按当前请求的 `Host` / `X-Forwarded-*` 推导 `ws(s)://{host}/ws/`,本地兜底 **`ws://127.0.0.1:3131/ws/`**。
|
||||
- **连接 URL**:优先使用环境变量 **`H5_WEBSOCKET_URL`**(完整 `ws://` / `wss://` 地址,建议带路径,如 `.env-example` 所示)。**生产环境勿将 `H5_WEBSOCKET_URL` 配成 `127.0.0.1` / `localhost`**:浏览器无法访问服务端本机地址。若 `.env` 中为回环地址且 HTTP 请求来自外网域名,`WebSocketConfigHelper` 会**忽略该配置**,改按当前请求的 `Host` / `X-Forwarded-*` 推导 `ws(s)://{host}/ws/`。未配置时,后台 **`GET /admin/test.GameCurrentStatus/wsConfig`**、**`GET /admin/game.Live/wsConfig`** 等同理;本地兜底 **`ws://127.0.0.1:3131/ws/`**。HTTPS 站点需在 Nginx 等反向代理将 **`/ws/`** 转发至 `gameWebSocketServer` 监听端口(默认 **3131**)。
|
||||
- **移动端配置缺口**:**`POST /api/game/lobbyInit` 当前不下发 WebSocket 地址**;H5 需与运维约定同一套 `H5_WEBSOCKET_URL`(打包进前端配置、远程配置中心等),与 HTTP API 基址可不同域。
|
||||
- **混合内容**:若 H5 页面为 **HTTPS**,浏览器要求 WebSocket 使用 **`wss://`**,否则会被拦截。
|
||||
- **事件投递依赖 Redis**:HTTP 侧业务通过 **`GameWebSocketEventBus`**(Redis 列表)将事件投递到 WebSocket 进程;Redis 不可用或队列异常时,**除 `admin.live.snapshot` 外**的广播类推送可能收不到。后台若订阅了 `admin.live.snapshot`,服务端有**每秒直连构建快照**的兜底,不依赖队列。
|
||||
@@ -819,7 +819,8 @@
|
||||
- `data.streak_level`:int
|
||||
- `data.odds_factor`:int
|
||||
- `data.is_jackpot`:bool
|
||||
- **`wallet.changed` / `bet.accepted`**:在原有字段上合并同上 **`current_streak`**、**`streak_level`**、**`odds_factor`**、**`is_jackpot`**;客户端按 `user_id` 过滤,仅处理本用户
|
||||
- **`wallet.changed` / `bet.accepted` / `bet.win`**:在原有字段上合并同上 **`current_streak`**、**`streak_level`**、**`odds_factor`**、**`is_jackpot`**;客户端按 `user_id` 过滤,仅处理本用户。
|
||||
- **`bet.accepted` 与 `bet.win` 的 `is_jackpot` 区别**:`bet.accepted` 表示**下注时**本笔适用档位是否大奖档(赔率展示);**开奖中奖通知以 `bet.win` 为准**,其 `is_jackpot` 表示**结算时**该用户中奖注单是否含大奖档(`streak_at_bet` 对应 `streak_win_reward.is_jackpot=true`,通常为第 10 档)。
|
||||
|
||||
#### 7.1.3 推送频率与触发规则(当前实现)
|
||||
|
||||
@@ -834,15 +835,20 @@
|
||||
- `admin.live.snapshot`:**每秒一次**(后台实时对局页全量快照;不受派彩静默期影响)。
|
||||
- `period.opened` / `period.payout` / `admin.live.opened`:按开奖流程阶段触发(事件触发型,非固定频率)。
|
||||
- `wallet.changed`:仅在余额发生变更时推送(如下注扣款、充值入账、派彩入账)。派彩时 `biz_type=payout`,并带 `amount`(本次派彩金额)、`period_no`、`period_id`、`result_number`(若有)。
|
||||
- **`bet.win`(本期中奖,小奖/大奖统一)**:开奖结算后,**凡本期有中奖的用户**均按用户聚合推送一帧(与 `wallet.changed(payout)` 同一结算时刻);客户端**统一监听此事件**做中奖弹窗/横幅,用 `data.is_jackpot` 区分展示样式。
|
||||
- **`bet.win`(本期中奖,小奖/大奖统一)**:开奖结算后,**凡本期有中奖的用户**均按用户聚合推送一帧(与 `wallet.changed(payout)` 同一结算批次);**个人中奖弹窗/横幅统一监听此主题**,用 `data.is_jackpot` 区分普通档与大奖档样式。**中大奖档用户同样会收到 `bet.win`**,无需仅依赖 `jackpot.hit`。
|
||||
- `data.user_id` / `data.period_id` / `data.period_no` / `data.result_number`
|
||||
- `data.total_win`:本期该用户派彩合计(已结算入账部分;待审核大奖可能尚未入账,但仍会推送本事件)
|
||||
- `data.total_win`:本期该用户派彩合计(已入账部分;若触发**后台大奖审核**(`win_amount >= game_config.jackpot_max_amount`)且注单为待审核,可能尚未入账,但仍会推送本事件)
|
||||
- `data.balance_after`:推送时用户余额(已派彩则为派彩后余额)
|
||||
- `data.bets[]`:`{ bet_id, win_amount }` 明细
|
||||
- **`data.is_jackpot`**:`bool`,`true` 表示该用户本注适用档位为大奖(`streak_win_reward` 对应档 `is_jackpot=true`),`false` 为普通档
|
||||
- **`data.is_jackpot`**:`bool`,`true` 表示该用户本期中奖注单含**大奖档**(`streak_win_reward` 中 `is_jackpot=true` 的档位,与下注时 `streak_at_bet` 对应),`false` 为普通档
|
||||
- **`data.is_win`**:`bool`,固定为 `true`(便于与 `user.streak` 的 `extra.is_win` 对齐)
|
||||
- **合并赔率字段**(与 §7.1.2A 一致):`current_streak`、`streak_level`、`odds_factor`、`is_jackpot`
|
||||
- `data.server_time`:Unix 秒
|
||||
- **`jackpot.hit`(公共大奖广播,补充)**:在 **`bet.win` 之后**(同一结算批次内),若本期存在**大奖档命中**用户,**额外**向公共频道推送一帧,供全站公告/跑马灯;无大奖命中则不推送。
|
||||
- **推送顺序**:先 `bet.win`(按用户,含 `is_jackpot`)→ 再 `jackpot.hit`(仅大奖)
|
||||
- **服务端去重**:Redis Key `dfw:v1:ws:betwin:{period_id}:{user_id}`(TTL 86400s),**每期每用户至多推送一次**;与 `user.streak` / `wallet.changed` 的整期去重键 `dfw:v1:settle:notify:{period_id}` **分离**,避免后者先占位导致 `bet.win` 被吞。
|
||||
- **补偿**:若内存聚合 `bet_wins` 为空但库内已有本期已结算中奖注单,结算服务会从库重建载荷并补发(`buildBetWinPayloadsFromSettledOrders`)。
|
||||
- **大奖审核通过后**:后台 `approveJackpot` 会再次向该用户推送 `bet.win`(入账后)。
|
||||
- **`jackpot.hit`(公共大奖广播,补充)**:在 **`bet.win` 之后**(同一结算批次内),若本期存在**大奖档命中**用户,**额外**向公共频道推送一帧,供全站公告/跑马灯;无大奖命中则不推送。**个人弹窗仍以 `bet.win` 为主**;`jackpot.hit` 用于全站展示昵称与金额。
|
||||
- **推送顺序**:先 `bet.win`(按用户,含 `is_jackpot`)→ 再 `jackpot.hit`(仅大奖档)
|
||||
- **载荷字段**:`period_id` / `period_no` / `result_number` / `hits[]` / `server_time`。
|
||||
- `hits[]` 数组每项字段:
|
||||
- `user_id`:int(中奖用户 ID)
|
||||
@@ -851,11 +857,31 @@
|
||||
- `total_win`:string(本期该用户的命中大奖派彩合计,金额字符串)
|
||||
- `result_number`:int
|
||||
|
||||
#### 7.1.4 结算推送去重与运维补发(2026-05)
|
||||
|
||||
| Redis Key | 作用 |
|
||||
|-----------|------|
|
||||
| `dfw:v1:settle:notify:{period_id}` | 整期 `user.streak` / `wallet.changed`(结算批次内)/ `jackpot.hit` 仅推一次 |
|
||||
| `dfw:v1:ws:betwin:{period_id}:{user_id}` | 该用户本期 `bet.win` 仅推一次(与上表独立) |
|
||||
|
||||
**运维补发**(已结算中奖但客户端未收到 `bet.win` 时):
|
||||
|
||||
```bash
|
||||
php scripts/republish_bet_win.php --play-record-id=1370
|
||||
php scripts/republish_bet_win.php --period-id=123
|
||||
php scripts/republish_bet_win.php --period-no=20260526-183418-c9c90ef1
|
||||
# 强制忽略 dedup 再推:加 --force
|
||||
```
|
||||
|
||||
联调脚本:`php scripts/verify_ws_topic_subscribe.php`(含 `bet.win` 入队/订阅校验)。
|
||||
|
||||
### 7.1A 后台连接方式(管理端联调)
|
||||
|
||||
- 后台菜单:仅保留一个菜单 `连接服务器websocket`,用于统一联调 WebSocket
|
||||
- 后台连接入口:
|
||||
- 后台菜单:`连接服务器websocket`(联调)、**`游戏管理` → `游戏实时对局`**(`/admin/game/live`,生产监控)
|
||||
- 后台 WebSocket 配置入口:
|
||||
- `/admin/test.GameCurrentStatus/wsConfig`
|
||||
- `/admin/game.Live/wsConfig`(实时对局页自动拉取并订阅,含 `admin.live.snapshot`、`bet.win` 等)
|
||||
- **HTTP 快照**:`GET /admin/game.Live/snapshot` 为**只读**快照(`buildSnapshot`),**不在此接口执行** `recoverLiveRoundState` / 自动开奖,避免请求超时;对局推进由进程 **`gameLiveTicker`** 与开奖流程负责。
|
||||
- 后台页面能力:
|
||||
- 读取 `ws_url`、`connect_tip`、`sample_messages`
|
||||
- 手动连接/断开 WebSocket
|
||||
@@ -881,9 +907,9 @@
|
||||
1. `GET /api/v1/authToken?secret=xxx×tamp=xxx&device_id=xxx&signature=xxx` 获取 `auth-token`
|
||||
2. `POST /api/user/login` 登录(请求头带 `auth-token`)
|
||||
3. `POST /api/game/lobbyInit` 拉首页初始化(请求头带 `auth-token`)
|
||||
4. 取得 WebSocket 基址(**当前非 lobbyInit 下发**:与运维/打包配置中的 `H5_WEBSOCKET_URL` 或自建配置接口一致)后建立 WebSocket 连接,**立即发送 `subscribe`** 监听状态流(见 §7.0 / §7.1)
|
||||
4. 取得 WebSocket 基址(**当前非 lobbyInit 下发**:与运维/打包配置中的 `H5_WEBSOCKET_URL` 或自建配置接口一致)后建立 WebSocket 连接,**立即发送 `subscribe`** 监听状态流(见 §7.0 / §7.1;**务必包含 `bet.win`**)
|
||||
5. 用户下注调用 `POST /api/game/placeBet`
|
||||
6. 下单后以 `placeBet.balance_after` 与 `wallet.changed` 同步余额
|
||||
6. 下单后以 `placeBet.balance_after` 与 `wallet.changed` 同步余额;开奖结算后监听 **`bet.win`**(`data.user_id` 为本用户且 `is_win=true`)展示中奖,大奖档看 `data.is_jackpot`
|
||||
7. 断线或页面回前台时,重连 WebSocket 并重新订阅主题回补实时状态
|
||||
|
||||
## 8.2 充值到下注到提现闭环
|
||||
@@ -915,7 +941,7 @@ flowchart TD
|
||||
E --> F[等待 wallet.changed 同步余额]
|
||||
D -- 否 --> G[进入封盘与开奖阶段]
|
||||
G --> H[服务端算票与开奖]
|
||||
H --> I[WebSocket 推送状态变化]
|
||||
H --> I[WebSocket: period.opened / bet.win / wallet.changed 等]
|
||||
I --> J[断线重连并重新订阅]
|
||||
J --> C
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user