From c15136c5e792ec76df46061d80dbf1d2c81d8a6f Mon Sep 17 00:00:00 2001 From: adonis Date: Thu, 18 Jun 2026 19:44:23 +0330 Subject: [PATCH] added wss tools 7 --- .../Site/PriceStreamController.php | 6 ++ app/Services/LivePriceCacheService.php | 12 ++++ app/Services/PriceBroadcastService.php | 72 ++++++++++++++++--- app/Services/PriceStreamService.php | 44 ++++++++++++ 4 files changed, 125 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Site/PriceStreamController.php b/app/Http/Controllers/Site/PriceStreamController.php index 48e01c5..3894f0b 100644 --- a/app/Http/Controllers/Site/PriceStreamController.php +++ b/app/Http/Controllers/Site/PriceStreamController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers\Site; use App\Http\Controllers\Controller; use App\Services\LivePriceCacheService; +use App\Services\PriceBroadcastService; use App\Services\PriceStreamService; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -44,6 +45,11 @@ class PriceStreamController extends Controller $send('last', $last); } + $list = app(PriceBroadcastService::class)->buildListPayload(); + if (is_array($list) && $list !== []) { + $send('list', $list); + } + $lastId = $service->currentSeq(); $heartbeatTicks = 0; diff --git a/app/Services/LivePriceCacheService.php b/app/Services/LivePriceCacheService.php index ec0ecc0..36cd2ef 100644 --- a/app/Services/LivePriceCacheService.php +++ b/app/Services/LivePriceCacheService.php @@ -33,6 +33,18 @@ class LivePriceCacheService public function put(array $body): array { + $cached = Cache::get(self::FULL_RESPONSE_KEY); + $cachedBody = is_array($cached['body'] ?? null) ? $cached['body'] : null; + + if ($cachedBody !== null && PriceBroadcastService::lastPriceIdentity($cachedBody) === PriceBroadcastService::lastPriceIdentity($body)) { + Cache::put(self::FULL_RESPONSE_KEY, [ + 'body' => $cachedBody, + 'stored_at' => now(), + ], now()->addSeconds(self::TTL_SECONDS + 5)); + + return $cachedBody; + } + Cache::put(self::FULL_RESPONSE_KEY, [ 'body' => $body, 'stored_at' => now(), diff --git a/app/Services/PriceBroadcastService.php b/app/Services/PriceBroadcastService.php index 5c30722..0f8fc3c 100644 --- a/app/Services/PriceBroadcastService.php +++ b/app/Services/PriceBroadcastService.php @@ -43,15 +43,34 @@ class PriceBroadcastService } $lastChanged = is_array($lastPayload) && $lastPayload !== [] - && $this->rememberHashIfChanged(self::LAST_HASH_KEY, $lastPayload); - - $this->publishListIfChanged(); + && $this->rememberHashIfChanged(self::LAST_HASH_KEY, self::lastPriceIdentity($lastPayload)); if ($lastChanged && is_array($lastPayload)) { $stream->publish('last', $lastPayload); + $this->publishListIfChanged(true); + } else { + $this->publishListIfChanged(); } } + /** + * @param array $payload + * @return array + */ + public static function lastPriceIdentity(array $payload): array + { + return [ + 'sell' => (int) ($payload['sell'] ?? 0), + 'buy' => (int) ($payload['buy'] ?? 0), + 'price_last' => (int) ($payload['price_last'] ?? 0), + 'price' => (int) ($payload['price'] ?? 0), + 'closed' => (bool) ($payload['closed'] ?? false), + 'main_product' => (int) ($payload['main_product'] ?? 0), + 'montzar' => (int) ($payload['montzar'] ?? 0), + 'zaarbox' => (int) ($payload['zaarbox'] ?? 0), + ]; + } + public function broadcastLastIfChanged(?array $lastPayload): void { $stream = app(PriceStreamService::class); @@ -63,39 +82,74 @@ class PriceBroadcastService return; } - if (! $this->rememberHashIfChanged(self::LAST_HASH_KEY, $lastPayload)) { + if (! $this->rememberHashIfChanged(self::LAST_HASH_KEY, self::lastPriceIdentity($lastPayload))) { return; } $stream->publish('last', $lastPayload); + $this->publishListIfChanged(true); } - public function broadcastListIfChanged(): bool + public function buildListPayload(): ?array + { + return $this->buildProductListPayload(); + } + + public function broadcastListIfChanged(bool $force = false): bool { $stream = app(PriceStreamService::class); if (! $stream->isEnabled()) { return false; } - return $this->publishListIfChanged(); + return $this->publishListIfChanged($force); } - private function publishListIfChanged(): bool + private function publishListIfChanged(bool $force = false): bool { $listPayload = $this->buildProductListPayload(); - if ($listPayload === null) { + if ($listPayload === null || $listPayload === []) { return false; } - if (! $this->rememberHashIfChanged(self::LIST_HASH_KEY, $listPayload)) { + if (! $force && ! $this->rememberHashIfChanged(self::LIST_HASH_KEY, $this->listIdentity($listPayload))) { return false; } + if ($force) { + $this->rememberHashIfChanged(self::LIST_HASH_KEY, $this->listIdentity($listPayload)); + } + app(PriceStreamService::class)->publish('list', $listPayload); return true; } + /** + * @param array> $listPayload + * @return array> + */ + private function listIdentity(array $listPayload): array + { + $identity = []; + + foreach ($listPayload as $product) { + if (! is_array($product)) { + continue; + } + + $identity[] = [ + 'id' => (int) ($product['id'] ?? 0), + 'price' => (int) ($product['price'] ?? 0), + 'price_profit' => (int) ($product['price_profit'] ?? 0), + 'show' => (bool) ($product['show'] ?? true), + 'active' => (bool) ($product['active'] ?? true), + ]; + } + + return $identity; + } + /** * @param array|array $payload */ diff --git a/app/Services/PriceStreamService.php b/app/Services/PriceStreamService.php index 37b2e8d..2d811b5 100644 --- a/app/Services/PriceStreamService.php +++ b/app/Services/PriceStreamService.php @@ -100,6 +100,15 @@ class PriceStreamService $key = $this->inboxKey(); $inbox = Cache::get($key, ['seq' => 0, 'events' => []]); + $events = is_array($inbox['events'] ?? null) ? $inbox['events'] : []; + $lastEvent = $events !== [] ? $events[array_key_last($events)] : null; + + if (is_array($lastEvent) + && ($lastEvent['event'] ?? null) === $event + && $this->eventDataHash($event, $lastEvent['data'] ?? null) === $this->eventDataHash($event, $data)) { + return; + } + $inbox['seq'] = (int) ($inbox['seq'] ?? 0) + 1; $inbox['events'][] = [ 'id' => $inbox['seq'], @@ -119,6 +128,41 @@ class PriceStreamService return self::INBOX_PREFIX.'global'; } + /** + * @param array|array $data + */ + private function eventDataHash(string $event, mixed $data): string + { + if (! is_array($data)) { + return md5(''); + } + + if ($event === 'last') { + return md5(json_encode(PriceBroadcastService::lastPriceIdentity($data), JSON_UNESCAPED_UNICODE)); + } + + if ($event === 'list') { + $identity = []; + foreach ($data as $product) { + if (! is_array($product)) { + continue; + } + + $identity[] = [ + 'id' => (int) ($product['id'] ?? 0), + 'price' => (int) ($product['price'] ?? 0), + 'price_profit' => (int) ($product['price_profit'] ?? 0), + 'show' => (bool) ($product['show'] ?? true), + 'active' => (bool) ($product['active'] ?? true), + ]; + } + + return md5(json_encode($identity, JSON_UNESCAPED_UNICODE)); + } + + return md5(json_encode($data, JSON_UNESCAPED_UNICODE)); + } + private function normalizeHost(string $host): string { $host = strtolower(trim($host));