[go: up one dir, main page]

worker/
fetcher.rs

1use crate::{env::EnvBinding, RequestInit, Result};
2use std::convert::TryInto;
3use wasm_bindgen::{JsCast, JsValue};
4use wasm_bindgen_futures::JsFuture;
5
6#[cfg(feature = "http")]
7use crate::HttpResponse;
8use crate::{Request, Response};
9/// A struct for invoking fetch events to other Workers.
10#[derive(Debug, Clone)]
11pub struct Fetcher(worker_sys::Fetcher);
12
13#[cfg(not(feature = "http"))]
14type FetchResponseType = Response;
15#[cfg(feature = "http")]
16type FetchResponseType = HttpResponse;
17
18impl Fetcher {
19    /// Invoke a fetch event in a worker with a url and optionally a [RequestInit].
20    ///
21    /// Return type is [`Response`](crate::Response) unless `http` feature is enabled
22    /// and then it is [`http::Response<worker::Body>`].
23    pub async fn fetch(
24        &self,
25        url: impl Into<String>,
26        init: Option<RequestInit>,
27    ) -> Result<FetchResponseType> {
28        let path = url.into();
29        let promise = match init {
30            Some(ref init) => self.0.fetch_with_str_and_init(&path, &init.into()),
31            None => self.0.fetch_with_str(&path),
32        }?;
33
34        let resp_sys: web_sys::Response = JsFuture::from(promise).await?.dyn_into()?;
35        #[cfg(not(feature = "http"))]
36        let result = Ok(Response::from(resp_sys));
37        #[cfg(feature = "http")]
38        let result = crate::response_from_wasm(resp_sys);
39        result
40    }
41
42    /// Invoke a fetch event with an existing [Request].
43    ///
44    /// Argument type is [`Request`](crate::Request) or [`http::Request<worker::Body>`].
45    ///
46    /// Return type is [`Response`](crate::Response) unless `http` feature is enabled
47    /// and then it is [`http::Response<worker::Body>`].
48    pub async fn fetch_request<T, E>(&self, request: T) -> Result<FetchResponseType>
49    where
50        T: TryInto<Request, Error = E>,
51        crate::Error: From<E>,
52    {
53        let req = request.try_into()?;
54        let promise = self.0.fetch(req.inner())?;
55        let resp_sys: web_sys::Response = JsFuture::from(promise).await?.dyn_into()?;
56        let response = Response::from(resp_sys);
57        #[cfg(feature = "http")]
58        let result = response.try_into();
59        #[cfg(not(feature = "http"))]
60        let result = Ok(response);
61        result
62    }
63
64    /// Convert Fetcher into user-defined RPC interface.
65    /// ```
66    /// #[wasm_bindgen]
67    /// extern "C" {
68    ///     #[wasm_bindgen(extends=js_sys::Object)]
69    ///     #[derive(Debug, Clone, PartialEq, Eq)]
70    ///     pub type MyRpcInterface;
71    ///
72    ///     #[wasm_bindgen(method, catch)]
73    ///     pub fn add(
74    ///         this: &MyRpcInterface,
75    ///         a: u32,
76    ///         b: u32,
77    ///     ) -> std::result::Result<js_sys::Promise, JsValue>;
78    /// }
79    ///
80    /// let rpc: MyRpcInterface = fetcher.into_rpc();
81    /// let result = rpc.add(1, 2);
82    /// ```
83    pub fn into_rpc<T: JsCast>(self) -> T {
84        self.0.unchecked_into()
85    }
86}
87
88impl EnvBinding for Fetcher {
89    const TYPE_NAME: &'static str = "Fetcher";
90}
91
92impl JsCast for Fetcher {
93    fn instanceof(val: &wasm_bindgen::JsValue) -> bool {
94        val.is_instance_of::<Fetcher>()
95    }
96
97    fn unchecked_from_js(val: wasm_bindgen::JsValue) -> Self {
98        Self(val.into())
99    }
100
101    fn unchecked_from_js_ref(val: &wasm_bindgen::JsValue) -> &Self {
102        unsafe { &*(val as *const JsValue as *const Self) }
103    }
104}
105
106impl From<Fetcher> for JsValue {
107    fn from(service: Fetcher) -> Self {
108        JsValue::from(service.0)
109    }
110}
111
112impl AsRef<wasm_bindgen::JsValue> for Fetcher {
113    fn as_ref(&self) -> &wasm_bindgen::JsValue {
114        &self.0
115    }
116}
117
118impl From<worker_sys::Fetcher> for Fetcher {
119    fn from(inner: worker_sys::Fetcher) -> Self {
120        Self(inner)
121    }
122}