1use std::{fmt::Display, ops::Deref, time::Duration};
14
15use crate::{
16 date::Date,
17 env::{Env, EnvBinding},
18 error::Error,
19 request::Request,
20 response::Response,
21 Result, WebSocket,
22};
23
24use chrono::{DateTime, Utc};
25use futures_util::Future;
26use js_sys::{Map, Number, Object};
27use serde::{de::DeserializeOwned, Serialize};
28use wasm_bindgen::{prelude::*, JsCast};
29use worker_sys::{
30 DurableObject as EdgeDurableObject, DurableObjectId,
31 DurableObjectNamespace as EdgeObjectNamespace, DurableObjectState, DurableObjectStorage,
32 DurableObjectTransaction,
33};
34use wasm_bindgen_futures::{future_to_promise, JsFuture};
36
37#[derive(Debug)]
39pub struct Stub {
40 inner: EdgeDurableObject,
41}
42
43unsafe impl Send for Stub {}
44unsafe impl Sync for Stub {}
45
46impl Stub {
47 pub async fn fetch_with_request(&self, req: Request) -> Result<Response> {
49 let promise = self.inner.fetch_with_request(req.inner())?;
50 let response = JsFuture::from(promise).await?;
51 Ok(response.dyn_into::<web_sys::Response>()?.into())
52 }
53
54 pub async fn fetch_with_str(&self, url: &str) -> Result<Response> {
56 let promise = self.inner.fetch_with_str(url)?;
57 let response = JsFuture::from(promise).await?;
58 Ok(response.dyn_into::<web_sys::Response>()?.into())
59 }
60
61 pub fn into_rpc<T: JsCast>(self) -> T {
62 self.inner.unchecked_into()
63 }
64}
65
66#[derive(Debug, Clone)]
70pub struct ObjectNamespace {
71 inner: EdgeObjectNamespace,
72}
73
74unsafe impl Send for ObjectNamespace {}
75unsafe impl Sync for ObjectNamespace {}
76
77impl ObjectNamespace {
78 pub fn id_from_name(&self, name: &str) -> Result<ObjectId> {
81 self.inner
82 .id_from_name(name)
83 .map_err(Error::from)
84 .map(|id| ObjectId {
85 inner: id,
86 namespace: Some(self),
87 })
88 }
89
90 pub fn id_from_string(&self, hex_id: &str) -> Result<ObjectId> {
99 self.inner
100 .id_from_string(hex_id)
101 .map_err(Error::from)
102 .map(|id| ObjectId {
103 inner: id,
104 namespace: Some(self),
105 })
106 }
107
108 pub fn unique_id(&self) -> Result<ObjectId> {
112 self.inner
113 .new_unique_id()
114 .map_err(Error::from)
115 .map(|id| ObjectId {
116 inner: id,
117 namespace: Some(self),
118 })
119 }
120
121 pub fn unique_id_with_jurisdiction(&self, jd: &str) -> Result<ObjectId> {
131 let options = Object::new();
132 js_sys::Reflect::set(&options, &JsValue::from("jurisdiction"), &jd.into())?;
133 self.inner
134 .new_unique_id_with_options(&options)
135 .map_err(Error::from)
136 .map(|id| ObjectId {
137 inner: id,
138 namespace: Some(self),
139 })
140 }
141}
142
143#[derive(Debug)]
146pub struct ObjectId<'a> {
147 inner: DurableObjectId,
148 namespace: Option<&'a ObjectNamespace>,
149}
150
151impl ObjectId<'_> {
152 pub fn get_stub(&self) -> Result<Stub> {
154 self.namespace
155 .ok_or_else(|| JsValue::from("Cannot get stub from within a Durable Object"))
156 .and_then(|n| {
157 Ok(Stub {
158 inner: n.inner.get(&self.inner)?,
159 })
160 })
161 .map_err(Error::from)
162 }
163
164 pub fn get_stub_with_location_hint(&self, location_hint: &str) -> Result<Stub> {
165 let options = Object::new();
166 js_sys::Reflect::set(
167 &options,
168 &JsValue::from("locationHint"),
169 &location_hint.into(),
170 )?;
171
172 self.namespace
173 .ok_or_else(|| JsValue::from("Cannot get stub from within a Durable Object"))
174 .and_then(|n| {
175 Ok(Stub {
176 inner: n.inner.get_with_options(&self.inner, &options)?,
177 })
178 })
179 .map_err(Error::from)
180 }
181
182 pub fn name(&self) -> Option<String> {
186 self.inner.name()
187 }
188}
189
190impl PartialEq for ObjectId<'_> {
191 fn eq(&self, other: &Self) -> bool {
194 self.inner.equals(&other.inner)
195 }
196}
197
198impl Display for ObjectId<'_> {
199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
200 write!(
201 f,
202 "{}",
203 self.inner.to_string().map_err(|_| { std::fmt::Error })?
204 )
205 }
206}
207
208#[derive(Debug)]
211pub struct State {
212 inner: DurableObjectState,
213}
214
215impl State {
216 pub fn id(&self) -> ObjectId<'_> {
219 ObjectId {
220 inner: self.inner.id().unwrap(),
221 namespace: None,
222 }
223 }
224
225 pub fn storage(&self) -> Storage {
228 Storage {
229 inner: self.inner.storage().unwrap(),
230 }
231 }
232
233 pub fn wait_until<F>(&self, future: F)
234 where
235 F: Future<Output = ()> + 'static,
236 {
237 self.inner
238 .wait_until(&future_to_promise(async {
239 future.await;
240 Ok(JsValue::UNDEFINED)
241 }))
242 .unwrap()
243 }
244
245 pub fn _inner(self) -> DurableObjectState {
247 self.inner
248 }
249
250 pub fn accept_web_socket(&self, ws: &WebSocket) {
251 self.inner.accept_websocket(ws.as_ref()).unwrap()
252 }
253
254 pub fn accept_websocket_with_tags(&self, ws: &WebSocket, tags: &[&str]) {
255 let tags = tags.iter().map(|it| (*it).into()).collect();
256
257 self.inner
258 .accept_websocket_with_tags(ws.as_ref(), tags)
259 .unwrap();
260 }
261
262 pub fn get_websockets(&self) -> Vec<WebSocket> {
263 self.inner
264 .get_websockets()
265 .unwrap()
266 .into_iter()
267 .map(Into::into)
268 .collect()
269 }
270
271 pub fn get_websockets_with_tag(&self, tag: &str) -> Vec<WebSocket> {
272 self.inner
273 .get_websockets_with_tag(tag)
274 .unwrap()
275 .into_iter()
276 .map(Into::into)
277 .collect()
278 }
279
280 pub fn get_tags(&self, websocket: &WebSocket) -> Vec<String> {
282 self.inner.get_tags(websocket.as_ref()).unwrap()
283 }
284
285 pub fn set_websocket_auto_response(&self, pair: &worker_sys::WebSocketRequestResponsePair) {
286 self.inner.set_websocket_auto_response(pair).unwrap();
287 }
288
289 pub fn get_websocket_auto_response(&self) -> Option<worker_sys::WebSocketRequestResponsePair> {
290 self.inner.get_websocket_auto_response().unwrap()
291 }
292}
293
294impl From<DurableObjectState> for State {
295 fn from(o: DurableObjectState) -> Self {
296 Self { inner: o }
297 }
298}
299
300pub struct Storage {
304 inner: DurableObjectStorage,
305}
306
307impl core::fmt::Debug for Storage {
308 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
309 f.debug_struct("Storage").finish()
310 }
311}
312
313impl Storage {
314 pub async fn get<T: serde::de::DeserializeOwned>(&self, key: &str) -> Result<T> {
319 JsFuture::from(self.inner.get(key)?)
320 .await
321 .and_then(|val| {
322 if val.is_undefined() {
323 Err(JsValue::from("No such value in storage."))
324 } else {
325 serde_wasm_bindgen::from_value(val).map_err(|e| JsValue::from(e.to_string()))
326 }
327 })
328 .map_err(Error::from)
329 }
330
331 pub async fn get_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<Map> {
333 let keys = self.inner.get_multiple(
334 keys.into_iter()
335 .map(|key| JsValue::from(key.deref()))
336 .collect(),
337 )?;
338 let keys = JsFuture::from(keys).await?;
339 keys.dyn_into::<Map>().map_err(Error::from)
340 }
341
342 pub async fn put<T: Serialize>(&self, key: &str, value: T) -> Result<()> {
344 self.put_raw(key, serde_wasm_bindgen::to_value(&value)?)
345 .await
346 }
347
348 pub async fn put_raw(&self, key: &str, value: impl Into<JsValue>) -> Result<()> {
349 JsFuture::from(self.inner.put(key, value.into())?)
350 .await
351 .map_err(Error::from)
352 .map(|_| ())
353 }
354
355 pub async fn put_multiple<T: Serialize>(&self, values: T) -> Result<()> {
357 let values = serde_wasm_bindgen::to_value(&values)?;
358 if !values.is_object() {
359 return Err("Must pass in a struct type".to_string().into());
360 }
361 self.put_multiple_raw(values.dyn_into().unwrap()).await
362 }
363
364 pub async fn put_multiple_raw(&self, values: Object) -> Result<()> {
378 JsFuture::from(self.inner.put_multiple(values.into())?)
379 .await
380 .map_err(Error::from)
381 .map(|_| ())
382 }
383
384 pub async fn delete(&self, key: &str) -> Result<bool> {
386 let fut: JsFuture = self.inner.delete(key)?.into();
387 fut.await
388 .and_then(|jsv| {
389 jsv.as_bool()
390 .ok_or_else(|| JsValue::from("Promise did not return bool"))
391 })
392 .map_err(Error::from)
393 }
394
395 pub async fn delete_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<usize> {
398 let fut: JsFuture = self
399 .inner
400 .delete_multiple(
401 keys.into_iter()
402 .map(|key| JsValue::from(key.deref()))
403 .collect(),
404 )?
405 .into();
406 fut.await
407 .and_then(|jsv| {
408 jsv.as_f64()
409 .map(|f| f as usize)
410 .ok_or_else(|| JsValue::from("Promise did not return number"))
411 })
412 .map_err(Error::from)
413 }
414
415 pub async fn delete_all(&self) -> Result<()> {
419 let fut: JsFuture = self.inner.delete_all()?.into();
420 fut.await.map(|_| ()).map_err(Error::from)
421 }
422
423 pub async fn list(&self) -> Result<Map> {
431 let fut: JsFuture = self.inner.list()?.into();
432 fut.await
433 .and_then(|jsv| jsv.dyn_into())
434 .map_err(Error::from)
435 }
436
437 pub async fn list_with_options(&self, opts: ListOptions<'_>) -> Result<Map> {
440 let fut: JsFuture = self
441 .inner
442 .list_with_options(serde_wasm_bindgen::to_value(&opts)?.into())?
443 .into();
444 fut.await
445 .and_then(|jsv| jsv.dyn_into())
446 .map_err(Error::from)
447 }
448
449 pub async fn get_alarm(&self) -> Result<Option<i64>> {
453 let fut: JsFuture = self.inner.get_alarm(JsValue::NULL.into())?.into();
454 fut.await
455 .map(|jsv| jsv.as_f64().map(|f| f as i64))
456 .map_err(Error::from)
457 }
458
459 pub async fn get_alarm_with_options(&self, options: GetAlarmOptions) -> Result<Option<i64>> {
460 let fut: JsFuture = self
461 .inner
462 .get_alarm(serde_wasm_bindgen::to_value(&options)?.into())?
463 .into();
464 fut.await
465 .map(|jsv| jsv.as_f64().map(|f| f as i64))
466 .map_err(Error::from)
467 }
468
469 pub async fn set_alarm(&self, scheduled_time: impl Into<ScheduledTime>) -> Result<()> {
478 let fut: JsFuture = self
479 .inner
480 .set_alarm(scheduled_time.into().schedule(), JsValue::NULL.into())?
481 .into();
482 fut.await.map(|_| ()).map_err(Error::from)
483 }
484
485 pub async fn set_alarm_with_options(
486 &self,
487 scheduled_time: impl Into<ScheduledTime>,
488 options: SetAlarmOptions,
489 ) -> Result<()> {
490 let fut: JsFuture = self
491 .inner
492 .set_alarm(
493 scheduled_time.into().schedule(),
494 serde_wasm_bindgen::to_value(&options)?.into(),
495 )?
496 .into();
497 fut.await.map(|_| ()).map_err(Error::from)
498 }
499
500 pub async fn delete_alarm(&self) -> Result<()> {
503 let fut: JsFuture = self.inner.delete_alarm(JsValue::NULL.into())?.into();
504 fut.await.map(|_| ()).map_err(Error::from)
505 }
506
507 pub async fn delete_alarm_with_options(&self, options: SetAlarmOptions) -> Result<()> {
508 let fut: JsFuture = self
509 .inner
510 .delete_alarm(serde_wasm_bindgen::to_value(&options)?.into())?
511 .into();
512 fut.await.map(|_| ()).map_err(Error::from)
513 }
514
515 pub async fn transaction<F, Fut>(&self, closure: F) -> Result<()>
516 where
517 F: FnOnce(Transaction) -> Fut + 'static,
518 Fut: Future<Output = Result<()>> + 'static,
519 {
520 let inner: Box<dyn FnOnce(DurableObjectTransaction) -> js_sys::Promise> =
521 Box::new(move |t: DurableObjectTransaction| -> js_sys::Promise {
522 future_to_promise(async move {
523 closure(Transaction { inner: t })
524 .await
525 .map_err(JsValue::from)
526 .map(|_| JsValue::NULL)
527 })
528 });
529 let clos = wasm_bindgen::closure::Closure::once(inner);
530 JsFuture::from(self.inner.transaction(&clos)?)
531 .await
532 .map_err(Error::from)
533 .map(|_| ())
534 }
535
536 pub fn sql(&self) -> crate::sql::SqlStorage {
538 crate::sql::SqlStorage::new(self.inner.sql())
539 }
540}
541
542#[derive(Debug)]
543pub struct Transaction {
544 inner: DurableObjectTransaction,
545}
546
547impl Transaction {
548 pub async fn get<T: DeserializeOwned>(&self, key: &str) -> Result<T> {
549 JsFuture::from(self.inner.get(key)?)
550 .await
551 .and_then(|val| {
552 if val.is_undefined() {
553 Err(JsValue::from("No such value in storage."))
554 } else {
555 serde_wasm_bindgen::from_value(val).map_err(std::convert::Into::into)
556 }
557 })
558 .map_err(Error::from)
559 }
560
561 pub async fn get_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<Map> {
562 let keys = self.inner.get_multiple(
563 keys.into_iter()
564 .map(|key| JsValue::from(key.deref()))
565 .collect(),
566 )?;
567 let keys = JsFuture::from(keys).await?;
568 keys.dyn_into::<Map>().map_err(Error::from)
569 }
570
571 pub async fn put<T: Serialize>(&self, key: &str, value: T) -> Result<()> {
572 JsFuture::from(self.inner.put(key, serde_wasm_bindgen::to_value(&value)?)?)
573 .await
574 .map_err(Error::from)
575 .map(|_| ())
576 }
577
578 pub async fn put_multiple<T: Serialize>(&self, values: T) -> Result<()> {
580 let values = serde_wasm_bindgen::to_value(&values)?;
581 if !values.is_object() {
582 return Err("Must pass in a struct type".to_string().into());
583 }
584 JsFuture::from(self.inner.put_multiple(values)?)
585 .await
586 .map_err(Error::from)
587 .map(|_| ())
588 }
589
590 pub async fn delete(&self, key: &str) -> Result<bool> {
591 let fut: JsFuture = self.inner.delete(key)?.into();
592 fut.await
593 .and_then(|jsv| {
594 jsv.as_bool()
595 .ok_or_else(|| JsValue::from("Promise did not return bool"))
596 })
597 .map_err(Error::from)
598 }
599
600 pub async fn delete_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<usize> {
601 let fut: JsFuture = self
602 .inner
603 .delete_multiple(
604 keys.into_iter()
605 .map(|key| JsValue::from(key.deref()))
606 .collect(),
607 )?
608 .into();
609 fut.await
610 .and_then(|jsv| {
611 jsv.as_f64()
612 .map(|f| f as usize)
613 .ok_or_else(|| JsValue::from("Promise did not return number"))
614 })
615 .map_err(Error::from)
616 }
617
618 pub async fn delete_all(&self) -> Result<()> {
619 let fut: JsFuture = self.inner.delete_all()?.into();
620 fut.await.map(|_| ()).map_err(Error::from)
621 }
622
623 pub async fn list(&self) -> Result<Map> {
624 let fut: JsFuture = self.inner.list()?.into();
625 fut.await
626 .and_then(|jsv| jsv.dyn_into())
627 .map_err(Error::from)
628 }
629
630 pub async fn list_with_options(&self, opts: ListOptions<'_>) -> Result<Map> {
631 let fut: JsFuture = self
632 .inner
633 .list_with_options(serde_wasm_bindgen::to_value(&opts)?.into())?
634 .into();
635 fut.await
636 .and_then(|jsv| jsv.dyn_into())
637 .map_err(Error::from)
638 }
639
640 pub fn rollback(&self) -> Result<()> {
641 self.inner.rollback().map_err(Error::from)
642 }
643}
644
645#[derive(Default, Serialize, Debug)]
646pub struct ListOptions<'a> {
647 #[serde(skip_serializing_if = "Option::is_none")]
649 start: Option<&'a str>,
650 #[serde(skip_serializing_if = "Option::is_none")]
652 end: Option<&'a str>,
653 #[serde(skip_serializing_if = "Option::is_none")]
655 prefix: Option<&'a str>,
656 #[serde(skip_serializing_if = "Option::is_none")]
659 reverse: Option<bool>,
660 #[serde(skip_serializing_if = "Option::is_none")]
662 limit: Option<usize>,
663}
664
665impl<'a> ListOptions<'a> {
666 pub fn new() -> Self {
668 Default::default()
669 }
670
671 pub fn start(mut self, val: &'a str) -> Self {
673 self.start = Some(val);
674 self
675 }
676
677 pub fn end(mut self, val: &'a str) -> Self {
679 self.end = Some(val);
680 self
681 }
682
683 pub fn prefix(mut self, val: &'a str) -> Self {
685 self.prefix = Some(val);
686 self
687 }
688
689 pub fn reverse(mut self, val: bool) -> Self {
692 self.reverse = Some(val);
693 self
694 }
695
696 pub fn limit(mut self, val: usize) -> Self {
698 self.limit = Some(val);
699 self
700 }
701}
702#[derive(Debug)]
703enum ScheduledTimeInit {
704 Date(js_sys::Date),
705 Offset(f64),
706}
707
708#[derive(Debug)]
718pub struct ScheduledTime {
719 init: ScheduledTimeInit,
720}
721
722impl ScheduledTime {
723 pub fn new(date: js_sys::Date) -> Self {
724 Self {
725 init: ScheduledTimeInit::Date(date),
726 }
727 }
728
729 fn schedule(self) -> js_sys::Date {
730 match self.init {
731 ScheduledTimeInit::Date(date) => date,
732 ScheduledTimeInit::Offset(offset_ms) => {
733 let now = Date::now().as_millis() as f64;
734 js_sys::Date::new(&Number::from(now + offset_ms))
735 }
736 }
737 }
738}
739
740impl From<i64> for ScheduledTime {
741 fn from(offset_ms: i64) -> Self {
742 ScheduledTime {
743 init: ScheduledTimeInit::Offset(offset_ms as f64),
744 }
745 }
746}
747
748impl From<DateTime<Utc>> for ScheduledTime {
749 fn from(date: DateTime<Utc>) -> Self {
750 ScheduledTime {
751 init: ScheduledTimeInit::Date(js_sys::Date::new(&Number::from(
752 date.timestamp_millis() as f64,
753 ))),
754 }
755 }
756}
757
758impl From<Duration> for ScheduledTime {
759 fn from(offset: Duration) -> Self {
760 ScheduledTime {
761 init: ScheduledTimeInit::Offset(offset.as_millis() as f64),
762 }
763 }
764}
765
766#[derive(Debug, Clone, Default, Serialize)]
767pub struct GetAlarmOptions {
768 #[serde(skip_serializing_if = "Option::is_none")]
769 pub allow_concurrency: Option<bool>,
770}
771
772#[derive(Debug, Clone, Default, Serialize)]
773pub struct SetAlarmOptions {
774 #[serde(skip_serializing_if = "Option::is_none")]
775 pub allow_concurrency: Option<bool>,
776 #[serde(skip_serializing_if = "Option::is_none")]
777 pub allow_unconfirmed: Option<bool>,
778}
779
780impl EnvBinding for ObjectNamespace {
781 const TYPE_NAME: &'static str = "DurableObjectNamespace";
782}
783
784impl JsCast for ObjectNamespace {
785 fn instanceof(val: &JsValue) -> bool {
786 val.is_instance_of::<EdgeObjectNamespace>()
787 }
788
789 fn unchecked_from_js(val: JsValue) -> Self {
790 Self { inner: val.into() }
791 }
792
793 fn unchecked_from_js_ref(val: &JsValue) -> &Self {
794 unsafe { &*(val as *const JsValue as *const Self) }
795 }
796}
797
798impl From<ObjectNamespace> for JsValue {
799 fn from(ns: ObjectNamespace) -> Self {
800 JsValue::from(ns.inner)
801 }
802}
803
804impl AsRef<JsValue> for ObjectNamespace {
805 fn as_ref(&self) -> &JsValue {
806 &self.inner
807 }
808}
809
810#[derive(Debug)]
811pub enum WebSocketIncomingMessage {
812 String(String),
813 Binary(Vec<u8>),
814}
815
816#[allow(async_fn_in_trait)] pub trait DurableObject: has_durable_object_attribute {
852 fn new(state: State, env: Env) -> Self;
853
854 async fn fetch(&self, req: Request) -> Result<Response>;
855
856 #[allow(clippy::diverging_sub_expression)]
857 async fn alarm(&self) -> Result<Response> {
858 worker_sys::console_error!("alarm() handler not implemented");
859 unimplemented!("alarm() handler")
860 }
861
862 #[allow(unused_variables, clippy::diverging_sub_expression)]
863 async fn websocket_message(
864 &self,
865 ws: WebSocket,
866 message: WebSocketIncomingMessage,
867 ) -> Result<()> {
868 worker_sys::console_error!("websocket_message() handler not implemented");
869 unimplemented!("websocket_message() handler")
870 }
871
872 #[allow(unused_variables, clippy::diverging_sub_expression)]
873 async fn websocket_close(
874 &self,
875 ws: WebSocket,
876 code: usize,
877 reason: String,
878 was_clean: bool,
879 ) -> Result<()> {
880 worker_sys::console_error!("websocket_close() handler not implemented");
881 unimplemented!("websocket_close() handler")
882 }
883
884 #[allow(unused_variables, clippy::diverging_sub_expression)]
885 async fn websocket_error(&self, ws: WebSocket, error: Error) -> Result<()> {
886 worker_sys::console_error!("websocket_error() handler not implemented");
887 unimplemented!("websocket_error() handler")
888 }
889}
890
891#[doc(hidden)]
892#[allow(non_camel_case_types)]
893pub trait has_durable_object_attribute {}