vscode-chrome-debug-core
Version:
A library for building VS Code debug adapters for targets that support the Chrome Remote Debug Protocol
171 lines (169 loc) • 8.58 kB
JavaScript
;
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const utils = require("../utils");
const executionTimingsReporter_1 = require("../executionTimingsReporter");
const chromeUtils = require("./chromeUtils");
const nls = require("vscode-nls");
const localize = nls.loadMessageBundle(__filename);
class ProtocolSchema {
constructor(_major, _minor) {
this._major = _major;
this._minor = _minor;
}
static unknownVersion() {
return new ProtocolSchema(0, 0); // Using 0.0 will make behave isAtLeastVersion as if this was the oldest possible version
}
isAtLeastVersion(major, minor) {
return major > this._major || (major === this._major && minor >= this._minor);
}
}
exports.ProtocolSchema = ProtocolSchema;
class ChromeTargetDiscovery {
constructor(_logger, _telemetry) {
this.events = new executionTimingsReporter_1.StepProgressEventsEmitter();
this.logger = _logger;
this.telemetry = _telemetry;
}
getTarget(address, port, targetFilter, targetUrl) {
return __awaiter(this, void 0, void 0, function* () {
const targets = yield this.getAllTargets(address, port, targetFilter, targetUrl);
if (targets.length > 1) {
this.logger.log('Warning: Found more than one valid target page. Attaching to the first one. Available pages: ' + JSON.stringify(targets.map(target => target.url)));
}
const selectedTarget = targets[0];
this.logger.verbose(`Attaching to target: ${JSON.stringify(selectedTarget)}`);
this.logger.verbose(`WebSocket Url: ${selectedTarget.webSocketDebuggerUrl}`);
return selectedTarget;
});
}
getAllTargets(address, port, targetFilter, targetUrl) {
return __awaiter(this, void 0, void 0, function* () {
const targets = yield this._getTargets(address, port);
/* __GDPR__
"targetCount" : {
"numTargets" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"${include}": [ "${DebugCommonProperties}" ]
}
*/
this.telemetry.reportEvent('targetCount', { numTargets: targets.length });
if (!targets.length) {
return utils.errP(localize(0, null));
}
return this._getMatchingTargets(targets, targetFilter, targetUrl);
});
}
_getVersionData(address, port) {
return __awaiter(this, void 0, void 0, function* () {
const url = `http://${address}:${port}/json/version`;
this.logger.log(`Getting browser and debug protocol version via ${url}`);
const jsonResponse = yield utils.getURL(url, { headers: { Host: 'localhost' } })
.catch(e => this.logger.log(`There was an error connecting to ${url} : ${e.message}`));
try {
if (jsonResponse) {
const response = JSON.parse(jsonResponse);
const versionString = response['Protocol-Version'];
this.logger.log(`Got browser version: ${response.Browser}`);
this.logger.log(`Got debug protocol version: ${versionString}`);
/* __GDPR__
"targetDebugProtocolVersion" : {
"debugProtocolVersion" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"${include}": [ "${DebugCommonProperties}" ]
}
*/
this.telemetry.reportEvent('targetDebugProtocolVersion', { debugProtocolVersion: response['Protcol-Version'] });
const majorAndMinor = versionString.split('.');
const major = parseInt(majorAndMinor[0], 10);
const minor = parseInt(majorAndMinor[1], 10);
return new ProtocolSchema(major, minor);
}
}
catch (e) {
this.logger.log(`Didn't get a valid response for /json/version call. Error: ${e.message}. Response: ${jsonResponse}`);
}
return ProtocolSchema.unknownVersion();
});
}
_getTargets(address, port) {
return __awaiter(this, void 0, void 0, function* () {
// Get the browser and the protocol version
const version = this._getVersionData(address, port);
/* __GDPR__FRAGMENT__
"StepNames" : {
"Attach.RequestDebuggerTargetsInformation" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.events.emitStepStarted('Attach.RequestDebuggerTargetsInformation');
const checkDiscoveryEndpoint = (url) => {
this.logger.log(`Discovering targets via ${url}`);
return utils.getURL(url, { headers: { Host: 'localhost' } });
};
const jsonResponse = yield checkDiscoveryEndpoint(`http://${address}:${port}/json/list`)
.catch(() => checkDiscoveryEndpoint(`http://${address}:${port}/json`))
.catch(e => utils.errP(localize(1, null, e.message)));
/* __GDPR__FRAGMENT__
"StepNames" : {
"Attach.ProcessDebuggerTargetsInformation" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.events.emitStepStarted('Attach.ProcessDebuggerTargetsInformation');
try {
const responseArray = JSON.parse(jsonResponse);
if (Array.isArray(responseArray)) {
return responseArray
.map(target => {
this._fixRemoteUrl(address, port, target);
target.version = version;
return target;
});
}
else {
return utils.errP(localize(2, null, jsonResponse));
}
}
catch (e) {
return utils.errP(localize(3, null, e.message, jsonResponse));
}
});
}
_getMatchingTargets(targets, targetFilter, targetUrl) {
let filteredTargets = targetFilter ?
targets.filter(targetFilter) : // Apply the consumer-specific target filter
targets;
// If a url was specified, try to filter to that url
filteredTargets = targetUrl ?
chromeUtils.getMatchingTargets(filteredTargets, targetUrl) :
filteredTargets;
if (!filteredTargets.length) {
throw new Error(localize(4, null, targetUrl, JSON.stringify(targets.map(target => target.url))));
}
// If all possible targets appear to be attached to have some other devtool attached, then fail
const targetsWithWSURLs = filteredTargets.filter(target => !!target.webSocketDebuggerUrl);
if (!targetsWithWSURLs.length) {
throw new Error(localize(5, null, filteredTargets[0].url));
}
return targetsWithWSURLs;
}
_fixRemoteUrl(remoteAddress, remotePort, target) {
if (target.webSocketDebuggerUrl) {
const addressMatch = target.webSocketDebuggerUrl.match(/ws:\/\/([^/]+)\/?/);
if (addressMatch) {
const replaceAddress = `${remoteAddress}:${remotePort}`;
target.webSocketDebuggerUrl = target.webSocketDebuggerUrl.replace(addressMatch[1], replaceAddress);
}
}
return target;
}
}
exports.ChromeTargetDiscovery = ChromeTargetDiscovery;
//# sourceMappingURL=chromeTargetDiscoveryStrategy.js.map