conjure_runtime/
client.rs

1// Copyright 2020 Palantir Technologies, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14use crate::builder::CachedConfig;
15use crate::service::gzip::{DecodedBody, GzipLayer};
16use crate::service::http_error::HttpErrorLayer;
17use crate::service::map_error::MapErrorLayer;
18use crate::service::metrics::MetricsLayer;
19use crate::service::node::{NodeMetricsLayer, NodeSelectorLayer, NodeUriLayer};
20use crate::service::proxy::ProxyLayer;
21use crate::service::raw::{RawClient, RawResponseBody};
22use crate::service::response_body::ResponseBodyLayer;
23use crate::service::retry::RetryLayer;
24use crate::service::root_span::RootSpanLayer;
25use crate::service::trace_propagation::TracePropagationLayer;
26use crate::service::user_agent::UserAgentLayer;
27use crate::service::wait_for_spans::{WaitForSpansBody, WaitForSpansLayer};
28use crate::service::Service;
29use crate::service::{Identity, Layer, ServiceBuilder, Stack};
30use crate::weak_cache::Cached;
31use crate::{builder, BodyWriter, Builder, ResponseBody};
32use arc_swap::ArcSwap;
33use conjure_error::Error;
34#[cfg(not(target_arch = "wasm32"))]
35use conjure_http::client::{AsyncClient, AsyncRequestBody};
36use conjure_http::client::{AsyncService, ConjureRuntime};
37#[cfg(target_arch = "wasm32")]
38use conjure_http::client::{
39    LocalAsyncClient as AsyncClient, LocalAsyncRequestBody as AsyncRequestBody,
40};
41use conjure_runtime_config::ServiceConfig;
42use http::{Request, Response};
43use refreshable::Subscription;
44use std::sync::Arc;
45
46macro_rules! layers {
47    () => { Identity };
48    ($layer:ty, $($rem:tt)*) => { Stack<$layer, layers!($($rem)*)> };
49}
50
51type BaseLayer = layers!(
52    ResponseBodyLayer,
53    MetricsLayer,
54    RootSpanLayer,
55    RetryLayer,
56    HttpErrorLayer,
57    WaitForSpansLayer,
58    NodeSelectorLayer,
59    NodeUriLayer,
60    NodeMetricsLayer,
61    ProxyLayer,
62    TracePropagationLayer,
63    UserAgentLayer,
64    GzipLayer,
65    MapErrorLayer,
66);
67
68type BaseService = <BaseLayer as Layer<RawClient>>::Service;
69
70pub(crate) type BaseBody = WaitForSpansBody<DecodedBody<RawResponseBody>>;
71
72pub(crate) struct ClientState {
73    service: BaseService,
74}
75
76impl ClientState {
77    pub(crate) fn new(builder: &Builder<builder::Complete>) -> Result<ClientState, Error> {
78        let client = RawClient::new(builder)?;
79
80        let service = ServiceBuilder::new()
81            .layer(ResponseBodyLayer)
82            .layer(MetricsLayer::new(builder))
83            .layer(RootSpanLayer)
84            .layer(RetryLayer::new(builder))
85            .layer(HttpErrorLayer::new(builder))
86            .layer(WaitForSpansLayer)
87            .layer(NodeSelectorLayer::new(builder)?)
88            .layer(NodeUriLayer)
89            .layer(NodeMetricsLayer)
90            .layer(ProxyLayer::new(builder)?)
91            .layer(TracePropagationLayer)
92            .layer(UserAgentLayer::new(builder))
93            .layer(GzipLayer)
94            .layer(MapErrorLayer)
95            .service(client);
96
97        Ok(ClientState { service })
98    }
99}
100
101/// An asynchronous HTTP client to a remote service.
102#[derive(Clone)]
103pub struct Client {
104    state: Arc<ArcSwap<Cached<CachedConfig, ClientState>>>,
105    _subscription: Option<Arc<Subscription<ServiceConfig, Error>>>,
106}
107
108impl Client {
109    /// Creates a new `Builder` for clients.
110    #[inline]
111    pub fn builder() -> Builder<builder::ServiceStage> {
112        Builder::new()
113    }
114}
115
116impl Client {
117    pub(crate) fn new(
118        state: Arc<ArcSwap<Cached<CachedConfig, ClientState>>>,
119        subscription: Option<Subscription<ServiceConfig, Error>>,
120    ) -> Client {
121        Client {
122            state,
123            _subscription: subscription.map(Arc::new),
124        }
125    }
126}
127
128impl AsyncService<Client> for Client {
129    fn new(client: Client, _: &Arc<ConjureRuntime>) -> Self {
130        client
131    }
132}
133
134impl AsyncClient for Client {
135    type BodyWriter = BodyWriter;
136
137    type ResponseBody = ResponseBody;
138
139    async fn send(
140        &self,
141        request: Request<AsyncRequestBody<'_, Self::BodyWriter>>,
142    ) -> Result<Response<Self::ResponseBody>, Error> {
143        self.state.load().service.call(request).await
144    }
145}