Skip to main content
Glama
pansin
by pansin
browser-manager.ts3.87 kB
/** * 浏览器管理器实现 */ import puppeteer, { Browser, Page } from 'puppeteer'; import { IBrowserManager } from '../interfaces/browser.js'; import { BrowserConfig } from '../types/index.js'; import { BrowserCrashError, ConfigurationError } from '../errors/index.js'; export class BrowserManager implements IBrowserManager { private browser: Browser | null = null; private pages: Map<string, Page> = new Map(); private config: BrowserConfig; private isInitialized = false; constructor(config: BrowserConfig) { this.config = config; } /** * 初始化浏览器管理器 */ async initialize(): Promise<void> { if (this.isInitialized) { return; } try { this.browser = await puppeteer.launch(this.config.launchOptions); // 监听浏览器断开事件 this.browser.on('disconnected', () => { this.browser = null; this.pages.clear(); this.isInitialized = false; console.error('浏览器意外断开连接'); }); this.isInitialized = true; console.log('浏览器管理器已初始化'); } catch (error) { throw new BrowserCrashError('无法启动浏览器', error as Error); } } /** * 创建新页面 */ async createPage(pageId?: string): Promise<string> { if (!this.browser) { await this.initialize(); } if (!this.browser) { throw new BrowserCrashError('浏览器未初始化'); } // 检查是否超过最大页面数量限制 if (this.pages.size >= this.config.security.maxPages) { throw new ConfigurationError(`已达到最大页面数量限制 (${this.config.security.maxPages})`); } // 生成唯一页面ID const id = pageId || `page_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`; // 创建新页面 const page = await this.browser.newPage(); // 设置视口大小 await page.setViewport(this.config.defaults.viewport); // 设置用户代理(如果配置中有) if (this.config.defaults.userAgent) { await page.setUserAgent(this.config.defaults.userAgent); } // 设置默认超时 page.setDefaultTimeout(this.config.defaults.timeout); // 存储页面引用 this.pages.set(id, page); return id; } /** * 根据ID获取页面 */ async getPage(pageId: string): Promise<Page> { const page = this.pages.get(pageId); if (!page) { throw new ConfigurationError(`找不到ID为 ${pageId} 的页面`); } return page; } /** * 根据ID关闭页面 */ async closePage(pageId: string): Promise<void> { const page = this.pages.get(pageId); if (!page) { return; // 如果页面不存在,直接返回 } try { await page.close(); } catch (error) { console.error(`关闭页面 ${pageId} 时出错:`, error); } finally { this.pages.delete(pageId); } } /** * 清理所有资源 */ async cleanup(): Promise<void> { // 关闭所有页面 for (const [pageId, page] of this.pages.entries()) { try { await page.close(); } catch (error) { console.error(`关闭页面 ${pageId} 时出错:`, error); } } this.pages.clear(); // 关闭浏览器 if (this.browser) { try { await this.browser.close(); } catch (error) { console.error('关闭浏览器时出错:', error); } this.browser = null; } this.isInitialized = false; console.log('浏览器管理器已清理'); } /** * 获取浏览器实例 */ getBrowser(): Browser | null { return this.browser; } /** * 检查浏览器是否运行中 */ isRunning(): boolean { return this.browser !== null && this.isInitialized; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pansin/browserMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server