fix: handle context destroyed, frame navigation URL
This commit is contained in:
@@ -66,6 +66,8 @@ export class RemoteBrowser {
|
|||||||
maxRepeats: 1,
|
maxRepeats: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private lastEmittedUrl: string | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link WorkflowGenerator} instance specific to the remote browser.
|
* {@link WorkflowGenerator} instance specific to the remote browser.
|
||||||
*/
|
*/
|
||||||
@@ -88,6 +90,64 @@ export class RemoteBrowser {
|
|||||||
this.generator = new WorkflowGenerator(socket);
|
this.generator = new WorkflowGenerator(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes URLs to prevent navigation loops while maintaining consistent format
|
||||||
|
*/
|
||||||
|
private normalizeUrl(url: string): string {
|
||||||
|
try {
|
||||||
|
const parsedUrl = new URL(url);
|
||||||
|
// Remove trailing slashes except for root path
|
||||||
|
parsedUrl.pathname = parsedUrl.pathname.replace(/\/+$/, '') || '/';
|
||||||
|
// Ensure consistent protocol handling
|
||||||
|
parsedUrl.protocol = parsedUrl.protocol.toLowerCase();
|
||||||
|
return parsedUrl.toString();
|
||||||
|
} catch {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a URL change is significant enough to emit
|
||||||
|
*/
|
||||||
|
private shouldEmitUrlChange(newUrl: string): boolean {
|
||||||
|
if (!this.lastEmittedUrl) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const normalizedNew = this.normalizeUrl(newUrl);
|
||||||
|
const normalizedLast = this.normalizeUrl(this.lastEmittedUrl);
|
||||||
|
return normalizedNew !== normalizedLast;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async setupPageEventListeners(page: Page) {
|
||||||
|
page.on('framenavigated', async (frame) => {
|
||||||
|
if (frame === page.mainFrame()) {
|
||||||
|
const currentUrl = page.url();
|
||||||
|
if (this.shouldEmitUrlChange(currentUrl)) {
|
||||||
|
this.lastEmittedUrl = currentUrl;
|
||||||
|
this.socket.emit('urlChanged', currentUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle page load events with retry mechanism
|
||||||
|
page.on('load', async () => {
|
||||||
|
const injectScript = async (): Promise<boolean> => {
|
||||||
|
try {
|
||||||
|
await page.waitForLoadState('networkidle', { timeout: 5000 });
|
||||||
|
|
||||||
|
await page.evaluate(getInjectableScript());
|
||||||
|
return true;
|
||||||
|
} catch (error: any) {
|
||||||
|
logger.log('warn', `Script injection attempt failed: ${error.message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const success = await injectScript();
|
||||||
|
console.log("Script injection result:", success);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An asynchronous constructor for asynchronously initialized properties.
|
* An asynchronous constructor for asynchronously initialized properties.
|
||||||
* Must be called right after creating an instance of RemoteBrowser class.
|
* Must be called right after creating an instance of RemoteBrowser class.
|
||||||
@@ -167,15 +227,7 @@ export class RemoteBrowser {
|
|||||||
this.context = await this.browser.newContext(contextOptions);
|
this.context = await this.browser.newContext(contextOptions);
|
||||||
this.currentPage = await this.context.newPage();
|
this.currentPage = await this.context.newPage();
|
||||||
|
|
||||||
this.currentPage.on('framenavigated', (frame) => {
|
await this.setupPageEventListeners(this.currentPage);
|
||||||
if (frame === this.currentPage?.mainFrame()) {
|
|
||||||
this.socket.emit('urlChanged', this.currentPage.url());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.currentPage.on('load', (page) => {
|
|
||||||
page.evaluate(getInjectableScript())
|
|
||||||
})
|
|
||||||
|
|
||||||
// await this.currentPage.setExtraHTTPHeaders({
|
// await this.currentPage.setExtraHTTPHeaders({
|
||||||
// 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
|
// 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
|
||||||
@@ -375,15 +427,7 @@ export class RemoteBrowser {
|
|||||||
await this.stopScreencast();
|
await this.stopScreencast();
|
||||||
this.currentPage = page;
|
this.currentPage = page;
|
||||||
|
|
||||||
this.currentPage.on('framenavigated', (frame) => {
|
await this.setupPageEventListeners(this.currentPage);
|
||||||
if (frame === this.currentPage?.mainFrame()) {
|
|
||||||
this.socket.emit('urlChanged', this.currentPage.url());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.currentPage.on('load', (page) => {
|
|
||||||
page.evaluate(getInjectableScript())
|
|
||||||
})
|
|
||||||
|
|
||||||
//await this.currentPage.setViewportSize({ height: 400, width: 900 })
|
//await this.currentPage.setViewportSize({ height: 400, width: 900 })
|
||||||
this.client = await this.currentPage.context().newCDPSession(this.currentPage);
|
this.client = await this.currentPage.context().newCDPSession(this.currentPage);
|
||||||
@@ -411,18 +455,8 @@ export class RemoteBrowser {
|
|||||||
await this.currentPage?.close();
|
await this.currentPage?.close();
|
||||||
this.currentPage = newPage;
|
this.currentPage = newPage;
|
||||||
if (this.currentPage) {
|
if (this.currentPage) {
|
||||||
this.currentPage.on('framenavigated', (frame) => {
|
await this.setupPageEventListeners(this.currentPage);
|
||||||
if (frame === this.currentPage?.mainFrame()) {
|
|
||||||
this.socket.emit('urlChanged', this.currentPage.url());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.currentPage.on('load', (page) => {
|
|
||||||
page.evaluate(getInjectableScript())
|
|
||||||
})
|
|
||||||
// this.currentPage.on('load', (page) => {
|
|
||||||
// this.socket.emit('urlChanged', page.url());
|
|
||||||
// })
|
|
||||||
this.client = await this.currentPage.context().newCDPSession(this.currentPage);
|
this.client = await this.currentPage.context().newCDPSession(this.currentPage);
|
||||||
await this.subscribeToScreencast();
|
await this.subscribeToScreencast();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user