Skip to content
This repository has been archived by the owner on Sep 16, 2024. It is now read-only.

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
soundofspace committed May 2, 2024
1 parent 7cd0283 commit f56cb40
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 176 deletions.
8 changes: 2 additions & 6 deletions agent/main/lib/Browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,8 @@ export default class Browser extends TypedEventEmitter<IBrowserEvents> implement
}
}
if (options.useRemoteDebuggingPort) {
const randomPort = (min: number, max: number): number => {
return Math.floor(Math.random() * (max - min) + min);
};
const port = randomPort(9900, 9999);
launchArgs.push(`--remote-debugging-port=${port}`);
this.engine.remoteDebuggingPort = port;
this.engine.useRemoteDebuggingPort = true;
launchArgs.push('--remote-debugging-port=0');
} else {
launchArgs.push('--remote-debugging-pipe');
}
Expand Down
25 changes: 19 additions & 6 deletions agent/main/lib/BrowserProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,36 @@ import { arch } from 'os';
import ShutdownHandler from '@ulixee/commons/lib/ShutdownHandler';
import { PipeTransport } from './PipeTransport';
import env from '../env';
import { PortTransport } from './PortTransport';
import { WebsocketTransport } from './WebsocketTransport';

const { log } = Log(module);

export default class BrowserProcess extends TypedEventEmitter<{ close: void }> {
public readonly transport: PipeTransport | PortTransport;
public readonly transport: PipeTransport | WebsocketTransport;

public isProcessFunctionalPromise = new Resolvable<boolean>();
public launchStderr: string[] = [];
private processKilled = false;
private readonly launchedProcess: ChildProcess;
private remoteDebuggingUrl?: Resolvable<string>;

constructor(private browserEngine: IBrowserEngine, private processEnv?: NodeJS.ProcessEnv) {
constructor(
private browserEngine: IBrowserEngine,
private processEnv?: NodeJS.ProcessEnv,
) {
super();

bindFunctions(this);
this.launchedProcess = this.launch();
this.bindProcessEvents();

if (browserEngine.remoteDebuggingPort) {
this.transport = new PortTransport(browserEngine.remoteDebuggingPort);
if (browserEngine.useRemoteDebuggingPort) {
this.remoteDebuggingUrl = new Resolvable<string>();
this.transport = new WebsocketTransport(this.remoteDebuggingUrl.promise);
} else {
this.transport = new PipeTransport(this.launchedProcess);
}

this.transport.connectedPromise
.then(() => this.isProcessFunctionalPromise.resolve(true))
.catch(err => setTimeout(() => this.isProcessFunctionalPromise.reject(err), 1.1e3));
Expand Down Expand Up @@ -94,6 +99,14 @@ export default class BrowserProcess extends TypedEventEmitter<{ close: void }> {
});
readline.createInterface({ input: stderr }).on('line', line => {
if (!line) return;

if (this.remoteDebuggingUrl?.isResolved === false) {
const match = line.match(/DevTools listening on (.*)/);
if (match) {
this.remoteDebuggingUrl.resolve(match[1].trim());
}
}

this.launchStderr.push(line);
// don't grow in perpetuity!
if (this.launchStderr.length > 100) {
Expand Down
69 changes: 0 additions & 69 deletions agent/main/lib/PortTransport.ts

This file was deleted.

134 changes: 134 additions & 0 deletions agent/main/lib/WebsocketTransport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import Log from '@ulixee/commons/lib/Logger';
import Resolvable from '@ulixee/commons/lib/Resolvable';
import * as WebSocket from 'ws';
import EventSubscriber from '@ulixee/commons/lib/EventSubscriber';
import IConnectionTransport from '../interfaces/IConnectionTransport';


// export class PortTransport implements IConnectionTransport {
// isClosed = false;

// connectedPromise = new Resolvable<void>();
// client: any;

// public onMessageFn: (message: string) => void;
// public readonly onCloseFns: (() => void)[] = [];

// constructor(urlPromise: Promise<string>) {
// urlPromise
// .then(url => this.connect(url))
// .catch(error => {
// if (!this.connectedPromise.isResolved) this.connectedPromise.reject(error);
// });
// }

// send(message: string): boolean {
// if (this.client) {
// this.client.send(message);
// return true;
// }
// return false;
// }

// close(): void {
// if (this.isClosed) return;
// this.isClosed = true;
// }

// private emit(message): void {
// if (this.onMessageFn) {
// setImmediate(this.onMessageFn, message);
// }
// }

// private onData(message: string): void {
// this.emit(message);
// }

// private connect(url: string): void {
// const client = new WebSocket(url);

// client.onerror = () => {
// if (!this.connectedPromise.isResolved)
// this.connectedPromise.reject(new Error('Failed to connect'));
// };
// client.onopen = () => {
// this.client = client;
// client.onmessage = e => {
// const msgData = e.data;
// this.onData(msgData);
// };
// if (!this.connectedPromise.isResolved) this.connectedPromise.resolve();
// };
// }
// }

const { log } = Log(module);

export class WebsocketTransport implements IConnectionTransport {
public get url(): string {
return this.webSocket.url;
}

public onMessageFn: (message: string) => void;
public readonly onCloseFns: (() => void)[] = [];
public connectedPromise = new Resolvable<void>();
public isClosed = false;

private events = new EventSubscriber();
private webSocket?: WebSocket;

constructor(urlPromise: Promise<string>) {
urlPromise
.then(url => this.connect(url))
.catch(error => {
if (!this.connectedPromise.isResolved) this.connectedPromise.reject(error);
});
}

send(message: string): boolean {
if (this.webSocket?.readyState === WebSocket.OPEN) {
this.webSocket.send(message);
return true;
}
return false;
}

close(): void {
this.isClosed = true;
this.events.close();
try {
this.webSocket?.close();
} catch {}
}

private onClosed(): void {
log.stats('WebSocketTransport.Closed');
for (const close of this.onCloseFns) close();
}

private onMessage(event: string): void {
this.onMessageFn?.(event);
}

private connect(url: string): void {
url = url.replace('localhost', '127.0.0.1');
this.webSocket = new WebSocket(url, [], {
perMessageDeflate: false,
followRedirects: true,
});
this.webSocket.once('open', this.connectedPromise.resolve);
this.webSocket.once('error', err => this.connectedPromise.reject(err, true));
this.events.on(this.webSocket, 'message', this.onMessage.bind(this));
this.events.once(this.webSocket, 'close', this.onClosed.bind(this));
this.events.once(this.webSocket, 'error', error => {
if (!this.connectedPromise.isResolved) this.connectedPromise.reject(error, true);
if (this.isClosed) return;
if (error.code !== 'EPIPE') {
log.error('WebsocketTransport.error', { error, sessionId: null });
}
});
}
}


2 changes: 1 addition & 1 deletion agent/main/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"devtools-protocol": "^0.0.1137505",
"nanoid": "^3.3.6",
"tough-cookie": "^4.1.3",
"websocket": "^1.0.34"
"ws": "^8.17.0"
},
"devDependencies": {
"@ulixee/unblocked-agent-testing": "2.0.0-alpha.28",
Expand Down
2 changes: 1 addition & 1 deletion specification/agent/browser/IBrowserEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export default interface IBrowserEngine {

isHeaded?: boolean;
isHeadlessNew?: boolean;
remoteDebuggingPort?: number;
useRemoteDebuggingPort?: boolean;
verifyLaunchable?(): Promise<any>;
}
Loading

0 comments on commit f56cb40

Please sign in to comment.