Skip to content

Commit 49ed0e9

Browse files
feat: Adds rust example for websocket
1 parent a62439a commit 49ed0e9

File tree

1 file changed

+111
-7
lines changed

1 file changed

+111
-7
lines changed

src/content/docs/workers/examples/websockets.mdx

Lines changed: 111 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
---
22
type: example
3-
summary: Use the WebSockets API to communicate in real time with your Cloudflare
4-
Workers.
3+
summary: Use the WebSockets API to communicate in real time with your Cloudflare Workers.
54
tags:
65
- WebSockets
76
languages:
7+
- Rust
88
- JavaScript
99
pcx_content_type: example
1010
title: Using the WebSockets API
1111
sidebar:
1212
order: 10000
13-
description: Use the WebSockets API to communicate in real time with your
14-
Cloudflare Workers.
15-
13+
description: Use the WebSockets API to communicate in real time with your Cloudflare Workers.
1614
---
1715

16+
import { TabItem, Tabs } from "~/components";
17+
1818
WebSockets allow you to communicate in real time with your Cloudflare Workers serverless functions. In this guide, you will learn the basics of WebSockets on Cloudflare Workers, both from the perspective of writing WebSocket servers in your Workers functions, as well as connecting to and working with those WebSocket servers as a client.
1919

2020
WebSockets are open connections sustained between the client and the origin server. Inside a WebSocket connection, the client and the origin can pass data back and forth without having to reestablish sessions. This makes exchanging data within a WebSocket connection fast. WebSockets are often used for real-time applications such as live chat and gaming.
@@ -56,6 +56,7 @@ For more details about creating and working with WebSockets in the client, refer
5656

5757
When an incoming WebSocket request reaches the Workers function, it will contain an `Upgrade` header, set to the string value `websocket`. Check for this header before continuing to instantiate a WebSocket:
5858

59+
<Tabs syncKey="workersExamples"> <TabItem label="JavaScript" icon="seti:javascript">
5960
```js
6061
async function handleRequest(request) {
6162
const upgradeHeader = request.headers.get('Upgrade');
@@ -64,9 +65,27 @@ async function handleRequest(request) {
6465
}
6566
}
6667
```
67-
68+
</TabItem> <TabItem label="Rust" icon="seti:rust">
69+
```rs
70+
71+
use worker::*;
72+
73+
#[event(fetch)]
74+
async fn fetch(req: HttpRequest, _env: Env, _ctx: Context) -> Result<worker::Response> {
75+
let upgrade_header = match req.headers().get("Upgrade") {
76+
Some(h) => h.to_str().unwrap(),
77+
None => "",
78+
};
79+
if upgrade_header != "websocket" {
80+
return worker::Response::error("Expected Upgrade: websocket", 426);
81+
}
82+
}
83+
```
84+
</TabItem> </Tabs>
6885
After you have appropriately checked for the `Upgrade` header, you can create a new instance of `WebSocketPair`, which contains server and client WebSockets. One of these WebSockets should be handled by the Workers function and the other should be returned as part of a `Response` with the [`101` status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/101), indicating the request is switching protocols:
6986

87+
88+
<Tabs syncKey="workersExamples"> <TabItem label="JavaScript" icon="seti:javascript">
7089
```js
7190
async function handleRequest(request) {
7291
const upgradeHeader = request.headers.get('Upgrade');
@@ -84,11 +103,37 @@ async function handleRequest(request) {
84103
});
85104
}
86105
```
106+
</TabItem> <TabItem label="Rust" icon="seti:rust">
107+
```rs
108+
use worker::*;
109+
110+
#[event(fetch)]
111+
async fn fetch(req: HttpRequest, _env: Env, _ctx: Context) -> Result<worker::Response> {
112+
let upgrade_header = match req.headers().get("Upgrade") {
113+
Some(h) => h.to_str().unwrap(),
114+
None => "",
115+
};
116+
if upgrade_header != "websocket" {
117+
return worker::Response::error("Expected Upgrade: websocket", 426);
118+
}
119+
120+
let ws = WebSocketPair::new()?;
121+
let client = ws.client;
122+
let server = ws.server;
123+
server.accept()?;
124+
125+
worker::Response::from_websocket(client)
126+
}
127+
128+
```
129+
</TabItem> </Tabs>
87130

88131
The `WebSocketPair` constructor returns an Object, with the `0` and `1` keys each holding a `WebSocket` instance as its value. It is common to grab the two WebSockets from this pair using [`Object.values`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values) and [ES6 destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment), as seen in the below example.
89132

90133
In order to begin communicating with the `client` WebSocket in your Worker, call `accept` on the `server` WebSocket. This will tell the Workers runtime that it should listen for WebSocket data and keep the connection open with your `client` WebSocket:
91134

135+
136+
<Tabs syncKey="workersExamples"> <TabItem label="JavaScript" icon="seti:javascript">
92137
```js
93138
async function handleRequest(request) {
94139
const upgradeHeader = request.headers.get('Upgrade');
@@ -107,9 +152,34 @@ async function handleRequest(request) {
107152
});
108153
}
109154
```
155+
</TabItem> <TabItem label="Rust" icon="seti:rust">
156+
```rs
157+
use worker::*;
158+
159+
#[event(fetch)]
160+
async fn fetch(req: HttpRequest, _env: Env, _ctx: Context) -> Result<worker::Response> {
161+
let upgrade_header = match req.headers().get("Upgrade") {
162+
Some(h) => h.to_str().unwrap(),
163+
None => "",
164+
};
165+
if upgrade_header != "websocket" {
166+
return worker::Response::error("Expected Upgrade: websocket", 426);
167+
}
168+
169+
let ws = WebSocketPair::new()?;
170+
let client = ws.client;
171+
let server = ws.server;
172+
server.accept()?;
173+
174+
worker::Response::from_websocket(client)
175+
}
176+
177+
```
178+
</TabItem> </Tabs>
110179

111180
WebSockets emit a number of [Events](/workers/runtime-apis/websockets/#events) that can be connected to using `addEventListener`. The below example hooks into the `message` event and emits a `console.log` with the data from it:
112181

182+
<Tabs syncKey="workersExamples"> <TabItem label="JavaScript" icon="seti:javascript">
113183
```js
114184
async function handleRequest(request) {
115185
const upgradeHeader = request.headers.get('Upgrade');
@@ -131,6 +201,40 @@ async function handleRequest(request) {
131201
});
132202
}
133203
```
204+
</TabItem> <TabItem label="Rust" icon="seti:rust">
205+
```rs
206+
use futures::StreamExt;
207+
use worker::*;
208+
209+
#[event(fetch)]
210+
async fn fetch(req: HttpRequest, _env: Env, _ctx: Context) -> Result<worker::Response> {
211+
let upgrade_header = match req.headers().get("Upgrade") {
212+
Some(h) => h.to_str().unwrap(),
213+
None => "",
214+
};
215+
if upgrade_header != "websocket" {
216+
return worker::Response::error("Expected Upgrade: websocket", 426);
217+
}
218+
219+
let ws = WebSocketPair::new()?;
220+
let client = ws.client;
221+
let server = ws.server;
222+
server.accept()?;
223+
224+
wasm_bindgen_futures::spawn_local(async move {
225+
let mut event_stream = server.events().expect("could not open stream");
226+
while let Some(event) = event_stream.next().await {
227+
match event.expect("received error in websocket") {
228+
WebsocketEvent::Message(msg) => server.send(&msg.text()).unwrap(),
229+
WebsocketEvent::Close(event) => console_log!("{:?}", event),
230+
}
231+
}
232+
});
233+
worker::Response::from_websocket(client)
234+
}
235+
236+
```
237+
</TabItem> </Tabs>
134238

135239
### Connect to the WebSocket server from a client
136240

@@ -196,4 +300,4 @@ async function websocket(url) {
196300

197301
## WebSocket compression
198302

199-
Cloudflare Workers supports WebSocket compression. Refer to [WebSocket Compression](/workers/configuration/compatibility-dates/#websocket-compression) for more information.
303+
Cloudflare Workers supports WebSocket compression. Refer to [WebSocket Compression](/workers/configuration/compatibility-dates/#websocket-compression) for more information.

0 commit comments

Comments
 (0)