feat: 增强内容脚本与后台通信,添加 PING 响应和确保脚本就绪的机制
This commit is contained in:
+67
-22
@@ -330,6 +330,55 @@ async function closeTabsByUrlPrefix(prefix, options = {}) {
|
|||||||
return matchedIds.length;
|
return matchedIds.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function pingContentScriptOnTab(tabId) {
|
||||||
|
if (!Number.isInteger(tabId)) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await chrome.tabs.sendMessage(tabId, {
|
||||||
|
type: 'PING',
|
||||||
|
source: 'background',
|
||||||
|
payload: {},
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureContentScriptReadyOnTab(source, tabId, options = {}) {
|
||||||
|
const { inject = null, injectSource = null } = options;
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (injectSource) {
|
||||||
|
await chrome.scripting.executeScript({
|
||||||
|
target: { tabId },
|
||||||
|
func: (injectedSource) => {
|
||||||
|
window.__MULTIPAGE_SOURCE = injectedSource;
|
||||||
|
},
|
||||||
|
args: [injectSource],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await chrome.scripting.executeScript({
|
||||||
|
target: { tabId },
|
||||||
|
files: inject,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Command Queue (for content scripts not yet ready)
|
// Command Queue (for content scripts not yet ready)
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@@ -2302,8 +2351,9 @@ async function executeStep8(state) {
|
|||||||
resolved = true;
|
resolved = true;
|
||||||
cleanupListener();
|
cleanupListener();
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
completeStepFromBackground(8, { localhostUrl: details.url }).then(() => {
|
addLog(`步骤 8:已捕获 localhost 地址:${details.url}`, 'ok').then(() => {
|
||||||
addLog(`步骤 8:已捕获 localhost 地址:${details.url}`, 'ok');
|
return completeStepFromBackground(8, { localhostUrl: details.url });
|
||||||
|
}).then(() => {
|
||||||
resolve();
|
resolve();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
reject(err);
|
reject(err);
|
||||||
@@ -2367,23 +2417,14 @@ async function executeStep9(state) {
|
|||||||
|
|
||||||
await addLog('步骤 9:正在打开 CPA 面板...');
|
await addLog('步骤 9:正在打开 CPA 面板...');
|
||||||
|
|
||||||
|
const injectFiles = ['content/utils.js', 'content/vps-panel.js'];
|
||||||
let tabId = await getTabId('vps-panel');
|
let tabId = await getTabId('vps-panel');
|
||||||
const alive = tabId && await isTabAlive('vps-panel');
|
const alive = tabId && await isTabAlive('vps-panel');
|
||||||
|
|
||||||
if (!alive) {
|
if (!alive) {
|
||||||
await closeConflictingTabsForSource('vps-panel', state.vpsUrl);
|
tabId = await reuseOrCreateTab('vps-panel', state.vpsUrl, {
|
||||||
// Create new tab
|
inject: injectFiles,
|
||||||
const tab = await chrome.tabs.create({ url: state.vpsUrl, active: true });
|
reloadIfSameUrl: true,
|
||||||
tabId = tab.id;
|
|
||||||
await rememberSourceLastUrl('vps-panel', state.vpsUrl);
|
|
||||||
await new Promise(resolve => {
|
|
||||||
const listener = (tid, info) => {
|
|
||||||
if (tid === tabId && info.status === 'complete') {
|
|
||||||
chrome.tabs.onUpdated.removeListener(listener);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
chrome.tabs.onUpdated.addListener(listener);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await closeConflictingTabsForSource('vps-panel', state.vpsUrl, { excludeTabIds: [tabId] });
|
await closeConflictingTabsForSource('vps-panel', state.vpsUrl, { excludeTabIds: [tabId] });
|
||||||
@@ -2391,21 +2432,25 @@ async function executeStep9(state) {
|
|||||||
await rememberSourceLastUrl('vps-panel', state.vpsUrl);
|
await rememberSourceLastUrl('vps-panel', state.vpsUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject scripts directly and wait for them to be ready
|
await ensureContentScriptReadyOnTab('vps-panel', tabId, {
|
||||||
await chrome.scripting.executeScript({
|
inject: injectFiles,
|
||||||
target: { tabId },
|
|
||||||
files: ['content/utils.js', 'content/vps-panel.js'],
|
|
||||||
});
|
});
|
||||||
await new Promise(r => setTimeout(r, 1000));
|
|
||||||
|
|
||||||
// Send command directly — bypass queue/ready mechanism
|
|
||||||
await addLog('步骤 9:正在填写回调地址...');
|
await addLog('步骤 9:正在填写回调地址...');
|
||||||
await chrome.tabs.sendMessage(tabId, {
|
const result = await sendToContentScriptResilient('vps-panel', {
|
||||||
type: 'EXECUTE_STEP',
|
type: 'EXECUTE_STEP',
|
||||||
step: 9,
|
step: 9,
|
||||||
source: 'background',
|
source: 'background',
|
||||||
payload: { localhostUrl: state.localhostUrl, vpsPassword: state.vpsPassword },
|
payload: { localhostUrl: state.localhostUrl, vpsPassword: state.vpsPassword },
|
||||||
|
}, {
|
||||||
|
timeoutMs: 30000,
|
||||||
|
retryDelayMs: 700,
|
||||||
|
logMessage: '步骤 9:CPA 面板通信未就绪,正在等待页面恢复...',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (result?.error) {
|
||||||
|
throw new Error(result.error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|||||||
+9
-1
@@ -17,10 +17,18 @@ const LOG_PREFIX = `[MultiPage:${SCRIPT_SOURCE}]`;
|
|||||||
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
|
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
|
||||||
let flowStopped = false;
|
let flowStopped = false;
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener((message) => {
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||||
if (message.type === 'STOP_FLOW') {
|
if (message.type === 'STOP_FLOW') {
|
||||||
flowStopped = true;
|
flowStopped = true;
|
||||||
console.warn(LOG_PREFIX, STOP_ERROR_MESSAGE);
|
console.warn(LOG_PREFIX, STOP_ERROR_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.type === 'PING') {
|
||||||
|
sendResponse({
|
||||||
|
ok: true,
|
||||||
|
source: SCRIPT_SOURCE,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+11
-3
@@ -25,8 +25,13 @@
|
|||||||
|
|
||||||
console.log('[MultiPage:vps-panel] Content script loaded on', location.href);
|
console.log('[MultiPage:vps-panel] Content script loaded on', location.href);
|
||||||
|
|
||||||
// Listen for commands from Background
|
const VPS_PANEL_LISTENER_SENTINEL = 'data-multipage-vps-panel-listener';
|
||||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
||||||
|
if (document.documentElement.getAttribute(VPS_PANEL_LISTENER_SENTINEL) !== '1') {
|
||||||
|
document.documentElement.setAttribute(VPS_PANEL_LISTENER_SENTINEL, '1');
|
||||||
|
|
||||||
|
// Listen for commands from Background
|
||||||
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||||
if (message.type === 'EXECUTE_STEP') {
|
if (message.type === 'EXECUTE_STEP') {
|
||||||
resetStopState();
|
resetStopState();
|
||||||
handleStep(message.step, message.payload).then(() => {
|
handleStep(message.step, message.payload).then(() => {
|
||||||
@@ -42,7 +47,10 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
console.log('[MultiPage:vps-panel] 消息监听已存在,跳过重复注册');
|
||||||
|
}
|
||||||
|
|
||||||
async function handleStep(step, payload) {
|
async function handleStep(step, payload) {
|
||||||
switch (step) {
|
switch (step) {
|
||||||
|
|||||||
Reference in New Issue
Block a user