Skip to content

Commit

Permalink
Update client/server examples (#95)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidbrochart authored Dec 10, 2024
1 parent 4b1bffd commit 3a74f65
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 30 deletions.
10 changes: 6 additions & 4 deletions docs/usage/client.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
A client connects their `Doc` through a [WebsocketProvider](../reference/WebSocket_provider.md).

Here is a code example using the [websockets](https://websockets.readthedocs.io) library:
Here is a code example using the [httpx-ws](https://frankie567.github.io/httpx-ws) library:
```py
import asyncio
from websockets import connect
from httpx_ws import aconnect_ws
from pycrdt import Doc, Map
from pycrdt_websocket import WebsocketProvider
from pycrdt_websocket.websocket import HttpxWebsocket

async def client():
ydoc = Doc()
ymap = ydoc.get("map", type=Map)
room_name = "my-roomname"
async with (
connect("ws://localhost:1234/my-roomname") as websocket,
WebsocketProvider(ydoc, websocket),
aconnect_ws(f"http://localhost:1234/{room_name}") as websocket,
WebsocketProvider(ydoc, HttpxWebsocket(websocket, room_name)),
):
# Changes to remote ydoc are applied to local ydoc.
# Changes to local ydoc are sent over the WebSocket and
Expand Down
35 changes: 9 additions & 26 deletions docs/usage/server.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,22 @@
A server connects multiple `YDoc` through a [WebsocketServer](../reference/WebSocket_server.md).
A server connects multiple `Doc` through a [WebsocketServer](../reference/WebSocket_server.md).

Here is a code example using the [websockets](https://websockets.readthedocs.io) library:
Pycrdt-websocket can be used with an [ASGI](https://asgi.readthedocs.io) server. Here is a code example using [Hypercorn](https://hypercorn.readthedocs.io):
```py
import asyncio
from websockets import serve
from pycrdt_websocket import WebsocketServer

async def server():
async with (
WebsocketServer() as websocket_server,
serve(websocket_server.serve, "localhost", 1234),
):
await asyncio.Future() # run forever

asyncio.run(server())
```
Pycrdt-websocket can also be used with an [ASGI](https://asgi.readthedocs.io) server. Here is a code example using [Uvicorn](https://www.uvicorn.org):
```py
# main.py
import asyncio
import uvicorn
from hypercorn import Config
from hypercorn.asyncio import serve
from pycrdt_websocket import ASGIServer, WebsocketServer

websocket_server = WebsocketServer()
app = ASGIServer(websocket_server)

async def main():
config = uvicorn.Config("main:app", port=5000, log_level="info")
server = uvicorn.Server(config)
websocket_server = WebsocketServer()
app = ASGIServer(websocket_server)
config = Config()
config.bind = ["localhost:1234"]
async with websocket_server:
task = asyncio.create_task(server.serve())
while not server.started:
await asyncio.sleep(0)

await asyncio.Future() # run forever
await serve(app, config, mode="asgi")

asyncio.run(main())
```
31 changes: 31 additions & 0 deletions pycrdt_websocket/websocket.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from typing import Protocol

from anyio import Lock


class Websocket(Protocol):
"""WebSocket.
Expand Down Expand Up @@ -51,3 +53,32 @@ async def recv(self) -> bytes:
The received message.
"""
...


class HttpxWebsocket(Websocket):
def __init__(self, websocket, path: str):
self._websocket = websocket
self._path = path
self._send_lock = Lock()

@property
def path(self) -> str:
return self._path

def __aiter__(self):
return self

async def __anext__(self) -> bytes:
try:
message = await self.recv()
except Exception:
raise StopAsyncIteration()
return message

async def send(self, message: bytes):
async with self._send_lock:
await self._websocket.send_bytes(message)

async def recv(self) -> bytes:
b = await self._websocket.receive_bytes()
return bytes(b)

0 comments on commit 3a74f65

Please sign in to comment.