Merging chrome-provided port feature from v1
This commit is contained in:
Родитель
cae9fae261
Коммит
7d7ad1df2d
|
@ -15,6 +15,7 @@ import { CDTPResourceContentGetter } from './cdtpComponents/cdtpResourceContentG
|
|||
import { ShowOverlayWhenPaused, CDTPDeprecatedPage } from './features/showOverlayWhenPaused';
|
||||
import { CustomizedUninitializedCDA } from './components/customizedUninitializedCDA';
|
||||
import { ReportVersionInformation } from './features/reportVersionInformation';
|
||||
import { ChromeProvidedPortConnection } from './chromeProvidedPortConnection';
|
||||
|
||||
const EXTENSION_NAME = 'debugger-for-chrome';
|
||||
|
||||
|
@ -46,6 +47,7 @@ extensibilityPoints.bindAdditionalComponents = (diContainer: DependencyInjection
|
|||
diContainer.configureClass(TYPES.IServiceComponent, ReportVersionInformation);
|
||||
diContainer.configureClass(CDTPDeprecatedPage, CDTPDeprecatedPage);
|
||||
};
|
||||
extensibilityPoints.chromeConnection = ChromeProvidedPortConnection;
|
||||
|
||||
ChromeDebugSession.run(ChromeDebugSession.getSession(
|
||||
{
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { chromeConnection } from 'vscode-chrome-debug-core';
|
||||
import { utils, chromeUtils } from 'vscode-chrome-debug-core';
|
||||
import { logger } from 'vscode-chrome-debug-core';
|
||||
import * as errors from './errors';
|
||||
|
||||
/**
|
||||
* Chrome connection class that supports launching with --remote-debugging-port=0 to get a random port for the debug session
|
||||
*/
|
||||
export class ChromeProvidedPortConnection extends chromeConnection.ChromeConnection {
|
||||
|
||||
private userDataDir: string | undefined = undefined;
|
||||
setUserDataDir(userDataDir: string) {
|
||||
this.userDataDir = userDataDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach the websocket to the first available tab in the chrome instance with the given remote debugging port number.
|
||||
* If we launched with port = 0, then this method will read the launched port from the user data directory, and wait until the port is open
|
||||
* before calling super.attach
|
||||
*/
|
||||
public attach(address = '127.0.0.1', port = 9222, targetUrl?: string, timeout = chromeConnection.ChromeConnection.ATTACH_TIMEOUT, extraCRDPChannelPort?: number): Promise<void> {
|
||||
if (port === 0 && (this.userDataDir === undefined || this.userDataDir === '')) return errors.chromeProvidedPortWithoutUserDataDir();
|
||||
return utils.retryAsync(async () => {
|
||||
const launchedPort = (port === 0 && this.userDataDir) ? await this.getLaunchedPort(address, this.userDataDir) : port;
|
||||
return launchedPort;
|
||||
}, timeout, /*intervalDelay=*/200)
|
||||
.catch(err => Promise.reject(err))
|
||||
.then(launchedPort => {
|
||||
return super.attach(address, launchedPort, targetUrl, timeout, extraCRDPChannelPort);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the port on which chrome was launched, and throw error if the port is not open or accepting connections
|
||||
* @param host The host address on which to check if the port is listening
|
||||
* @param userDataDir Chrome user data directory in which to check for a port file
|
||||
*/
|
||||
private async getLaunchedPort(host: string, userDataDir: string): Promise<number> {
|
||||
logger.verbose('Looking for DevToolsActivePort file...');
|
||||
const launchedPort = await chromeUtils.getLaunchedPort(userDataDir);
|
||||
logger.verbose('Got the port, checking if its ready...');
|
||||
const portInUse = await chromeUtils.isPortInUse(launchedPort, host, 100);
|
||||
if (!portInUse) {
|
||||
// bail, the port isn't open
|
||||
logger.verbose('Port not open yet...');
|
||||
return errors.couldNotConnectToPort(host, launchedPort);
|
||||
}
|
||||
return launchedPort;
|
||||
}
|
||||
}
|
|
@ -18,3 +18,20 @@ export function getNotExistErrorResponse(attribute: string, path: string): Promi
|
|||
variables: { path }
|
||||
}));
|
||||
}
|
||||
|
||||
export function chromeProvidedPortWithoutUserDataDir() {
|
||||
return Promise.reject(new ErrorWithMessage(<DebugProtocol.Message>{
|
||||
id: 2008,
|
||||
format: localize('random.port.no.userdatadir', 'When the remote debugging port is set to 0, you must also provide the "userDataDir" launch argument'),
|
||||
sendTelemetry: true
|
||||
}));
|
||||
}
|
||||
|
||||
export function couldNotConnectToPort(address: string, port: number) {
|
||||
return Promise.reject(new ErrorWithMessage(<DebugProtocol.Message>{
|
||||
id: 2008,
|
||||
format: localize('launch.port.not.open', 'Could not open a connection to Chrome at: {address}:{port}', '{address}', '{port}'),
|
||||
variables: { address, port: port.toString() },
|
||||
sendTelemetry: true
|
||||
}));
|
||||
}
|
|
@ -15,8 +15,9 @@ import { isWindows } from './testSetup';
|
|||
import * as puppeteer from 'puppeteer';
|
||||
import { expect } from 'chai';
|
||||
import { killAllChrome } from '../testUtils';
|
||||
import { IAttachRequestArgs } from 'vscode-chrome-debug-core';
|
||||
import { IAttachRequestArgs, utils } from 'vscode-chrome-debug-core';
|
||||
import { getDebugAdapterLogFilePath } from './utils/logging';
|
||||
import { DebugClient } from 'vscode-debugadapter-testsupport';
|
||||
|
||||
const DATA_ROOT = testSetup.DATA_ROOT;
|
||||
|
||||
|
@ -185,5 +186,50 @@ suite('Chrome Debug Adapter etc', () => {
|
|||
// force kill chrome here, as it will be left open by the debug adapter (same behavior as v1)
|
||||
killAllChrome();
|
||||
});
|
||||
|
||||
test('Should launch successfully on port 0', async () => {
|
||||
// browser already launched to the default port, and navigated away from about:blank
|
||||
const remoteDebuggingPort = 0;
|
||||
await Promise.all([
|
||||
dc.configurationSequence(),
|
||||
dc.launch({ url: 'http://localhost:7890', timeout: 5000, webRoot: testProjectRoot, port: remoteDebuggingPort }),
|
||||
]);
|
||||
|
||||
// wait for url to === http://localhost:7890 (launch response can come back before the navigation completes)
|
||||
return waitForUrl(dc, 'http://localhost:7890/');
|
||||
});
|
||||
|
||||
test('Should launch successfully on port 0, even when a browser instance is already running', async () => {
|
||||
// browser already launched to the default port, and navigated away from about:blank
|
||||
const remoteDebuggingPort = 0;
|
||||
const dataDir = path.join(__dirname, 'testDataDir');
|
||||
const browser = await puppeteer.launch({ headless: false, args: ['https://bing.com', `--user-data-dir=${dataDir}`, `--remote-debugging-port=${remoteDebuggingPort}`] });
|
||||
|
||||
try {
|
||||
await Promise.all([
|
||||
dc.configurationSequence(),
|
||||
dc.launch({ url: 'http://localhost:7890', timeout: 5000, webRoot: testProjectRoot, port: remoteDebuggingPort, userDataDir: dataDir }),
|
||||
]);
|
||||
|
||||
await waitForUrl(dc, 'http://localhost:7890/');
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function waitForUrl(dc: DebugClient, url: string): Promise<string> {
|
||||
const timeoutMs = 5000;
|
||||
const intervalDelayMs = 50;
|
||||
|
||||
return await utils.retryAsync(async () => {
|
||||
const response = await dc.evaluateRequest({
|
||||
context: 'repl',
|
||||
expression: 'window.location.href'
|
||||
});
|
||||
|
||||
expect(response.body.result).to.equal(`"${url}"`);
|
||||
return url;
|
||||
}, timeoutMs, intervalDelayMs).catch(err => { throw err; });
|
||||
}
|
Загрузка…
Ссылка в новой задаче