2023-05-12 18:16:25 +09:00
|
|
|
import puppeteer, {Browser, Page, PuppeteerLaunchOptions} from "puppeteer";
|
|
|
|
import path from "path";
|
|
|
|
import run from "node:test";
|
2023-06-08 10:33:59 +09:00
|
|
|
import * as fs from "fs";
|
2023-06-08 10:58:41 +09:00
|
|
|
import {sleep} from "../utils";
|
2023-05-12 18:16:25 +09:00
|
|
|
|
|
|
|
const runPath = path.join(__dirname, 'run');
|
|
|
|
|
2023-06-05 23:11:03 +09:00
|
|
|
export interface PageInfo<T> {
|
2023-06-06 13:38:30 +09:00
|
|
|
id: string;
|
2023-06-05 23:11:03 +09:00
|
|
|
ready: boolean;
|
|
|
|
page?: Page;
|
|
|
|
data?: T;
|
2023-05-12 18:16:25 +09:00
|
|
|
}
|
|
|
|
|
2023-06-08 10:33:59 +09:00
|
|
|
type PrepareFunc<T> = (id: string, browser: Browser) => Promise<[Page | undefined, T, string]>
|
2023-05-12 18:16:25 +09:00
|
|
|
|
2023-06-05 23:11:03 +09:00
|
|
|
export class BrowserPool<T> {
|
|
|
|
private readonly pool: PageInfo<T>[] = [];
|
|
|
|
private readonly size: number;
|
|
|
|
private readonly prepare: PrepareFunc<T>
|
2023-05-12 18:16:25 +09:00
|
|
|
|
2023-06-06 13:38:30 +09:00
|
|
|
constructor(size: number, initialIDs: string[], prepare: PrepareFunc<T>) {
|
2023-06-05 23:11:03 +09:00
|
|
|
this.size = size
|
|
|
|
this.prepare = prepare;
|
2023-06-06 13:38:30 +09:00
|
|
|
this.init(initialIDs);
|
2023-05-12 18:16:25 +09:00
|
|
|
}
|
|
|
|
|
2023-06-06 13:38:30 +09:00
|
|
|
init(initialIDs: string[]) {
|
2023-06-05 23:11:03 +09:00
|
|
|
for (let i = 0; i < this.size; i++) {
|
2023-06-06 13:38:30 +09:00
|
|
|
const id = initialIDs[i];
|
2023-06-05 23:11:03 +09:00
|
|
|
const info: PageInfo<T> = {
|
2023-06-06 13:38:30 +09:00
|
|
|
id,
|
2023-06-05 23:11:03 +09:00
|
|
|
ready: false,
|
|
|
|
}
|
2023-06-08 10:33:59 +09:00
|
|
|
this.initOne(id).then(([page, data, newID]) => {
|
2023-06-07 10:33:45 +09:00
|
|
|
if (!page) {
|
|
|
|
return;
|
|
|
|
}
|
2023-06-08 10:33:59 +09:00
|
|
|
info.id = newID;
|
2023-06-05 23:11:03 +09:00
|
|
|
info.page = page;
|
2023-06-06 13:38:30 +09:00
|
|
|
info.data = data;
|
2023-06-05 23:11:03 +09:00
|
|
|
info.ready = true;
|
2023-06-06 13:38:30 +09:00
|
|
|
}).catch(e => {
|
2023-06-05 23:11:03 +09:00
|
|
|
console.error(e);
|
|
|
|
})
|
|
|
|
this.pool.push(info)
|
2023-05-12 18:16:25 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-08 10:33:59 +09:00
|
|
|
async initOne(id: string): Promise<[Page, T, string]> {
|
2023-06-04 14:14:28 +09:00
|
|
|
const options: PuppeteerLaunchOptions = {
|
2023-06-05 23:11:03 +09:00
|
|
|
headless: process.env.DEBUG === "1" ? false : 'new',
|
2023-06-08 19:27:14 +09:00
|
|
|
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
2023-06-08 10:33:59 +09:00
|
|
|
userDataDir: `run/${id}`,
|
2023-06-04 14:14:28 +09:00
|
|
|
};
|
2023-06-06 13:38:30 +09:00
|
|
|
const browser = await puppeteer.launch(options);
|
2023-06-08 10:33:59 +09:00
|
|
|
const [page, data, newID] = await this.prepare(id, browser)
|
|
|
|
if (!page) {
|
|
|
|
console.log(`init ${id} failed, delete! init new ${newID}`);
|
|
|
|
await browser.close();
|
|
|
|
if (options.userDataDir) {
|
|
|
|
fs.rmdirSync(options.userDataDir, {recursive: true});
|
|
|
|
}
|
2023-06-08 10:58:41 +09:00
|
|
|
await sleep(5000);
|
2023-06-08 10:33:59 +09:00
|
|
|
return this.initOne(newID);
|
|
|
|
}
|
|
|
|
return [page, data, newID];
|
2023-06-04 14:14:28 +09:00
|
|
|
}
|
|
|
|
|
2023-06-05 23:11:03 +09:00
|
|
|
//@ts-ignore
|
2023-06-06 13:38:30 +09:00
|
|
|
get(): [page: Page | undefined, data: T | undefined, done: (data: T) => void, destroy: (newID: string) => void] {
|
2023-06-05 23:11:03 +09:00
|
|
|
for (const item of this.pool) {
|
|
|
|
if (item.ready) {
|
|
|
|
item.ready = false;
|
|
|
|
return [
|
|
|
|
item.page,
|
|
|
|
item.data,
|
|
|
|
(data: T) => {
|
|
|
|
item.ready = true
|
|
|
|
item.data = data;
|
|
|
|
},
|
2023-06-06 13:38:30 +09:00
|
|
|
(newID: string) => {
|
2023-06-05 23:22:12 +09:00
|
|
|
item.page?.close();
|
2023-06-08 10:33:59 +09:00
|
|
|
this.initOne(newID).then(([page, data, newID]) => {
|
|
|
|
item.id = newID;
|
2023-06-05 23:11:03 +09:00
|
|
|
item.page = page
|
2023-06-06 13:38:30 +09:00
|
|
|
item.data = data;
|
2023-06-05 23:11:03 +09:00
|
|
|
item.ready = true;
|
|
|
|
})
|
|
|
|
}
|
|
|
|
]
|
2023-06-04 14:14:28 +09:00
|
|
|
}
|
|
|
|
}
|
2023-06-05 23:22:12 +09:00
|
|
|
return [] as any;
|
2023-06-04 14:14:28 +09:00
|
|
|
}
|
2023-05-12 18:16:25 +09:00
|
|
|
}
|