This commit is contained in:
eric
2026-03-26 11:08:35 -05:00
parent eaa92ddf36
commit db65182dc1
3 changed files with 67 additions and 43 deletions

View File

@@ -3,6 +3,8 @@
# ========== PocketBase ========== # ========== PocketBase ==========
NEXT_PUBLIC_POCKETBASE_URL=https://pocketbase.hackrobot.cn NEXT_PUBLIC_POCKETBASE_URL=https://pocketbase.hackrobot.cn
# 服务端 API 可优先走内网/本机,避免公网超时
# POCKETBASE_INTERNAL_URL=http://127.0.0.1:8090
POCKETBASE_EMAIL=xiaoshuang.eric@gmail.com POCKETBASE_EMAIL=xiaoshuang.eric@gmail.com
POCKETBASE_PASSWORD=Xiao4669805@ POCKETBASE_PASSWORD=Xiao4669805@
@@ -15,6 +17,8 @@ NEXT_PUBLIC_API_URL=http://127.0.0.1:8007
# PAYMENT_API_INTERNAL_URL=http://127.0.0.1:8007 # PAYMENT_API_INTERNAL_URL=http://127.0.0.1:8007
# 内网/慢网络可适当提高超时(毫秒):check_vip 默认 15s,payh5/redirect 默认 60s # 内网/慢网络可适当提高超时(毫秒):check_vip 默认 15s,payh5/redirect 默认 60s
# PAYJSAPI_CHECK_TIMEOUT=15000 # PAYJSAPI_CHECK_TIMEOUT=15000
# PAYJSAPI_CHECK_BY_EMAIL_TIMEOUT=15000
# PAYJSAPI_CHECK_BY_EMAIL_RETRIES=1
# PAYJSAPI_PAYH5_TIMEOUT=60000 # PAYJSAPI_PAYH5_TIMEOUT=60000
# PAYJSAPI_REDIRECT_TIMEOUT=60000 # PAYJSAPI_REDIRECT_TIMEOUT=60000
PAYMENT_PROVIDER=zpay PAYMENT_PROVIDER=zpay

View File

@@ -37,6 +37,8 @@ type RecoveryResult = {
const PAYJS_CHECK_BY_EMAIL_TIMEOUT = const PAYJS_CHECK_BY_EMAIL_TIMEOUT =
Number(process.env.PAYJSAPI_CHECK_BY_EMAIL_TIMEOUT) || 5000; Number(process.env.PAYJSAPI_CHECK_BY_EMAIL_TIMEOUT) || 5000;
const PAYJS_CHECK_BY_EMAIL_RETRIES =
Math.max(0, Number(process.env.PAYJSAPI_CHECK_BY_EMAIL_RETRIES) || 1);
function resolvePayApiUrl(request: NextRequest): string { function resolvePayApiUrl(request: NextRequest): string {
const payConfig = getPaymentConfig(); const payConfig = getPaymentConfig();
@@ -53,51 +55,64 @@ async function checkVipByEmailFromPayjsapi(
password: string, password: string,
userId?: string userId?: string
): Promise<PayjsVipEmailResult | null> { ): Promise<PayjsVipEmailResult | null> {
try { const payConfig = getPaymentConfig();
const apiUrl = resolvePayApiUrl(request); const primaryUrl = resolvePayApiUrl(request);
const res = await fetch(`${apiUrl}/nomadvip/check_vip_by_email`, { const candidates = Array.from(
method: "POST", new Set([primaryUrl, payConfig.apiUrl].map((x) => (x || "").trim().replace(/\/$/, "")).filter(Boolean))
headers: { "Content-Type": "application/json" }, );
body: JSON.stringify({
email,
password,
...(userId ? { user_id: userId } : {}),
}),
cache: "no-store",
signal: AbortSignal.timeout(PAYJS_CHECK_BY_EMAIL_TIMEOUT),
});
if (!res.ok) {
return null;
}
const data = await res.json().catch(() => ({})); for (const apiUrl of candidates) {
if (!data?.vip) { for (let i = 0; i <= PAYJS_CHECK_BY_EMAIL_RETRIES; i += 1) {
return { try {
vip: false, const res = await fetch(`${apiUrl}/nomadvip/check_vip_by_email`, {
error: method: "POST",
typeof data?.error === "string" && data.error.trim() headers: { "Content-Type": "application/json" },
? data.error.trim() body: JSON.stringify({
: undefined, email,
}; password,
} ...(userId ? { user_id: userId } : {}),
}),
cache: "no-store",
signal: AbortSignal.timeout(PAYJS_CHECK_BY_EMAIL_TIMEOUT),
});
if (!res.ok) {
continue;
}
return { const data = await res.json().catch(() => ({}));
vip: true, if (!data?.vip) {
effectiveUserId: return {
typeof data?.effectiveUserId === "string" vip: false,
? data.effectiveUserId.trim() error:
: undefined, typeof data?.error === "string" && data.error.trim()
anonymousUserId: ? data.error.trim()
typeof data?.anonymousUserId === "string" : undefined,
? data.anonymousUserId.trim() };
: undefined, }
token: typeof data?.token === "string" ? data.token : undefined,
record: data?.record?.id ? data.record : undefined, return {
}; vip: true,
} catch (error) { effectiveUserId:
console.log("[check-by-email] payjsapi request failed:", error); typeof data?.effectiveUserId === "string"
return null; ? data.effectiveUserId.trim()
: undefined,
anonymousUserId:
typeof data?.anonymousUserId === "string"
? data.anonymousUserId.trim()
: undefined,
token: typeof data?.token === "string" ? data.token : undefined,
record: data?.record?.id ? data.record : undefined,
};
} catch (error) {
if (i >= PAYJS_CHECK_BY_EMAIL_RETRIES) {
console.log("[check-by-email] payjsapi request failed url=%s error=%o", apiUrl, error);
} else {
await new Promise((resolve) => setTimeout(resolve, 250 * (i + 1)));
}
}
}
} }
return null;
} }
async function loginPocketBaseUser( async function loginPocketBaseUser(

View File

@@ -31,10 +31,15 @@ export interface MinioConfig {
} }
export function getPocketBaseConfig(): PocketBaseConfig { export function getPocketBaseConfig(): PocketBaseConfig {
const serverSide = typeof window === "undefined";
const internal = process.env.POCKETBASE_INTERNAL_URL?.trim();
if (serverSide && internal) {
return { url: internal.replace(/\/$/, "") };
}
return { return {
url: url:
process.env.NEXT_PUBLIC_POCKETBASE_URL ||
process.env.POCKETBASE_URL || process.env.POCKETBASE_URL ||
process.env.NEXT_PUBLIC_POCKETBASE_URL ||
"https://pocketbase.hackrobot.cn", "https://pocketbase.hackrobot.cn",
}; };
} }