You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
3.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* MotherShip 登录态刷价 hold 状态(Redis)
*/
import {
MS_REFINE_HOLD_REDIS_PREFIX,
MS_REFINE_MSG,
MS_REFINE_TOTAL_MS,
type MsRefineHoldState,
buildMsRefineHoldState,
isMsRefineHoldExpired,
} from "@/lib/constants/ms-refine-hold";
import { withBoundedRedis } from "@/lib/redis";
function key(sessionId: string): string {
return `${MS_REFINE_HOLD_REDIS_PREFIX}${sessionId}`;
}
function ttlSeconds(): number {
return Math.ceil(MS_REFINE_TOTAL_MS / 1000) + 30;
}
export async function saveMsRefineHold(
state: MsRefineHoldState,
): Promise<void> {
const ok = await withBoundedRedis((redis) =>
redis.setex(
key(state.quote_session_id),
ttlSeconds(),
JSON.stringify(state),
),
);
if (ok === null) {
console.warn("[ms-refine-hold] save skipped: Redis 不可达");
}
}
export async function readMsRefineHold(
sessionId: string,
): Promise<MsRefineHoldState | null> {
const raw = await withBoundedRedis((redis) => redis.get(key(sessionId)));
if (!raw) return null;
try {
return JSON.parse(raw) as MsRefineHoldState;
} catch {
return null;
}
}
export async function readMsRefineHoldByQuoteId(
quoteId: string,
): Promise<MsRefineHoldState | null> {
const sid = await withBoundedRedis((redis) =>
redis.get(`${MS_REFINE_HOLD_REDIS_PREFIX}by_quote:${quoteId}`),
);
if (!sid) return null;
return readMsRefineHold(sid);
}
export async function createMsRefineHold(input: {
quoteId: string;
sessionId: string;
customerId: string;
}): Promise<MsRefineHoldState> {
const state = buildMsRefineHoldState(input);
await saveMsRefineHold(state);
await withBoundedRedis((redis) =>
redis.setex(
`${MS_REFINE_HOLD_REDIS_PREFIX}by_quote:${input.quoteId}`,
ttlSeconds(),
input.sessionId,
),
);
return state;
}
export async function updateMsRefineHoldStatus(
sessionId: string,
status: MsRefineHoldState["status"],
): Promise<MsRefineHoldState | null> {
const cur = await readMsRefineHold(sessionId);
if (!cur) return null;
const next = { ...cur, status };
await saveMsRefineHold(next);
return next;
}
export async function clearMsRefineHold(sessionId: string): Promise<void> {
const cur = await readMsRefineHold(sessionId);
await withBoundedRedis(async (redis) => {
await redis.del(key(sessionId));
if (cur?.quote_id) {
await redis.del(
`${MS_REFINE_HOLD_REDIS_PREFIX}by_quote:${cur.quote_id}`,
);
}
});
}
export async function assertMsRefineHoldUsable(
sessionId: string,
): Promise<MsRefineHoldState> {
const state = await readMsRefineHold(sessionId);
if (!state) {
throw new Error("刷价会话不存在或已释放");
}
if (isMsRefineHoldExpired(state)) {
throw new Error(MS_REFINE_MSG.sessionGone);
}
if (state.status === "declined" || state.status === "expired") {
throw new Error(MS_REFINE_MSG.sessionGone);
}
if (state.status === "refined") {
throw new Error("该报价已完成更新");
}
return state;
}