优化步骤在日志中的显示

This commit is contained in:
QLHazyCoder
2026-05-03 19:25:55 +08:00
parent 4410fea3d1
commit 691ac39514
25 changed files with 691 additions and 297 deletions
+23 -12
View File
@@ -47,6 +47,10 @@
return visibleStep >= 12 ? 10 : 7;
}
function addStepLog(step, message, level = 'info') {
return addLog(message, level, { step, stepKey: 'confirm-oauth' });
}
async function executeStep9(state) {
const visibleStep = getVisibleStep(state, 9);
let activeState = state;
@@ -56,7 +60,7 @@
throw new Error(`缺少登录用 OAuth 链接,请先完成步骤 ${authLoginStep}`);
}
await addLog(`步骤 ${visibleStep}正在监听 localhost 回调地址...`);
await addStepLog(visibleStep, '正在监听 localhost 回调地址...');
let callbackTimeoutMs = LOCALHOST_CALLBACK_LOCAL_TIMEOUT_MS;
let timeoutRecoveryAttempted = false;
@@ -115,7 +119,7 @@
resolved = true;
cleanupListener();
addLog(`步骤 ${visibleStep}已捕获 localhost 地址:${callbackUrl}`, 'ok').then(() => {
addStepLog(visibleStep, `已捕获 localhost 地址:${callbackUrl}`, 'ok').then(() => {
return completeStepFromBackground(visibleStep, { localhostUrl: callbackUrl });
}).then(() => {
resolve();
@@ -185,10 +189,10 @@
if (signupTabId && await isTabAlive('signup-page')) {
await chrome.tabs.update(signupTabId, { active: true });
await addLog(`步骤 ${visibleStep}已切回认证页,正在准备调试器点击...`);
await addStepLog(visibleStep, '已切回认证页,正在准备调试器点击...');
} else {
signupTabId = await reuseOrCreateTab('signup-page', activeState.oauthUrl);
await addLog(`步骤 ${visibleStep}已重新打开认证页,正在准备调试器点击...`);
await addStepLog(visibleStep, '已重新打开认证页,正在准备调试器点击...');
}
throwIfStep8SettledOrStopped(resolved);
@@ -202,7 +206,9 @@
actionLabel: '等待 OAuth 同意页内容脚本就绪',
})
: 15000,
logMessage: `步骤 ${visibleStep}:认证页内容脚本尚未就绪,正在等待页面恢复...`,
visibleStep,
logStepKey: 'confirm-oauth',
logMessage: '认证页内容脚本尚未就绪,正在等待页面恢复...',
});
for (let round = 1; round <= STEP8_MAX_ROUNDS && !resolved; round++) {
@@ -214,7 +220,8 @@
step: visibleStep,
actionLabel: '等待 OAuth 同意页出现',
})
: STEP8_READY_WAIT_TIMEOUT_MS
: STEP8_READY_WAIT_TIMEOUT_MS,
{ visibleStep }
);
if (!pageState?.consentReady) {
await sleepWithStop(STEP8_CLICK_RETRY_DELAY_MS);
@@ -223,7 +230,7 @@
const strategy = STEP8_STRATEGIES[Math.min(round - 1, STEP8_STRATEGIES.length - 1)];
await addLog(`步骤 ${visibleStep}${round}/${STEP8_MAX_ROUNDS} 轮尝试点击“继续”(${strategy.label}...`);
await addStepLog(visibleStep, `${round}/${STEP8_MAX_ROUNDS} 轮尝试点击“继续”(${strategy.label}...`);
if (strategy.mode === 'debugger') {
const clickActionTimeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
@@ -235,9 +242,10 @@
const clickTarget = await prepareStep8DebuggerClick(signupTabId, {
timeoutMs: clickActionTimeoutMs,
responseTimeoutMs: clickActionTimeoutMs,
visibleStep,
});
throwIfStep8SettledOrStopped(resolved);
await clickWithDebugger(signupTabId, clickTarget?.rect);
await clickWithDebugger(signupTabId, clickTarget?.rect, { visibleStep });
} else {
const clickActionTimeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
? await getOAuthFlowStepTimeoutMs(15000, {
@@ -248,6 +256,7 @@
await triggerStep8ContentStrategy(signupTabId, strategy.strategy, {
timeoutMs: clickActionTimeoutMs,
responseTimeoutMs: clickActionTimeoutMs,
visibleStep,
});
}
@@ -263,14 +272,15 @@
step: visibleStep,
actionLabel: '等待 OAuth 同意页点击生效',
})
: 15000
: 15000,
{ visibleStep }
);
if (resolved) {
return;
}
if (effect.progressed) {
await addLog(`步骤 ${visibleStep}检测到本次点击已生效,${getStep8EffectLabel(effect)},继续等待 localhost 回调...`, 'info');
await addStepLog(visibleStep, `检测到本次点击已生效,${getStep8EffectLabel(effect)},继续等待 localhost 回调...`, 'info');
break;
}
@@ -278,7 +288,7 @@
throw new Error(`步骤 ${visibleStep}:连续 ${STEP8_MAX_ROUNDS} 轮点击“继续”后页面仍无反应。`);
}
await addLog(`步骤 ${visibleStep}${strategy.label} 本轮点击后页面无反应,正在刷新认证页后重试(下一轮 ${round + 1}/${STEP8_MAX_ROUNDS}...`, 'warn');
await addStepLog(visibleStep, `${strategy.label} 本轮点击后页面无反应,正在刷新认证页后重试(下一轮 ${round + 1}/${STEP8_MAX_ROUNDS}...`, 'warn');
await reloadStep8ConsentPage(
signupTabId,
typeof getOAuthFlowStepTimeoutMs === 'function'
@@ -286,7 +296,8 @@
step: visibleStep,
actionLabel: '刷新 OAuth 同意页',
})
: 30000
: 30000,
{ visibleStep }
);
await sleepWithStop(STEP8_CLICK_RETRY_DELAY_MS);
}
+36 -4
View File
@@ -5,7 +5,7 @@
function createStep8Executor(deps = {}) {
const {
addLog,
addLog: rawAddLog = async () => {},
chrome,
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
completeStepFromBackground,
@@ -32,6 +32,33 @@
STEP7_MAIL_POLLING_RECOVERY_MAX_ATTEMPTS,
throwIfStopped,
} = deps;
let activeFetchLoginCodeStep = null;
function normalizeLogStep(value) {
const step = Math.floor(Number(value) || 0);
return step > 0 ? step : null;
}
function normalizeStepLogMessage(message) {
return String(message || '')
.replace(/^步骤\s*\d+\s*[:]\s*/, '')
.replace(/^Step\s+\d+\s*[:]\s*/i, '')
.trim();
}
function addLog(message, level = 'info', options = {}) {
const normalizedOptions = options && typeof options === 'object' ? { ...options } : {};
const step = normalizeLogStep(normalizedOptions.step || normalizedOptions.visibleStep)
|| normalizeLogStep(activeFetchLoginCodeStep);
if (step) {
normalizedOptions.step = step;
if (!normalizedOptions.stepKey) {
normalizedOptions.stepKey = 'fetch-login-code';
}
}
delete normalizedOptions.visibleStep;
return rawAddLog(normalizeStepLogMessage(message), level, normalizedOptions);
}
function getVisibleStep(state, fallback = 8) {
const visibleStep = Math.floor(Number(state?.visibleStep) || 0);
@@ -181,6 +208,7 @@
async function runStep8Attempt(state, runtime = {}) {
const visibleStep = getVisibleStep(state, 8);
activeFetchLoginCodeStep = visibleStep;
const mail = getMailConfig(state);
if (mail.error) throw new Error(mail.error);
const stateLastResendAt = Number(state?.loginVerificationRequestedAt) || 0;
@@ -371,7 +399,9 @@
'warn'
);
await rerunStep7ForStep8Recovery({
logMessage: `步骤 ${visibleStep}邮箱通信异常持续未恢复,正在回到步骤 ${authLoginStep} 重新发起登录流程...`,
logMessage: `邮箱通信异常持续未恢复,正在回到步骤 ${authLoginStep} 重新发起登录流程...`,
logStep: visibleStep,
logStepKey: 'fetch-login-code',
});
currentState = await getState();
retryWithoutStep7Streak = 0;
@@ -415,8 +445,10 @@
);
await rerunStep7ForStep8Recovery({
logMessage: isStep8RestartStep7Error(currentError)
? `步骤 ${visibleStep}认证页进入重试/超时报错状态,正在回到步骤 ${authLoginStep} 重新发起登录流程...`
: `步骤 ${visibleStep}正在回到步骤 ${authLoginStep},重新发起登录验证码流程...`,
? `认证页进入重试/超时报错状态,正在回到步骤 ${authLoginStep} 重新发起登录流程...`
: `正在回到步骤 ${authLoginStep},重新发起登录验证码流程...`,
logStep: visibleStep,
logStepKey: 'fetch-login-code',
});
currentState = await getState();
}
+24 -11
View File
@@ -59,20 +59,26 @@
const password = currentState.password || currentState.customPassword || '';
const oauthUrl = await refreshOAuthUrlBeforeStep6(currentState);
if (typeof startOAuthFlowTimeoutWindow === 'function') {
await startOAuthFlowTimeoutWindow({ step: 7, oauthUrl });
await startOAuthFlowTimeoutWindow({ step: completionStep, oauthUrl });
}
const loginTimeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
? await getOAuthFlowStepTimeoutMs(180000, {
step: 7,
step: completionStep,
actionLabel: 'OAuth 登录并进入验证码页',
oauthUrl,
})
: 180000;
if (attempt === 1) {
await addLog('步骤 7正在打开最新 OAuth 链接并登录...');
await addLog('正在打开最新 OAuth 链接并登录...', 'info', {
step: completionStep,
stepKey: 'oauth-login',
});
} else {
await addLog(`步骤 7上一轮失败后,正在进行第 ${attempt} 次尝试(最多 ${STEP6_MAX_ATTEMPTS} 次)...`, 'warn');
await addLog(`上一轮失败后,正在进行第 ${attempt} 次尝试(最多 ${STEP6_MAX_ATTEMPTS} 次)...`, 'warn', {
step: completionStep,
stepKey: 'oauth-login',
});
}
await reuseOrCreateTab('signup-page', oauthUrl);
@@ -86,13 +92,16 @@
payload: {
email: currentState.email,
password,
visibleStep: completionStep,
},
},
{
timeoutMs: loginTimeoutMs,
responseTimeoutMs: loginTimeoutMs,
retryDelayMs: 700,
logMessage: '步骤 7认证页正在切换,等待页面重新就绪后继续登录...',
logMessage: '认证页正在切换,等待页面重新就绪后继续登录...',
logStep: completionStep,
logStepKey: 'oauth-login',
}
);
@@ -117,11 +126,11 @@
if (isStep6RecoverableResult(result)) {
const reasonMessage = result.message
|| `当前停留在${getLoginAuthStateLabel(result.state)},准备重新执行步骤 7`;
|| `当前停留在${getLoginAuthStateLabel(result.state)},准备重新执行步骤 ${completionStep}`;
throw new Error(reasonMessage);
}
throw new Error('步骤 7:认证页未返回可识别的登录结果。');
throw new Error(`步骤 ${completionStep}:认证页未返回可识别的登录结果。`);
} catch (err) {
throwIfStopped(err);
if (isAddPhoneAuthFailure(err)) {
@@ -129,8 +138,9 @@
}
if (isManagementSecretConfigError(err)) {
await addLog(
`步骤 7检测到来源后台管理密钥缺失或错误,不再重试,当前流程停止。原因:${getErrorMessage(err)}`,
'error'
`检测到来源后台管理密钥缺失或错误,不再重试,当前流程停止。原因:${getErrorMessage(err)}`,
'error',
{ step: completionStep, stepKey: 'oauth-login' }
);
throw err;
}
@@ -139,11 +149,14 @@
break;
}
await addLog(`步骤 7${attempt} 次尝试失败,原因:${getErrorMessage(err)};准备重试...`, 'warn');
await addLog(`${attempt} 次尝试失败,原因:${getErrorMessage(err)};准备重试...`, 'warn', {
step: completionStep,
stepKey: 'oauth-login',
});
}
}
throw new Error(`步骤 7:判断失败后已重试 ${STEP6_MAX_ATTEMPTS - 1} 次,仍未成功。最后原因:${getErrorMessage(lastError)}`);
throw new Error(`步骤 ${completionStep}:判断失败后已重试 ${STEP6_MAX_ATTEMPTS - 1} 次,仍未成功。最后原因:${getErrorMessage(lastError)}`);
}
return { executeStep7 };
+45 -25
View File
@@ -31,18 +31,31 @@
return visibleStep >= 10 ? visibleStep : 10;
}
function parseLocalhostCallback(rawUrl) {
function resolveConfirmOauthStep(platformVerifyStep = 10) {
return Number(platformVerifyStep) >= 13 ? 12 : 9;
}
function resolveAuthLoginStep(platformVerifyStep = 10) {
return Number(platformVerifyStep) >= 13 ? 10 : 7;
}
function addStepLog(step, message, level = 'info') {
return addLog(message, level, { step, stepKey: 'platform-verify' });
}
function parseLocalhostCallback(rawUrl, platformVerifyStep = 10) {
const confirmOauthStep = resolveConfirmOauthStep(platformVerifyStep);
let parsed;
try {
parsed = new URL(rawUrl);
} catch {
throw new Error('步骤 10 捕获到的 localhost OAuth 回调地址格式无效,请重新执行步骤 9。');
throw new Error(`步骤 ${platformVerifyStep} 捕获到的 localhost OAuth 回调地址格式无效,请重新执行步骤 ${confirmOauthStep}`);
}
const code = normalizeString(parsed.searchParams.get('code'));
const state = normalizeString(parsed.searchParams.get('state'));
if (!code || !state) {
throw new Error('步骤 10 捕获到的 localhost OAuth 回调地址缺少 code 或 state,请重新执行步骤 9。');
throw new Error(`步骤 ${platformVerifyStep} 捕获到的 localhost OAuth 回调地址缺少 code 或 state,请重新执行步骤 ${confirmOauthStep}`);
}
return {
@@ -206,18 +219,20 @@
async function executeCpaStep10(state) {
const platformVerifyStep = resolvePlatformVerifyStep(state);
const confirmOauthStep = resolveConfirmOauthStep(platformVerifyStep);
const authLoginStep = resolveAuthLoginStep(platformVerifyStep);
if (state.localhostUrl && !isLocalhostOAuthCallbackUrl(state.localhostUrl)) {
throw new Error('步骤 9 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 9。');
throw new Error(`步骤 ${confirmOauthStep} 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 ${confirmOauthStep}`);
}
if (!state.localhostUrl) {
throw new Error('缺少 localhost 回调地址,请先完成步骤 9。');
throw new Error(`缺少 localhost 回调地址,请先完成步骤 ${confirmOauthStep}`);
}
if (!state.vpsUrl) {
throw new Error('尚未填写 CPA 地址,请先在侧边栏输入。');
}
if (shouldBypassStep9ForLocalCpa(state)) {
await addLog('步骤 10检测到本地 CPA,且当前策略为“跳过第10步”,本轮不再重复提交回调地址。', 'info');
await addStepLog(platformVerifyStep, '检测到本地 CPA,且当前策略为“跳过平台回调验证”,本轮不再重复提交回调地址。', 'info');
await completeStepFromBackground(platformVerifyStep, {
localhostUrl: state.localhostUrl,
verifiedStatus: 'local-auto',
@@ -225,17 +240,17 @@
return;
}
const callback = parseLocalhostCallback(state.localhostUrl);
const callback = parseLocalhostCallback(state.localhostUrl, platformVerifyStep);
const expectedState = normalizeString(state.cpaOAuthState);
if (expectedState && expectedState !== callback.state) {
throw new Error('CPA 回调 state 与当前授权会话不匹配,请重新执行步骤 7。');
throw new Error(`CPA 回调 state 与当前授权会话不匹配,请重新执行步骤 ${authLoginStep}`);
}
const managementKey = normalizeString(state.vpsPassword);
if (!managementKey) {
throw new Error('尚未配置 CPA 管理密钥,请先在侧边栏填写。');
}
await addLog('步骤 10正在通过 CPA 管理接口提交回调地址...');
await addStepLog(platformVerifyStep, '正在通过 CPA 管理接口提交回调地址...');
try {
const origin = normalizeString(state.cpaManagementOrigin) || deriveCpaManagementOrigin(state.vpsUrl);
const result = await fetchCpaManagementJson(origin, '/v0/management/oauth-callback', {
@@ -250,43 +265,45 @@
const verifiedStatus = normalizeString(result?.message)
|| normalizeString(result?.status_message)
|| 'CPA 已通过接口提交回调';
await addLog(`步骤 10${verifiedStatus}`, 'ok');
await addStepLog(platformVerifyStep, verifiedStatus, 'ok');
await completeStepFromBackground(platformVerifyStep, {
localhostUrl: callback.url,
verifiedStatus,
});
} catch (error) {
const reason = normalizeString(error?.message) || 'unknown error';
await addLog(`步骤 10CPA 接口提交失败:${reason}`, 'error');
await addStepLog(platformVerifyStep, `CPA 接口提交失败:${reason}`, 'error');
throw error;
}
}
async function executeCodex2ApiStep10(state) {
const platformVerifyStep = resolvePlatformVerifyStep(state);
const confirmOauthStep = resolveConfirmOauthStep(platformVerifyStep);
const authLoginStep = resolveAuthLoginStep(platformVerifyStep);
if (state.localhostUrl && !isLocalhostOAuthCallbackUrl(state.localhostUrl)) {
throw new Error('步骤 9 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 9。');
throw new Error(`步骤 ${confirmOauthStep} 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 ${confirmOauthStep}`);
}
if (!state.localhostUrl) {
throw new Error('缺少 localhost 回调地址,请先完成步骤 9。');
throw new Error(`缺少 localhost 回调地址,请先完成步骤 ${confirmOauthStep}`);
}
if (!state.codex2apiSessionId) {
throw new Error('缺少 Codex2API 会话信息,请重新执行步骤 7。');
throw new Error(`缺少 Codex2API 会话信息,请重新执行步骤 ${authLoginStep}`);
}
if (!normalizeString(state.codex2apiAdminKey)) {
throw new Error('尚未配置 Codex2API 管理密钥,请先在侧边栏填写。');
}
const callback = parseLocalhostCallback(state.localhostUrl);
const callback = parseLocalhostCallback(state.localhostUrl, platformVerifyStep);
const expectedState = normalizeString(state.codex2apiOAuthState);
if (expectedState && expectedState !== callback.state) {
throw new Error('Codex2API 回调 state 与当前授权会话不匹配,请重新执行步骤 7。');
throw new Error(`Codex2API 回调 state 与当前授权会话不匹配,请重新执行步骤 ${authLoginStep}`);
}
const codex2apiUrl = normalizeCodex2ApiUrl(state.codex2apiUrl);
const origin = new URL(codex2apiUrl).origin;
await addLog('步骤 10正在向 Codex2API 提交回调并创建账号...');
await addStepLog(platformVerifyStep, '正在向 Codex2API 提交回调并创建账号...');
const result = await fetchCodex2ApiJson(origin, '/api/admin/oauth/exchange-code', {
adminKey: state.codex2apiAdminKey,
method: 'POST',
@@ -298,7 +315,7 @@
});
const verifiedStatus = normalizeString(result?.message) || 'Codex2API OAuth 账号添加成功';
await addLog(`步骤 10${verifiedStatus}`, 'ok');
await addStepLog(platformVerifyStep, verifiedStatus, 'ok');
await completeStepFromBackground(platformVerifyStep, {
localhostUrl: callback.url,
verifiedStatus,
@@ -307,11 +324,12 @@
async function executeSub2ApiStep10(state) {
const visibleStep = resolvePlatformVerifyStep(state);
const confirmOauthStep = resolveConfirmOauthStep(visibleStep);
if (state.localhostUrl && !isLocalhostOAuthCallbackUrl(state.localhostUrl)) {
throw new Error('步骤 9 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 9。');
throw new Error(`步骤 ${confirmOauthStep} 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 ${confirmOauthStep}`);
}
if (!state.localhostUrl) {
throw new Error('缺少 localhost 回调地址,请先完成步骤 9。');
throw new Error(`缺少 localhost 回调地址,请先完成步骤 ${confirmOauthStep}`);
}
if (!state.sub2apiSessionId) {
throw new Error('缺少 SUB2API 会话信息,请重新执行步骤 1。');
@@ -326,7 +344,7 @@
const sub2apiUrl = normalizeSub2ApiUrl(state.sub2apiUrl);
const injectFiles = ['content/utils.js', 'content/sub2api-panel.js'];
await addLog('步骤 10正在打开 SUB2API 后台...');
await addStepLog(visibleStep, '正在打开 SUB2API 后台...');
let tabId = await getTabId('sub2api-panel');
const alive = tabId && await isTabAlive('sub2api-panel');
@@ -348,13 +366,14 @@
injectSource: 'sub2api-panel',
});
await addLog(`步骤 ${visibleStep}正在向 SUB2API 提交回调并创建账号...`);
await addStepLog(visibleStep, '正在向 SUB2API 提交回调并创建账号...');
const requestMessage = {
type: 'EXECUTE_STEP',
step: 10,
step: visibleStep,
source: 'background',
payload: {
localhostUrl: state.localhostUrl,
visibleStep,
sub2apiUrl,
sub2apiEmail: state.sub2apiEmail,
sub2apiPassword: state.sub2apiPassword,
@@ -384,8 +403,9 @@
throw error;
}
await addLog(
`步骤 ${visibleStep}SUB2API 回调交换出现临时网络波动(${error.message}),正在重试 ${attempt + 1}/${maxExchangeAttempts}...`,
'warn'
`SUB2API 回调交换出现临时网络波动(${error.message}),正在重试 ${attempt + 1}/${maxExchangeAttempts}...`,
'warn',
{ step: visibleStep, stepKey: 'platform-verify' }
);
await sleep(1200 * attempt);
}