feat: 添加步骤7重试机制,优化回退重跑步骤时自动失效后续状态

This commit is contained in:
QLHazyCoder
2026-04-10 00:25:21 +08:00
parent 67add2c2e4
commit 2165a0537f
+131 -2
View File
@@ -7,6 +7,7 @@ const DUCK_AUTOFILL_URL = 'https://duckduckgo.com/email/settings/autofill';
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
const HUMAN_STEP_DELAY_MIN = 700;
const HUMAN_STEP_DELAY_MAX = 2200;
const STEP7_RESTART_MAX_ROUNDS = 5;
initializeSessionStorageAccess();
@@ -643,6 +644,15 @@ function isRetryableContentScriptTransportError(error) {
return /back\/forward cache|message channel is closed|Receiving end does not exist|port closed before a response was received|A listener indicated an asynchronous response/i.test(message);
}
function getErrorMessage(error) {
return String(typeof error === 'string' ? error : error?.message || '');
}
function isVerificationMailPollingError(error) {
const message = getErrorMessage(error);
return /未在 .*邮箱中找到新的匹配邮件|邮箱轮询结束,但未获取到验证码|无法获取新的(?:注册|登录)验证码|页面未能重新就绪|页面通信异常|did not respond in \d+s/i.test(message);
}
function isRestartCurrentAttemptError(error) {
const message = String(typeof error === 'string' ? error : error?.message || '');
return /当前邮箱已存在,需要重新开始新一轮/.test(message);
@@ -670,6 +680,80 @@ function hasSavedProgress(statuses = {}) {
return Object.values({ ...DEFAULT_STATE.stepStatuses, ...statuses }).some((status) => status !== 'pending');
}
function getDownstreamStateResets(step) {
if (step <= 1) {
return {
oauthUrl: null,
flowStartTime: null,
password: null,
lastEmailTimestamp: null,
lastSignupCode: null,
lastLoginCode: null,
localhostUrl: null,
};
}
if (step === 2) {
return {
password: null,
lastEmailTimestamp: null,
lastSignupCode: null,
lastLoginCode: null,
localhostUrl: null,
};
}
if (step === 3 || step === 4) {
return {
lastEmailTimestamp: null,
lastSignupCode: null,
lastLoginCode: null,
localhostUrl: null,
};
}
if (step === 5 || step === 6 || step === 7) {
return {
lastLoginCode: null,
localhostUrl: null,
};
}
if (step === 8) {
return {
localhostUrl: null,
};
}
return {};
}
async function invalidateDownstreamAfterStepRestart(step, options = {}) {
const { logLabel = `步骤 ${step} 重新执行` } = options;
const state = await getState();
const statuses = { ...(state.stepStatuses || {}) };
const changedSteps = [];
for (let downstream = step + 1; downstream <= 9; downstream++) {
if (statuses[downstream] !== 'pending') {
statuses[downstream] = 'pending';
changedSteps.push(downstream);
}
}
if (changedSteps.length) {
await setState({ stepStatuses: statuses });
for (const downstream of changedSteps) {
chrome.runtime.sendMessage({
type: 'STEP_STATUS_CHANGED',
payload: { step: downstream, status: 'pending' },
}).catch(() => {});
}
await addLog(`${logLabel},已重置后续步骤状态:${changedSteps.join(', ')}`, 'warn');
}
const resets = getDownstreamStateResets(step);
if (Object.keys(resets).length) {
await setState(resets);
broadcastDataUpdate(resets);
}
}
function clearStopRequest() {
stopRequested = false;
}
@@ -928,6 +1012,9 @@ async function handleMessage(message, sender) {
await ensureManualInteractionAllowed('手动执行步骤');
}
const step = message.payload.step;
if (message.source === 'sidepanel') {
await invalidateDownstreamAfterStepRestart(step, { logLabel: `步骤 ${step} 重新执行` });
}
// Save email if provided (from side panel step 3)
if (message.payload.email) {
await setEmailState(message.payload.email);
@@ -1340,6 +1427,9 @@ async function runAutoSequenceFromStep(startStep, context = {}) {
`步骤 9:检测到 OAuth callback 超时,正在回到步骤 6 重新开始授权流程(${step9RestartAttempts}/${maxStep9RestartAttempts}...`,
'warn'
);
await invalidateDownstreamAfterStepRestart(6, {
logLabel: `步骤 9 超时后准备回到步骤 6 重试(${step9RestartAttempts}/${maxStep9RestartAttempts}`,
});
step = 6;
continue;
}
@@ -2022,7 +2112,7 @@ async function executeStep6(state) {
// Step 7: Get Login Verification Code (qq-mail.js polls, then fills in chatgpt.js)
// ============================================================
async function executeStep7(state) {
async function runStep7Attempt(state) {
const mail = getMailConfig(state);
if (mail.error) throw new Error(mail.error);
const stepStartedAt = Date.now();
@@ -2073,7 +2163,46 @@ async function executeStep7(state) {
filterAfterTimestamp: stepStartedAt,
requestFreshCodeFirst: true,
});
return;
}
async function rerunStep6ForStep7Recovery() {
const currentState = await getState();
const waitForStep6 = waitForStepComplete(6, 120000);
await addLog('步骤 7:正在回到步骤 6,重新发起登录验证码流程...', 'warn');
await executeStep6(currentState);
await waitForStep6;
await sleepWithStop(3000);
}
async function executeStep7(state) {
let lastError = null;
for (let round = 1; round <= STEP7_RESTART_MAX_ROUNDS; round++) {
const currentState = round === 1 ? state : await getState();
try {
if (round > 1) {
await addLog(`步骤 7:正在进行第 ${round}/${STEP7_RESTART_MAX_ROUNDS} 轮登录验证码恢复尝试。`, 'warn');
}
await runStep7Attempt(currentState);
return;
} catch (err) {
lastError = err;
if (!isVerificationMailPollingError(err)) {
throw err;
}
if (round >= STEP7_RESTART_MAX_ROUNDS) {
break;
}
await addLog(`步骤 7:检测到邮箱轮询类失败,准备从步骤 6 重新开始(${round + 1}/${STEP7_RESTART_MAX_ROUNDS}...`, 'warn');
await rerunStep6ForStep7Recovery();
}
}
throw lastError || new Error(`步骤 7:登录验证码流程在 ${STEP7_RESTART_MAX_ROUNDS} 轮后仍未成功。`);
}
// ============================================================