[go: up one dir, main page]

worker/
durable.rs

1//! Durable Objects provide low-latency coordination and consistent storage for the Workers platform.
2//! A given namespace can support essentially unlimited Durable Objects, with each Object having
3//! access to a transactional, key-value storage API.
4//!
5//! Durable Objects consist of two components: a class that defines a template for creating Durable
6//! Objects and a Workers script that instantiates and uses those Durable Objects.
7//!
8//! The class and the Workers script are linked together with a binding.
9//!
10//! [Learn more](https://developers.cloudflare.com/workers/learning/using-durable-objects) about
11//! using Durable Objects.
12
13use std::{fmt::Display, ops::Deref, time::Duration};
14
15use crate::{
16    container::Container,
17    date::Date,
18    env::{Env, EnvBinding},
19    error::Error,
20    request::Request,
21    response::Response,
22    Result, WebSocket,
23};
24
25use chrono::{DateTime, Utc};
26use futures_util::Future;
27use js_sys::{Map, Number, Object};
28use serde::{de::DeserializeOwned, Serialize};
29use wasm_bindgen::{prelude::*, JsCast};
30use worker_sys::{
31    DurableObject as EdgeDurableObject, DurableObjectId,
32    DurableObjectNamespace as EdgeObjectNamespace, DurableObjectState, DurableObjectStorage,
33    DurableObjectTransaction,
34};
35// use wasm_bindgen_futures::future_to_promise;
36use wasm_bindgen_futures::{future_to_promise, JsFuture};
37
38/// A Durable Object stub is a client object used to send requests to a remote Durable Object.
39#[derive(Debug)]
40pub struct Stub {
41    inner: EdgeDurableObject,
42}
43
44unsafe impl Send for Stub {}
45unsafe impl Sync for Stub {}
46
47impl Stub {
48    /// Send an internal Request to the Durable Object to which the stub points.
49    pub async fn fetch_with_request(&self, req: Request) -> Result<Response> {
50        let promise = self.inner.fetch_with_request(req.inner())?;
51        let response = JsFuture::from(promise).await?;
52        Ok(response.dyn_into::<web_sys::Response>()?.into())
53    }
54
55    /// Construct a Request from a URL to the Durable Object to which the stub points.
56    pub async fn fetch_with_str(&self, url: &str) -> Result<Response> {
57        let promise = self.inner.fetch_with_str(url)?;
58        let response = JsFuture::from(promise).await?;
59        Ok(response.dyn_into::<web_sys::Response>()?.into())
60    }
61
62    pub fn into_rpc<T: JsCast>(self) -> T {
63        self.inner.unchecked_into()
64    }
65}
66
67/// Use an ObjectNamespace to get access to Stubs for communication with a Durable Object instance.
68/// A given namespace can support essentially unlimited Durable Objects, with each Object having
69/// access to a transactional, key-value storage API.
70#[derive(Debug, Clone)]
71pub struct ObjectNamespace {
72    inner: EdgeObjectNamespace,
73}
74
75unsafe impl Send for ObjectNamespace {}
76unsafe impl Sync for ObjectNamespace {}
77
78impl ObjectNamespace {
79    /// This method derives a unique object ID from the given name string. It will always return the
80    /// same ID when given the same name as input.
81    pub fn id_from_name(&self, name: &str) -> Result<ObjectId<'_>> {
82        self.inner
83            .id_from_name(name)
84            .map_err(Error::from)
85            .map(|id| ObjectId {
86                inner: id,
87                namespace: Some(self),
88            })
89    }
90
91    /// This method parses an ID that was previously stringified. This is useful in particular with
92    /// IDs created using `unique_id(&self)`, as these IDs need to be stored somewhere, probably as
93    // as a string.
94    ///
95    /// A stringified object ID is a 64-digit hexadecimal number. However, not all 64-digit hex
96    /// numbers are valid IDs. This method will throw if it is passed an ID that was not originally
97    /// created by newUniqueId() or idFromName(). It will also throw if the ID was originally
98    /// created for a different namespace.
99    pub fn id_from_string(&self, hex_id: &str) -> Result<ObjectId<'_>> {
100        self.inner
101            .id_from_string(hex_id)
102            .map_err(Error::from)
103            .map(|id| ObjectId {
104                inner: id,
105                namespace: Some(self),
106            })
107    }
108
109    /// Creates a new object ID randomly. This method will never return the same ID twice, and thus
110    /// it is guaranteed that the object does not yet exist and has never existed at the time the
111    /// method returns.
112    pub fn unique_id(&self) -> Result<ObjectId<'_>> {
113        self.inner
114            .new_unique_id()
115            .map_err(Error::from)
116            .map(|id| ObjectId {
117                inner: id,
118                namespace: Some(self),
119            })
120    }
121
122    /// Durable Objects can be created so that they only run and store data within a specific
123    /// jurisdiction to comply with local regulations. You must specify the jurisdiction when
124    /// generating the Durable Object's id.
125    ///
126    /// Jurisdiction constraints can only be used with ids created by `unique_id()` and are not
127    /// currently compatible with ids created by `id_from_name()`.
128    ///
129    /// See supported jurisdictions and more documentation at:
130    /// <https://developers.cloudflare.com/durable-objects/reference/data-location/#restrict-durable-objects-to-a-jurisdiction>
131    pub fn unique_id_with_jurisdiction(&self, jd: &str) -> Result<ObjectId<'_>> {
132        let options = Object::new();
133        js_sys::Reflect::set(&options, &JsValue::from("jurisdiction"), &jd.into())?;
134        self.inner
135            .new_unique_id_with_options(&options)
136            .map_err(Error::from)
137            .map(|id| ObjectId {
138                inner: id,
139                namespace: Some(self),
140            })
141    }
142
143    /// Get a Durable Object stub directly by name. This combines the functionality of
144    /// `id_from_name()` and `get_stub()` into a single method call.
145    pub fn get_by_name(&self, name: &str) -> Result<Stub> {
146        self.inner
147            .get_by_name(name)
148            .map_err(Error::from)
149            .map(|stub| Stub { inner: stub })
150    }
151
152    /// Get a Durable Object stub directly by name with options (such as location hints).
153    /// This combines the functionality of `id_from_name()` and `get_stub_with_location_hint()`
154    /// into a single method call.
155    pub fn get_by_name_with_location_hint(&self, name: &str, location_hint: &str) -> Result<Stub> {
156        let options = Object::new();
157        js_sys::Reflect::set(
158            &options,
159            &JsValue::from("locationHint"),
160            &location_hint.into(),
161        )?;
162        self.inner
163            .get_by_name_with_options(name, &options)
164            .map_err(Error::from)
165            .map(|stub| Stub { inner: stub })
166    }
167}
168
169/// An ObjectId is used to identify, locate, and access a Durable Object via interaction with its
170/// Stub.
171#[derive(Debug)]
172pub struct ObjectId<'a> {
173    inner: DurableObjectId,
174    namespace: Option<&'a ObjectNamespace>,
175}
176
177impl ObjectId<'_> {
178    /// Get a Stub for the Durable Object instance identified by this ObjectId.
179    pub fn get_stub(&self) -> Result<Stub> {
180        self.namespace
181            .ok_or_else(|| JsValue::from("Cannot get stub from within a Durable Object"))
182            .and_then(|n| {
183                Ok(Stub {
184                    inner: n.inner.get(&self.inner)?,
185                })
186            })
187            .map_err(Error::from)
188    }
189
190    pub fn get_stub_with_location_hint(&self, location_hint: &str) -> Result<Stub> {
191        let options = Object::new();
192        js_sys::Reflect::set(
193            &options,
194            &JsValue::from("locationHint"),
195            &location_hint.into(),
196        )?;
197
198        self.namespace
199            .ok_or_else(|| JsValue::from("Cannot get stub from within a Durable Object"))
200            .and_then(|n| {
201                Ok(Stub {
202                    inner: n.inner.get_with_options(&self.inner, &options)?,
203                })
204            })
205            .map_err(Error::from)
206    }
207
208    /// The name that was used to create the `ObjectId` via [`id_from_name`](https://developers.cloudflare.com/durable-objects/api/namespace/#idfromname).
209    /// `None` is returned if the `ObjectId` was constructed using [`unique_id`](https://developers.cloudflare.com/durable-objects/api/namespace/#newuniqueid).
210    /// `None` is also returned within the Durable Object constructor, as the `name` property is not accessible there (see <https://github.com/cloudflare/workerd/issues/2240>).
211    pub fn name(&self) -> Option<String> {
212        self.inner.name()
213    }
214}
215
216impl PartialEq for ObjectId<'_> {
217    /// Compare equality between two ObjectIds using [`equals`](<https://developers.cloudflare.com/durable-objects/api/id/#equals>).
218    /// <div class="warning">The equality check ignores the namespace.</div>
219    fn eq(&self, other: &Self) -> bool {
220        self.inner.equals(&other.inner)
221    }
222}
223
224impl Display for ObjectId<'_> {
225    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
226        write!(
227            f,
228            "{}",
229            self.inner.to_string().map_err(|_| { std::fmt::Error })?
230        )
231    }
232}
233
234/// Passed from the runtime to provide access to the Durable Object's storage as well as various
235/// metadata about the Object.
236#[derive(Debug)]
237pub struct State {
238    inner: DurableObjectState,
239}
240
241impl State {
242    /// The ID of this Durable Object which can be converted into a hex string using its `to_string()`
243    /// method.
244    pub fn id(&self) -> ObjectId<'_> {
245        ObjectId {
246            inner: self.inner.id().unwrap(),
247            namespace: None,
248        }
249    }
250
251    /// Contains methods for accessing persistent storage via the transactional storage API. See
252    /// [Transactional Storage API](https://developers.cloudflare.com/workers/runtime-apis/durable-objects#transactional-storage-api) for a detailed reference.
253    pub fn storage(&self) -> Storage {
254        Storage {
255            inner: self.inner.storage().unwrap(),
256        }
257    }
258
259    pub fn container(&self) -> Option<Container> {
260        self.inner.container().map(|inner| Container { inner })
261    }
262
263    pub fn wait_until<F>(&self, future: F)
264    where
265        F: Future<Output = ()> + 'static,
266    {
267        self.inner
268            .wait_until(&future_to_promise(async {
269                future.await;
270                Ok(JsValue::UNDEFINED)
271            }))
272            .unwrap()
273    }
274
275    // needs to be accessed by the `#[durable_object]` macro in a conversion step
276    pub fn _inner(self) -> DurableObjectState {
277        self.inner
278    }
279
280    pub fn accept_web_socket(&self, ws: &WebSocket) {
281        self.inner.accept_websocket(ws.as_ref()).unwrap()
282    }
283
284    pub fn accept_websocket_with_tags(&self, ws: &WebSocket, tags: &[&str]) {
285        let tags = tags.iter().map(|it| (*it).into()).collect();
286
287        self.inner
288            .accept_websocket_with_tags(ws.as_ref(), tags)
289            .unwrap();
290    }
291
292    pub fn get_websockets(&self) -> Vec<WebSocket> {
293        self.inner
294            .get_websockets()
295            .unwrap()
296            .into_iter()
297            .map(Into::into)
298            .collect()
299    }
300
301    pub fn get_websockets_with_tag(&self, tag: &str) -> Vec<WebSocket> {
302        self.inner
303            .get_websockets_with_tag(tag)
304            .unwrap()
305            .into_iter()
306            .map(Into::into)
307            .collect()
308    }
309
310    /// Retrieve tags from a hibernatable websocket
311    pub fn get_tags(&self, websocket: &WebSocket) -> Vec<String> {
312        self.inner.get_tags(websocket.as_ref()).unwrap()
313    }
314
315    pub fn set_websocket_auto_response(&self, pair: &worker_sys::WebSocketRequestResponsePair) {
316        self.inner.set_websocket_auto_response(pair).unwrap();
317    }
318
319    pub fn get_websocket_auto_response(&self) -> Option<worker_sys::WebSocketRequestResponsePair> {
320        self.inner.get_websocket_auto_response().unwrap()
321    }
322}
323
324impl From<DurableObjectState> for State {
325    fn from(o: DurableObjectState) -> Self {
326        Self { inner: o }
327    }
328}
329
330/// Access a Durable Object's Storage API. Each method is implicitly wrapped inside a transaction,
331/// such that its results are atomic and isolated from all other storage operations, even when
332/// accessing multiple key-value pairs.
333pub struct Storage {
334    inner: DurableObjectStorage,
335}
336
337impl core::fmt::Debug for Storage {
338    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
339        f.debug_struct("Storage").finish()
340    }
341}
342
343impl Storage {
344    /// Retrieves the value associated with the given key. The type of the returned value will be
345    /// whatever was previously written for the key.
346    ///
347    /// Returns [Err] if the key does not exist.
348    pub async fn get<T: serde::de::DeserializeOwned>(&self, key: &str) -> Result<T> {
349        JsFuture::from(self.inner.get(key)?)
350            .await
351            .and_then(|val| {
352                if val.is_undefined() {
353                    Err(JsValue::from("No such value in storage."))
354                } else {
355                    serde_wasm_bindgen::from_value(val).map_err(|e| JsValue::from(e.to_string()))
356                }
357            })
358            .map_err(Error::from)
359    }
360
361    /// Retrieves the values associated with each of the provided keys.
362    pub async fn get_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<Map> {
363        let keys = self.inner.get_multiple(
364            keys.into_iter()
365                .map(|key| JsValue::from(key.deref()))
366                .collect(),
367        )?;
368        let keys = JsFuture::from(keys).await?;
369        keys.dyn_into::<Map>().map_err(Error::from)
370    }
371
372    /// Stores the value and associates it with the given key.
373    pub async fn put<T: Serialize>(&self, key: &str, value: T) -> Result<()> {
374        self.put_raw(key, serde_wasm_bindgen::to_value(&value)?)
375            .await
376    }
377
378    pub async fn put_raw(&self, key: &str, value: impl Into<JsValue>) -> Result<()> {
379        JsFuture::from(self.inner.put(key, value.into())?)
380            .await
381            .map_err(Error::from)
382            .map(|_| ())
383    }
384
385    /// Takes a serializable struct and stores each of its keys and values to storage.
386    pub async fn put_multiple<T: Serialize>(&self, values: T) -> Result<()> {
387        let values = serde_wasm_bindgen::to_value(&values)?;
388        if !values.is_object() {
389            return Err("Must pass in a struct type".to_string().into());
390        }
391        self.put_multiple_raw(values.dyn_into().unwrap()).await
392    }
393
394    /// Takes an object and stores each of its keys and values to storage.
395    ///
396    /// ```no_run
397    /// # use worker::Storage;
398    /// use worker::JsValue;
399    ///
400    /// # let storage: Storage = todo!();
401    ///
402    /// let obj = js_sys::Object::new();
403    /// js_sys::Reflect::set(&obj, &JsValue::from_str("foo"), JsValue::from_u64(1));
404    ///
405    /// storage.put_multiple_raw(obj);
406    /// ```
407    pub async fn put_multiple_raw(&self, values: Object) -> Result<()> {
408        JsFuture::from(self.inner.put_multiple(values.into())?)
409            .await
410            .map_err(Error::from)
411            .map(|_| ())
412    }
413
414    /// Deletes the key and associated value. Returns true if the key existed or false if it didn't.
415    pub async fn delete(&self, key: &str) -> Result<bool> {
416        let fut: JsFuture = self.inner.delete(key)?.into();
417        fut.await
418            .and_then(|jsv| {
419                jsv.as_bool()
420                    .ok_or_else(|| JsValue::from("Promise did not return bool"))
421            })
422            .map_err(Error::from)
423    }
424
425    /// Deletes the provided keys and their associated values. Returns a count of the number of
426    /// key-value pairs deleted.
427    pub async fn delete_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<usize> {
428        let fut: JsFuture = self
429            .inner
430            .delete_multiple(
431                keys.into_iter()
432                    .map(|key| JsValue::from(key.deref()))
433                    .collect(),
434            )?
435            .into();
436        fut.await
437            .and_then(|jsv| {
438                jsv.as_f64()
439                    .map(|f| f as usize)
440                    .ok_or_else(|| JsValue::from("Promise did not return number"))
441            })
442            .map_err(Error::from)
443    }
444
445    /// Deletes all keys and associated values, effectively deallocating all storage used by the
446    /// Durable Object. In the event of a failure while the operation is still in flight, it may be
447    /// that only a subset of the data is properly deleted.
448    pub async fn delete_all(&self) -> Result<()> {
449        let fut: JsFuture = self.inner.delete_all()?.into();
450        fut.await.map(|_| ()).map_err(Error::from)
451    }
452
453    /// Returns all keys and values associated with the current Durable Object in ascending
454    /// lexicographic sorted order.
455    ///
456    /// Be aware of how much data may be stored in your Durable Object before calling this version
457    /// of list without options, because it will all be loaded into the Durable Object's memory,
458    /// potentially hitting its [limit](https://developers.cloudflare.com/workers/platform/limits#durable-objects-limits).
459    /// If that is a concern, use the alternate `list_with_options()` method.
460    pub async fn list(&self) -> Result<Map> {
461        let fut: JsFuture = self.inner.list()?.into();
462        fut.await
463            .and_then(|jsv| jsv.dyn_into())
464            .map_err(Error::from)
465    }
466
467    /// Returns keys associated with the current Durable Object according to the parameters in the
468    /// provided options object.
469    pub async fn list_with_options(&self, opts: ListOptions<'_>) -> Result<Map> {
470        let fut: JsFuture = self
471            .inner
472            .list_with_options(serde_wasm_bindgen::to_value(&opts)?.into())?
473            .into();
474        fut.await
475            .and_then(|jsv| jsv.dyn_into())
476            .map_err(Error::from)
477    }
478
479    /// Retrieves the current alarm time (if set) as integer milliseconds since epoch.
480    /// The alarm is considered to be set if it has not started, or if it has failed
481    /// and any retry has not begun. If no alarm is set, `get_alarm()` returns `None`.
482    pub async fn get_alarm(&self) -> Result<Option<i64>> {
483        let fut: JsFuture = self.inner.get_alarm(JsValue::NULL.into())?.into();
484        fut.await
485            .map(|jsv| jsv.as_f64().map(|f| f as i64))
486            .map_err(Error::from)
487    }
488
489    pub async fn get_alarm_with_options(&self, options: GetAlarmOptions) -> Result<Option<i64>> {
490        let fut: JsFuture = self
491            .inner
492            .get_alarm(serde_wasm_bindgen::to_value(&options)?.into())?
493            .into();
494        fut.await
495            .map(|jsv| jsv.as_f64().map(|f| f as i64))
496            .map_err(Error::from)
497    }
498
499    /// Sets the current alarm time to the given datetime.
500    ///
501    /// If `set_alarm()` is called with a time equal to or before Date.now(), the alarm
502    /// will be scheduled for asynchronous execution in the immediate future. If the
503    /// alarm handler is currently executing in this case, it will not be canceled.
504    /// Alarms can be set to millisecond granularity and will usually execute within
505    /// a few milliseconds after the set time, but can be delayed by up to a minute
506    /// due to maintenance or failures while failover takes place.
507    pub async fn set_alarm(&self, scheduled_time: impl Into<ScheduledTime>) -> Result<()> {
508        let fut: JsFuture = self
509            .inner
510            .set_alarm(scheduled_time.into().schedule(), JsValue::NULL.into())?
511            .into();
512        fut.await.map(|_| ()).map_err(Error::from)
513    }
514
515    pub async fn set_alarm_with_options(
516        &self,
517        scheduled_time: impl Into<ScheduledTime>,
518        options: SetAlarmOptions,
519    ) -> Result<()> {
520        let fut: JsFuture = self
521            .inner
522            .set_alarm(
523                scheduled_time.into().schedule(),
524                serde_wasm_bindgen::to_value(&options)?.into(),
525            )?
526            .into();
527        fut.await.map(|_| ()).map_err(Error::from)
528    }
529
530    /// Deletes the alarm if one exists. Does not cancel the alarm handler if it is
531    /// currently executing.
532    pub async fn delete_alarm(&self) -> Result<()> {
533        let fut: JsFuture = self.inner.delete_alarm(JsValue::NULL.into())?.into();
534        fut.await.map(|_| ()).map_err(Error::from)
535    }
536
537    pub async fn delete_alarm_with_options(&self, options: SetAlarmOptions) -> Result<()> {
538        let fut: JsFuture = self
539            .inner
540            .delete_alarm(serde_wasm_bindgen::to_value(&options)?.into())?
541            .into();
542        fut.await.map(|_| ()).map_err(Error::from)
543    }
544
545    pub async fn transaction<F, Fut>(&self, closure: F) -> Result<()>
546    where
547        F: FnOnce(Transaction) -> Fut + 'static,
548        Fut: Future<Output = Result<()>> + 'static,
549    {
550        let inner: Box<dyn FnOnce(DurableObjectTransaction) -> js_sys::Promise> =
551            Box::new(move |t: DurableObjectTransaction| -> js_sys::Promise {
552                future_to_promise(async move {
553                    closure(Transaction { inner: t })
554                        .await
555                        .map_err(JsValue::from)
556                        .map(|_| JsValue::NULL)
557                })
558            });
559        let clos = wasm_bindgen::closure::Closure::once(inner);
560        JsFuture::from(self.inner.transaction(&clos)?)
561            .await
562            .map_err(Error::from)
563            .map(|_| ())
564    }
565
566    // Add new method to access SQLite APIs
567    pub fn sql(&self) -> crate::sql::SqlStorage {
568        crate::sql::SqlStorage::new(self.inner.sql())
569    }
570}
571
572#[derive(Debug)]
573pub struct Transaction {
574    inner: DurableObjectTransaction,
575}
576
577impl Transaction {
578    pub async fn get<T: DeserializeOwned>(&self, key: &str) -> Result<T> {
579        JsFuture::from(self.inner.get(key)?)
580            .await
581            .and_then(|val| {
582                if val.is_undefined() {
583                    Err(JsValue::from("No such value in storage."))
584                } else {
585                    serde_wasm_bindgen::from_value(val).map_err(std::convert::Into::into)
586                }
587            })
588            .map_err(Error::from)
589    }
590
591    pub async fn get_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<Map> {
592        let keys = self.inner.get_multiple(
593            keys.into_iter()
594                .map(|key| JsValue::from(key.deref()))
595                .collect(),
596        )?;
597        let keys = JsFuture::from(keys).await?;
598        keys.dyn_into::<Map>().map_err(Error::from)
599    }
600
601    pub async fn put<T: Serialize>(&self, key: &str, value: T) -> Result<()> {
602        JsFuture::from(self.inner.put(key, serde_wasm_bindgen::to_value(&value)?)?)
603            .await
604            .map_err(Error::from)
605            .map(|_| ())
606    }
607
608    // Each key-value pair in the serialized object will be added to the storage
609    pub async fn put_multiple<T: Serialize>(&self, values: T) -> Result<()> {
610        let values = serde_wasm_bindgen::to_value(&values)?;
611        if !values.is_object() {
612            return Err("Must pass in a struct type".to_string().into());
613        }
614        JsFuture::from(self.inner.put_multiple(values)?)
615            .await
616            .map_err(Error::from)
617            .map(|_| ())
618    }
619
620    pub async fn delete(&self, key: &str) -> Result<bool> {
621        let fut: JsFuture = self.inner.delete(key)?.into();
622        fut.await
623            .and_then(|jsv| {
624                jsv.as_bool()
625                    .ok_or_else(|| JsValue::from("Promise did not return bool"))
626            })
627            .map_err(Error::from)
628    }
629
630    pub async fn delete_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<usize> {
631        let fut: JsFuture = self
632            .inner
633            .delete_multiple(
634                keys.into_iter()
635                    .map(|key| JsValue::from(key.deref()))
636                    .collect(),
637            )?
638            .into();
639        fut.await
640            .and_then(|jsv| {
641                jsv.as_f64()
642                    .map(|f| f as usize)
643                    .ok_or_else(|| JsValue::from("Promise did not return number"))
644            })
645            .map_err(Error::from)
646    }
647
648    pub async fn delete_all(&self) -> Result<()> {
649        let fut: JsFuture = self.inner.delete_all()?.into();
650        fut.await.map(|_| ()).map_err(Error::from)
651    }
652
653    pub async fn list(&self) -> Result<Map> {
654        let fut: JsFuture = self.inner.list()?.into();
655        fut.await
656            .and_then(|jsv| jsv.dyn_into())
657            .map_err(Error::from)
658    }
659
660    pub async fn list_with_options(&self, opts: ListOptions<'_>) -> Result<Map> {
661        let fut: JsFuture = self
662            .inner
663            .list_with_options(serde_wasm_bindgen::to_value(&opts)?.into())?
664            .into();
665        fut.await
666            .and_then(|jsv| jsv.dyn_into())
667            .map_err(Error::from)
668    }
669
670    pub fn rollback(&self) -> Result<()> {
671        self.inner.rollback().map_err(Error::from)
672    }
673}
674
675#[derive(Default, Serialize, Debug)]
676pub struct ListOptions<'a> {
677    /// Key at which the list results should start, inclusive.
678    #[serde(skip_serializing_if = "Option::is_none")]
679    start: Option<&'a str>,
680    /// Key at which the list results should end, exclusive.
681    #[serde(skip_serializing_if = "Option::is_none")]
682    end: Option<&'a str>,
683    /// Restricts results to only include key-value pairs whose keys begin with the prefix.
684    #[serde(skip_serializing_if = "Option::is_none")]
685    prefix: Option<&'a str>,
686    /// If true, return results in descending lexicographic order instead of the default ascending
687    /// order.
688    #[serde(skip_serializing_if = "Option::is_none")]
689    reverse: Option<bool>,
690    /// Maximum number of key-value pairs to return.
691    #[serde(skip_serializing_if = "Option::is_none")]
692    limit: Option<usize>,
693}
694
695impl<'a> ListOptions<'a> {
696    /// Create a new ListOptions struct with no options set.
697    pub fn new() -> Self {
698        Default::default()
699    }
700
701    /// Key at which the list results should start, inclusive.
702    pub fn start(mut self, val: &'a str) -> Self {
703        self.start = Some(val);
704        self
705    }
706
707    /// Key at which the list results should end, exclusive.
708    pub fn end(mut self, val: &'a str) -> Self {
709        self.end = Some(val);
710        self
711    }
712
713    /// Restricts results to only include key-value pairs whose keys begin with the prefix.
714    pub fn prefix(mut self, val: &'a str) -> Self {
715        self.prefix = Some(val);
716        self
717    }
718
719    /// If true, return results in descending lexicographic order instead of the default ascending
720    /// order.
721    pub fn reverse(mut self, val: bool) -> Self {
722        self.reverse = Some(val);
723        self
724    }
725
726    /// Maximum number of key-value pairs to return.
727    pub fn limit(mut self, val: usize) -> Self {
728        self.limit = Some(val);
729        self
730    }
731}
732#[derive(Debug)]
733enum ScheduledTimeInit {
734    Date(js_sys::Date),
735    Offset(f64),
736}
737
738/// Determines when a Durable Object alarm should be ran, based on a timestamp or offset in milliseconds.
739///
740/// Implements [`From`] for:
741/// - [`Duration`], interpreted as an offset (in milliseconds).
742/// - [`i64`], interpreted as an offset (in milliseconds).
743/// - [`DateTime`], interpreted as a timestamp.
744///
745/// When an offset is used, the time at which `set_alarm()` or `set_alarm_with_options()` is called
746/// is used to compute the scheduled time. [`Date::now`] is used as the current time.
747#[derive(Debug)]
748pub struct ScheduledTime {
749    init: ScheduledTimeInit,
750}
751
752impl ScheduledTime {
753    pub fn new(date: js_sys::Date) -> Self {
754        Self {
755            init: ScheduledTimeInit::Date(date),
756        }
757    }
758
759    fn schedule(self) -> js_sys::Date {
760        match self.init {
761            ScheduledTimeInit::Date(date) => date,
762            ScheduledTimeInit::Offset(offset_ms) => {
763                let now = Date::now().as_millis() as f64;
764                js_sys::Date::new(&Number::from(now + offset_ms))
765            }
766        }
767    }
768}
769
770impl From<i64> for ScheduledTime {
771    fn from(offset_ms: i64) -> Self {
772        ScheduledTime {
773            init: ScheduledTimeInit::Offset(offset_ms as f64),
774        }
775    }
776}
777
778impl From<DateTime<Utc>> for ScheduledTime {
779    fn from(date: DateTime<Utc>) -> Self {
780        ScheduledTime {
781            init: ScheduledTimeInit::Date(js_sys::Date::new(&Number::from(
782                date.timestamp_millis() as f64,
783            ))),
784        }
785    }
786}
787
788impl From<Duration> for ScheduledTime {
789    fn from(offset: Duration) -> Self {
790        ScheduledTime {
791            init: ScheduledTimeInit::Offset(offset.as_millis() as f64),
792        }
793    }
794}
795
796#[derive(Debug, Clone, Default, Serialize)]
797pub struct GetAlarmOptions {
798    #[serde(skip_serializing_if = "Option::is_none")]
799    pub allow_concurrency: Option<bool>,
800}
801
802#[derive(Debug, Clone, Default, Serialize)]
803pub struct SetAlarmOptions {
804    #[serde(skip_serializing_if = "Option::is_none")]
805    pub allow_concurrency: Option<bool>,
806    #[serde(skip_serializing_if = "Option::is_none")]
807    pub allow_unconfirmed: Option<bool>,
808}
809
810impl EnvBinding for ObjectNamespace {
811    const TYPE_NAME: &'static str = "DurableObjectNamespace";
812}
813
814impl JsCast for ObjectNamespace {
815    fn instanceof(val: &JsValue) -> bool {
816        val.is_instance_of::<EdgeObjectNamespace>()
817    }
818
819    fn unchecked_from_js(val: JsValue) -> Self {
820        Self { inner: val.into() }
821    }
822
823    fn unchecked_from_js_ref(val: &JsValue) -> &Self {
824        unsafe { &*(val as *const JsValue as *const Self) }
825    }
826}
827
828impl From<ObjectNamespace> for JsValue {
829    fn from(ns: ObjectNamespace) -> Self {
830        JsValue::from(ns.inner)
831    }
832}
833
834impl AsRef<JsValue> for ObjectNamespace {
835    fn as_ref(&self) -> &JsValue {
836        &self.inner
837    }
838}
839
840#[derive(Debug)]
841pub enum WebSocketIncomingMessage {
842    String(String),
843    Binary(Vec<u8>),
844}
845
846/**
847**Note:** Implement this trait with a standard `impl DurableObject for YourType` block, but in order to
848integrate them with the Workers Runtime, you must also add the **`#[durable_object]`** attribute
849to the struct.
850
851## Example
852```no_run
853use worker::*;
854
855#[durable_object]
856pub struct Chatroom {
857    users: Vec<User>,
858    messages: Vec<Message>,
859    state: State,
860    env: Env, // access `Env` across requests, use inside `fetch`
861}
862
863impl DurableObject for Chatroom {
864    fn new(state: State, env: Env) -> Self {
865        Self {
866            users: vec![],
867            messages: vec![],
868            state,
869            env,
870        }
871    }
872
873    async fn fetch(&self, _req: Request) -> Result<Response> {
874        // do some work when a worker makes a request to this DO
875        Response::ok(&format!("{} active users.", self.users.len()))
876    }
877}
878```
879*/
880#[allow(async_fn_in_trait)] // Send is not needed
881pub trait DurableObject: has_durable_object_attribute {
882    fn new(state: State, env: Env) -> Self;
883
884    async fn fetch(&self, req: Request) -> Result<Response>;
885
886    #[allow(clippy::diverging_sub_expression)]
887    async fn alarm(&self) -> Result<Response> {
888        worker_sys::console_error!("alarm() handler not implemented");
889        unimplemented!("alarm() handler")
890    }
891
892    #[allow(unused_variables, clippy::diverging_sub_expression)]
893    async fn websocket_message(
894        &self,
895        ws: WebSocket,
896        message: WebSocketIncomingMessage,
897    ) -> Result<()> {
898        worker_sys::console_error!("websocket_message() handler not implemented");
899        unimplemented!("websocket_message() handler")
900    }
901
902    #[allow(unused_variables, clippy::diverging_sub_expression)]
903    async fn websocket_close(
904        &self,
905        ws: WebSocket,
906        code: usize,
907        reason: String,
908        was_clean: bool,
909    ) -> Result<()> {
910        worker_sys::console_error!("websocket_close() handler not implemented");
911        unimplemented!("websocket_close() handler")
912    }
913
914    #[allow(unused_variables, clippy::diverging_sub_expression)]
915    async fn websocket_error(&self, ws: WebSocket, error: Error) -> Result<()> {
916        worker_sys::console_error!("websocket_error() handler not implemented");
917        unimplemented!("websocket_error() handler")
918    }
919}
920
921#[doc(hidden)]
922#[allow(non_camel_case_types)]
923pub trait has_durable_object_attribute {}