Skip to main content

worker_macros/
lib.rs

1mod durable_object;
2mod event;
3mod send;
4
5use proc_macro::TokenStream;
6
7/// Integrate the struct with the Workers Runtime as Durable Object.\
8/// Requires the `DurableObject` trait with the durable_object attribute macro on the struct.
9///
10/// ## Example
11///
12/// ```rust
13/// #[durable_object]
14/// pub struct Chatroom {
15///     users: Vec<User>,
16///     messages: Vec<Message>,
17///     state: State,
18///     env: Env, // access `Env` across requests, use inside `fetch`
19/// }
20///
21/// impl DurableObject for Chatroom {
22///     fn new(state: State, env: Env) -> Self {
23///         Self {
24///             users: vec![],
25///             messages: vec![],
26///             state,
27///             env,
28///         }
29///     }
30///
31///     async fn fetch(&self, _req: Request) -> Result<Response> {
32///         // do some work when a worker makes a request to this DO
33///         Response::ok(&format!("{} active users.", self.users.len()))
34///     }
35/// }
36/// ```
37///
38/// ## Note
39///
40/// By default all durable object events are enabled.
41/// Arguments may be provided to the macro to only generate the desired events, and reduce the generated JS & Wasm output:
42///
43/// * `fetch`: simple `fetch` target
44/// * `alarm`: with [Alarms API](https://developers.cloudflare.com/durable-objects/examples/alarms-api/)
45/// * `websocket`: [WebSocket server](https://developers.cloudflare.com/durable-objects/examples/websocket-hibernation-server/)
46///
47/// ```rust
48/// #[durable_object(fetch)]
49/// pub struct Chatroom {
50///     users: Vec<User>,
51///     messages: Vec<Message>,
52///     state: State,
53///     env: Env, // access `Env` across requests, use inside `fetch`
54/// }
55/// ```
56#[proc_macro_attribute]
57pub fn durable_object(attr: TokenStream, item: TokenStream) -> TokenStream {
58    durable_object::expand_macro(attr.into(), item.into())
59        .unwrap_or_else(syn::Error::into_compile_error)
60        .into()
61}
62
63/// The `event` macro is used to denote a [Worker handler](https://developers.cloudflare.com/workers/runtime-apis/handlers/), essentially binding from
64/// the JS runtime to a Rust function.
65///
66/// As of right now, the following attributes are supported:
67/// * `fetch`: [Fetch Handler](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/)
68/// * `scheduled`: [Scheduled Handler](https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/)
69/// * `queue`: [Queue Handler](https://developers.cloudflare.com/queues/reference/javascript-apis/#consumer)
70///   * This attribute is only available when the `queue` feature is enabled.
71/// * `start`: merely creates a [wasm-bindgen start function](https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-rust-exports/start.html)
72/// * `respond_with_errors`: if this attribute is present, the function will return a `Response` object with a 500 status code and the status text of the error message, if an error occurs
73///
74/// The macro is expanded into a different function signature, depending on the attributes used
75///
76/// Canonical signatures validated by the macro:
77///
78/// * `#[event(fetch)]`: `async fn(req, env, ctx) -> Result<impl IntoResponse>`
79/// * `#[event(scheduled)]`: `async fn(event, env, ctx) -> Result<()>`
80/// * `#[event(email)]`: `async fn(message, env, ctx) -> Result<()>`
81/// * `#[event(tail)]`: `async fn(event, env, ctx) -> Result<()>`
82/// * `#[event(queue)]`: `async fn(batch, env, ctx) -> Result<()>`
83/// * `#[event(start)]`: `fn()`
84///
85/// # Fetch
86///
87/// At a high-level, the `fetch` handler is used to handle incoming HTTP requests. The function signature for a `fetch` handler is conceptually something like:
88///  
89/// ```rust
90/// async fn fetch(req: impl From<web_sys::Request>, env: Env, ctx: Context) -> Result<impl Into<web_sys::Response>, impl Into<Box<dyn Error>>>
91/// ```
92///
93/// In other words, it takes some "request" object that can be derived *from* a `web_sys::Request` (into whatever concrete Request type you like),
94/// and returns some "response" object that can be converted *into* a `web_sys::Response` (from whatever concrete Response type you like).
95/// Error types can be any type that implements [`std::error::Error`].
96///
97/// In practice, the "request" and "response" objects are usually one of these concrete types, supported out of the box:
98///
99/// ### worker::{Request, Response}
100///
101/// ```rust
102/// #[event(fetch, respond_with_errors)]
103/// async fn main(req: worker::Request, env: Env, ctx: Context) -> Result<worker::Response> {
104///   worker::Response::ok("Hello World (worker type)")
105/// }
106/// ```
107///
108/// ### web_sys::{Request, Response}
109///
110/// ```rust
111/// #[event(fetch, respond_with_errors)]
112/// async fn main(req: web_sys::Request, env: Env, ctx: Context) -> Result<web_sys::Response> {
113///   Ok(web_sys::Response::new_with_opt_str(Some("Hello World (native type)".into())).unwrap())
114/// }
115/// ```
116///
117/// ### axum (with `http` feature)
118///
119/// ```rust
120///  #[event(fetch)]
121/// async fn fetch(req: HttpRequest, env: Env, ctx: Context) -> Result<http::Response<axum::body::Body>> {
122///   Ok(router().call(req).await?)
123/// }
124/// ```
125#[proc_macro_attribute]
126pub fn event(attr: TokenStream, item: TokenStream) -> TokenStream {
127    event::expand_macro(attr, item)
128}
129
130#[proc_macro_attribute]
131/// Convert an async function which is `!Send` to be `Send`.
132///
133/// This is useful for implementing async handlers in frameworks which
134/// expect the handler to be `Send`, such as `axum`.
135///
136/// ```rust
137/// #[worker::send]
138/// async fn foo() {
139///     // JsFuture is !Send
140///     let fut = JsFuture::from(promise);
141///     fut.await
142/// }
143/// ```
144pub fn send(attr: TokenStream, stream: TokenStream) -> TokenStream {
145    send::expand_macro(attr, stream)
146}
147
148#[doc(hidden)]
149#[proc_macro_attribute]
150pub fn consume(_: TokenStream, _: TokenStream) -> TokenStream {
151    TokenStream::new()
152}