HotTRDealsBackend/services/redis/dealVote.service.js
2026-02-04 06:39:10 +00:00

98 lines
3.3 KiB
JavaScript

const { getRedisClient } = require("./client")
const { ensureMinDealTtl } = require("./dealCache.service")
function createRedisClient() {
return getRedisClient()
}
const DEAL_VOTE_HASH_PREFIX = "data:deals:votes:"
async function updateDealVoteInRedis({ dealId, userId, voteType, score }) {
if (!dealId || !userId) return
const redis = createRedisClient()
try {
const key = `data:deals:${dealId}`
const voteKey = `${DEAL_VOTE_HASH_PREFIX}${dealId}`
const raw = await redis.call("JSON.GET", key)
if (!raw) return { updated: false, delta: 0, score: null }
const deal = JSON.parse(raw)
const currentScore = Number.isFinite(deal?.score) ? Number(deal.score) : 0
const maxNotifiedMilestone = Number.isFinite(deal?.maxNotifiedMilestone)
? Number(deal.maxNotifiedMilestone)
: 0
const dealUserId = Number(deal?.userId)
const rawVotes = deal?.votes ?? []
let votes = []
votes = Array.isArray(rawVotes) ? rawVotes : []
const normalizedUserId = Number(userId)
const normalizedVoteType = Number(voteType)
const idx = votes.findIndex((vote) => Number(vote.userId) === normalizedUserId)
const oldVote = idx >= 0 ? Number(votes[idx]?.voteType ?? 0) : 0
if (idx >= 0) {
votes[idx] = { userId: normalizedUserId, voteType: normalizedVoteType }
} else {
votes.push({ userId: normalizedUserId, voteType: normalizedVoteType })
}
await redis.call("JSON.SET", key, "$.votes", JSON.stringify(votes))
const delta = normalizedVoteType - oldVote
const nextScore =
score !== undefined && score !== null ? Number(score) : currentScore + delta
await redis.call("JSON.SET", key, "$.score", nextScore)
await redis.hset(voteKey, String(normalizedUserId), String(normalizedVoteType))
const dealTtl = await redis.ttl(key)
if (Number.isFinite(dealTtl) && dealTtl > 0) {
await redis.expire(voteKey, dealTtl)
}
await ensureMinDealTtl(dealId, { minSeconds: 15 * 60 })
return { updated: true, delta, score: nextScore, maxNotifiedMilestone, dealUserId }
} finally {}
}
async function getDealVoteFromRedis(dealId, userId) {
const id = Number(dealId)
const uid = Number(userId)
if (!Number.isInteger(id) || !Number.isInteger(uid)) return 0
const redis = createRedisClient()
try {
const voteKey = `${DEAL_VOTE_HASH_PREFIX}${id}`
const raw = await redis.hget(voteKey, String(uid))
const value = raw == null ? 0 : Number(raw)
return Number.isFinite(value) ? value : 0
} finally {}
}
async function getMyVotesForDeals(dealIds = [], userId) {
const uid = Number(userId)
if (!Number.isInteger(uid)) return new Map()
const ids = (Array.isArray(dealIds) ? dealIds : [])
.map((id) => Number(id))
.filter((id) => Number.isInteger(id) && id > 0)
if (!ids.length) return new Map()
const redis = createRedisClient()
try {
const pipeline = redis.pipeline()
ids.forEach((id) => {
pipeline.hget(`${DEAL_VOTE_HASH_PREFIX}${id}`, String(uid))
})
const results = await pipeline.exec()
const map = new Map()
results.forEach(([, raw], idx) => {
const value = raw == null ? 0 : Number(raw)
map.set(ids[idx], Number.isFinite(value) ? value : 0)
})
return map
} finally {}
}
module.exports = {
updateDealVoteInRedis,
getDealVoteFromRedis,
getMyVotesForDeals,
}