Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebSocket support #124

Merged
merged 9 commits into from
Jan 28, 2022
Merged
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
27 changes: 27 additions & 0 deletions worker-sandbox/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,33 @@ pub async fn main(req: Request, env: Env, _ctx: worker::Context) -> Result<Respo
router
.get("/request", handle_a_request) // can pass a fn pointer to keep routes tidy
.get_async("/async-request", handle_async_request)
.get("/websocket", |_, _| {
// Accept / handle a websocket connection
let pair = WebSocketPair::new()?;
let server = pair.server;
server.accept()?;
server.send_with_str("Hi")?;
server.send_with_str("Other message")?;
let inner_server = server.clone();
server.on_message_async(move |event| {
let server = inner_server.clone();
async move {
server
.send_with_str(event.get_data().as_string().unwrap())
.unwrap();
console_log!("Message received");
}
})?;
server.on_close(|close| {
console_log!("{:?}", close);
})?;
server.on_error(|error| {
console_log!("{:?}", error);
})?;
Ok(Response::empty()?
.with_status(101)
.with_websocket(Some(pair.client)))
})
.get("/test-data", |_, ctx| {
// just here to test data works
if ctx.data.regex.is_match("2014-01-01") {
Expand Down
6 changes: 5 additions & 1 deletion worker-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ features = [
"ReadableStream",
"RequestRedirect",
"RequestInit",
"ResponseInit",
"FormData",
"Blob",
"BinaryType",
"ErrorEvent",
"MessageEvent",
"CloseEvent",
"ProgressEvent",
]
6 changes: 5 additions & 1 deletion worker-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ pub mod headers;
pub mod request;
pub mod request_init;
pub mod response;
pub mod response_init;
pub mod schedule;
pub mod websocket;

/// When debugging your Worker via `wrangler dev`, `wrangler tail`, or from the Workers Dashboard,
/// anything passed to this macro will be printed to the terminal or written to the console.
Expand Down Expand Up @@ -63,5 +65,7 @@ pub use headers::Headers;
pub use request::Request;
pub use request_init::*;
pub use response::Response;
pub use response_init::ResponseInit;
pub use schedule::*;
pub use web_sys::ResponseInit;
pub use web_sys::{CloseEvent, ErrorEvent, MessageEvent};
pub use websocket::*;
12 changes: 8 additions & 4 deletions worker-sys/src/response.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::response_init::ResponseInit;
use crate::FormData;
use crate::ResponseInit;

use js_sys::Uint8Array;
use wasm_bindgen::prelude::*;
Expand Down Expand Up @@ -34,6 +34,10 @@ extern "C" {
#[doc = "Getter for the `headers` field of this object."]
pub fn headers(this: &Response) -> crate::headers::Headers;

#[wasm_bindgen(structural, method, getter, js_class=Response, js_name=webSocket)]
#[doc = "Getter for the `webSocket` field of this object."]
pub fn websocket(this: &Response) -> Option<crate::websocket::WebSocket>;

#[wasm_bindgen(structural, method, getter, js_class=Response, js_name=bodyUsed)]
#[doc = "Getter for the `bodyUsed` field of this object."]
pub fn body_used(this: &Response) -> bool;
Expand Down Expand Up @@ -62,7 +66,7 @@ extern "C" {
#[doc = "The `new Response(..)` constructor, creating a new instance of `Response`."]
pub fn new_with_opt_u8_array_and_init(
body: Option<Uint8Array>,
init: &web_sys::ResponseInit,
init: &ResponseInit,
) -> Result<Response, JsValue>;

#[wasm_bindgen(catch, constructor, js_class=Response)]
Expand All @@ -76,14 +80,14 @@ extern "C" {
#[doc = "The `new Response(..)` constructor, creating a new instance of `Response`."]
pub fn new_with_opt_str_and_init(
body: Option<&str>,
init: &web_sys::ResponseInit,
init: &ResponseInit,
) -> Result<Response, JsValue>;

#[wasm_bindgen(catch, constructor, js_class=Response)]
#[doc = "The `new Response(..)` constructor, creating a new instance of `Response`."]
pub fn new_with_opt_stream_and_init(
body: Option<web_sys::ReadableStream>,
init: &web_sys::ResponseInit,
init: &ResponseInit,
) -> Result<Response, JsValue>;

#[wasm_bindgen(catch, method, structural, js_class=Response, js_name=clone)]
Expand Down
75 changes: 75 additions & 0 deletions worker-sys/src/response_init.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use crate::websocket::WebSocket;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(extends = js_sys::Object , js_name = ResponseInit)]
#[derive(Debug, Clone, PartialEq, Eq)]
#[doc = "The `ResponseInit` dictionary."]
pub type ResponseInit;
}
impl ResponseInit {
#[doc = "Construct a new `ResponseInit`."]
pub fn new() -> Self {
#[allow(unused_mut)]
let mut ret: Self = wasm_bindgen::JsCast::unchecked_into(js_sys::Object::new());
ret
}

#[doc = "Change the `headers` field of this object."]
pub fn headers(&mut self, val: &::wasm_bindgen::JsValue) -> &mut Self {
let r = js_sys::Reflect::set(
self.as_ref(),
&JsValue::from("headers"),
&JsValue::from(val),
);
debug_assert!(
r.is_ok(),
"setting properties should never fail on our dictionary objects"
);
let _ = r;
self
}

#[doc = "Change the `status` field of this object."]
pub fn status(&mut self, val: u16) -> &mut Self {
let r = js_sys::Reflect::set(self.as_ref(), &JsValue::from("status"), &JsValue::from(val));
debug_assert!(
r.is_ok(),
"setting properties should never fail on our dictionary objects"
);
let _ = r;
self
}

#[doc = "Change the `statusText` field of this object."]
pub fn status_text(&mut self, val: &str) -> &mut Self {
let r = js_sys::Reflect::set(
self.as_ref(),
&JsValue::from("statusText"),
&JsValue::from(val),
);
debug_assert!(
r.is_ok(),
"setting properties should never fail on our dictionary objects"
);
let _ = r;
self
}

#[doc = "Change the `webSocket` field of this object."]
pub fn websocket(&mut self, val: &WebSocket) -> &mut Self {
let r = js_sys::Reflect::set(self.as_ref(), &JsValue::from("webSocket"), val.as_ref());
debug_assert!(
r.is_ok(),
"setting properties should never fail on our dictionary objects"
);
let _ = r;
self
}
}
impl Default for ResponseInit {
fn default() -> Self {
Self::new()
}
}
89 changes: 89 additions & 0 deletions worker-sys/src/websocket.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use crate::global::EventTarget;
use js_sys::Uint8Array;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {

#[wasm_bindgen(extends = js_sys::Object, js_name = WebSocketPair)]
#[derive(Debug, Clone, PartialEq, Eq)]
#[doc = "The `WebSocketPair` dictionary."]
pub type WebSocketPair;

#[wasm_bindgen(constructor, js_class = WebSocketPair)]
pub fn new() -> WebSocketPair;
}

impl WebSocketPair {
pub fn client(&mut self) -> Result<WebSocket, JsValue> {
let value = ::js_sys::Reflect::get(self.as_ref(), &JsValue::from("0"))?;
Ok(WebSocket::from(value))
}

pub fn server(&mut self) -> Result<WebSocket, JsValue> {
let value = ::js_sys::Reflect::get(self.as_ref(), &JsValue::from("1"))?;
Ok(WebSocket::from(value))
}
}

#[wasm_bindgen]
extern "C" {

#[wasm_bindgen(extends = EventTarget, extends = js_sys::Object, js_name = WebSocket)]
#[derive(Debug, Clone, PartialEq, Eq)]
#[doc = "The `WebSocket` class."]
#[doc = ""]
#[doc = "[MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)"]
pub type WebSocket;

#[wasm_bindgen(catch, structural, method, js_class = "WebSocket", js_name = accept)]
#[doc = "Accepts the server side of the WebSocket."]
#[doc = ""]
#[doc = "[CF Documentation](https://developers.cloudflare.com/workers/runtime-apis/websockets#accept)"]
pub fn accept(this: &WebSocket) -> Result<(), JsValue>;

#[wasm_bindgen(catch, method, structural, js_class = "WebSocket", js_name = close)]
#[doc = "The `close()` method."]
#[doc = ""]
#[doc = "[MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close)"]
pub fn close(this: &WebSocket) -> Result<(), JsValue>;

#[wasm_bindgen(catch, method, structural, js_class = "WebSocket", js_name = close)]
#[doc = "The `close()` method."]
#[doc = ""]
#[doc = "[MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close)"]
pub fn close_with_code(this: &WebSocket, code: u16) -> Result<(), JsValue>;

#[wasm_bindgen(catch, method, structural, js_class = "WebSocket", js_name = close)]
#[doc = "The `close()` method."]
#[doc = ""]
#[doc = "[MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close)"]
pub fn close_with_code_and_reason(
this: &WebSocket,
code: u16,
reason: &str,
) -> Result<(), JsValue>;

#[wasm_bindgen(catch, method, structural, js_class = "WebSocket", js_name = send)]
#[doc = "The `send()` method."]
#[doc = ""]
#[doc = "[MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send)"]
pub fn send_with_str(this: &WebSocket, data: &str) -> Result<(), JsValue>;

#[wasm_bindgen(catch, method, structural, js_class = "WebSocket", js_name = send)]
#[doc = "The `send()` method."]
#[doc = ""]
#[doc = "[MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send)"]
pub fn send_with_u8_array(this: &WebSocket, data: Uint8Array) -> Result<(), JsValue>;

#[wasm_bindgen(catch, method, structural, js_class = "WebSocket", js_name = addEventListener)]
#[doc = "The `addEventListener()` method."]
#[doc = ""]
#[doc = "[CF Documentation](https://developers.cloudflare.com/workers/runtime-apis/websockets#addeventlistener)"]
pub fn add_event_listener(
this: &WebSocket,
r#type: JsValue,
value: Option<&::js_sys::Function>,
) -> Result<(), JsValue>;
}
2 changes: 2 additions & 0 deletions worker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod request_init;
mod response;
mod router;
mod schedule;
mod websocket;

#[doc(hidden)]
use std::result::Result as StdResult;
Expand All @@ -37,6 +38,7 @@ pub use crate::request_init::*;
pub use crate::response::{Response, ResponseBody};
pub use crate::router::{RouteContext, RouteParams, Router};
pub use crate::schedule::*;
pub use crate::websocket::*;
pub use cf::Cf;
pub use url::Url;

Expand Down
Loading