2021-12-15 16:19:52 +01:00
|
|
|
import {SHOW_FETCH, DEBUG, context, ERROR_CODE_SAFE_TO_IGNORE} from './common.js';
|
2021-11-03 05:51:04 +01:00
|
|
|
|
|
|
|
const ROOT_SESSION = "browser";
|
|
|
|
// actually we use 'tot' but in chrome.debugger.attach 'tot' is
|
|
|
|
// not a supported version string
|
|
|
|
const VERSION = "1.3";
|
2021-12-13 07:30:20 +01:00
|
|
|
const MESSAGES = new Map();
|
2021-11-03 05:51:04 +01:00
|
|
|
|
|
|
|
function promisify(context, name, err) {
|
|
|
|
return async function(...args) {
|
|
|
|
let resolver, rejector;
|
|
|
|
const pr = new Promise((res,rej) => ([resolver, rejector] = [res,rej]));
|
|
|
|
|
|
|
|
args.push(promisifiedCallback);
|
|
|
|
|
|
|
|
context[name](...args);
|
|
|
|
|
|
|
|
return pr;
|
|
|
|
|
|
|
|
function promisifiedCallback(...result) {
|
|
|
|
let error = err(name);
|
|
|
|
if ( !! error ) {
|
|
|
|
return rejector(error);
|
|
|
|
}
|
|
|
|
return resolver(...result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let Ws, Fetch;
|
|
|
|
|
|
|
|
async function loadDependencies() {
|
|
|
|
if ( context == 'extension' ) {
|
|
|
|
// no need to do anything here
|
|
|
|
} else if ( context == 'node' ) {
|
|
|
|
const {default:ws} = await import('ws');
|
|
|
|
const {default:nodeFetch} = await import('node-fetch');
|
|
|
|
|
|
|
|
Ws = ws;
|
|
|
|
Fetch = nodeFetch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function connect({port:port = 9222} = {}) {
|
2021-12-12 08:00:49 +01:00
|
|
|
if ( ! Ws || ! Fetch ) {
|
|
|
|
await loadDependencies();
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
const {webSocketDebuggerUrl} = await Fetch(`http://localhost:${port}/json/version`).then(r => r.json());
|
|
|
|
const socket = new Ws(webSocketDebuggerUrl);
|
|
|
|
const Resolvers = {};
|
2021-11-03 05:51:04 +01:00
|
|
|
const Handlers = {};
|
2021-12-12 08:00:49 +01:00
|
|
|
socket.on('message', handle);
|
|
|
|
let id = 0;
|
2021-11-03 05:51:04 +01:00
|
|
|
|
2021-12-12 08:00:49 +01:00
|
|
|
let resolve;
|
|
|
|
const promise = new Promise(res => resolve = res);
|
2021-11-03 05:51:04 +01:00
|
|
|
|
2021-12-12 08:00:49 +01:00
|
|
|
socket.on('open', () => resolve());
|
2021-11-03 05:51:04 +01:00
|
|
|
|
2021-12-12 08:00:49 +01:00
|
|
|
await promise;
|
2021-11-03 05:51:04 +01:00
|
|
|
|
2021-12-12 08:00:49 +01:00
|
|
|
return {
|
|
|
|
send,
|
|
|
|
on, ons,
|
|
|
|
close
|
2021-11-03 05:51:04 +01:00
|
|
|
}
|
2021-12-12 08:00:49 +01:00
|
|
|
|
|
|
|
async function send(method, params = {}, sessionId) {
|
|
|
|
const message = {
|
|
|
|
method, params, sessionId,
|
|
|
|
id: ++id
|
|
|
|
};
|
|
|
|
if ( ! sessionId ) {
|
|
|
|
delete message[sessionId];
|
2021-11-03 05:51:04 +01:00
|
|
|
}
|
2021-12-12 08:00:49 +01:00
|
|
|
const key = `${sessionId||ROOT_SESSION}:${message.id}`;
|
|
|
|
let resolve;
|
|
|
|
const promise = new Promise(res => resolve = res);
|
|
|
|
Resolvers[key] = resolve;
|
2021-12-13 07:30:20 +01:00
|
|
|
const outGoing = JSON.stringify(message);
|
|
|
|
MESSAGES.set(key, outGoing);
|
|
|
|
socket.send(outGoing);
|
2021-12-15 16:19:52 +01:00
|
|
|
DEBUG && (SHOW_FETCH || !method.startsWith('Fetch')) && console.log("Sent", message);
|
2021-12-12 08:00:49 +01:00
|
|
|
return promise;
|
2021-11-03 05:51:04 +01:00
|
|
|
}
|
|
|
|
|
2021-12-12 08:00:49 +01:00
|
|
|
async function handle(message) {
|
|
|
|
const stringMessage = message;
|
|
|
|
message = JSON.parse(message);
|
|
|
|
if ( message.error ) {
|
2021-12-13 07:30:20 +01:00
|
|
|
const showError = DEBUG || !ERROR_CODE_SAFE_TO_IGNORE.has(message.error.code);
|
|
|
|
if ( showError ) {
|
|
|
|
console.warn(message);
|
|
|
|
}
|
2021-11-03 05:51:04 +01:00
|
|
|
}
|
2021-12-12 08:00:49 +01:00
|
|
|
const {sessionId} = message;
|
|
|
|
const {method, params} = message;
|
|
|
|
const {id, result} = message;
|
|
|
|
|
|
|
|
if ( id ) {
|
|
|
|
const key = `${sessionId||ROOT_SESSION}:${id}`;
|
|
|
|
const resolve = Resolvers[key];
|
|
|
|
if ( ! resolve ) {
|
|
|
|
console.warn(`No resolver for key`, key, stringMessage.slice(0,140));
|
|
|
|
} else {
|
|
|
|
Resolvers[key] = undefined;
|
2021-11-03 05:51:04 +01:00
|
|
|
try {
|
2021-12-12 08:00:49 +01:00
|
|
|
await resolve(result);
|
2021-11-03 05:51:04 +01:00
|
|
|
} catch(e) {
|
2021-12-12 08:00:49 +01:00
|
|
|
console.warn(`Resolver failed`, e, key, stringMessage.slice(0,140), resolve);
|
2021-11-03 05:51:04 +01:00
|
|
|
}
|
|
|
|
}
|
2021-12-13 07:30:20 +01:00
|
|
|
if ( DEBUG ) {
|
|
|
|
if ( message.error ) {
|
|
|
|
const showError = DEBUG || !ERROR_CODE_SAFE_TO_IGNORE.has(message.error.code);
|
|
|
|
if ( showError ) {
|
|
|
|
const originalMessage = MESSAGES.get(key);
|
|
|
|
console.warn({originalMessage});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MESSAGES.delete(key);
|
2021-12-12 08:00:49 +01:00
|
|
|
} else if ( method ) {
|
|
|
|
const listeners = Handlers[method];
|
|
|
|
if ( Array.isArray(listeners) ) {
|
|
|
|
for( const func of listeners ) {
|
2021-11-03 05:51:04 +01:00
|
|
|
try {
|
2021-12-12 08:00:49 +01:00
|
|
|
func({message, sessionId});
|
2021-11-03 05:51:04 +01:00
|
|
|
} catch(e) {
|
2021-12-12 08:00:49 +01:00
|
|
|
console.warn(`Listener failed`, method, e, func.toString().slice(0,140), stringMessage.slice(0,140));
|
2021-11-03 05:51:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-12 08:00:49 +01:00
|
|
|
} else {
|
|
|
|
console.warn(`Unknown message on socket`, message);
|
2021-11-03 05:51:04 +01:00
|
|
|
}
|
2021-12-12 08:00:49 +01:00
|
|
|
}
|
2021-11-03 05:51:04 +01:00
|
|
|
|
2021-12-12 08:00:49 +01:00
|
|
|
function on(method, handler) {
|
|
|
|
let listeners = Handlers[method];
|
|
|
|
if ( ! listeners ) {
|
|
|
|
Handlers[method] = listeners = [];
|
2021-11-03 05:51:04 +01:00
|
|
|
}
|
2021-12-12 08:00:49 +01:00
|
|
|
listeners.push(wrap(handler));
|
|
|
|
}
|
2021-11-03 05:51:04 +01:00
|
|
|
|
2021-12-12 08:00:49 +01:00
|
|
|
function ons(method, handler) {
|
|
|
|
let listeners = Handlers[method];
|
|
|
|
if ( ! listeners ) {
|
|
|
|
Handlers[method] = listeners = [];
|
2021-11-03 05:51:04 +01:00
|
|
|
}
|
2021-12-12 08:00:49 +01:00
|
|
|
listeners.push(handler);
|
|
|
|
}
|
2021-11-03 05:51:04 +01:00
|
|
|
|
2021-12-12 08:00:49 +01:00
|
|
|
function close() {
|
|
|
|
socket.close();
|
|
|
|
}
|
2021-11-03 05:51:04 +01:00
|
|
|
|
2021-12-12 08:00:49 +01:00
|
|
|
function wrap(fn) {
|
|
|
|
return ({message, sessionId}) => fn(message.params)
|
2021-11-03 05:51:04 +01:00
|
|
|
}
|
2021-12-12 08:00:49 +01:00
|
|
|
} catch(e) {
|
|
|
|
console.log("Error communicating with browser", e);
|
|
|
|
process.exit(1);
|
2021-11-03 05:51:04 +01:00
|
|
|
}
|
|
|
|
}
|