feat: verify hotmail mailbox before auto-run attempts

This commit is contained in:
EmptyDust
2026-04-28 10:30:56 +08:00
parent 5c5296afec
commit 0ac0e65e6c
4 changed files with 641 additions and 10 deletions
+153 -10
View File
@@ -2121,30 +2121,78 @@ async function setCurrentHotmailAccount(accountId, options = {}) {
return account;
}
async function ensureHotmailAccountForFlow(options = {}) {
const { allowAllocate = true, markUsed = false, preferredAccountId = null } = options;
const state = await getState();
const accounts = normalizeHotmailAccounts(state.hotmailAccounts);
const isAccountAllocatable = (candidate) => Boolean(candidate)
function isAuthorizedHotmailRunAccount(candidate) {
return Boolean(candidate)
&& candidate.status === 'authorized'
&& !candidate.used
&& Boolean(candidate.refreshToken);
}
function isPendingHotmailVerificationCandidate(candidate) {
return Boolean(candidate)
&& candidate.status === 'pending'
&& !candidate.used
&& Boolean(candidate.refreshToken);
}
function compareHotmailAccountAllocationPriority(left, right) {
const leftUsedAt = Number(left?.lastUsedAt) || 0;
const rightUsedAt = Number(right?.lastUsedAt) || 0;
if (leftUsedAt !== rightUsedAt) {
return leftUsedAt - rightUsedAt;
}
return String(left?.email || '').localeCompare(String(right?.email || ''));
}
function pickPendingHotmailAccountForVerification(accounts, options = {}) {
const excludeIds = new Set((options.excludeIds || []).filter(Boolean));
const candidates = normalizeHotmailAccounts(accounts)
.filter((candidate) => isPendingHotmailVerificationCandidate(candidate) && !excludeIds.has(candidate.id));
if (!candidates.length) {
return null;
}
const preferredAccountId = String(options.preferredAccountId || '').trim();
if (preferredAccountId) {
const preferredCandidate = candidates.find((candidate) => candidate.id === preferredAccountId);
if (preferredCandidate) {
return preferredCandidate;
}
}
return candidates
.slice()
.sort(compareHotmailAccountAllocationPriority)[0] || null;
}
async function ensureHotmailAccountForFlow(options = {}) {
const {
allowAllocate = true,
markUsed = false,
preferredAccountId = null,
excludeIds = [],
} = options;
const state = await getState();
const accounts = normalizeHotmailAccounts(state.hotmailAccounts);
const excludedAccountIds = new Set((excludeIds || []).filter(Boolean));
const availableAccounts = accounts.filter((candidate) => isAuthorizedHotmailRunAccount(candidate) && !excludedAccountIds.has(candidate.id));
let account = null;
if (preferredAccountId) {
if (preferredAccountId && !excludedAccountIds.has(preferredAccountId)) {
account = findHotmailAccount(accounts, preferredAccountId);
}
if (!account && state.currentHotmailAccountId) {
if ((!account || !isAuthorizedHotmailRunAccount(account)) && state.currentHotmailAccountId && !excludedAccountIds.has(state.currentHotmailAccountId)) {
account = findHotmailAccount(accounts, state.currentHotmailAccountId);
}
if ((!account || !isAccountAllocatable(account)) && allowAllocate) {
account = pickHotmailAccountForRun(accounts, {});
if ((!account || !isAuthorizedHotmailRunAccount(account)) && allowAllocate) {
account = availableAccounts.length ? pickHotmailAccountForRun(availableAccounts, {}) : null;
}
if (!account) {
throw new Error('没有可用的 Hotmail 账号。请先在侧边栏添加至少一个带刷新令牌(refresh token)的账号。');
}
if (!isAccountAllocatable(account)) {
if (!isAuthorizedHotmailRunAccount(account)) {
throw new Error(`Hotmail 账号 ${account.email || account.id} 尚未就绪,无法读取邮件。`);
}
@@ -2482,6 +2530,100 @@ async function verifyHotmailAccount(accountId) {
};
}
async function ensureHotmailMailboxReadyForAutoRunRound(options = {}) {
const {
targetRun = 0,
totalRuns = 0,
attemptRun = 1,
} = options;
const state = await getState();
if (!isHotmailProvider(state)) {
return null;
}
const buildRoundLabel = () => {
if (targetRun > 0 && totalRuns > 0) {
return `${targetRun}/${totalRuns}`;
}
return '当前轮';
};
const exhaustedAccountIds = new Set();
let preferredAccountId = state.currentHotmailAccountId || null;
let lastError = null;
while (true) {
throwIfStopped();
const latestState = await getState();
const latestAccounts = normalizeHotmailAccounts(latestState.hotmailAccounts);
const remainingAuthorizedAccounts = latestAccounts
.filter((candidate) => isAuthorizedHotmailRunAccount(candidate) && !exhaustedAccountIds.has(candidate.id));
const remainingPendingAccounts = latestAccounts
.filter((candidate) => isPendingHotmailVerificationCandidate(candidate) && !exhaustedAccountIds.has(candidate.id));
if (!remainingAuthorizedAccounts.length && !remainingPendingAccounts.length) {
if (lastError) {
throw new Error(`自动运行${buildRoundLabel()}开始前未找到可通过校验的 Hotmail 账号:${lastError.message}`);
}
throw new Error('没有可用的 Hotmail 账号。请先在侧边栏添加至少一个带刷新令牌(refresh token)的账号。');
}
let account = null;
if (remainingAuthorizedAccounts.length) {
account = await ensureHotmailAccountForFlow({
allowAllocate: true,
markUsed: false,
preferredAccountId,
excludeIds: [...exhaustedAccountIds],
});
} else {
const pendingAccount = pickPendingHotmailAccountForVerification(latestAccounts, {
preferredAccountId,
excludeIds: [...exhaustedAccountIds],
});
if (!pendingAccount) {
throw new Error('没有可用的 Hotmail 账号。请先在侧边栏添加至少一个带刷新令牌(refresh token)的账号。');
}
account = await setCurrentHotmailAccount(pendingAccount.id, {
markUsed: false,
syncEmail: true,
});
await addLog(
`自动运行${buildRoundLabel()}开始前未找到已校验 Hotmail 账号,正在尝试校验待校验账号 ${account.email}`,
'warn'
);
}
try {
await addLog(
`自动运行${buildRoundLabel()}${attemptRun} 次尝试开始前,正在校验 Hotmail 账号 ${account.email} 的邮箱可用性。`,
'info'
);
const result = await verifyHotmailAccount(account.id);
await addLog(
`自动运行${buildRoundLabel()}开始前已校验 Hotmail 账号 ${result.account?.email || account.email}INBOX 当前 ${result.messageCount} 封邮件。`,
'ok'
);
return result.account;
} catch (error) {
lastError = error;
exhaustedAccountIds.add(account.id);
preferredAccountId = null;
const latestErrorMessage = error?.message || '未知错误';
await addLog(
`自动运行${buildRoundLabel()}开始前校验 Hotmail 账号 ${account.email} 失败:${latestErrorMessage}`,
'warn'
);
const nextState = await getState();
const hasRemainingAccounts = normalizeHotmailAccounts(nextState.hotmailAccounts)
.some((candidate) => (
isAuthorizedHotmailRunAccount(candidate) || isPendingHotmailVerificationCandidate(candidate)
) && !exhaustedAccountIds.has(candidate.id));
if (hasRemainingAccounts) {
await addLog(`自动运行${buildRoundLabel()}开始前将切换下一个 Hotmail 账号并重试。`, 'warn');
}
}
}
}
async function testHotmailAccountMailAccess(accountId) {
const state = await getState();
const account = findHotmailAccount(state.hotmailAccounts, accountId);
@@ -7638,6 +7780,7 @@ const autoRunController = self.MultiPageBackgroundAutoRunController?.createAutoR
cancelPendingCommands,
clearStopRequest: () => clearStopRequest(),
createAutoRunSessionId: () => createAutoRunSessionId(),
ensureHotmailMailboxReadyForAutoRunRound: (...args) => ensureHotmailMailboxReadyForAutoRunRound(...args),
getAutoRunStatusPayload,
getErrorMessage,
getFirstUnfinishedStep,