98 lines
2.8 KiB
JavaScript
98 lines
2.8 KiB
JavaScript
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 }
|