103 lines
2.5 KiB
TypeScript
103 lines
2.5 KiB
TypeScript
import { chromium } from 'playwright'
|
|
|
|
import { runtimeConfig } from '../../config/runtime.js'
|
|
import {
|
|
buildChromiumLaunchOptions as buildChromiumLaunchOptionsBase,
|
|
resolveBrowserLaunchOptions as resolveBrowserLaunchOptionsBase,
|
|
} from './session-browser-config.js'
|
|
import { CHROME_PATH } from './session-service-config.js'
|
|
|
|
type BrowserLike = {
|
|
on: (event: 'disconnected', listener: () => void) => void
|
|
close: () => Promise<void>
|
|
newContext: (options?: Record<string, unknown>) => Promise<any>
|
|
}
|
|
|
|
type SessionServiceErrorOptions = {
|
|
statusCode?: number
|
|
errorCode?: string
|
|
}
|
|
|
|
let browserPromise: Promise<BrowserLike> | null = null
|
|
|
|
export class SessionServiceError extends Error {
|
|
statusCode: number
|
|
errorCode: string
|
|
|
|
constructor(message: string, { statusCode = 500, errorCode = 'session_error' }: SessionServiceErrorOptions = {}) {
|
|
super(message)
|
|
this.name = 'SessionServiceError'
|
|
this.statusCode = statusCode
|
|
this.errorCode = errorCode
|
|
}
|
|
}
|
|
|
|
export async function warmupTencentBrowser() {
|
|
const browserLaunch = resolveBrowserLaunchOptions()
|
|
|
|
if (!browserLaunch.prewarm) {
|
|
return {
|
|
warmed: false,
|
|
reason: 'disabled',
|
|
browserLaunch,
|
|
}
|
|
}
|
|
|
|
await ensureBrowser()
|
|
|
|
return {
|
|
warmed: true,
|
|
reason: 'ready',
|
|
browserLaunch,
|
|
}
|
|
}
|
|
|
|
export async function ensureBrowser(): Promise<BrowserLike> {
|
|
if (!browserPromise) {
|
|
const launchOptions = resolveBrowserLaunchOptions()
|
|
browserPromise = (chromium.launch(buildChromiumLaunchOptions(launchOptions)) as Promise<BrowserLike>)
|
|
.then((browser) => {
|
|
browser.on('disconnected', () => {
|
|
browserPromise = null
|
|
})
|
|
return browser
|
|
})
|
|
.catch((error) => {
|
|
browserPromise = null
|
|
throw error
|
|
})
|
|
}
|
|
|
|
return browserPromise
|
|
}
|
|
|
|
export function resolveBrowserLaunchOptions() {
|
|
return resolveBrowserLaunchOptionsBase({
|
|
browserConfig: runtimeConfig.browser,
|
|
chromePath: CHROME_PATH,
|
|
})
|
|
}
|
|
|
|
export async function closeBrowserIfIdle({ activeSessionCount = 0 }: { activeSessionCount?: number } = {}): Promise<void> {
|
|
if (activeSessionCount > 0 || !browserPromise) {
|
|
return
|
|
}
|
|
|
|
if (resolveBrowserLaunchOptions().keepAlive) {
|
|
return
|
|
}
|
|
|
|
try {
|
|
const browser = await browserPromise
|
|
await browser.close()
|
|
} catch {
|
|
// ignore browser close failures
|
|
} finally {
|
|
browserPromise = null
|
|
}
|
|
}
|
|
|
|
function buildChromiumLaunchOptions(launchOptions: ReturnType<typeof resolveBrowserLaunchOptionsBase>) {
|
|
return buildChromiumLaunchOptionsBase(launchOptions, { chromePath: CHROME_PATH })
|
|
}
|