|
|
import { getHostQuotePollIntervalMs } from "@/lib/constants/host-public-api";
|
|
|
import { QUOTE_TIMEOUT_MS } from "@/lib/constants/quote";
|
|
|
import { prisma } from "@/lib/prisma";
|
|
|
import {
|
|
|
serializeQuoteDetail,
|
|
|
type QuoteDetailResponse,
|
|
|
} from "@/modules/quote/quote-serializer";
|
|
|
|
|
|
function sleep(ms: number): Promise<void> {
|
|
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
}
|
|
|
|
|
|
export class HostQuoteWaitError extends Error {
|
|
|
constructor(
|
|
|
message: string,
|
|
|
readonly code: "QUOTE_NOT_FOUND" | "QUOTE_TIMEOUT" | "QUOTE_FAILED",
|
|
|
readonly detail?: QuoteDetailResponse,
|
|
|
) {
|
|
|
super(message);
|
|
|
this.name = "HostQuoteWaitError";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** 服务端轮询 DB,直至报价完成或超时(供宿主同步接口使用) */
|
|
|
export async function waitForQuoteDetail(
|
|
|
quoteId: string,
|
|
|
customerId: string,
|
|
|
options?: { timeoutMs?: number },
|
|
|
): Promise<QuoteDetailResponse> {
|
|
|
const timeoutMs = options?.timeoutMs ?? QUOTE_TIMEOUT_MS;
|
|
|
const deadline = Date.now() + timeoutMs;
|
|
|
|
|
|
while (Date.now() < deadline) {
|
|
|
const record = await prisma.quoteRecord.findFirst({
|
|
|
where: { quoteId, customerId, isDeleted: false },
|
|
|
});
|
|
|
|
|
|
if (!record) {
|
|
|
throw new HostQuoteWaitError("报价不存在", "QUOTE_NOT_FOUND");
|
|
|
}
|
|
|
|
|
|
const detail = serializeQuoteDetail(record);
|
|
|
if (detail.status === "processing") {
|
|
|
const remaining = deadline - Date.now();
|
|
|
if (remaining <= 0) {
|
|
|
break;
|
|
|
}
|
|
|
await sleep(Math.min(getHostQuotePollIntervalMs(), remaining));
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
if (detail.status === "failed") {
|
|
|
throw new HostQuoteWaitError(
|
|
|
detail.error_message ?? "询价失败",
|
|
|
"QUOTE_FAILED",
|
|
|
detail,
|
|
|
);
|
|
|
}
|
|
|
|
|
|
if (detail.status === "expired") {
|
|
|
throw new HostQuoteWaitError("报价已过期", "QUOTE_FAILED", detail);
|
|
|
}
|
|
|
|
|
|
return detail;
|
|
|
}
|
|
|
|
|
|
throw new HostQuoteWaitError("询价超时,请稍后重试", "QUOTE_TIMEOUT");
|
|
|
}
|