Skip to main content

wstd_aws/
lib.rs

1#![deprecated(since = "0.6.6", note = "The `wstd-aws` crate has been deprecated in favor of upstream support in `aws-smithy-wasm`. See https://github.com/bytecodealliance/wstd/tree/main/aws-example for details on using upstream support.")]
2
3use anyhow::anyhow;
4use aws_smithy_async::rt::sleep::{AsyncSleep, Sleep};
5use aws_smithy_runtime_api::client::http::{
6    HttpClient, HttpConnector, HttpConnectorFuture, HttpConnectorSettings, SharedHttpConnector,
7};
8use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
9use aws_smithy_runtime_api::client::result::ConnectorError;
10use aws_smithy_runtime_api::client::retries::ErrorKind;
11use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
12use aws_smithy_runtime_api::http::Response;
13use aws_smithy_types::body::SdkBody;
14use http_body_util::{BodyStream, StreamBody};
15use std::time::Duration;
16use sync_wrapper::SyncStream;
17use wstd::http::{Body as WstdBody, BodyExt, Client};
18
19pub fn sleep_impl() -> impl AsyncSleep + 'static {
20    WstdSleep
21}
22
23#[derive(Debug)]
24struct WstdSleep;
25impl AsyncSleep for WstdSleep {
26    fn sleep(&self, duration: Duration) -> Sleep {
27        Sleep::new(async move {
28            wstd::task::sleep(wstd::time::Duration::from(duration)).await;
29        })
30    }
31}
32
33pub fn http_client() -> impl HttpClient + 'static {
34    WstdHttpClient
35}
36
37#[derive(Debug)]
38struct WstdHttpClient;
39
40impl HttpClient for WstdHttpClient {
41    fn http_connector(
42        &self,
43        settings: &HttpConnectorSettings,
44        // afaict, none of these components are relevant to this
45        // implementation.
46        _components: &RuntimeComponents,
47    ) -> SharedHttpConnector {
48        let mut client = Client::new();
49        if let Some(timeout) = settings.connect_timeout() {
50            client.set_connect_timeout(timeout);
51        }
52        if let Some(timeout) = settings.read_timeout() {
53            client.set_first_byte_timeout(timeout);
54        }
55        SharedHttpConnector::new(WstdHttpConnector(client))
56    }
57}
58
59#[derive(Debug)]
60struct WstdHttpConnector(Client);
61
62impl HttpConnector for WstdHttpConnector {
63    fn call(&self, request: HttpRequest) -> HttpConnectorFuture {
64        let client = self.0.clone();
65        HttpConnectorFuture::new(async move {
66            let request = request
67                .try_into_http1x()
68                // This can only fail if the Extensions fail to convert
69                .map_err(|e| ConnectorError::other(Box::new(e), None))?;
70            // smithy's SdkBody Error is a non-'static boxed dyn stderror.
71            // Anyhow can't represent that, so convert it to the debug impl.
72            let request =
73                request.map(|body| WstdBody::from_http_body(body.map_err(|e| anyhow!("{e:?}"))));
74            // Any error given by send is considered a "ClientError" kind
75            // which should prevent smithy from retrying like it would for a
76            // throttling error
77            let response = client
78                .send(request)
79                .await
80                .map_err(|e| ConnectorError::other(e.into(), Some(ErrorKind::ClientError)))?;
81
82            Response::try_from(response.map(|wstd_body| {
83                // You'd think that an SdkBody would just be an impl Body with
84                // the usual error type dance.
85                let nonsync_body = wstd_body
86                    .into_boxed_body()
87                    .map_err(|e| e.into_boxed_dyn_error());
88                // But we have to do this weird dance: because Axum insists
89                // bodies are not Sync, wstd settled on non-Sync bodies.
90                // Smithy insists on Sync bodies. The SyncStream type exists
91                // to assert, because all Stream operations are on &mut self,
92                // all Streams are Sync. So, turn the Body into a Stream, make
93                // it sync, then back to a Body.
94                let nonsync_stream = BodyStream::new(nonsync_body);
95                let sync_stream = SyncStream::new(nonsync_stream);
96                let sync_body = StreamBody::new(sync_stream);
97                SdkBody::from_body_1_x(sync_body)
98            }))
99            // This can only fail if the Extensions fail to convert
100            .map_err(|e| ConnectorError::other(Box::new(e), None))
101        })
102    }
103}