Skip to content

Commit 12371da

Browse files
committed
Allow room to sync with provider
1 parent 748bfdf commit 12371da

File tree

10 files changed

+215
-346
lines changed

10 files changed

+215
-346
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ test = [
4848
"hypercorn >=0.16.0",
4949
"trio >=0.25.0",
5050
"sniffio",
51+
"channels",
5152
]
5253
docs = [
5354
"mkdocs",

src/pycrdt/websocket/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from .asgi_server import ASGIServer as ASGIServer
2-
from .websocket_provider import WebsocketProvider as WebsocketProvider
32
from .websocket_server import WebsocketServer as WebsocketServer
43
from .websocket_server import exception_logger as exception_logger
54
from .yroom import YRoom as YRoom

src/pycrdt/websocket/django_channels_consumer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from logging import getLogger
44
from typing import TypedDict
55

6-
from channels.generic.websocket import AsyncWebsocketConsumer # type: ignore[import-not-found]
6+
from channels.generic.websocket import AsyncWebsocketConsumer # type: ignore[import-untyped]
77

88
from pycrdt import (
99
Doc,
@@ -13,12 +13,12 @@
1313
handle_sync_message,
1414
)
1515

16-
from .websocket import Websocket
16+
from pycrdt import Channel
1717

1818
logger = getLogger(__name__)
1919

2020

21-
class _WebsocketShim(Websocket):
21+
class _WebsocketShim(Channel):
2222
def __init__(self, path, send_func) -> None:
2323
self._path = path
2424
self._send_func = send_func

src/pycrdt/websocket/websocket.py

Lines changed: 6 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,12 @@
1-
from typing import Protocol
2-
31
from anyio import Lock
2+
from pycrdt import Channel
43

54

6-
class Websocket(Protocol):
7-
"""WebSocket.
8-
9-
The Websocket instance can receive messages using an async iterator,
10-
until the connection is closed:
11-
```py
12-
async for message in websocket:
13-
...
14-
```
15-
Or directly by calling `recv()`:
16-
```py
17-
message = await websocket.recv()
18-
```
19-
Sending messages is done with `send()`:
20-
```py
21-
await websocket.send(message)
22-
```
23-
"""
24-
25-
@property
26-
def path(self) -> str:
27-
"""The WebSocket path."""
28-
...
29-
30-
def __aiter__(self):
31-
return self
5+
class HttpxWebsocket(Channel):
6+
def __init__(self, websocket, path: str):
7+
self._websocket = websocket
8+
self._path = path
9+
self._send_lock = Lock()
3210

3311
async def __anext__(self) -> bytes:
3412
try:
@@ -38,43 +16,10 @@ async def __anext__(self) -> bytes:
3816

3917
return message
4018

41-
async def send(self, message: bytes) -> None:
42-
"""Send a message.
43-
44-
Arguments:
45-
message: The message to send.
46-
"""
47-
...
48-
49-
async def recv(self) -> bytes:
50-
"""Receive a message.
51-
52-
Returns:
53-
The received message.
54-
"""
55-
...
56-
57-
58-
class HttpxWebsocket(Websocket):
59-
def __init__(self, websocket, path: str):
60-
self._websocket = websocket
61-
self._path = path
62-
self._send_lock = Lock()
63-
6419
@property
6520
def path(self) -> str:
6621
return self._path
6722

68-
def __aiter__(self):
69-
return self
70-
71-
async def __anext__(self) -> bytes:
72-
try:
73-
message = await self.recv()
74-
except Exception:
75-
raise StopAsyncIteration()
76-
return message
77-
7823
async def send(self, message: bytes):
7924
async with self._send_lock:
8025
await self._websocket.send_bytes(message)

src/pycrdt/websocket/websocket_provider.py

Lines changed: 0 additions & 170 deletions
This file was deleted.

src/pycrdt/websocket/websocket_server.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
from anyio import TASK_STATUS_IGNORED, Event, Lock, create_task_group
99
from anyio.abc import TaskGroup, TaskStatus
10+
from pycrdt import Channel, Doc, Provider
1011

11-
from .websocket import Websocket
12-
from .yroom import YRoom
12+
from .yroom import ProviderFactory, YRoom
1313

1414

1515
class WebsocketServer:
@@ -28,6 +28,7 @@ def __init__(
2828
auto_clean_rooms: bool = True,
2929
exception_handler: Callable[[Exception, Logger], bool] | None = None,
3030
log: Logger | None = None,
31+
provider_factory: ProviderFactory | None = None,
3132
) -> None:
3233
"""Initialize the object.
3334
@@ -50,11 +51,13 @@ def __init__(
5051
exception_handler: An optional callback to call when an exception is raised, that
5152
returns True if the exception was handled.
5253
log: An optional logger.
54+
provider_factory: An optional provider factory used to synchronize the rooms with external documents.
5355
"""
5456
self.rooms_ready = rooms_ready
5557
self.auto_clean_rooms = auto_clean_rooms
5658
self.exception_handler = exception_handler
5759
self.log = log or getLogger(__name__)
60+
self.provider_factory = provider_factory
5861
self.rooms = {}
5962
self._stopped = Event()
6063

@@ -81,7 +84,8 @@ async def get_room(self, name: str) -> YRoom:
8184
The room with the given name, or a new one if no room with that name was found.
8285
"""
8386
if name not in self.rooms.keys():
84-
self.rooms[name] = YRoom(ready=self.rooms_ready, log=self.log)
87+
provider_factory = partial(self.provider_factory, path=name) if self.provider_factory is not None else None
88+
self.rooms[name] = YRoom(ready=self.rooms_ready, log=self.log, provider_factory=provider_factory)
8589
room = self.rooms[name]
8690
await self.start_room(room)
8791
return room
@@ -144,7 +148,7 @@ async def delete_room(self, *, name: str | None = None, room: YRoom | None = Non
144148
room = self.rooms.pop(name)
145149
await room.stop()
146150

147-
async def serve(self, websocket: Websocket) -> None:
151+
async def serve(self, websocket: Channel) -> None:
148152
"""Serve a client through a WebSocket.
149153
150154
Arguments:

0 commit comments

Comments
 (0)