Skip to content

Commit 2de45fb

Browse files
committed
chore(protocol): implement client side hello
1 parent 7de9061 commit 2de45fb

File tree

6 files changed

+62
-31
lines changed

6 files changed

+62
-31
lines changed

playwright/_impl/_browser_type.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import asyncio
1616
import pathlib
1717
from pathlib import Path
18-
from typing import Dict, List, Optional, Union, cast
18+
from typing import TYPE_CHECKING, Dict, List, Optional, Union, cast
1919

2020
from playwright._impl._api_structures import (
2121
Geolocation,
@@ -42,6 +42,9 @@
4242
from playwright._impl._transport import WebSocketTransport
4343
from playwright._impl._wait_helper import throw_on_timeout
4444

45+
if TYPE_CHECKING:
46+
from playwright._impl._playwright import Playwright
47+
4548

4649
class BrowserType(ChannelOwner):
4750
def __init__(
@@ -183,8 +186,13 @@ async def connect(
183186
if timeout is None:
184187
timeout = 30000
185188

189+
on_ready = asyncio.Event()
186190
transport = WebSocketTransport(
187-
self._connection._loop, ws_endpoint, headers, slow_mo
191+
self._connection._loop,
192+
ws_endpoint,
193+
headers,
194+
slow_mo,
195+
lambda: on_ready.set(),
188196
)
189197
connection = Connection(
190198
self._connection._dispatcher_fiber,
@@ -194,9 +202,12 @@ async def connect(
194202
connection._is_sync = self._connection._is_sync
195203
connection._loop = self._connection._loop
196204
connection._loop.create_task(connection.run())
197-
future = connection._loop.create_task(
198-
connection.wait_for_object_with_known_name("Playwright")
199-
)
205+
206+
async def initialize() -> "Playwright":
207+
await on_ready.wait()
208+
return await connection.initialize_playwright()
209+
210+
future = asyncio.create_task(initialize())
200211
timeout_future = throw_on_timeout(timeout, Error("Connection timed out"))
201212
done, pending = await asyncio.wait(
202213
{transport.on_error_future, future, timeout_future},
@@ -206,7 +217,7 @@ async def connect(
206217
future.cancel()
207218
if not timeout_future.done():
208219
timeout_future.cancel()
209-
playwright = next(iter(done)).result()
220+
playwright: "Playwright" = next(iter(done)).result()
210221
self._connection._child_ws_connections.append(connection)
211222
pre_launched_browser = playwright._initializer.get("preLaunchedBrowser")
212223
assert pre_launched_browser

playwright/_impl/_connection.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@
1616
import sys
1717
import traceback
1818
from pathlib import Path
19-
from typing import Any, Callable, Dict, List, Optional, Union
19+
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union
2020

2121
from greenlet import greenlet
2222
from pyee import AsyncIOEventEmitter
2323

2424
from playwright._impl._helper import ParsedMessagePayload, parse_error
2525
from playwright._impl._transport import Transport
2626

27+
if TYPE_CHECKING:
28+
from playwright._impl._playwright import Playwright
29+
2730

2831
class Channel(AsyncIOEventEmitter):
2932
def __init__(self, connection: "Connection", guid: str) -> None:
@@ -119,7 +122,7 @@ def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
119122

120123
class RootChannelOwner(ChannelOwner):
121124
def __init__(self, connection: "Connection") -> None:
122-
super().__init__(connection, "", "", {})
125+
super().__init__(connection, "Root", "", {})
123126

124127

125128
class Connection:
@@ -164,16 +167,15 @@ def cleanup(self) -> None:
164167
for ws_connection in self._child_ws_connections:
165168
ws_connection._transport.dispose()
166169

167-
async def wait_for_object_with_known_name(self, guid: str) -> ChannelOwner:
168-
if guid in self._objects:
169-
return self._objects[guid]
170-
callback: asyncio.Future[ChannelOwner] = self._loop.create_future()
171-
172-
def callback_wrapper(result: ChannelOwner) -> None:
173-
callback.set_result(result)
174-
175-
self._waiting_for_object[guid] = callback_wrapper
176-
return await callback
170+
async def initialize_playwright(self) -> "Playwright":
171+
result = await self._send_message_to_server(
172+
"",
173+
"initialize",
174+
{
175+
"language": "python",
176+
},
177+
).future
178+
return from_channel(result["playwright"])
177179

178180
def call_on_object_with_known_name(
179181
self, guid: str, callback: Callable[[ChannelOwner], None]

playwright/_impl/_transport.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@ def _get_stderr_fileno() -> Optional[int]:
4444

4545

4646
class Transport(ABC):
47-
def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
47+
def __init__(self, loop: asyncio.AbstractEventLoop, on_ready: Callable) -> None:
4848
self._loop = loop
4949
self.on_message: Callable[[ParsedMessagePayload], None] = lambda _: None
5050
self.on_error_future: asyncio.Future = loop.create_future()
51+
self._on_ready = on_ready
5152

5253
@abstractmethod
5354
def request_stop(self) -> None:
@@ -84,9 +85,12 @@ def deserialize_message(self, data: Union[str, bytes]) -> ParsedMessagePayload:
8485

8586
class PipeTransport(Transport):
8687
def __init__(
87-
self, loop: asyncio.AbstractEventLoop, driver_executable: Path
88+
self,
89+
loop: asyncio.AbstractEventLoop,
90+
driver_executable: Path,
91+
on_ready: Callable,
8892
) -> None:
89-
super().__init__(loop)
93+
super().__init__(loop, on_ready)
9094
self._stopped = False
9195
self._driver_executable = driver_executable
9296

@@ -128,6 +132,7 @@ async def run(self) -> None:
128132
assert proc.stdout
129133
assert proc.stdin
130134
self._output = proc.stdin
135+
self._on_ready()
131136

132137
while not self._stopped:
133138
try:
@@ -162,16 +167,18 @@ def __init__(
162167
self,
163168
loop: asyncio.AbstractEventLoop,
164169
ws_endpoint: str,
165-
headers: Dict[str, str] = None,
166-
slow_mo: float = None,
170+
headers: Optional[Dict[str, str]],
171+
slow_mo: Optional[float],
172+
on_ready: Callable,
167173
) -> None:
168-
super().__init__(loop)
169-
Transport.__init__(self, loop)
174+
AsyncIOEventEmitter.__init__(self)
175+
Transport.__init__(self, loop, on_ready)
170176

171177
self._stopped = False
172178
self.ws_endpoint = ws_endpoint
173179
self.headers = headers
174180
self.slow_mo = slow_mo
181+
self._on_ready = on_ready
175182

176183
def request_stop(self) -> None:
177184
self._stopped = True
@@ -192,7 +199,7 @@ async def run(self) -> None:
192199
except Exception as exc:
193200
self.on_error_future.set_exception(Error(f"websocket.connect: {str(exc)}"))
194201
return
195-
202+
self._on_ready()
196203
while not self._stopped:
197204
try:
198205
message = await self._connection.recv()

playwright/async_api/_context_manager.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,22 @@ def __init__(self) -> None:
2828

2929
async def __aenter__(self) -> AsyncPlaywright:
3030
loop = asyncio.get_running_loop()
31+
on_ready = asyncio.Event()
3132
self._connection = Connection(
3233
None,
3334
create_remote_object,
34-
PipeTransport(loop, compute_driver_executable()),
35+
PipeTransport(
36+
loop,
37+
compute_driver_executable(),
38+
lambda: on_ready.set(),
39+
),
3540
)
3641
self._connection._loop = loop
3742
loop.create_task(self._connection.run())
38-
playwright_future = loop.create_task(
39-
self._connection.wait_for_object_with_known_name("Playwright")
43+
await on_ready.wait()
44+
45+
playwright_future = asyncio.create_task(
46+
self._connection.initialize_playwright()
4047
)
4148
done, pending = await asyncio.wait(
4249
{self._connection._transport.on_error_future, playwright_future},

playwright/sync_api/_context_manager.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,14 @@ def greenlet_main() -> None:
5252
loop.close()
5353

5454
dispatcher_fiber = greenlet(greenlet_main)
55+
56+
def on_ready() -> None:
57+
asyncio.ensure_future(self._connection.initialize_playwright())
58+
5559
self._connection = Connection(
5660
dispatcher_fiber,
5761
create_remote_object,
58-
PipeTransport(loop, compute_driver_executable()),
62+
PipeTransport(loop, compute_driver_executable(), on_ready),
5963
)
6064

6165
g_self = greenlet.getcurrent()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
InWheel = None
2929
from wheel.bdist_wheel import bdist_wheel as BDistWheelCommand
3030

31-
driver_version = "1.14.0-1628783206000"
31+
driver_version = "1.15.0-next-1629387074000"
3232

3333

3434
def extractall(zip: zipfile.ZipFile, path: str) -> None:

0 commit comments

Comments
 (0)