From aa48b5e3bf6065ede0349c86deb98bbf84ba0298 Mon Sep 17 00:00:00 2001 From: QLHazyCoder <2825305047@qq.com> Date: Tue, 14 Apr 2026 01:25:39 +0800 Subject: [PATCH] fix(step9): align completion signal handling and extend CPA wait --- background.js | 108 ++++++++++++++++++++++++++++++++++--------- content/vps-panel.js | 3 +- 2 files changed, 87 insertions(+), 24 deletions(-) diff --git a/background.js b/background.js index ce56b82..0525267 100644 --- a/background.js +++ b/background.js @@ -2805,7 +2805,11 @@ async function handleMessage(message, sender) { await setPersistentSettings({ emailPrefix: message.payload.emailPrefix }); await setState({ emailPrefix: message.payload.emailPrefix }); } - await executeStep(step); + if (doesStepUseCompletionSignal(step)) { + await executeStepViaCompletionSignal(step); + } else { + await executeStep(step); + } return { ok: true }; } @@ -3083,6 +3087,7 @@ const stepWaiters = new Map(); let resumeWaiter = null; const AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS = 120000; const AUTO_RUN_BACKGROUND_COMPLETED_STEPS = new Set([4, 7, 8]); +const STEP_COMPLETION_SIGNAL_STEPS = new Set([1, 2, 3, 5, 6, 9]); function waitForStepComplete(step, timeoutMs = 120000) { return new Promise((resolve, reject) => { @@ -3104,6 +3109,10 @@ function waitForStepComplete(step, timeoutMs = 120000) { }); } +function doesStepUseCompletionSignal(step) { + return STEP_COMPLETION_SIGNAL_STEPS.has(step); +} + function notifyStepComplete(step, payload) { const waiter = stepWaiters.get(step); console.log(LOG_PREFIX, `[notifyStepComplete] step ${step}, hasWaiter=${Boolean(waiter)}`); @@ -3129,6 +3138,66 @@ async function completeStepFromBackground(step, payload = {}) { notifyStepComplete(step, payload); } +async function finalizeDeferredStepExecutionError(step, error) { + const latestState = await getState(); + const currentStatus = latestState.stepStatuses?.[step]; + if (currentStatus === 'completed' || currentStatus === 'failed' || currentStatus === 'stopped') { + return; + } + + if (isStopError(error)) { + await setStepStatus(step, 'stopped'); + await addLog(`步骤 ${step} 已被用户停止`, 'warn'); + return; + } + + await setStepStatus(step, 'failed'); + await addLog(`步骤 ${step} 失败:${getErrorMessage(error)}`, 'error'); +} + +async function executeStepViaCompletionSignal(step, timeoutMs = AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS) { + const completionResultPromise = waitForStepComplete(step, timeoutMs).then( + payload => ({ ok: true, payload }), + error => ({ ok: false, error }), + ); + + let executeError = null; + try { + await executeStep(step, { deferRetryableTransportError: true }); + } catch (err) { + executeError = err; + if (isStopError(err) || !isRetryableContentScriptTransportError(err)) { + notifyStepError(step, getErrorMessage(err)); + } + } + + const completionResult = await completionResultPromise; + if (completionResult.ok) { + if (executeError) { + console.warn( + LOG_PREFIX, + `[executeStepViaCompletionSignal] step ${step} completed after deferred execute error: ${getErrorMessage(executeError)}` + ); + } + return completionResult.payload; + } + + if (executeError && isRetryableContentScriptTransportError(executeError)) { + const completionMessage = getErrorMessage(completionResult.error); + if (/等待超时/.test(completionMessage)) { + await finalizeDeferredStepExecutionError(step, executeError); + throw executeError; + } + throw completionResult.error; + } + + if (executeError) { + throw executeError; + } + + throw completionResult.error; +} + async function waitForRunningStepsToFinish(payload = {}) { let currentState = await getState(); let runningSteps = getRunningSteps(currentState.stepStatuses); @@ -3204,7 +3273,8 @@ async function requestStop(options = {}) { // Step Execution // ============================================================ -async function executeStep(step) { +async function executeStep(step, options = {}) { + const { deferRetryableTransportError = false } = options; console.log(LOG_PREFIX, `Executing step ${step}`); throwIfStopped(); await setStepStatus(step, 'running'); @@ -3238,8 +3308,15 @@ async function executeStep(step) { await addLog(`步骤 ${step} 已被用户停止`, 'warn'); throw err; } - await setStepStatus(step, 'failed'); - await addLog(`步骤 ${step} 失败:${err.message}`, 'error'); + if (!(deferRetryableTransportError && doesStepUseCompletionSignal(step) && isRetryableContentScriptTransportError(err))) { + await setStepStatus(step, 'failed'); + await addLog(`步骤 ${step} 失败:${err.message}`, 'error'); + } else { + console.warn( + LOG_PREFIX, + `[executeStep] deferring retryable transport error for step ${step}: ${getErrorMessage(err)}` + ); + } throw err; } } @@ -3266,27 +3343,12 @@ async function executeStepAndWait(step, delayAfter = 2000) { await executeStep(step); const latestState = await getState(); await addLog(`自动运行:步骤 ${step} 已执行返回,当前状态为 ${latestState.stepStatuses?.[step] || 'pending'},准备继续后续步骤。`, 'info'); - } else { + } else if (doesStepUseCompletionSignal(step)) { await addLog(`自动运行:步骤 ${step} 已发起,正在等待完成信号(超时 ${AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS / 1000} 秒)。`, 'info'); - const completionResultPromise = waitForStepComplete(step, AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS).then( - payload => ({ ok: true, payload }), - error => ({ ok: false, error }), - ); - - try { - await executeStep(step); - } catch (err) { - notifyStepError(step, getErrorMessage(err)); - await completionResultPromise; - throw err; - } - - const completionResult = await completionResultPromise; - if (!completionResult.ok) { - throw completionResult.error; - } - + await executeStepViaCompletionSignal(step, AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS); await addLog(`自动运行:步骤 ${step} 已收到完成信号,准备继续后续步骤。`, 'info'); + } else { + await executeStep(step); } // Extra delay for page transitions / DOM updates diff --git a/content/vps-panel.js b/content/vps-panel.js index 187499b..184b195 100644 --- a/content/vps-panel.js +++ b/content/vps-panel.js @@ -26,6 +26,7 @@ console.log('[MultiPage:vps-panel] Content script loaded on', location.href); const VPS_PANEL_LISTENER_SENTINEL = 'data-multipage-vps-panel-listener'; +const STEP9_SUCCESS_BADGE_TIMEOUT_MS = 120000; const { isRecoverableStep9AuthFailure, } = self.MultiPageActivationUtils || {}; @@ -205,7 +206,7 @@ function isOAuthCallbackTimeoutFailure(statusText) { return /认证失败:\s*Timeout waiting for OAuth callback/i.test(statusText || ''); } -async function waitForExactSuccessBadge(timeout = 30000) { +async function waitForExactSuccessBadge(timeout = STEP9_SUCCESS_BADGE_TIMEOUT_MS) { const start = Date.now(); while (Date.now() - start < timeout) {