feat: 添加自动运行新尝试的状态重置逻辑,确保清除过期的运行状态
This commit is contained in:
+3
-1
@@ -3511,8 +3511,10 @@ async function autoRunLoop(totalRuns, options = {}) {
|
||||
inbucketMailbox: prevState.inbucketMailbox,
|
||||
cloudflareDomain: prevState.cloudflareDomain,
|
||||
cloudflareDomains: prevState.cloudflareDomains,
|
||||
// Fresh attempts must drop stale tab/url runtime state from the prior run.
|
||||
tabRegistry: {},
|
||||
sourceLastUrls: {},
|
||||
...getAutoRunStatusPayload('running', { currentRun: targetRun, totalRuns, attemptRun: attemptRuns }),
|
||||
...(forceFreshTabsNextRun ? { tabRegistry: {} } : {}),
|
||||
};
|
||||
await resetState();
|
||||
await setState(keepSettings);
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
|
||||
const source = fs.readFileSync('background.js', 'utf8');
|
||||
|
||||
function extractFunction(name) {
|
||||
const markers = [`async function ${name}(`, `function ${name}(`];
|
||||
const start = markers
|
||||
.map(marker => source.indexOf(marker))
|
||||
.find(index => index >= 0);
|
||||
if (start < 0) {
|
||||
throw new Error(`missing function ${name}`);
|
||||
}
|
||||
|
||||
let parenDepth = 0;
|
||||
let signatureEnded = false;
|
||||
let braceStart = -1;
|
||||
for (let i = start; i < source.length; i += 1) {
|
||||
const ch = source[i];
|
||||
if (ch === '(') {
|
||||
parenDepth += 1;
|
||||
} else if (ch === ')') {
|
||||
parenDepth -= 1;
|
||||
if (parenDepth === 0) {
|
||||
signatureEnded = true;
|
||||
}
|
||||
} else if (ch === '{' && signatureEnded) {
|
||||
braceStart = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (braceStart < 0) {
|
||||
throw new Error(`missing body for function ${name}`);
|
||||
}
|
||||
|
||||
let depth = 0;
|
||||
let end = braceStart;
|
||||
for (; end < source.length; end += 1) {
|
||||
const ch = source[end];
|
||||
if (ch === '{') depth += 1;
|
||||
if (ch === '}') {
|
||||
depth -= 1;
|
||||
if (depth === 0) {
|
||||
end += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return source.slice(start, end);
|
||||
}
|
||||
|
||||
const bundle = [
|
||||
extractFunction('clearStopRequest'),
|
||||
extractFunction('throwIfStopped'),
|
||||
extractFunction('isStopError'),
|
||||
extractFunction('isStepDoneStatus'),
|
||||
extractFunction('isRestartCurrentAttemptError'),
|
||||
extractFunction('getFirstUnfinishedStep'),
|
||||
extractFunction('hasSavedProgress'),
|
||||
extractFunction('getRunningSteps'),
|
||||
extractFunction('getAutoRunStatusPayload'),
|
||||
extractFunction('autoRunLoop'),
|
||||
].join('\n');
|
||||
|
||||
const api = new Function(`
|
||||
const STOP_ERROR_MESSAGE = 'Flow stopped.';
|
||||
const DEFAULT_STATE = {
|
||||
stepStatuses: {
|
||||
1: 'pending',
|
||||
2: 'pending',
|
||||
3: 'pending',
|
||||
4: 'pending',
|
||||
5: 'pending',
|
||||
6: 'pending',
|
||||
7: 'pending',
|
||||
8: 'pending',
|
||||
9: 'pending',
|
||||
},
|
||||
};
|
||||
|
||||
let stopRequested = false;
|
||||
let autoRunActive = false;
|
||||
let autoRunCurrentRun = 0;
|
||||
let autoRunTotalRuns = 1;
|
||||
let autoRunAttemptRun = 0;
|
||||
let runCalls = 0;
|
||||
|
||||
const logs = [];
|
||||
const broadcasts = [];
|
||||
let currentState = {
|
||||
...DEFAULT_STATE,
|
||||
stepStatuses: { ...DEFAULT_STATE.stepStatuses },
|
||||
vpsUrl: 'https://example.com/vps',
|
||||
vpsPassword: 'secret',
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: false,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
mailProvider: '163',
|
||||
emailGenerator: 'duck',
|
||||
emailPrefix: 'demo',
|
||||
inbucketHost: '',
|
||||
inbucketMailbox: '',
|
||||
cloudflareDomain: '',
|
||||
cloudflareDomains: [],
|
||||
tabRegistry: {},
|
||||
sourceLastUrls: {},
|
||||
};
|
||||
|
||||
async function getState() {
|
||||
return {
|
||||
...currentState,
|
||||
stepStatuses: { ...(currentState.stepStatuses || {}) },
|
||||
tabRegistry: { ...(currentState.tabRegistry || {}) },
|
||||
sourceLastUrls: { ...(currentState.sourceLastUrls || {}) },
|
||||
};
|
||||
}
|
||||
|
||||
async function setState(updates) {
|
||||
currentState = {
|
||||
...currentState,
|
||||
...updates,
|
||||
stepStatuses: updates.stepStatuses
|
||||
? { ...updates.stepStatuses }
|
||||
: currentState.stepStatuses,
|
||||
tabRegistry: updates.tabRegistry
|
||||
? { ...updates.tabRegistry }
|
||||
: currentState.tabRegistry,
|
||||
sourceLastUrls: updates.sourceLastUrls
|
||||
? { ...updates.sourceLastUrls }
|
||||
: currentState.sourceLastUrls,
|
||||
};
|
||||
}
|
||||
|
||||
async function resetState() {
|
||||
const prev = await getState();
|
||||
currentState = {
|
||||
...DEFAULT_STATE,
|
||||
stepStatuses: { ...DEFAULT_STATE.stepStatuses },
|
||||
vpsUrl: prev.vpsUrl,
|
||||
vpsPassword: prev.vpsPassword,
|
||||
customPassword: prev.customPassword,
|
||||
autoRunSkipFailures: prev.autoRunSkipFailures,
|
||||
autoRunFallbackThreadIntervalMinutes: prev.autoRunFallbackThreadIntervalMinutes,
|
||||
autoRunDelayEnabled: prev.autoRunDelayEnabled,
|
||||
autoRunDelayMinutes: prev.autoRunDelayMinutes,
|
||||
autoStepDelaySeconds: prev.autoStepDelaySeconds,
|
||||
mailProvider: prev.mailProvider,
|
||||
emailGenerator: prev.emailGenerator,
|
||||
emailPrefix: prev.emailPrefix,
|
||||
inbucketHost: prev.inbucketHost,
|
||||
inbucketMailbox: prev.inbucketMailbox,
|
||||
cloudflareDomain: prev.cloudflareDomain,
|
||||
cloudflareDomains: [...(prev.cloudflareDomains || [])],
|
||||
tabRegistry: { ...(prev.tabRegistry || {}) },
|
||||
sourceLastUrls: { ...(prev.sourceLastUrls || {}) },
|
||||
};
|
||||
}
|
||||
|
||||
async function addLog(message, level = 'info') {
|
||||
logs.push({ message, level });
|
||||
}
|
||||
|
||||
async function broadcastAutoRunStatus(phase, payload = {}) {
|
||||
broadcasts.push({ phase, ...payload });
|
||||
await setState({
|
||||
...getAutoRunStatusPayload(phase, payload),
|
||||
});
|
||||
}
|
||||
|
||||
async function sleepWithStop() {}
|
||||
async function waitForRunningStepsToFinish() {
|
||||
return getState();
|
||||
}
|
||||
async function broadcastStopToContentScripts() {}
|
||||
function cancelPendingCommands() {}
|
||||
function normalizeAutoRunFallbackThreadIntervalMinutes(value) {
|
||||
return Math.max(0, Math.floor(Number(value) || 0));
|
||||
}
|
||||
|
||||
const chrome = {
|
||||
runtime: {
|
||||
sendMessage() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async function runAutoSequenceFromStep() {
|
||||
runCalls += 1;
|
||||
const state = await getState();
|
||||
|
||||
if (
|
||||
runCalls === 2
|
||||
&& (Object.keys(state.tabRegistry || {}).length || Object.keys(state.sourceLastUrls || {}).length)
|
||||
) {
|
||||
throw new Error('fresh auto-run attempt reused stale runtime tab context');
|
||||
}
|
||||
|
||||
currentState = {
|
||||
...currentState,
|
||||
stepStatuses: {
|
||||
1: 'completed',
|
||||
2: 'completed',
|
||||
3: 'completed',
|
||||
4: 'completed',
|
||||
5: 'completed',
|
||||
6: 'completed',
|
||||
7: 'completed',
|
||||
8: 'completed',
|
||||
9: 'completed',
|
||||
},
|
||||
tabRegistry: {
|
||||
'signup-page': { tabId: 88, ready: true },
|
||||
},
|
||||
sourceLastUrls: {
|
||||
'signup-page': 'https://auth.openai.com/authorize',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
${bundle}
|
||||
|
||||
return {
|
||||
autoRunLoop,
|
||||
snapshot() {
|
||||
return {
|
||||
runCalls,
|
||||
autoRunActive,
|
||||
autoRunCurrentRun,
|
||||
autoRunTotalRuns,
|
||||
autoRunAttemptRun,
|
||||
currentState,
|
||||
logs,
|
||||
broadcasts,
|
||||
};
|
||||
},
|
||||
};
|
||||
`)();
|
||||
|
||||
(async () => {
|
||||
await api.autoRunLoop(2, { autoRunSkipFailures: false, mode: 'restart' });
|
||||
|
||||
const snapshot = api.snapshot();
|
||||
assert.strictEqual(snapshot.runCalls, 2, 'auto-run should enter the second fresh attempt');
|
||||
assert.strictEqual(snapshot.currentState.autoRunPhase, 'complete', 'both runs should complete after reset');
|
||||
assert.strictEqual(snapshot.currentState.autoRunCurrentRun, 2, 'final run index should be recorded');
|
||||
assert.strictEqual(snapshot.autoRunActive, false, 'auto-run should exit active state after completion');
|
||||
|
||||
console.log('auto-run fresh attempt reset tests passed');
|
||||
})().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user