driverSupportsRealtime()) { return; } $ms = (int) floor(microtime(true) * 1000); broadcast(new DrawCountdownBroadcast($this->snapshot->build(), $ms)); } /** * Tick 首尾对比:**数据库**当期指纹({@see DrawHallSnapshotBuilder::hallTargetFingerprint})变了再发, * 载荷仍为 {@see DrawHallSnapshotBuilder::build()}(含未到 tick 时对 `open` 的展示规范化)。 */ public function notifyStatusChangeIfHallDbChanged(?array $fpBefore, ?array $fpAfter, ?array $snapshotPayload): void { if (! $this->driverSupportsRealtime()) { return; } if (($fpBefore['draw_no'] ?? null) === ($fpAfter['draw_no'] ?? null) && ($fpBefore['status'] ?? null) === ($fpAfter['status'] ?? null)) { return; } $this->notifyStatusChange($snapshotPayload); } /** `draw.status_change`(管理端发布后等不与 tick 同路径时使用)。 */ public function notifyStatusChange(?array $data): void { if (! $this->driverSupportsRealtime()) { return; } broadcast(new DrawStatusChangeBroadcast($data, (int) floor(microtime(true) * 1000))); } /** `result.published` */ public function notifyResultPublished(?array $data): void { if (! $this->driverSupportsRealtime()) { return; } broadcast(new DrawResultPublishedBroadcast($data, (int) floor(microtime(true) * 1000))); } /** `risk.sold_out` —— 号码赔付池耗尽 */ public function notifyRiskSoldOut(int $drawId, string $drawNo, string $normalizedNumber): void { if (! $this->driverSupportsRealtime()) { return; } broadcast(new RiskSoldOutBroadcast( $drawId, $drawNo, $normalizedNumber, (int) floor(microtime(true) * 1000), )); } /** `risk.warning` —— 号码赔付池占用超 80% 预警 */ public function notifyRiskWarning(int $drawId, string $drawNo, string $normalizedNumber, float $usageRatio): void { if (! $this->driverSupportsRealtime()) { return; } broadcast(new RiskWarningBroadcast( $drawId, $drawNo, $normalizedNumber, $usageRatio, (int) floor(microtime(true) * 1000), )); } /** `play.toggle` —— 玩法开关变更 */ public function notifyPlayToggle(string $playCode, bool $enabled, ?string $reason = null): void { if (! $this->driverSupportsRealtime()) { return; } broadcast(new PlayToggleBroadcast( $playCode, $enabled, $reason, (int) floor(microtime(true) * 1000), )); } /** * `play.catalog_updated` —— 玩法/赔率/封顶版本发布(全量目录变更)。 * * @param string $module play_config|odds|risk_cap */ public function notifyPlayCatalogUpdated( string $module, int $versionId, string $versionLabel, ?array $meta = null, ): void { if (! $this->driverSupportsRealtime()) { return; } broadcast(new PlayCatalogUpdatedBroadcast( $module, $versionId, $versionLabel, $meta, (int) floor(microtime(true) * 1000), )); } /** `odds.update` —— 赔率变更 */ public function notifyOddsUpdate(int $versionId, string $versionName, ?array $diff = null): void { if (! $this->driverSupportsRealtime()) { return; } broadcast(new OddsUpdateBroadcast( $versionId, $versionName, $diff, (int) floor(microtime(true) * 1000), )); } /** `jackpot.burst` —— Jackpot 爆池动画与浏览器通知 */ public function notifyJackpotBurst( int $drawId, string $drawNo, string $firstPrizeNumber, string $currencyCode, int $totalPayoutAmount, int $winnerCount, string $triggerType, int $poolAmountAfter, ): void { if (! $this->driverSupportsRealtime()) { return; } broadcast(new JackpotBurstBroadcast( $drawId, $drawNo, $firstPrizeNumber, strtoupper($currencyCode), $totalPayoutAmount, $winnerCount, $triggerType, $poolAmountAfter, (int) floor(microtime(true) * 1000), )); } private function driverSupportsRealtime(): bool { $default = config('broadcasting.default'); if ($default === null || $default === 'null') { return false; } $driver = config("broadcasting.connections.{$default}.driver") ?? $default; return ! in_array($driver, ['null', 'log'], true); } }