Skip to main content

kithara_net/
timeout.rs

1use async_trait::async_trait;
2use bytes::Bytes;
3use kithara_platform::time::Duration;
4#[cfg(not(target_arch = "wasm32"))]
5use kithara_platform::tokio;
6#[cfg(not(target_arch = "wasm32"))]
7use tokio::time::timeout;
8use url::Url;
9
10use crate::{
11    ByteStream,
12    error::NetError,
13    traits::Net,
14    types::{Headers, RangeSpec},
15};
16
17/// Timeout decorator for Net implementations
18pub struct TimeoutNet<N> {
19    inner: N,
20    #[cfg(not(target_arch = "wasm32"))]
21    timeout: Duration,
22}
23
24impl<N: Net> TimeoutNet<N> {
25    #[cfg(not(target_arch = "wasm32"))]
26    pub fn new(inner: N, timeout: Duration) -> Self {
27        Self { inner, timeout }
28    }
29
30    #[cfg(target_arch = "wasm32")]
31    pub fn new(inner: N, _timeout: Duration) -> Self {
32        Self { inner }
33    }
34}
35
36#[cfg(not(target_arch = "wasm32"))]
37#[async_trait]
38impl<N: Net> Net for TimeoutNet<N> {
39    async fn get_bytes(&self, url: Url, headers: Option<Headers>) -> Result<Bytes, NetError> {
40        timeout(self.timeout, self.inner.get_bytes(url, headers))
41            .await
42            .map_err(|_| NetError::timeout())?
43    }
44
45    async fn get_range(
46        &self,
47        url: Url,
48        range: RangeSpec,
49        headers: Option<Headers>,
50    ) -> Result<ByteStream, NetError> {
51        timeout(self.timeout, self.inner.get_range(url, range, headers))
52            .await
53            .map_err(|_| NetError::timeout())?
54    }
55
56    async fn head(&self, url: Url, headers: Option<Headers>) -> Result<Headers, NetError> {
57        timeout(self.timeout, self.inner.head(url, headers))
58            .await
59            .map_err(|_| NetError::timeout())?
60    }
61
62    async fn stream(&self, url: Url, headers: Option<Headers>) -> Result<ByteStream, NetError> {
63        timeout(self.timeout, self.inner.stream(url, headers))
64            .await
65            .map_err(|_| NetError::timeout())?
66    }
67}
68
69/// On wasm32, pass through to inner without timeout wrapping.
70/// Browser fetch has its own timeout mechanisms.
71#[cfg(target_arch = "wasm32")]
72#[async_trait(?Send)]
73impl<N: Net> Net for TimeoutNet<N> {
74    async fn get_bytes(&self, url: Url, headers: Option<Headers>) -> Result<Bytes, NetError> {
75        self.inner.get_bytes(url, headers).await
76    }
77
78    async fn get_range(
79        &self,
80        url: Url,
81        range: RangeSpec,
82        headers: Option<Headers>,
83    ) -> Result<ByteStream, NetError> {
84        self.inner.get_range(url, range, headers).await
85    }
86
87    async fn head(&self, url: Url, headers: Option<Headers>) -> Result<Headers, NetError> {
88        self.inner.head(url, headers).await
89    }
90
91    async fn stream(&self, url: Url, headers: Option<Headers>) -> Result<ByteStream, NetError> {
92        self.inner.stream(url, headers).await
93    }
94}