修正短信验证码轮询等待逻辑
This commit is contained in:
@@ -565,6 +565,17 @@
|
|||||||
return Math.max(PHONE_CODE_POLL_ROUNDS_MIN, Math.min(PHONE_CODE_POLL_ROUNDS_MAX, parsed));
|
return Math.max(PHONE_CODE_POLL_ROUNDS_MIN, Math.min(PHONE_CODE_POLL_ROUNDS_MAX, parsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolvePhoneCodePollMaxRoundsForWindow(waitSeconds, pollIntervalSeconds, configuredMaxRounds) {
|
||||||
|
const normalizedWaitSeconds = normalizePhoneCodeWaitSeconds(waitSeconds);
|
||||||
|
const normalizedPollIntervalSeconds = normalizePhoneCodePollIntervalSeconds(pollIntervalSeconds);
|
||||||
|
const normalizedConfiguredRounds = normalizePhoneCodePollMaxRounds(configuredMaxRounds);
|
||||||
|
const roundsNeededForWaitWindow = Math.max(
|
||||||
|
PHONE_CODE_POLL_ROUNDS_MIN,
|
||||||
|
Math.ceil(normalizedWaitSeconds / normalizedPollIntervalSeconds)
|
||||||
|
);
|
||||||
|
return Math.max(normalizedConfiguredRounds, roundsNeededForWaitWindow);
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeHeroSmsReuseEnabled(value) {
|
function normalizeHeroSmsReuseEnabled(value) {
|
||||||
if (value === undefined || value === null) {
|
if (value === undefined || value === null) {
|
||||||
return Boolean(DEFAULT_HERO_SMS_REUSE_ENABLED);
|
return Boolean(DEFAULT_HERO_SMS_REUSE_ENABLED);
|
||||||
@@ -5461,15 +5472,17 @@
|
|||||||
const waitSeconds = normalizePhoneCodeWaitSeconds(state?.phoneCodeWaitSeconds);
|
const waitSeconds = normalizePhoneCodeWaitSeconds(state?.phoneCodeWaitSeconds);
|
||||||
const timeoutWindows = normalizePhoneCodeTimeoutWindows(state?.phoneCodeTimeoutWindows);
|
const timeoutWindows = normalizePhoneCodeTimeoutWindows(state?.phoneCodeTimeoutWindows);
|
||||||
const pollIntervalSeconds = normalizePhoneCodePollIntervalSeconds(state?.phoneCodePollIntervalSeconds);
|
const pollIntervalSeconds = normalizePhoneCodePollIntervalSeconds(state?.phoneCodePollIntervalSeconds);
|
||||||
const pollMaxRounds = normalizePhoneCodePollMaxRounds(state?.phoneCodePollMaxRounds);
|
const pollMaxRounds = resolvePhoneCodePollMaxRoundsForWindow(
|
||||||
let lastLoggedStatus = '';
|
waitSeconds,
|
||||||
let lastLoggedPollCount = 0;
|
pollIntervalSeconds,
|
||||||
|
state?.phoneCodePollMaxRounds
|
||||||
|
);
|
||||||
let resendTriggeredForCurrentNumber = false;
|
let resendTriggeredForCurrentNumber = false;
|
||||||
|
|
||||||
for (let windowIndex = 1; windowIndex <= timeoutWindows; windowIndex += 1) {
|
for (let windowIndex = 1; windowIndex <= timeoutWindows; windowIndex += 1) {
|
||||||
await setPhoneRuntimeCountdown(normalizedActivation, waitSeconds, windowIndex, timeoutWindows);
|
await setPhoneRuntimeCountdown(normalizedActivation, waitSeconds, windowIndex, timeoutWindows);
|
||||||
await addLog(
|
await addLog(
|
||||||
`步骤 9:等待号码 ${normalizedActivation.phoneNumber} 接收短信,最长 ${waitSeconds} 秒(第 ${windowIndex}/${timeoutWindows} 轮)。`,
|
`步骤 9:等待号码 ${normalizedActivation.phoneNumber} 接收短信(等待窗口 ${windowIndex}/${timeoutWindows},最长 ${waitSeconds} 秒,每 ${pollIntervalSeconds} 秒轮询一次,最多 ${pollMaxRounds} 次轮询)。`,
|
||||||
'info'
|
'info'
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
@@ -5502,16 +5515,6 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const shouldLog = (
|
|
||||||
pollCount === 1
|
|
||||||
|| statusText !== lastLoggedStatus
|
|
||||||
|| pollCount - lastLoggedPollCount >= 3
|
|
||||||
);
|
|
||||||
if (!shouldLog) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastLoggedStatus = statusText;
|
|
||||||
lastLoggedPollCount = pollCount;
|
|
||||||
await addLog(
|
await addLog(
|
||||||
`步骤 9:${getPhoneSmsProviderLabel(normalizedActivation.provider)} 号码 ${normalizedActivation.phoneNumber} 状态:${statusText}(已等待 ${Math.ceil(elapsedMs / 1000)} 秒,第 ${pollCount}/${pollMaxRounds} 次轮询)。`,
|
`步骤 9:${getPhoneSmsProviderLabel(normalizedActivation.provider)} 号码 ${normalizedActivation.phoneNumber} 状态:${statusText}(已等待 ${Math.ceil(elapsedMs / 1000)} 秒,第 ${pollCount}/${pollMaxRounds} 次轮询)。`,
|
||||||
'info'
|
'info'
|
||||||
@@ -5737,9 +5740,11 @@
|
|||||||
const waitSeconds = normalizePhoneCodeWaitSeconds(state?.phoneCodeWaitSeconds);
|
const waitSeconds = normalizePhoneCodeWaitSeconds(state?.phoneCodeWaitSeconds);
|
||||||
const timeoutWindows = normalizePhoneCodeTimeoutWindows(state?.phoneCodeTimeoutWindows);
|
const timeoutWindows = normalizePhoneCodeTimeoutWindows(state?.phoneCodeTimeoutWindows);
|
||||||
const pollIntervalSeconds = normalizePhoneCodePollIntervalSeconds(state?.phoneCodePollIntervalSeconds);
|
const pollIntervalSeconds = normalizePhoneCodePollIntervalSeconds(state?.phoneCodePollIntervalSeconds);
|
||||||
const pollMaxRounds = normalizePhoneCodePollMaxRounds(state?.phoneCodePollMaxRounds);
|
const pollMaxRounds = resolvePhoneCodePollMaxRoundsForWindow(
|
||||||
let lastLoggedStatus = '';
|
waitSeconds,
|
||||||
let lastLoggedPollCount = 0;
|
pollIntervalSeconds,
|
||||||
|
state?.phoneCodePollMaxRounds
|
||||||
|
);
|
||||||
|
|
||||||
for (let windowIndex = 1; windowIndex <= timeoutWindows; windowIndex += 1) {
|
for (let windowIndex = 1; windowIndex <= timeoutWindows; windowIndex += 1) {
|
||||||
await setPhoneRuntimeState({
|
await setPhoneRuntimeState({
|
||||||
@@ -5752,7 +5757,7 @@
|
|||||||
[PHONE_RUNTIME_COUNTDOWN_WINDOW_TOTAL_KEY]: timeoutWindows,
|
[PHONE_RUNTIME_COUNTDOWN_WINDOW_TOTAL_KEY]: timeoutWindows,
|
||||||
});
|
});
|
||||||
await addLog(
|
await addLog(
|
||||||
`步骤 ${visibleStep}:正在等待 ${normalizedActivation.phoneNumber} 的短信验证码(${windowIndex}/${timeoutWindows},最长 ${waitSeconds} 秒)。`,
|
`步骤 ${visibleStep}:正在等待 ${normalizedActivation.phoneNumber} 的短信验证码(等待窗口 ${windowIndex}/${timeoutWindows},最长 ${waitSeconds} 秒,每 ${pollIntervalSeconds} 秒轮询一次,最多 ${pollMaxRounds} 次轮询)。`,
|
||||||
'info',
|
'info',
|
||||||
{ step: visibleStep, stepKey }
|
{ step: visibleStep, stepKey }
|
||||||
);
|
);
|
||||||
@@ -5765,18 +5770,8 @@
|
|||||||
intervalMs: pollIntervalSeconds * 1000,
|
intervalMs: pollIntervalSeconds * 1000,
|
||||||
maxRounds: pollMaxRounds,
|
maxRounds: pollMaxRounds,
|
||||||
onStatus: async ({ elapsedMs, pollCount, statusText }) => {
|
onStatus: async ({ elapsedMs, pollCount, statusText }) => {
|
||||||
const shouldLog = (
|
|
||||||
pollCount === 1
|
|
||||||
|| statusText !== lastLoggedStatus
|
|
||||||
|| pollCount - lastLoggedPollCount >= 3
|
|
||||||
);
|
|
||||||
if (!shouldLog) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastLoggedStatus = statusText;
|
|
||||||
lastLoggedPollCount = pollCount;
|
|
||||||
await addLog(
|
await addLog(
|
||||||
`步骤 ${visibleStep}:${providerLabel} 状态 ${normalizedActivation.phoneNumber}: ${statusText}(已等待 ${Math.ceil(elapsedMs / 1000)} 秒,第 ${pollCount}/${pollMaxRounds} 轮)。`,
|
`步骤 ${visibleStep}:${providerLabel} 状态 ${normalizedActivation.phoneNumber}: ${statusText}(已等待 ${Math.ceil(elapsedMs / 1000)} 秒,第 ${pollCount}/${pollMaxRounds} 次轮询)。`,
|
||||||
'info',
|
'info',
|
||||||
{ step: visibleStep, stepKey }
|
{ step: visibleStep, stepKey }
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1549,7 +1549,7 @@
|
|||||||
<div id="row-phone-code-poll-max-rounds" class="hero-sms-settings-cell" style="display:none;">
|
<div id="row-phone-code-poll-max-rounds" class="hero-sms-settings-cell" style="display:none;">
|
||||||
<span class="hero-sms-settings-caption">轮询次数</span>
|
<span class="hero-sms-settings-caption">轮询次数</span>
|
||||||
<div class="setting-controls">
|
<div class="setting-controls">
|
||||||
<input type="number" id="input-phone-code-poll-max-rounds" class="data-input auto-delay-input" value="4" min="1" max="120" step="1" title="每轮验证码等待窗口最多轮询次数" />
|
<input type="number" id="input-phone-code-poll-max-rounds" class="data-input auto-delay-input" value="4" min="1" max="120" step="1" title="每个验证码等待窗口的基础轮询次数;如果低于等待时长和轮询间隔所需次数,会自动补足,避免提前结束" />
|
||||||
<span class="data-unit">次</span>
|
<span class="data-unit">次</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -715,7 +715,7 @@ test('signup phone helper does not let a hung page-state probe stall HeroSMS pol
|
|||||||
heroSmsReuseEnabled: false,
|
heroSmsReuseEnabled: false,
|
||||||
phoneCodeWaitSeconds: 15,
|
phoneCodeWaitSeconds: 15,
|
||||||
phoneCodeTimeoutWindows: 1,
|
phoneCodeTimeoutWindows: 1,
|
||||||
phoneCodePollIntervalSeconds: 1,
|
phoneCodePollIntervalSeconds: 15,
|
||||||
phoneCodePollMaxRounds: 1,
|
phoneCodePollMaxRounds: 1,
|
||||||
signupPhoneNumber: '66959916439',
|
signupPhoneNumber: '66959916439',
|
||||||
signupPhoneVerificationPurpose: 'signup',
|
signupPhoneVerificationPurpose: 'signup',
|
||||||
@@ -795,7 +795,7 @@ test('signup phone helper does not let a hung page-state probe stall HeroSMS pol
|
|||||||
caughtError = error;
|
caughtError = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.equal(smsPollCount, 1, 'HeroSMS polling should continue after the first waiting status');
|
assert.equal(smsPollCount, 1, 'HeroSMS polling should time out cleanly even when the page-state probe hangs');
|
||||||
assert.equal(pageReadyCalls, 2, 'should attempt the page-state probe during SMS polling');
|
assert.equal(pageReadyCalls, 2, 'should attempt the page-state probe during SMS polling');
|
||||||
assert.deepStrictEqual(contentMessages.map((message) => message.type), ['STEP8_GET_STATE']);
|
assert.deepStrictEqual(contentMessages.map((message) => message.type), ['STEP8_GET_STATE']);
|
||||||
assert.deepStrictEqual(statusActions, ['8']);
|
assert.deepStrictEqual(statusActions, ['8']);
|
||||||
@@ -3712,9 +3712,10 @@ test('phone verification helper replaces numbers in step 9 and stops after repla
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('phone verification helper honors timeout-window and poll-round settings before replacing numbers', async () => {
|
test('phone verification helper supplements poll rounds to cover the full wait window before replacing numbers', async () => {
|
||||||
const requests = [];
|
const requests = [];
|
||||||
const messages = [];
|
const messages = [];
|
||||||
|
const logs = [];
|
||||||
let currentState = {
|
let currentState = {
|
||||||
heroSmsApiKey: 'demo-key',
|
heroSmsApiKey: 'demo-key',
|
||||||
verificationResendCount: 0,
|
verificationResendCount: 0,
|
||||||
@@ -3728,7 +3729,9 @@ test('phone verification helper honors timeout-window and poll-round settings be
|
|||||||
};
|
};
|
||||||
|
|
||||||
const helpers = api.createPhoneVerificationHelpers({
|
const helpers = api.createPhoneVerificationHelpers({
|
||||||
addLog: async () => {},
|
addLog: async (message) => {
|
||||||
|
logs.push(String(message || ''));
|
||||||
|
},
|
||||||
ensureStep8SignupPageReady: async () => {},
|
ensureStep8SignupPageReady: async () => {},
|
||||||
fetchImpl: async (url) => {
|
fetchImpl: async (url) => {
|
||||||
const parsedUrl = new URL(url);
|
const parsedUrl = new URL(url);
|
||||||
@@ -3787,8 +3790,16 @@ test('phone verification helper honors timeout-window and poll-round settings be
|
|||||||
|
|
||||||
assert.equal(messages.includes('RESEND_PHONE_VERIFICATION_CODE'), false);
|
assert.equal(messages.includes('RESEND_PHONE_VERIFICATION_CODE'), false);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
requests.filter((requestUrl) => requestUrl.searchParams.get('action') === 'getStatus').length >= 2,
|
logs.some((message) => message.includes('等待窗口 1/1') && message.includes('最多 60 次轮询')),
|
||||||
'each replacement attempt should still poll HeroSMS at least once'
|
'wait log should show the effective poll count for the full window'
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
logs.some((message) => message.includes('第 2/60 次轮询')),
|
||||||
|
'status logs should include consecutive poll counts instead of skipping from 1 to the last poll'
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
requests.filter((requestUrl) => requestUrl.searchParams.get('action') === 'getStatus').length >= 60,
|
||||||
|
'each replacement attempt should poll long enough to cover the configured wait window'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -6203,9 +6214,9 @@ test('phone verification helper replaces number immediately when phone-verificat
|
|||||||
heroSmsCountryLabel: 'Thailand',
|
heroSmsCountryLabel: 'Thailand',
|
||||||
verificationResendCount: 0,
|
verificationResendCount: 0,
|
||||||
phoneVerificationReplacementLimit: 2,
|
phoneVerificationReplacementLimit: 2,
|
||||||
phoneCodeWaitSeconds: 60,
|
phoneCodeWaitSeconds: 15,
|
||||||
phoneCodeTimeoutWindows: 2,
|
phoneCodeTimeoutWindows: 2,
|
||||||
phoneCodePollIntervalSeconds: 1,
|
phoneCodePollIntervalSeconds: 15,
|
||||||
phoneCodePollMaxRounds: 1,
|
phoneCodePollMaxRounds: 1,
|
||||||
currentPhoneActivation: null,
|
currentPhoneActivation: null,
|
||||||
reusablePhoneActivation: null,
|
reusablePhoneActivation: null,
|
||||||
@@ -6309,9 +6320,9 @@ test('phone verification helper directly navigates back to add-phone when replac
|
|||||||
heroSmsCountryLabel: 'Thailand',
|
heroSmsCountryLabel: 'Thailand',
|
||||||
verificationResendCount: 0,
|
verificationResendCount: 0,
|
||||||
phoneVerificationReplacementLimit: 2,
|
phoneVerificationReplacementLimit: 2,
|
||||||
phoneCodeWaitSeconds: 60,
|
phoneCodeWaitSeconds: 15,
|
||||||
phoneCodeTimeoutWindows: 2,
|
phoneCodeTimeoutWindows: 2,
|
||||||
phoneCodePollIntervalSeconds: 1,
|
phoneCodePollIntervalSeconds: 15,
|
||||||
phoneCodePollMaxRounds: 1,
|
phoneCodePollMaxRounds: 1,
|
||||||
currentPhoneActivation: null,
|
currentPhoneActivation: null,
|
||||||
reusablePhoneActivation: null,
|
reusablePhoneActivation: null,
|
||||||
@@ -6474,9 +6485,9 @@ test('phone verification helper stops when add-phone recovery cannot be verified
|
|||||||
heroSmsCountryLabel: 'Thailand',
|
heroSmsCountryLabel: 'Thailand',
|
||||||
verificationResendCount: 0,
|
verificationResendCount: 0,
|
||||||
phoneVerificationReplacementLimit: 2,
|
phoneVerificationReplacementLimit: 2,
|
||||||
phoneCodeWaitSeconds: 60,
|
phoneCodeWaitSeconds: 15,
|
||||||
phoneCodeTimeoutWindows: 2,
|
phoneCodeTimeoutWindows: 2,
|
||||||
phoneCodePollIntervalSeconds: 1,
|
phoneCodePollIntervalSeconds: 15,
|
||||||
phoneCodePollMaxRounds: 1,
|
phoneCodePollMaxRounds: 1,
|
||||||
currentPhoneActivation: null,
|
currentPhoneActivation: null,
|
||||||
reusablePhoneActivation: null,
|
reusablePhoneActivation: null,
|
||||||
@@ -6597,9 +6608,9 @@ test('signup phone verification cancels activation when resend lands on contact-
|
|||||||
heroSmsCountryId: 52,
|
heroSmsCountryId: 52,
|
||||||
heroSmsCountryLabel: 'Thailand',
|
heroSmsCountryLabel: 'Thailand',
|
||||||
verificationResendCount: 0,
|
verificationResendCount: 0,
|
||||||
phoneCodeWaitSeconds: 60,
|
phoneCodeWaitSeconds: 15,
|
||||||
phoneCodeTimeoutWindows: 2,
|
phoneCodeTimeoutWindows: 2,
|
||||||
phoneCodePollIntervalSeconds: 1,
|
phoneCodePollIntervalSeconds: 15,
|
||||||
phoneCodePollMaxRounds: 1,
|
phoneCodePollMaxRounds: 1,
|
||||||
signupPhoneActivation: {
|
signupPhoneActivation: {
|
||||||
activationId: '920001',
|
activationId: '920001',
|
||||||
@@ -6662,9 +6673,9 @@ test('signup phone verification cancels activation when resend lands on contact-
|
|||||||
heroSmsCountryId: 52,
|
heroSmsCountryId: 52,
|
||||||
heroSmsCountryLabel: 'Thailand',
|
heroSmsCountryLabel: 'Thailand',
|
||||||
verificationResendCount: 0,
|
verificationResendCount: 0,
|
||||||
phoneCodeWaitSeconds: 60,
|
phoneCodeWaitSeconds: 15,
|
||||||
phoneCodeTimeoutWindows: 2,
|
phoneCodeTimeoutWindows: 2,
|
||||||
phoneCodePollIntervalSeconds: 1,
|
phoneCodePollIntervalSeconds: 15,
|
||||||
phoneCodePollMaxRounds: 1,
|
phoneCodePollMaxRounds: 1,
|
||||||
signupPhoneActivation: {
|
signupPhoneActivation: {
|
||||||
activationId: '930001',
|
activationId: '930001',
|
||||||
@@ -6746,9 +6757,9 @@ test('signup phone verification does not treat contact-verification URL-only sna
|
|||||||
heroSmsCountryId: 52,
|
heroSmsCountryId: 52,
|
||||||
heroSmsCountryLabel: 'Thailand',
|
heroSmsCountryLabel: 'Thailand',
|
||||||
verificationResendCount: 0,
|
verificationResendCount: 0,
|
||||||
phoneCodeWaitSeconds: 60,
|
phoneCodeWaitSeconds: 15,
|
||||||
phoneCodeTimeoutWindows: 2,
|
phoneCodeTimeoutWindows: 2,
|
||||||
phoneCodePollIntervalSeconds: 1,
|
phoneCodePollIntervalSeconds: 15,
|
||||||
phoneCodePollMaxRounds: 1,
|
phoneCodePollMaxRounds: 1,
|
||||||
signupPhoneActivation: {
|
signupPhoneActivation: {
|
||||||
activationId: '930002',
|
activationId: '930002',
|
||||||
@@ -6828,9 +6839,9 @@ test('signup phone verification fails when contact-verification 500 appears afte
|
|||||||
heroSmsCountryId: 52,
|
heroSmsCountryId: 52,
|
||||||
heroSmsCountryLabel: 'Thailand',
|
heroSmsCountryLabel: 'Thailand',
|
||||||
verificationResendCount: 0,
|
verificationResendCount: 0,
|
||||||
phoneCodeWaitSeconds: 60,
|
phoneCodeWaitSeconds: 15,
|
||||||
phoneCodeTimeoutWindows: 2,
|
phoneCodeTimeoutWindows: 2,
|
||||||
phoneCodePollIntervalSeconds: 1,
|
phoneCodePollIntervalSeconds: 15,
|
||||||
phoneCodePollMaxRounds: 1,
|
phoneCodePollMaxRounds: 1,
|
||||||
signupPhoneActivation: {
|
signupPhoneActivation: {
|
||||||
activationId: '930003',
|
activationId: '930003',
|
||||||
@@ -6922,9 +6933,9 @@ test('phone verification helper skips page resend for 5sim timeouts and rotates
|
|||||||
fiveSimProduct: 'openai',
|
fiveSimProduct: 'openai',
|
||||||
verificationResendCount: 0,
|
verificationResendCount: 0,
|
||||||
phoneVerificationReplacementLimit: 2,
|
phoneVerificationReplacementLimit: 2,
|
||||||
phoneCodeWaitSeconds: 60,
|
phoneCodeWaitSeconds: 15,
|
||||||
phoneCodeTimeoutWindows: 2,
|
phoneCodeTimeoutWindows: 2,
|
||||||
phoneCodePollIntervalSeconds: 1,
|
phoneCodePollIntervalSeconds: 15,
|
||||||
phoneCodePollMaxRounds: 1,
|
phoneCodePollMaxRounds: 1,
|
||||||
currentPhoneActivation: null,
|
currentPhoneActivation: null,
|
||||||
reusablePhoneActivation: null,
|
reusablePhoneActivation: null,
|
||||||
|
|||||||
Reference in New Issue
Block a user