Files
lotteryLaravel/app/Services/Draw/LotteryHallRealtimeBroadcaster.php

176 lines
5.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Services\Draw;
use App\Events\OddsUpdateBroadcast;
use App\Events\PlayToggleBroadcast;
use App\Events\RiskSoldOutBroadcast;
use App\Events\RiskWarningBroadcast;
use App\Events\JackpotBurstBroadcast;
use App\Events\DrawCountdownBroadcast;
use App\Events\DrawStatusChangeBroadcast;
use App\Events\DrawResultPublishedBroadcast;
/**
* 对齐界面文档 §2.1:大厅公共频道广播(`lottery-hall`)。
* 包含draw.countdown、draw.status_change、result.published、
* risk.sold_out、risk.warning、play.toggle、odds.update、jackpot.burst
*/
final class LotteryHallRealtimeBroadcaster
{
public function __construct(
private readonly DrawHallSnapshotBuilder $snapshot,
) {}
/** 每秒调度:`draw.countdown` 仅发送轻量心跳,不重查全量大厅快照。 */
public function countdownPulse(): void
{
if (! $this->driverSupportsRealtime()) {
return;
}
$ms = (int) floor(microtime(true) * 1000);
broadcast(new DrawCountdownBroadcast(null, $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),
));
}
/** `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);
}
}