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

Make Durable Objects support DECENT #675

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
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
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,21 +221,19 @@ For more information about how to configure these bindings, see:
### Define a Durable Object in Rust

To define a Durable Object using the `worker` crate you need to implement the `DurableObject` trait
on your own struct. Additionally, the `#[durable_object]` attribute macro must be applied to _both_
your struct definition and the trait `impl` block for it.
on your own struct. Additionally, the `#[DurableObject]` attribute macro must be applied to your struct definition.

```rust
use worker::*;

#[durable_object]
#[DurableObject]
pub struct Chatroom {
users: Vec<User>,
messages: Vec<Message>,
state: State,
env: Env, // access `Env` across requests, use inside `fetch`
}

#[durable_object]
impl DurableObject for Chatroom {
fn new(state: State, env: Env) -> Self {
Self {
Expand Down
464 changes: 190 additions & 274 deletions worker-macros/src/durable_object.rs

Large diffs are not rendered by default.

67 changes: 65 additions & 2 deletions worker-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,66 @@ mod send;

use proc_macro::TokenStream;

/// Integrate the struct with Workers runtime as a Durable Object.\
/// This requires to impl `DurableObject` trait and the trait requires this attribute.
///
/// ## Example
///
/// ```rust
/// #[DurableObject]
/// pub struct Chatroom {
/// users: Vec<User>,
/// messages: Vec<Message>,
/// state: State,
/// env: Env, // access `Env` across requests, use inside `fetch`
/// }
///
/// impl DurableObject for Chatroom {
/// fn new(state: State, env: Env) -> Self {
/// Self {
/// users: vec![],
/// messages: vec![],
/// state,
/// env,
/// }
/// }
///
/// async fn fetch(&mut self, _req: Request) -> Result<Response> {
/// // do some work when a worker makes a request to this DO
/// Response::ok(&format!("{} active users.", self.users.len()))
/// }
/// }
/// ```
///
/// ## Note
///
/// You can specify the usage of the Durable Object via an argument in order to control WASM/JS outout:
///
/// * `fetch`: simple `fetch` target
/// * `alarm`: with [Alarms API](https://developers.cloudflare.com/durable-objects/examples/alarms-api/)
/// * `websocket`: [WebSocket server](https://developers.cloudflare.com/durable-objects/examples/websocket-hibernation-server/)
///
/// ```rust
/// #[DurableObject(fetch)]
/// pub struct Chatroom {
/// users: Vec<User>,
/// messages: Vec<Message>,
/// state: State,
/// env: Env, // access `Env` across requests, use inside `fetch`
/// }
/// ```
#[proc_macro_attribute]
pub fn durable_object(_attr: TokenStream, item: TokenStream) -> TokenStream {
durable_object::expand_macro(item.into())
#[allow(non_snake_case)]
pub fn DurableObject(attr: TokenStream, item: TokenStream) -> TokenStream {
durable_object::expand_macro(attr.into(), item.into())
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}

#[deprecated = "use `#[DurableObject]` instead"]
#[proc_macro_attribute]
pub fn durable_object(_: TokenStream, item: TokenStream) -> TokenStream {
durable_object::expand_macro(TokenStream::new().into(), item.into())
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
Expand Down Expand Up @@ -86,3 +143,9 @@ pub fn event(attr: TokenStream, item: TokenStream) -> TokenStream {
pub fn send(attr: TokenStream, stream: TokenStream) -> TokenStream {
send::expand_macro(attr, stream)
}

#[doc(hidden)]
#[proc_macro_attribute]
pub fn consume(_: TokenStream, _: TokenStream) -> TokenStream {
TokenStream::new()
}
3 changes: 1 addition & 2 deletions worker-sandbox/src/alarm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ use worker::*;

use super::SomeSharedData;

#[durable_object]
#[DurableObject]
pub struct AlarmObject {
state: State,
}

#[durable_object]
impl DurableObject for AlarmObject {
fn new(state: State, _: Env) -> Self {
Self { state }
Expand Down
3 changes: 1 addition & 2 deletions worker-sandbox/src/counter.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use worker::*;

#[durable_object]
#[DurableObject]
pub struct Counter {
count: usize,
state: State,
initialized: bool,
env: Env,
}

#[durable_object]
impl DurableObject for Counter {
fn new(state: State, env: Env) -> Self {
Self {
Expand Down
3 changes: 1 addition & 2 deletions worker-sandbox/src/test/export_durable_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ use worker::{js_sys::Uint8Array, wasm_bindgen::JsValue, *};

use crate::ensure;

#[durable_object]
#[DurableObject]
pub struct MyClass {
state: State,
number: usize,
}

#[durable_object]
impl DurableObject for MyClass {
fn new(state: State, _env: Env) -> Self {
Self { state, number: 0 }
Expand Down
3 changes: 1 addition & 2 deletions worker-sandbox/src/test/put_raw.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use worker::{js_sys::Uint8Array, wasm_bindgen::JsValue, *};

#[durable_object]
#[DurableObject]
pub struct PutRawTestObject {
state: State,
}
Expand Down Expand Up @@ -39,7 +39,6 @@ impl PutRawTestObject {
}
}

#[durable_object]
impl DurableObject for PutRawTestObject {
fn new(state: State, _env: Env) -> Self {
Self { state }
Expand Down
22 changes: 14 additions & 8 deletions worker/src/durable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use crate::{
Result, WebSocket,
};

use async_trait::async_trait;
use chrono::{DateTime, Utc};
use futures_util::Future;
use js_sys::{Map, Number, Object};
Expand Down Expand Up @@ -221,7 +220,7 @@ impl State {
.unwrap()
}

// needs to be accessed by the `durable_object` macro in a conversion step
// needs to be accessed by the `#[DurableObject]` macro in a conversion step
pub fn _inner(self) -> DurableObjectState {
self.inner
}
Expand Down Expand Up @@ -772,22 +771,21 @@ pub enum WebSocketIncomingMessage {

/**
**Note:** Implement this trait with a standard `impl DurableObject for YourType` block, but in order to
integrate them with the Workers Runtime, you must also add the **`#[durable_object]`** attribute
macro to both the impl block and the struct type definition.
integrate them with the Workers Runtime, you must also add the **`#[DurableObject]`** attribute
to the struct.

## Example
```no_run
use worker::*;

#[durable_object]
#[DurableObject]
pub struct Chatroom {
users: Vec<User>,
messages: Vec<Message>,
state: State,
env: Env, // access `Env` across requests, use inside `fetch`
}

#[durable_object]
impl DurableObject for Chatroom {
fn new(state: State, env: Env) -> Self {
Self {
Expand All @@ -806,14 +804,15 @@ impl DurableObject for Chatroom {
```
*/

#[async_trait(?Send)]
pub trait DurableObject {
#[allow(async_fn_in_trait)] // Send is not needed
pub trait DurableObject: has_DurableObject_attribute {
fn new(state: State, env: Env) -> Self;

async fn fetch(&mut self, req: Request) -> Result<Response>;

#[allow(clippy::diverging_sub_expression)]
async fn alarm(&mut self) -> Result<Response> {
worker_sys::console_error!("alarm() handler not implemented");
unimplemented!("alarm() handler not implemented")
}

Expand All @@ -823,6 +822,7 @@ pub trait DurableObject {
ws: WebSocket,
message: WebSocketIncomingMessage,
) -> Result<()> {
worker_sys::console_error!("websocket_message() handler not implemented");
unimplemented!("websocket_message() handler not implemented")
}

Expand All @@ -834,11 +834,17 @@ pub trait DurableObject {
reason: String,
was_clean: bool,
) -> Result<()> {
worker_sys::console_error!("websocket_close() handler not implemented");
unimplemented!("websocket_close() handler not implemented")
}

#[allow(unused_variables, clippy::diverging_sub_expression)]
async fn websocket_error(&mut self, ws: WebSocket, error: Error) -> Result<()> {
worker_sys::console_error!("websocket_error() handler not implemented");
unimplemented!("websocket_error() handler not implemented")
}
}

#[doc(hidden)]
#[allow(non_camel_case_types)]
pub trait has_DurableObject_attribute {}
2 changes: 1 addition & 1 deletion worker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ pub use wasm_bindgen_futures;
pub use worker_kv as kv;

pub use cf::{Cf, CfResponseProperties, TlsClientAuth};
pub use worker_macros::{durable_object, event, send};
pub use worker_macros::{DurableObject, durable_object, event, send, consume};
#[doc(hidden)]
pub use worker_sys;
pub use worker_sys::{console_debug, console_error, console_log, console_warn};
Expand Down