Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 65 additions & 15 deletions docs_src/src/pages/documentation/en/api_reference/websockets.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,18 @@ To handle real-time bidirectional communication, Batman learned how to work with

---

## Receiving Messages {{ tag: 'receive_text', label: 'receive_text' }}
## Receiving Messages {{ tag: 'receive', label: 'receive' }}

<Row>
<Col>
The `receive_text()` method blocks until the next message arrives from the client. It is backed by a Rust `tokio::mpsc` channel, so the Python handler genuinely suspends without holding the GIL.
Robyn provides several methods for receiving WebSocket messages, all backed by a Rust `tokio::mpsc` channel so the Python handler genuinely suspends without holding the GIL.

When the client disconnects, `receive_text()` raises `WebSocketDisconnect`. You can either catch it explicitly or let the internal wrapper handle it silently.
- `receive()` returns the next frame as `str` (text frame) or `bytes` (binary frame).
- `receive_text()` returns the next text frame, raising `TypeError` if a binary frame arrives.
- `receive_bytes()` returns the next binary frame, raising `TypeError` if a text frame arrives.
- `receive_json()` receives a text frame and JSON-decodes it.

All receive methods raise `WebSocketDisconnect` when the client disconnects. You can either catch it explicitly or let the internal wrapper handle it silently.
</Col>
<Col sticky>
<CodeGroup title="Receiving Messages" tag="WebSocket" label="/web_socket">
Expand All @@ -82,6 +87,26 @@ To handle real-time bidirectional communication, Batman learned how to work with
print(f"Client {websocket.id} disconnected")
```

```python {{ title: 'Binary Messages' }}
@app.websocket("/ws")
async def handler(websocket):
while True:
data = await websocket.receive_bytes()
result = process(data)
await websocket.send_bytes(result)
```

```python {{ title: 'Mixed Frames' }}
@app.websocket("/ws")
async def handler(websocket):
while True:
msg = await websocket.receive()
if isinstance(msg, str):
await websocket.send_text(f"Got text: {msg}")
else:
await websocket.send_bytes(msg) # echo binary
```

```python {{ title: 'JSON Messages' }}
@app.websocket("/api")
async def handler(websocket):
Expand All @@ -96,11 +121,16 @@ To handle real-time bidirectional communication, Batman learned how to work with

---

## Sending Messages {{ tag: 'send_text', label: 'send_text' }}
## Sending Messages {{ tag: 'send', label: 'send' }}

<Row>
<Col>
To send a message to the current client, use `send_text()` or `send_json()`. All send methods are async.
To send a message to the current client, use any of the send methods. All are async.

- `send(data)` accepts `str` or `bytes` — a `str` sends a text frame, `bytes` sends a binary frame.
- `send_text(data)` sends a text frame.
- `send_bytes(data)` sends a binary frame.
- `send_json(data)` serializes to JSON and sends a text frame.
</Col>
<Col sticky>
<CodeGroup title="Sending Messages" tag="WebSocket" label="/web_socket">
Expand All @@ -113,6 +143,15 @@ To handle real-time bidirectional communication, Batman learned how to work with
await websocket.send_text(f"Echo: {msg}")
```

```python {{ title: 'Send Binary' }}
@app.websocket("/ws")
async def handler(websocket):
while True:
data = await websocket.receive_bytes()
compressed = zlib.compress(data)
await websocket.send_bytes(compressed)
```

```python {{ title: 'Send JSON' }}
@app.websocket("/ws")
async def handler(websocket):
Expand All @@ -130,12 +169,12 @@ To handle real-time bidirectional communication, Batman learned how to work with

<Row>
<Col>
To send a message to all connected clients on the same WebSocket endpoint, use the `broadcast()` method.
To send a message to all connected clients on the same WebSocket endpoint, use the `broadcast()` method. It accepts both `str` (text frame) and `bytes` (binary frame).
</Col>
<Col sticky>
<CodeGroup title="Broadcasting" tag="WebSocket" label="/chat">

```python {{ title: 'Broadcast' }}
```python {{ title: 'Broadcast Text' }}
@app.websocket("/chat")
async def handler(websocket):
while True:
Expand All @@ -145,6 +184,15 @@ To handle real-time bidirectional communication, Batman learned how to work with
# Also send a confirmation to this client only
await websocket.send_text("Your message was sent")
```

```python {{ title: 'Broadcast Binary' }}
@app.websocket("/stream")
async def handler(websocket):
while True:
data = await websocket.receive_bytes()
# Broadcast binary data to all clients
await websocket.broadcast(data)
```
</CodeGroup>
</Col>
</Row>
Expand Down Expand Up @@ -225,7 +273,7 @@ To handle real-time bidirectional communication, Batman learned how to work with
To programmatically close a WebSocket connection from the server side, use `websocket.close()`. This will:
1. Close the WebSocket connection.
2. Remove the client from the WebSocket registry.
3. Cause any pending `receive_text()` to raise `WebSocketDisconnect`.
3. Cause any pending `receive()` / `receive_text()` / `receive_bytes()` to raise `WebSocketDisconnect`.
</Col>
<Col sticky>
<CodeGroup title="Close Connection" tag="WebSocket" label="/ws">
Expand Down Expand Up @@ -289,13 +337,15 @@ To handle real-time bidirectional communication, Batman learned how to work with

| Method / Property | Description |
|---|---|
| `await websocket.receive_text()` | Block until next message; raises `WebSocketDisconnect` on close |
| `await websocket.receive_bytes()` | Block until next binary message; raises `WebSocketDisconnect` on close |
| `await websocket.receive_json()` | Same as `receive_text()` but JSON-decoded |
| `await websocket.send_text(data)` | Send string to this client |
| `await websocket.send_bytes(data)` | Send binary data to this client |
| `await websocket.send_json(data)` | Send JSON to this client |
| `await websocket.broadcast(data)` | Send to all clients on this endpoint |
| `await websocket.receive()` | Block until next frame; returns `str` for text frames, `bytes` for binary frames; raises `WebSocketDisconnect` on close |
| `await websocket.receive_text()` | Block until next text frame; raises `TypeError` if a binary frame arrives; raises `WebSocketDisconnect` on close |
| `await websocket.receive_bytes()` | Block until next binary frame; raises `TypeError` if a text frame arrives; raises `WebSocketDisconnect` on close |
| `await websocket.receive_json()` | Receive a text frame and JSON-decode it |
| `await websocket.send(data)` | Send `str` as a text frame or `bytes` as a binary frame |
| `await websocket.send_text(data)` | Send a text frame to this client |
| `await websocket.send_bytes(data)` | Send a binary frame to this client |
| `await websocket.send_json(data)` | Send JSON as a text frame to this client |
| `await websocket.broadcast(data)` | Broadcast `str` (text) or `bytes` (binary) to all clients on this endpoint |
| `await websocket.close()` | Close the connection server-side |
| `websocket.id` | Connection UUID string |
| `websocket.query_params` | Query parameters from the connection URL |
Expand Down
80 changes: 65 additions & 15 deletions docs_src/src/pages/documentation/zh/api_reference/websockets.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,18 @@ export const description =

---

## 接收消息 {{ tag: 'receive_text', label: 'receive_text' }}
## 接收消息 {{ tag: 'receive', label: 'receive' }}

<Row>
<Col>
`receive_text()` 方法会阻塞直到下一条消息到达。它由 Rust 的 `tokio::mpsc` 通道支持,因此 Python 处理程序在等待时不会持有 GIL。
Robyn 提供了多种接收 WebSocket 消息的方法,所有方法都由 Rust 的 `tokio::mpsc` 通道支持,因此 Python 处理程序在等待时不会持有 GIL。

当客户端断开连接时,`receive_text()` 会抛出 `WebSocketDisconnect` 异常。您可以显式捕获它,也可以让内部包装器静默处理。
- `receive()` 返回下一帧,文本帧返回 `str`,二进制帧返回 `bytes`。
- `receive_text()` 返回下一个文本帧,如果收到二进制帧则抛出 `TypeError`。
- `receive_bytes()` 返回下一个二进制帧,如果收到文本帧则抛出 `TypeError`。
- `receive_json()` 接收文本帧并进行 JSON 解码。

所有接收方法在客户端断开连接时都会抛出 `WebSocketDisconnect` 异常。您可以显式捕获它,也可以让内部包装器静默处理。
</Col>
<Col sticky>
<CodeGroup title="接收消息" tag="WebSocket" label="/web_socket">
Expand All @@ -79,6 +84,26 @@ export const description =
print(f"客户端 {websocket.id} 已断开")
```

```python {{ title: '二进制消息' }}
@app.websocket("/ws")
async def handler(websocket):
while True:
data = await websocket.receive_bytes()
result = process(data)
await websocket.send_bytes(result)
```

```python {{ title: '混合帧' }}
@app.websocket("/ws")
async def handler(websocket):
while True:
msg = await websocket.receive()
if isinstance(msg, str):
await websocket.send_text(f"收到文本: {msg}")
else:
await websocket.send_bytes(msg) # 回显二进制
```

```python {{ title: 'JSON 消息' }}
@app.websocket("/api")
async def handler(websocket):
Expand All @@ -93,11 +118,16 @@ export const description =

---

## 发送消息 {{ tag: 'send_text', label: 'send_text' }}
## 发送消息 {{ tag: 'send', label: 'send' }}

<Row>
<Col>
使用 `send_text()` 或 `send_json()` 向当前客户端发送消息。所有发送方法都是异步的。
使用以下方法向当前客户端发送消息。所有方法都是异步的。

- `send(data)` 接受 `str` 或 `bytes` — `str` 发送文本帧,`bytes` 发送二进制帧。
- `send_text(data)` 发送文本帧。
- `send_bytes(data)` 发送二进制帧。
- `send_json(data)` 序列化为 JSON 并发送文本帧。
</Col>
<Col sticky>
<CodeGroup title="发送消息" tag="WebSocket" label="/web_socket">
Expand All @@ -110,6 +140,15 @@ export const description =
await websocket.send_text(f"Echo: {msg}")
```

```python {{ title: '发送二进制' }}
@app.websocket("/ws")
async def handler(websocket):
while True:
data = await websocket.receive_bytes()
compressed = zlib.compress(data)
await websocket.send_bytes(compressed)
```

```python {{ title: '发送 JSON' }}
@app.websocket("/ws")
async def handler(websocket):
Expand All @@ -127,12 +166,12 @@ export const description =

<Row>
<Col>
使用 `broadcast()` 方法向同一 WebSocket 端点上的所有已连接客户端发送消息。
使用 `broadcast()` 方法向同一 WebSocket 端点上的所有已连接客户端发送消息。它同时接受 `str`(文本帧)和 `bytes`(二进制帧)。
</Col>
<Col sticky>
<CodeGroup title="广播" tag="WebSocket" label="/chat">

```python {{ title: '广播' }}
```python {{ title: '广播文本' }}
@app.websocket("/chat")
async def handler(websocket):
while True:
Expand All @@ -142,6 +181,15 @@ export const description =
# 仅向当前客户端发送确认
await websocket.send_text("您的消息已发送")
```

```python {{ title: '广播二进制' }}
@app.websocket("/stream")
async def handler(websocket):
while True:
data = await websocket.receive_bytes()
# 向所有客户端广播二进制数据
await websocket.broadcast(data)
```
</CodeGroup>
</Col>
</Row>
Expand Down Expand Up @@ -222,7 +270,7 @@ export const description =
使用 `websocket.close()` 从服务端关闭 WebSocket 连接。该方法将:
1. 关闭 WebSocket 连接。
2. 从 WebSocket 注册表中移除客户端。
3. 使任何挂起的 `receive_text()` 抛出 `WebSocketDisconnect` 异常。
3. 使任何挂起的 `receive()` / `receive_text()` / `receive_bytes()` 抛出 `WebSocketDisconnect` 异常。
</Col>
<Col sticky>
<CodeGroup title="关闭连接" tag="WebSocket" label="/ws">
Expand Down Expand Up @@ -286,13 +334,15 @@ export const description =

| 方法 / 属性 | 描述 |
|---|---|
| `await websocket.receive_text()` | 阻塞直到下一条消息;连接关闭时抛出 `WebSocketDisconnect` |
| `await websocket.receive_bytes()` | 阻塞直到下一条二进制消息;连接关闭时抛出 `WebSocketDisconnect` |
| `await websocket.receive_json()` | 与 `receive_text()` 相同,但返回 JSON 解码后的数据 |
| `await websocket.send_text(data)` | 向当前客户端发送文本 |
| `await websocket.send_bytes(data)` | 向当前客户端发送二进制数据 |
| `await websocket.send_json(data)` | 向当前客户端发送 JSON |
| `await websocket.broadcast(data)` | 向此端点的所有客户端广播 |
| `await websocket.receive()` | 阻塞直到下一帧;文本帧返回 `str`,二进制帧返回 `bytes`;连接关闭时抛出 `WebSocketDisconnect` |
| `await websocket.receive_text()` | 阻塞直到下一个文本帧;收到二进制帧时抛出 `TypeError`;连接关闭时抛出 `WebSocketDisconnect` |
| `await websocket.receive_bytes()` | 阻塞直到下一个二进制帧;收到文本帧时抛出 `TypeError`;连接关闭时抛出 `WebSocketDisconnect` |
| `await websocket.receive_json()` | 接收文本帧并进行 JSON 解码 |
| `await websocket.send(data)` | 发送 `str` 为文本帧或 `bytes` 为二进制帧 |
| `await websocket.send_text(data)` | 向当前客户端发送文本帧 |
| `await websocket.send_bytes(data)` | 向当前客户端发送二进制帧 |
| `await websocket.send_json(data)` | 向当前客户端发送 JSON 文本帧 |
| `await websocket.broadcast(data)` | 向此端点的所有客户端广播 `str`(文本)或 `bytes`(二进制) |
| `await websocket.close()` | 从服务端关闭连接 |
| `websocket.id` | 连接 UUID 字符串 |
| `websocket.query_params` | 连接 URL 中的查询参数 |
Expand Down
20 changes: 10 additions & 10 deletions robyn/robyn.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -534,38 +534,38 @@ class WebSocketConnector:
id: str
query_params: QueryParams

async def async_broadcast(self, message: str) -> None:
async def async_broadcast(self, message: str | bytes) -> None:
"""
Broadcasts a message to all clients.

Args:
message (str): The message to broadcast
message (str | bytes): The message to broadcast. str sends a text frame, bytes sends a binary frame.
"""
pass
async def async_send_to(self, sender_id: str, message: str) -> None:
async def async_send_to(self, recipient_id: str, message: str | bytes) -> None:
"""
Sends a message to a specific client.

Args:
sender_id (str): The id of the sender
message (str): The message to send
recipient_id (str): The id of the recipient
message (str | bytes): The message to send. str sends a text frame, bytes sends a binary frame.
"""
pass
def sync_broadcast(self, message: str) -> None:
def sync_broadcast(self, message: str | bytes) -> None:
"""
Broadcasts a message to all clients.

Args:
message (str): The message to broadcast
message (str | bytes): The message to broadcast. str sends a text frame, bytes sends a binary frame.
"""
pass
def sync_send_to(self, sender_id: str, message: str) -> None:
def sync_send_to(self, recipient_id: str, message: str | bytes) -> None:
"""
Sends a message to a specific client.

Args:
sender_id (str): The id of the sender
message (str): The message to send
recipient_id (str): The id of the recipient
message (str | bytes): The message to send. str sends a text frame, bytes sends a binary frame.
"""
pass
def close(self) -> None:
Expand Down
Loading
Loading