feat: 添加步骤7重试机制,优化回退重跑步骤时自动失效后续状态
This commit is contained in:
+131
-2
@@ -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} 轮后仍未成功。`);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
|
||||
Reference in New Issue
Block a user