Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for using existing cdp websocket in launchServer #4344

Closed
wants to merge 6 commits into from

Conversation

berstend
Copy link

@berstend berstend commented Nov 4, 2020

This PR:

CDP

As a side effect of switching to the new wire protocol we lost the ability to connect to existing CDP websockets. This is an issue for services that wish to make existing browsers (not created by Playwright) available to Playwright clients.

User-Agent

Adding a user-agent makes it much easier for services that wish to expose a single websocket to both Playwright and Puppeteer clients. In combination with cdpWebsocketEndpoint Playwright clients can then be piped through a wire protocol websocket created by launchServer that in turn will communicate with an existing CDP websocket endpoint.

                   +------------+                             +---------------+
pptr client  +-->  |            |  +----------------------->  |               |
                   |  custom    |                             |  Chromium CDP |
                   |  websocket |        playwright           |  websocket    |
  pw client  +-->  |            |  +-->  wire protocol  +-->  |               |
                   +------------+        websocket            +---------------+

I tried following the available naming pattern & style guide, kindly let me know if there are more preferred options. :-)

@ghost
Copy link

ghost commented Nov 4, 2020

CLA assistant check
All CLA requirements met.

@berstend
Copy link
Author

berstend commented Nov 4, 2020

Urgh, seems like optional chaining is not supported in CI (or rather node v10.15.3)

@@ -17,7 +17,7 @@

import { it, expect, describe } from './fixtures';

describe('lauch server', (suite, { wire }) => {
describe('launch server', (suite, { wire }) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😄

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought I fix that while I'm there 😄

@@ -62,4 +62,17 @@ describe('lauch server', (suite, { wire }) => {
expect(result['exitCode']).toBe(0);
expect(result['signal']).toBe(null);
});

it('should allow using an existing cdp endpoint', async ({ browserType, server}) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test don't really prove that the cdp websocket works. @dgozman should we add another bot that runs all the tests via cdp?

Or we can just have a smoke test that.

  1. launches a browser server with --remote-debugging-port
  2. launches a second browser server that connects to the first via cdpWebSocketEndpoint
  3. connect to that second browser server and create a page and eval 1+1=2 in there.

Copy link
Author

@berstend berstend Nov 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, doing that was my first instinct :-) I had the impression the other tests were a bit shallow so I opted to just test the basics. Happy to change this to a more full-fledged test.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering about the best way to get the webSocketDebuggerUrl from /json/version (there doesn't seem to be an http client around)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do await page.evaluate(() => fetch(url)) and use the browser 😄

Copy link
Author

@berstend berstend Nov 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my attempt with vanilla http 😄

image

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JoelEinbinder added an additional smoke test to ensure the cdp websocket works :-)

@berstend
Copy link
Author

berstend commented Nov 4, 2020

I think mapping upgrade to onRequest in the testserver has side-effects, I made a dedicated onUpgrade handler


export interface BrowserServerLauncher {
launchServer(options?: LaunchServerOptions): Promise<BrowserServer>;
}

export interface BrowserServer {
process(): ChildProcess;
process(): ChildProcess | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not change this signature, it's not backwards-compatible. Instead, throw an error from process() when running in "connect over cdp" mode.

@@ -93,11 +96,13 @@ export class BrowserServerImpl extends EventEmitter implements BrowserServer {
}

async close(): Promise<void> {
await this._browser._options.browserProcess.close();
if (this._browser._options.browserProcess)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the right way is to connect right here, in the BrowserServerImpl, instead of going all the way to _innerLaunch and back.

Now that I think about this more: when connecting over existing cdp, all other launch parameters are actually ignored. This hints at using a different method, something like chromium.connectServer that only takes the websocket url. WDYT?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, when connecting to an existing cdp websocket virtually all of the launch code isn't needed. Also the flag feels a bit shoehorned into there, so it might be cleaner to keep it separate. If promoting this feature to it's own top-level API is fine then I'm happy to work on the changes 😄

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a dedicated API implementation for comparison

@@ -62,4 +62,17 @@ describe('lauch server', (suite, { wire }) => {
expect(result['exitCode']).toBe(0);
expect(result['signal']).toBe(null);
});

it('should allow using an existing cdp endpoint', async ({ browserType, server}) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do await page.evaluate(() => fetch(url)) and use the browser 😄

@berstend
Copy link
Author

berstend commented Nov 4, 2020

Thanks for all the valuable input and suggestions, will get back at it tomorrow. :-)

@berstend
Copy link
Author

berstend commented Nov 5, 2020

@dgozman I added a dedicated browserType.connectServer API as well, so we can see if we like it better:
image

Personally I think it's the better approach than cramping this into the existing .launchServer 😄

Note: I placed the meaty stuff in server/browserType.ts as I'd otherwise would need to re-import a bunch of things in src/browserServerImpl.ts :-)

Copy link
Contributor

@dgozman dgozman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely like the separate method more! Please give us some time to discuss the shape of this new API, and I'll get back to you with detailed PR review 😄

@mxschmitt
Copy link
Member

@berstend seems like it was implemented in #5207

@pavelfeldman
Copy link
Member

This is now obsolete and we have connectOverCDP, so closing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[REGRESSION]: chromium.connect does not work with vanilla CDP servers anymore
5 participants