|
|
import { createHash } from "node:crypto";
|
|
|
import type {
|
|
|
AddressLookupInput,
|
|
|
MothershipAddressCandidate,
|
|
|
} from "@/modules/address/types";
|
|
|
import {
|
|
|
getAddressCandidatesCache,
|
|
|
setAddressCandidatesCache,
|
|
|
} from "@/modules/cache/redis-cache";
|
|
|
|
|
|
export type AddressCandidatesCachePayload = {
|
|
|
pickup_candidates: MothershipAddressCandidate[];
|
|
|
delivery_candidates: MothershipAddressCandidate[];
|
|
|
};
|
|
|
|
|
|
function normalizeAddressLookup(input: AddressLookupInput): string {
|
|
|
return JSON.stringify({
|
|
|
street: input.street.trim(),
|
|
|
city: input.city.trim(),
|
|
|
state: input.state.trim().toUpperCase(),
|
|
|
zip: input.zip.trim(),
|
|
|
country: (input.country ?? "USA").trim().toUpperCase(),
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/** pickup + delivery 草稿地址 MD5,用于 addr-cand 缓存键 */
|
|
|
export function buildAddressCandidatesCacheHash(input: {
|
|
|
pickup: AddressLookupInput;
|
|
|
delivery: AddressLookupInput;
|
|
|
}): string {
|
|
|
const raw = [
|
|
|
normalizeAddressLookup(input.pickup),
|
|
|
normalizeAddressLookup(input.delivery),
|
|
|
].join("|");
|
|
|
return createHash("md5").update(raw).digest("hex");
|
|
|
}
|
|
|
|
|
|
export async function loadAddressCandidatesCache(input: {
|
|
|
pickup: AddressLookupInput;
|
|
|
delivery: AddressLookupInput;
|
|
|
}): Promise<AddressCandidatesCachePayload | null> {
|
|
|
try {
|
|
|
const hash = buildAddressCandidatesCacheHash(input);
|
|
|
return await getAddressCandidatesCache<AddressCandidatesCachePayload>(hash);
|
|
|
} catch {
|
|
|
return null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export async function saveAddressCandidatesCache(
|
|
|
input: {
|
|
|
pickup: AddressLookupInput;
|
|
|
delivery: AddressLookupInput;
|
|
|
},
|
|
|
payload: AddressCandidatesCachePayload,
|
|
|
): Promise<void> {
|
|
|
try {
|
|
|
const hash = buildAddressCandidatesCacheHash(input);
|
|
|
await setAddressCandidatesCache(hash, payload);
|
|
|
} catch {
|
|
|
// Redis 不可用时跳过缓存,不影响主流程
|
|
|
}
|
|
|
}
|