const Redis = require("ioredis") const { randomUUID } = require("crypto") const { getRedisClient } = require("./client") const { getRedisConnectionOptions } = require("./connection") const DEFAULT_QUEUE_KEY = "scraper:requests" const DEFAULT_RESPONSE_CHANNEL_PREFIX = "scraper:response:" const DEFAULT_TIMEOUT_MS = 20000 function normalizeTimeoutMs(value) { const num = Number(value) if (!Number.isFinite(num) || num < 1000) return DEFAULT_TIMEOUT_MS return Math.floor(num) } async function requestProductPreviewOverRedis(url, options = {}) { if (!url) throw new Error("url parametresi zorunlu") const queueKey = process.env.SCRAPER_QUEUE_KEY || DEFAULT_QUEUE_KEY const responsePrefix = process.env.SCRAPER_RESPONSE_CHANNEL_PREFIX || DEFAULT_RESPONSE_CHANNEL_PREFIX const timeoutMs = normalizeTimeoutMs( options.timeoutMs ?? process.env.SCRAPER_RPC_TIMEOUT_MS ) const requestId = randomUUID() const responseChannel = `${responsePrefix}${requestId}` const redis = getRedisClient() const subscriber = new Redis(getRedisConnectionOptions()) const requestPayload = { requestId, type: "PRODUCT_PREVIEW", url: String(url), createdAt: new Date().toISOString(), } let timeoutHandle = null let settled = false function finish() { if (timeoutHandle) { clearTimeout(timeoutHandle) timeoutHandle = null } subscriber.removeAllListeners("message") subscriber .unsubscribe(responseChannel) .catch(() => {}) .finally(() => subscriber.disconnect()) } return new Promise(async (resolve, reject) => { const safeResolve = (data) => { if (settled) return settled = true finish() resolve(data) } const safeReject = (err) => { if (settled) return settled = true finish() reject(err) } try { subscriber.on("message", (channel, rawMessage) => { if (channel !== responseChannel) return try { const parsed = JSON.parse(String(rawMessage || "{}")) if (parsed?.error) { return safeReject(new Error(String(parsed.error))) } if (parsed && typeof parsed === "object" && parsed.product) { return safeResolve(parsed.product) } return safeResolve(parsed) } catch { return safeReject(new Error("Scraper yaniti parse edilemedi")) } }) await subscriber.subscribe(responseChannel) await redis.rpush(queueKey, JSON.stringify(requestPayload)) timeoutHandle = setTimeout(() => { safeReject(new Error("Scraper yaniti zaman asimina ugradi")) }, timeoutMs) } catch (err) { safeReject(err instanceof Error ? err : new Error("Scraper RPC hatasi")) } }) } module.exports = { requestProductPreviewOverRedis }