|
|
/**
|
|
|
* 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;
|
|
|
}
|