123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- "use strict";
- var __importDefault = (this && this.__importDefault) || function (mod) {
- return (mod && mod.__esModule) ? mod : { "default": mod };
- };
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.BidiServerRunner = exports.debugInfo = void 0;
- /**
- * Copyright 2021 Google LLC.
- * Copyright (c) Microsoft Corporation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- const http_1 = __importDefault(require("http"));
- const debug_1 = __importDefault(require("debug"));
- const websocket_1 = __importDefault(require("websocket"));
- exports.debugInfo = (0, debug_1.default)('bidi:server:info');
- const debugInternal = (0, debug_1.default)('bidi:server:internal');
- const debugSend = (0, debug_1.default)('bidi:server:SEND ▸');
- const debugRecv = (0, debug_1.default)('bidi:server:RECV ◂');
- function getHttpRequestPayload(request) {
- return new Promise((resolve, reject) => {
- let data = '';
- request.on('data', (chunk) => {
- data += chunk;
- });
- request.on('end', () => {
- resolve(data);
- });
- request.on('error', (error) => {
- reject(error);
- });
- });
- }
- class BidiServerRunner {
- /**
- *
- * @param bidiPort port to start ws server on
- * @param onNewBidiConnectionOpen delegate to be called for each new
- * connection. `onNewBidiConnectionOpen` delegate should return another
- * `onConnectionClose` delegate, which will be called after the connection is
- * closed.
- */
- run(bidiPort, onNewBidiConnectionOpen) {
- const server = http_1.default.createServer(async (request, response) => {
- debugInternal(`${new Date().toString()} Received ${request.method ?? 'UNKNOWN METHOD'} request for ${request.url ?? 'UNKNOWN URL'}`);
- if (!request.url)
- return response.end(404);
- // https://w3c.github.io/webdriver-bidi/#transport, step 2.
- if (request.url === '/session') {
- response.writeHead(200, {
- 'Content-Type': 'application/json;charset=utf-8',
- 'Cache-Control': 'no-cache',
- });
- response.write(JSON.stringify({
- value: {
- sessionId: '1',
- capabilities: {
- webSocketUrl: `ws://localhost:${bidiPort}`,
- },
- },
- }));
- }
- else if (request.url.startsWith('/session')) {
- debugInternal(`Unknown session command ${request.method ?? 'UNKNOWN METHOD'} request for ${request.url} with payload ${await getHttpRequestPayload(request)}. 200 returned.`);
- response.writeHead(200, {
- 'Content-Type': 'application/json;charset=utf-8',
- 'Cache-Control': 'no-cache',
- });
- response.write(JSON.stringify({
- value: {},
- }));
- }
- else {
- debugInternal(`Unknown ${JSON.stringify(request.method)} request for ${JSON.stringify(request.url)} with payload ${JSON.stringify(await getHttpRequestPayload(request))}. 404 returned.`);
- response.writeHead(404);
- }
- return response.end();
- });
- server.listen(bidiPort, () => {
- (0, exports.debugInfo)('Server is listening on port', bidiPort);
- });
- const wsServer = new websocket_1.default.server({
- httpServer: server,
- autoAcceptConnections: false,
- });
- wsServer.on('request', async (request) => {
- debugInternal('new WS request received:', request.resourceURL.path);
- const bidiServer = new BidiServer();
- const onBidiConnectionClosed = await onNewBidiConnectionOpen(bidiServer);
- const connection = request.accept();
- connection.on('message', (message) => {
- // 1. If |type| is not text, return.
- if (message.type !== 'utf8') {
- this.#respondWithError(connection, {}, 'invalid argument', `not supported type (${message.type})`);
- return;
- }
- const plainCommandData = message.utf8Data;
- debugRecv(plainCommandData);
- bidiServer.onMessage(plainCommandData);
- });
- connection.on('close', () => {
- debugInternal(`${new Date().toString()} Peer ${connection.remoteAddress} disconnected.`);
- onBidiConnectionClosed();
- });
- bidiServer.initialize((messageStr) => {
- return this.#sendClientMessageStr(messageStr, connection);
- });
- });
- }
- #sendClientMessageStr(messageStr, connection) {
- debugSend(messageStr);
- connection.sendUTF(messageStr);
- return Promise.resolve();
- }
- #sendClientMessage(messageObj, connection) {
- const messageStr = JSON.stringify(messageObj);
- return this.#sendClientMessageStr(messageStr, connection);
- }
- #respondWithError(connection, plainCommandData, errorCode, errorMessage) {
- const errorResponse = this.#getErrorResponse(plainCommandData, errorCode, errorMessage);
- void this.#sendClientMessage(errorResponse, connection);
- }
- #getErrorResponse(plainCommandData, errorCode, errorMessage) {
- // XXX: this is bizarre per spec. We reparse the payload and
- // extract the ID, regardless of what kind of value it was.
- let commandId;
- try {
- const commandData = JSON.parse(plainCommandData);
- if ('id' in commandData) {
- commandId = commandData.id;
- }
- }
- catch { }
- return {
- id: commandId,
- error: errorCode,
- message: errorMessage,
- // XXX: optional stacktrace field.
- };
- }
- }
- exports.BidiServerRunner = BidiServerRunner;
- class BidiServer {
- #handlers = [];
- #sendBidiMessage = null;
- setOnMessage(handler) {
- this.#handlers.push(handler);
- }
- sendMessage(message) {
- if (!this.#sendBidiMessage)
- throw new Error('BiDi connection is not initialised yet');
- return this.#sendBidiMessage(message);
- }
- close() {
- // Intentionally empty.
- }
- initialize(sendBidiMessage) {
- this.#sendBidiMessage = sendBidiMessage;
- }
- onMessage(messageStr) {
- for (const handler of this.#handlers)
- handler(messageStr);
- }
- }
- //# sourceMappingURL=bidiServerRunner.js.map
|