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 STOP_ERROR_MESSAGE = '流程已被用户停止。';
|
||||||
const HUMAN_STEP_DELAY_MIN = 700;
|
const HUMAN_STEP_DELAY_MIN = 700;
|
||||||
const HUMAN_STEP_DELAY_MAX = 2200;
|
const HUMAN_STEP_DELAY_MAX = 2200;
|
||||||
|
const STEP7_RESTART_MAX_ROUNDS = 5;
|
||||||
|
|
||||||
initializeSessionStorageAccess();
|
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);
|
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) {
|
function isRestartCurrentAttemptError(error) {
|
||||||
const message = String(typeof error === 'string' ? error : error?.message || '');
|
const message = String(typeof error === 'string' ? error : error?.message || '');
|
||||||
return /当前邮箱已存在,需要重新开始新一轮/.test(message);
|
return /当前邮箱已存在,需要重新开始新一轮/.test(message);
|
||||||
@@ -670,6 +680,80 @@ function hasSavedProgress(statuses = {}) {
|
|||||||
return Object.values({ ...DEFAULT_STATE.stepStatuses, ...statuses }).some((status) => status !== 'pending');
|
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() {
|
function clearStopRequest() {
|
||||||
stopRequested = false;
|
stopRequested = false;
|
||||||
}
|
}
|
||||||
@@ -928,6 +1012,9 @@ async function handleMessage(message, sender) {
|
|||||||
await ensureManualInteractionAllowed('手动执行步骤');
|
await ensureManualInteractionAllowed('手动执行步骤');
|
||||||
}
|
}
|
||||||
const step = message.payload.step;
|
const step = message.payload.step;
|
||||||
|
if (message.source === 'sidepanel') {
|
||||||
|
await invalidateDownstreamAfterStepRestart(step, { logLabel: `步骤 ${step} 重新执行` });
|
||||||
|
}
|
||||||
// Save email if provided (from side panel step 3)
|
// Save email if provided (from side panel step 3)
|
||||||
if (message.payload.email) {
|
if (message.payload.email) {
|
||||||
await setEmailState(message.payload.email);
|
await setEmailState(message.payload.email);
|
||||||
@@ -1340,6 +1427,9 @@ async function runAutoSequenceFromStep(startStep, context = {}) {
|
|||||||
`步骤 9:检测到 OAuth callback 超时,正在回到步骤 6 重新开始授权流程(${step9RestartAttempts}/${maxStep9RestartAttempts})...`,
|
`步骤 9:检测到 OAuth callback 超时,正在回到步骤 6 重新开始授权流程(${step9RestartAttempts}/${maxStep9RestartAttempts})...`,
|
||||||
'warn'
|
'warn'
|
||||||
);
|
);
|
||||||
|
await invalidateDownstreamAfterStepRestart(6, {
|
||||||
|
logLabel: `步骤 9 超时后准备回到步骤 6 重试(${step9RestartAttempts}/${maxStep9RestartAttempts})`,
|
||||||
|
});
|
||||||
step = 6;
|
step = 6;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2022,7 +2112,7 @@ async function executeStep6(state) {
|
|||||||
// Step 7: Get Login Verification Code (qq-mail.js polls, then fills in chatgpt.js)
|
// 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);
|
const mail = getMailConfig(state);
|
||||||
if (mail.error) throw new Error(mail.error);
|
if (mail.error) throw new Error(mail.error);
|
||||||
const stepStartedAt = Date.now();
|
const stepStartedAt = Date.now();
|
||||||
@@ -2073,7 +2163,46 @@ async function executeStep7(state) {
|
|||||||
filterAfterTimestamp: stepStartedAt,
|
filterAfterTimestamp: stepStartedAt,
|
||||||
requestFreshCodeFirst: true,
|
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