Files
mv2_simple_crx/server/services/puppeteer_runner.js
张成 5b671d320b 1
2026-03-18 14:18:41 +08:00

103 lines
2.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import dotenv from 'dotenv';
import path from 'node:path';
import puppeteer from 'puppeteer';
dotenv.config();
let browser_singleton = null;
function get_action_timeout_ms() {
return Number(process.env.ACTION_TIMEOUT_MS || 300000);
}
function get_crx_src_path() {
const crx_src_path = process.env.CRX_SRC_PATH;
if (!crx_src_path) {
throw new Error('缺少环境变量 CRX_SRC_PATH');
}
return crx_src_path;
}
function get_extension_id_from_targets(targets) {
for (const target of targets) {
const url = target.url();
if (!url) continue;
if (url.startsWith('chrome-extension://')) {
const match = url.match(/^chrome-extension:\/\/([^/]+)\//);
if (match && match[1]) return match[1];
}
}
return null;
}
export async function get_or_create_browser() {
if (browser_singleton) {
return browser_singleton;
}
const extension_path = path.resolve(get_crx_src_path());
const headless = String(process.env.PUPPETEER_HEADLESS || 'false') === 'true';
browser_singleton = await puppeteer.launch({
headless,
args: [
`--disable-extensions-except=${extension_path}`,
`--load-extension=${extension_path}`,
'--no-default-browser-check',
'--disable-popup-blocking',
'--disable-dev-shm-usage'
]
});
return browser_singleton;
}
export async function invoke_extension_action(action_name, action_payload) {
const browser = await get_or_create_browser();
const page = await browser.newPage();
await page.goto('about:blank');
const targets = await browser.targets();
const extension_id = get_extension_id_from_targets(targets);
if (!extension_id) {
await page.close();
throw new Error('未找到扩展 extension_id请确认 CRX_SRC_PATH 指向 src 且成功加载)');
}
const bridge_url = `chrome-extension://${extension_id}/bridge/bridge.html`;
await page.goto(bridge_url, { waitUntil: 'domcontentloaded' });
const timeout_ms = get_action_timeout_ms();
const action_res = await page.evaluate(
async (action, payload, timeout) => {
function with_timeout(promise, timeout_ms_inner) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error('action_timeout')), timeout_ms_inner);
promise
.then((v) => {
clearTimeout(timer);
resolve(v);
})
.catch((e) => {
clearTimeout(timer);
reject(e);
});
});
}
if (!window.server_bridge_invoke) {
throw new Error('bridge 未注入 window.server_bridge_invoke');
}
return await with_timeout(window.server_bridge_invoke(action, payload), timeout);
},
action_name,
action_payload || {},
timeout_ms
);
await page.close();
return action_res;
}