1use 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};
35use wasm_bindgen_futures::{future_to_promise, JsFuture};
37
38#[derive(Debug)]
40pub struct Stub {
41 inner: EdgeDurableObject,
42}
43
44unsafe impl Send for Stub {}
45unsafe impl Sync for Stub {}
46
47impl Stub {
48 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 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#[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 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 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 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 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 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 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#[derive(Debug)]
172pub struct ObjectId<'a> {
173 inner: DurableObjectId,
174 namespace: Option<&'a ObjectNamespace>,
175}
176
177impl ObjectId<'_> {
178 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 pub fn name(&self) -> Option<String> {
212 self.inner.name()
213 }
214}
215
216impl PartialEq for ObjectId<'_> {
217 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#[derive(Debug)]
237pub struct State {
238 inner: DurableObjectState,
239}
240
241impl State {
242 pub fn id(&self) -> ObjectId<'_> {
245 ObjectId {
246 inner: self.inner.id().unwrap(),
247 namespace: None,
248 }
249 }
250
251 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 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 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
330pub 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 #[serde(skip_serializing_if = "Option::is_none")]
679 start: Option<&'a str>,
680 #[serde(skip_serializing_if = "Option::is_none")]
682 end: Option<&'a str>,
683 #[serde(skip_serializing_if = "Option::is_none")]
685 prefix: Option<&'a str>,
686 #[serde(skip_serializing_if = "Option::is_none")]
689 reverse: Option<bool>,
690 #[serde(skip_serializing_if = "Option::is_none")]
692 limit: Option<usize>,
693}
694
695impl<'a> ListOptions<'a> {
696 pub fn new() -> Self {
698 Default::default()
699 }
700
701 pub fn start(mut self, val: &'a str) -> Self {
703 self.start = Some(val);
704 self
705 }
706
707 pub fn end(mut self, val: &'a str) -> Self {
709 self.end = Some(val);
710 self
711 }
712
713 pub fn prefix(mut self, val: &'a str) -> Self {
715 self.prefix = Some(val);
716 self
717 }
718
719 pub fn reverse(mut self, val: bool) -> Self {
722 self.reverse = Some(val);
723 self
724 }
725
726 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#[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#[allow(async_fn_in_trait)] pub 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 {}