feat: 增强内容脚本的加载机制,添加超时与重试逻辑,优化消息监听器的初始化
This commit is contained in:
+90
-42
@@ -344,39 +344,90 @@ async function pingContentScriptOnTab(tabId) {
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForTabUrlFamily(source, tabId, referenceUrl, options = {}) {
|
||||
const { timeoutMs = 15000, retryDelayMs = 400 } = options;
|
||||
const start = Date.now();
|
||||
|
||||
while (Date.now() - start < timeoutMs) {
|
||||
try {
|
||||
const tab = await chrome.tabs.get(tabId);
|
||||
if (matchesSourceUrlFamily(source, tab.url, referenceUrl)) {
|
||||
return tab;
|
||||
}
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async function ensureContentScriptReadyOnTab(source, tabId, options = {}) {
|
||||
const { inject = null, injectSource = null } = options;
|
||||
const pong = await pingContentScriptOnTab(tabId);
|
||||
const {
|
||||
inject = null,
|
||||
injectSource = null,
|
||||
timeoutMs = 30000,
|
||||
retryDelayMs = 700,
|
||||
logMessage = '',
|
||||
} = options;
|
||||
|
||||
if (pong?.ok && (!pong.source || pong.source === source)) {
|
||||
await registerTab(source, tabId);
|
||||
return;
|
||||
const start = Date.now();
|
||||
let lastError = null;
|
||||
let logged = false;
|
||||
|
||||
while (Date.now() - start < timeoutMs) {
|
||||
const pong = await pingContentScriptOnTab(tabId);
|
||||
if (pong?.ok && (!pong.source || pong.source === source)) {
|
||||
await registerTab(source, tabId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inject || !inject.length) {
|
||||
throw new Error(`${getSourceLabel(source)} 内容脚本未就绪,且未提供可用的注入文件。`);
|
||||
}
|
||||
|
||||
const registry = await getTabRegistry();
|
||||
if (registry[source]) {
|
||||
registry[source].ready = false;
|
||||
await setState({ tabRegistry: registry });
|
||||
}
|
||||
|
||||
try {
|
||||
if (injectSource) {
|
||||
await chrome.scripting.executeScript({
|
||||
target: { tabId },
|
||||
func: (injectedSource) => {
|
||||
window.__MULTIPAGE_SOURCE = injectedSource;
|
||||
},
|
||||
args: [injectSource],
|
||||
});
|
||||
}
|
||||
|
||||
await chrome.scripting.executeScript({
|
||||
target: { tabId },
|
||||
files: inject,
|
||||
});
|
||||
} catch (err) {
|
||||
lastError = err;
|
||||
}
|
||||
|
||||
const pongAfterInject = await pingContentScriptOnTab(tabId);
|
||||
if (pongAfterInject?.ok && (!pongAfterInject.source || pongAfterInject.source === source)) {
|
||||
await registerTab(source, tabId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (logMessage && !logged) {
|
||||
await addLog(logMessage, 'warn');
|
||||
logged = true;
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
||||
}
|
||||
|
||||
if (!inject || !inject.length) {
|
||||
throw new Error(`${getSourceLabel(source)} 内容脚本未就绪,且未提供可用的注入文件。`);
|
||||
}
|
||||
|
||||
const registry = await getTabRegistry();
|
||||
if (registry[source]) {
|
||||
registry[source].ready = false;
|
||||
await setState({ tabRegistry: registry });
|
||||
}
|
||||
|
||||
if (injectSource) {
|
||||
await chrome.scripting.executeScript({
|
||||
target: { tabId },
|
||||
func: (injectedSource) => {
|
||||
window.__MULTIPAGE_SOURCE = injectedSource;
|
||||
},
|
||||
args: [injectSource],
|
||||
});
|
||||
}
|
||||
|
||||
await chrome.scripting.executeScript({
|
||||
target: { tabId },
|
||||
files: inject,
|
||||
});
|
||||
throw lastError || new Error(`${getSourceLabel(source)} 内容脚本长时间未就绪。`);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
@@ -1799,23 +1850,20 @@ async function executeStep1(state) {
|
||||
const tabId = tab.id;
|
||||
await rememberSourceLastUrl('vps-panel', state.vpsUrl);
|
||||
|
||||
await new Promise((resolve) => {
|
||||
const timer = setTimeout(() => {
|
||||
chrome.tabs.onUpdated.removeListener(listener);
|
||||
resolve();
|
||||
}, 30000);
|
||||
const listener = (updatedTabId, info) => {
|
||||
if (updatedTabId === tabId && info.status === 'complete') {
|
||||
chrome.tabs.onUpdated.removeListener(listener);
|
||||
clearTimeout(timer);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
chrome.tabs.onUpdated.addListener(listener);
|
||||
await addLog('步骤 1:CPA 面板已打开,正在等待页面进入目标地址...');
|
||||
const matchedTab = await waitForTabUrlFamily('vps-panel', tabId, state.vpsUrl, {
|
||||
timeoutMs: 15000,
|
||||
retryDelayMs: 400,
|
||||
});
|
||||
if (!matchedTab) {
|
||||
await addLog('步骤 1:CPA 页面尚未完全进入目标地址,继续尝试连接内容脚本...', 'warn');
|
||||
}
|
||||
|
||||
await ensureContentScriptReadyOnTab('vps-panel', tabId, {
|
||||
inject: injectFiles,
|
||||
timeoutMs: 45000,
|
||||
retryDelayMs: 900,
|
||||
logMessage: '步骤 1:CPA 面板仍在加载,正在重试连接内容脚本...',
|
||||
});
|
||||
|
||||
const result = await sendToContentScriptResilient('vps-panel', {
|
||||
|
||||
+17
-13
@@ -17,20 +17,24 @@ const LOG_PREFIX = `[MultiPage:${SCRIPT_SOURCE}]`;
|
||||
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
|
||||
let flowStopped = false;
|
||||
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
if (message.type === 'STOP_FLOW') {
|
||||
flowStopped = true;
|
||||
console.warn(LOG_PREFIX, STOP_ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
if (!window.__MULTIPAGE_UTILS_LISTENER_READY__) {
|
||||
window.__MULTIPAGE_UTILS_LISTENER_READY__ = true;
|
||||
|
||||
if (message.type === 'PING') {
|
||||
sendResponse({
|
||||
ok: true,
|
||||
source: SCRIPT_SOURCE,
|
||||
});
|
||||
}
|
||||
});
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
if (message.type === 'STOP_FLOW') {
|
||||
flowStopped = true;
|
||||
console.warn(LOG_PREFIX, STOP_ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type === 'PING') {
|
||||
sendResponse({
|
||||
ok: true,
|
||||
source: SCRIPT_SOURCE,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function resetStopState() {
|
||||
flowStopped = false;
|
||||
|
||||
Reference in New Issue
Block a user