Node updated. Some todos.
This commit is contained in:
127
Scripts/node_modules/chromium-bidi/lib/cjs/bidiServer/WebSocketServer.js
generated
vendored
127
Scripts/node_modules/chromium-bidi/lib/cjs/bidiServer/WebSocketServer.js
generated
vendored
@ -46,6 +46,7 @@ exports.WebSocketServer = exports.debugInfo = void 0;
|
||||
const http_1 = __importDefault(require("http"));
|
||||
const debug_1 = __importDefault(require("debug"));
|
||||
const websocket = __importStar(require("websocket"));
|
||||
const Deferred_js_1 = require("../utils/Deferred.js");
|
||||
const uuid_js_1 = require("../utils/uuid.js");
|
||||
const BrowserInstance_js_1 = require("./BrowserInstance.js");
|
||||
exports.debugInfo = (0, debug_1.default)('bidi:server:info');
|
||||
@ -55,30 +56,55 @@ const debugRecv = (0, debug_1.default)('bidi:server:RECV ◂');
|
||||
class WebSocketServer {
|
||||
#sessions = new Map();
|
||||
#port;
|
||||
#channel;
|
||||
#headless;
|
||||
#verbose;
|
||||
#server;
|
||||
#wsServer;
|
||||
constructor(port, channel, headless, verbose) {
|
||||
constructor(port, verbose) {
|
||||
this.#port = port;
|
||||
this.#channel = channel;
|
||||
this.#headless = headless;
|
||||
this.#verbose = verbose;
|
||||
this.#server = http_1.default.createServer(this.#onRequest.bind(this));
|
||||
this.#server = http_1.default.createServer((request, response) => {
|
||||
return this.#onRequest(request, response).catch((e) => {
|
||||
(0, exports.debugInfo)('Error while processing request', e);
|
||||
response.writeHead(500, String(e));
|
||||
});
|
||||
});
|
||||
this.#wsServer = new websocket.server({
|
||||
httpServer: this.#server,
|
||||
autoAcceptConnections: false,
|
||||
});
|
||||
this.#wsServer.on('request', this.#onWsRequest.bind(this));
|
||||
this.#server.listen(this.#port, () => {
|
||||
(0, exports.debugInfo)('BiDi server is listening on port', this.#port);
|
||||
});
|
||||
void this.#listen();
|
||||
}
|
||||
#logServerStarted() {
|
||||
(0, exports.debugInfo)('BiDi server is listening on port', this.#port);
|
||||
(0, exports.debugInfo)('BiDi server was started successfully.');
|
||||
}
|
||||
async #listen() {
|
||||
try {
|
||||
this.#server.listen(this.#port, () => {
|
||||
this.#logServerStarted();
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
if (error &&
|
||||
typeof error === 'object' &&
|
||||
'code' in error &&
|
||||
error.code === 'EADDRINUSE') {
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, 500);
|
||||
});
|
||||
(0, exports.debugInfo)('Retrying to run BiDi server');
|
||||
this.#server.listen(this.#port, () => {
|
||||
this.#logServerStarted();
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async #onRequest(request, response) {
|
||||
debugInternal(`Received HTTP ${JSON.stringify(request.method)} request for ${JSON.stringify(request.url)}`);
|
||||
if (!request.url) {
|
||||
return response.end(404);
|
||||
throw new Error('Request URL is empty.');
|
||||
}
|
||||
// https://w3c.github.io/webdriver-bidi/#transport, step 2.
|
||||
if (request.url === '/session') {
|
||||
@ -92,6 +118,7 @@ class WebSocketServer {
|
||||
resolve(Buffer.concat(bodyArray));
|
||||
});
|
||||
});
|
||||
debugInternal(`Creating session by HTTP request ${body.toString()}`);
|
||||
// https://w3c.github.io/webdriver-bidi/#transport, step 3.
|
||||
const jsonBody = JSON.parse(body.toString());
|
||||
response.writeHead(200, {
|
||||
@ -105,9 +132,9 @@ class WebSocketServer {
|
||||
// tests clean up is switched to pure BiDi.
|
||||
browserInstancePromise: undefined,
|
||||
sessionOptions: {
|
||||
chromeOptions: this.#getChromeOptions(jsonBody.capabilities, this.#channel, this.#headless),
|
||||
mapperOptions: this.#getMapperOptions(jsonBody.capabilities),
|
||||
chromeOptions: this.#getChromeOptions(jsonBody.capabilities),
|
||||
verbose: this.#verbose,
|
||||
sessionNewBody: `{"id":0,"method":"session.new","params":${body.toString()}}`,
|
||||
},
|
||||
};
|
||||
this.#sessions.set(sessionId, session);
|
||||
@ -134,13 +161,16 @@ class WebSocketServer {
|
||||
}));
|
||||
return response.end();
|
||||
}
|
||||
debugInternal(`Unknown ${request.method} request for ${JSON.stringify(request.url)} with payload ${await this.#getHttpRequestPayload(request)}. 404 returned.`);
|
||||
return response.end(404);
|
||||
throw new Error(`Unknown "${request.method}" request for "${JSON.stringify(request.url)}" with payload "${await this.#getHttpRequestPayload(request)}".`);
|
||||
}
|
||||
#onWsRequest(request) {
|
||||
// Session is set either by Classic or BiDi commands.
|
||||
let session;
|
||||
const requestSessionId = (request.resource ?? '').split('/').pop();
|
||||
// Request to `/session` should be treated as a new session request.
|
||||
let requestSessionId = '';
|
||||
if ((request.resource ?? '').startsWith(`/session/`)) {
|
||||
requestSessionId = (request.resource ?? '').split('/').pop() ?? '';
|
||||
}
|
||||
debugInternal(`new WS request received. Path: ${JSON.stringify(request.resourceURL.path)}, sessionId: ${JSON.stringify(requestSessionId)}`);
|
||||
if (requestSessionId !== '' &&
|
||||
requestSessionId !== undefined &&
|
||||
@ -186,8 +216,8 @@ class WebSocketServer {
|
||||
try {
|
||||
parsedCommandData = JSON.parse(plainCommandData);
|
||||
}
|
||||
catch (e) {
|
||||
this.#respondWithError(connection, {}, "invalid argument" /* ErrorCode.InvalidArgument */, `Cannot parse data as JSON`);
|
||||
catch (error) {
|
||||
this.#respondWithError(connection, {}, "invalid argument" /* ErrorCode.InvalidArgument */, `Cannot parse data as JSON, ${error}`);
|
||||
return;
|
||||
}
|
||||
// Handle creating new session.
|
||||
@ -199,11 +229,11 @@ class WebSocketServer {
|
||||
}
|
||||
try {
|
||||
const sessionOptions = {
|
||||
chromeOptions: this.#getChromeOptions(parsedCommandData.params?.capabilities, this.#channel, this.#headless),
|
||||
mapperOptions: this.#getMapperOptions(parsedCommandData.params?.capabilities),
|
||||
chromeOptions: this.#getChromeOptions(parsedCommandData.params?.capabilities),
|
||||
verbose: this.#verbose,
|
||||
sessionNewBody: plainCommandData,
|
||||
};
|
||||
const browserInstance = await this.#launchBrowserInstance(connection, sessionOptions);
|
||||
const browserInstance = await this.#launchBrowserInstance(connection, sessionOptions, true);
|
||||
const sessionId = (0, uuid_js_1.uuidv4)();
|
||||
session = {
|
||||
sessionId,
|
||||
@ -217,14 +247,28 @@ class WebSocketServer {
|
||||
this.#respondWithError(connection, plainCommandData, "session not created" /* ErrorCode.SessionNotCreated */, e?.message ?? 'Unknown error');
|
||||
return;
|
||||
}
|
||||
// TODO: extend with capabilities.
|
||||
return;
|
||||
}
|
||||
// Handle ending session. Close browser if open, remove session.
|
||||
if (parsedCommandData.method === 'session.end') {
|
||||
if (session === undefined) {
|
||||
(0, exports.debugInfo)('WS connection does not have an associated session.');
|
||||
this.#respondWithError(connection, plainCommandData, "session not created" /* ErrorCode.SessionNotCreated */, 'WS connection does not have an associated session.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await this.#closeBrowserInstanceIfLaunched(session);
|
||||
this.#sessions.delete(session.sessionId);
|
||||
}
|
||||
catch (e) {
|
||||
(0, exports.debugInfo)('Error while closing session', e);
|
||||
this.#respondWithError(connection, plainCommandData, "unknown error" /* ErrorCode.UnknownError */, `Session cannot be closed. Error: ${e?.message}`);
|
||||
return;
|
||||
}
|
||||
this.#sendClientMessage({
|
||||
id: parsedCommandData.id,
|
||||
type: 'success',
|
||||
result: {
|
||||
sessionId: session.sessionId,
|
||||
capabilities: {},
|
||||
},
|
||||
result: {},
|
||||
}, connection);
|
||||
return;
|
||||
}
|
||||
@ -266,23 +310,36 @@ class WebSocketServer {
|
||||
session.browserInstancePromise = undefined;
|
||||
void browserInstance.close();
|
||||
}
|
||||
#getMapperOptions(capabilities) {
|
||||
const acceptInsecureCerts = capabilities?.alwaysMatch?.acceptInsecureCerts ?? false;
|
||||
const sharedIdWithFrame = capabilities?.alwaysMatch?.sharedIdWithFrame ?? false;
|
||||
return { acceptInsecureCerts, sharedIdWithFrame };
|
||||
}
|
||||
#getChromeOptions(capabilities, channel, headless) {
|
||||
#getChromeOptions(capabilities) {
|
||||
const chromeCapabilities = capabilities?.alwaysMatch?.['goog:chromeOptions'];
|
||||
return {
|
||||
chromeArgs: chromeCapabilities?.args ?? [],
|
||||
channel,
|
||||
headless,
|
||||
chromeBinary: chromeCapabilities?.binary ?? undefined,
|
||||
};
|
||||
}
|
||||
async #launchBrowserInstance(connection, sessionOptions) {
|
||||
async #launchBrowserInstance(connection, sessionOptions, passSessionNewThrough = false) {
|
||||
(0, exports.debugInfo)('Scheduling browser launch...');
|
||||
const browserInstance = await BrowserInstance_js_1.BrowserInstance.run(sessionOptions.chromeOptions, sessionOptions.mapperOptions, sessionOptions.verbose);
|
||||
const browserInstance = await BrowserInstance_js_1.BrowserInstance.run(sessionOptions.chromeOptions, sessionOptions.verbose);
|
||||
const body = JSON.parse(sessionOptions.sessionNewBody);
|
||||
const id = body.id;
|
||||
const sessionCreated = new Deferred_js_1.Deferred();
|
||||
const sessionResponseListener = (message) => {
|
||||
const jsonMessage = JSON.parse(message);
|
||||
if (jsonMessage['id'] === id) {
|
||||
(0, exports.debugInfo)('Receiving session.new response from mapper', message);
|
||||
sessionCreated.resolve();
|
||||
if (passSessionNewThrough) {
|
||||
this.#sendClientMessageString(message, connection);
|
||||
}
|
||||
}
|
||||
};
|
||||
browserInstance.bidiSession().on('message', sessionResponseListener);
|
||||
(0, exports.debugInfo)('Sending session.new to mapper', sessionOptions.sessionNewBody);
|
||||
await browserInstance
|
||||
.bidiSession()
|
||||
.sendCommand(sessionOptions.sessionNewBody);
|
||||
await sessionCreated;
|
||||
browserInstance.bidiSession().off('message', sessionResponseListener);
|
||||
// Forward messages from BiDi Mapper to the client unconditionally.
|
||||
browserInstance.bidiSession().on('message', (message) => {
|
||||
this.#sendClientMessageString(message, connection);
|
||||
|
||||
Reference in New Issue
Block a user