|null $lastPayload */ public function broadcastAfterPriceUpdate(?array $lastPayload = null, bool $force = false): void { $stream = app(PriceStreamService::class); if (! $stream->isEnabled()) { return; } if ($lastPayload === null) { $cache = app(LivePriceCacheService::class); $lastPayload = $cache->get() ?? $cache->buildFromDatabase(); } if ($force) { if (is_array($lastPayload) && $lastPayload !== []) { $stream->publish('last', $lastPayload); } $listPayload = $this->buildProductListPayload(); if ($listPayload !== null) { $stream->publish('list', $listPayload); } return; } $lastChanged = is_array($lastPayload) && $lastPayload !== [] && $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); if (! $stream->isEnabled()) { return; } if (! is_array($lastPayload) || $lastPayload === []) { return; } if (! $this->rememberHashIfChanged(self::LAST_HASH_KEY, self::lastPriceIdentity($lastPayload))) { return; } $stream->publish('last', $lastPayload); $this->publishListIfChanged(true); } public function buildListPayload(bool $allowCached = false): ?array { if ($allowCached) { $cached = Cache::get(self::LIST_SNAPSHOT_KEY); if ( is_array($cached) && is_array($cached['body'] ?? null) && isset($cached['stored_at']) && now()->diffInSeconds($cached['stored_at']) <= self::LIST_SNAPSHOT_SECONDS ) { return $cached['body']; } } $body = $this->buildProductListPayload(); if ($body !== null && $body !== []) { Cache::put(self::LIST_SNAPSHOT_KEY, [ 'body' => $body, 'stored_at' => now(), ], now()->addSeconds(self::LIST_SNAPSHOT_SECONDS + 5)); } return $body; } public function broadcastListIfChanged(bool $force = false): bool { $stream = app(PriceStreamService::class); if (! $stream->isEnabled()) { return false; } return $this->publishListIfChanged($force); } private function publishListIfChanged(bool $force = false): bool { $listPayload = $this->buildProductListPayload(); if ($listPayload === null || $listPayload === []) { return false; } if (! $force && ! $this->rememberHashIfChanged(self::LIST_HASH_KEY, self::listIdentity($listPayload))) { return false; } if ($force) { $this->rememberHashIfChanged(self::LIST_HASH_KEY, self::listIdentity($listPayload)); } Cache::forget(self::LIST_SNAPSHOT_KEY); app(PriceStreamService::class)->publish('list', $listPayload); return true; } /** * @param array> $listPayload * @return array> */ public static 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), 'reference_provider_active' => (bool) ($product['reference_provider_active'] ?? false), ]; } return $identity; } /** * @param array|array $payload */ private function rememberHashIfChanged(string $cacheKey, array $payload): bool { $hash = md5(json_encode($payload, JSON_UNESCAPED_UNICODE)); if (Cache::get($cacheKey) === $hash) { return false; } Cache::put($cacheKey, $hash, now()->addHour()); return true; } /** * @return array|null */ private function buildProductListPayload(): ?array { if (app(ConfigService::class)->isStore()) { return app(ProductController::class)->customerStoreProductListPayload(); } $request = Request::create('/customer/product/list', 'GET'); app()->instance('request', $request); $response = app(ProductController::class)->listProduct(); $decoded = json_decode($response->getContent(), true); return is_array($decoded) ? $decoded : null; } }