apollo_client/conf/
requests.rs

1//! Configuration api requests.
2
3use crate::{
4    conf::{
5        meta::{IpValue, Notification},
6        responses::FetchResponse,
7    },
8    errors::ApolloClientResult,
9    meta::{PerformRequest, DEFAULT_CLUSTER_NAME, DEFAULT_NOTIFY_TIMEOUT},
10};
11use ini::Properties;
12use reqwest::RequestBuilder;
13use std::{borrow::Cow, time::Duration};
14
15/// Request executed by [crate::conf::ApolloConfClient::execute];
16pub(crate) trait PerformConfRequest: PerformRequest {}
17
18/// Request configuration from cache.
19#[derive(Clone, Debug)]
20pub struct CachedFetchRequest {
21    pub app_id: String,
22    pub namespace_name: String,
23    pub ip: Option<IpValue>,
24    pub cluster_name: String,
25    pub extras_queries: Vec<(String, String)>,
26    #[cfg(feature = "auth")]
27    #[cfg_attr(docsrs, doc(cfg(feature = "auth")))]
28    pub access_key: Option<String>,
29}
30
31impl Default for CachedFetchRequest {
32    fn default() -> Self {
33        Self {
34            app_id: "".to_string(),
35            namespace_name: "".to_string(),
36            ip: None,
37            cluster_name: DEFAULT_CLUSTER_NAME.to_string(),
38            extras_queries: vec![],
39            #[cfg(feature = "auth")]
40            access_key: None,
41        }
42    }
43}
44
45impl PerformRequest for CachedFetchRequest {
46    type Response = Properties;
47
48    fn path(&self) -> String {
49        format!(
50            "/configfiles/{app_id}/{cluster_name}/{namespace_name}",
51            app_id = self.app_id,
52            cluster_name = self.cluster_name,
53            namespace_name = self.namespace_name
54        )
55    }
56
57    fn queries(&self) -> ApolloClientResult<Vec<(Cow<'static, str>, Cow<'static, str>)>> {
58        let mut pairs = vec![];
59        if let Some(ip) = &self.ip {
60            pairs.push(("ip".into(), ip.to_string().into()));
61        }
62        if !self.extras_queries.is_empty() {
63            pairs.extend(
64                self.extras_queries
65                    .iter()
66                    .map(|(k, v)| (k.clone().into(), v.clone().into())),
67            );
68        }
69        Ok(pairs)
70    }
71
72    fn app_id(&self) -> Option<&str> {
73        Some(&self.app_id)
74    }
75
76    #[cfg(feature = "auth")]
77    fn access_key(&self) -> Option<&str> {
78        self.access_key.as_deref()
79    }
80}
81
82impl PerformConfRequest for CachedFetchRequest {}
83
84/// Request configuration without cache.
85#[derive(Clone, Debug)]
86pub struct FetchRequest {
87    pub app_id: String,
88    pub namespace_name: String,
89    pub cluster_name: String,
90    pub ip: Option<IpValue>,
91    pub release_key: Option<String>,
92    pub extras_queries: Vec<(String, String)>,
93    #[cfg(feature = "auth")]
94    #[cfg_attr(docsrs, doc(cfg(feature = "auth")))]
95    pub access_key: Option<String>,
96}
97
98impl Default for FetchRequest {
99    fn default() -> Self {
100        FetchRequest {
101            app_id: "".to_string(),
102            namespace_name: "".to_string(),
103            cluster_name: DEFAULT_CLUSTER_NAME.to_string(),
104            ip: None,
105            release_key: None,
106            extras_queries: vec![],
107            #[cfg(feature = "auth")]
108            access_key: None,
109        }
110    }
111}
112
113impl FetchRequest {
114    pub(crate) fn namespace_name(&self) -> String {
115        self.namespace_name.to_string()
116    }
117
118    pub(crate) fn from_watch(watch: &WatchRequest, namespace_name: String) -> Self {
119        Self {
120            app_id: watch.app_id.clone(),
121            cluster_name: watch.cluster_name.clone(),
122            namespace_name,
123            ip: watch.ip.clone(),
124            release_key: None,
125            extras_queries: watch.extras_queries.clone(),
126            #[cfg(feature = "auth")]
127            access_key: watch.access_key.clone(),
128        }
129    }
130}
131
132impl PerformRequest for FetchRequest {
133    type Response = FetchResponse;
134
135    fn path(&self) -> String {
136        format!(
137            "/configs/{app_id}/{cluster_name}/{namespace_name}",
138            app_id = self.app_id,
139            cluster_name = self.cluster_name,
140            namespace_name = self.namespace_name
141        )
142    }
143
144    fn queries(&self) -> ApolloClientResult<Vec<(Cow<'_, str>, Cow<'_, str>)>> {
145        let mut pairs = vec![];
146        if let Some(ip) = &self.ip {
147            pairs.push(("ip".into(), ip.to_string().into()));
148        }
149        if let Some(release_key) = &self.release_key {
150            pairs.push(("releaseKey".into(), release_key.clone().into()));
151        }
152        if !self.extras_queries.is_empty() {
153            pairs.extend(
154                self.extras_queries
155                    .iter()
156                    .map(|(k, v)| (k.clone().into(), v.clone().into())),
157            );
158        }
159        Ok(pairs)
160    }
161
162    fn app_id(&self) -> Option<&str> {
163        Some(&self.app_id)
164    }
165
166    #[cfg(feature = "auth")]
167    fn access_key(&self) -> Option<&str> {
168        self.access_key.as_deref()
169    }
170}
171
172impl PerformConfRequest for FetchRequest {}
173
174/// Listen apollo notification api.
175#[derive(Clone, Debug)]
176pub struct NotifyRequest {
177    pub app_id: String,
178    pub notifications: Vec<Notification>,
179    pub cluster_name: String,
180    pub timeout: Duration,
181    #[cfg(feature = "auth")]
182    #[cfg_attr(docsrs, doc(cfg(feature = "auth")))]
183    pub access_key: Option<String>,
184}
185
186impl Default for NotifyRequest {
187    fn default() -> Self {
188        NotifyRequest {
189            app_id: "".to_string(),
190            notifications: vec![],
191            cluster_name: DEFAULT_CLUSTER_NAME.to_string(),
192            timeout: DEFAULT_NOTIFY_TIMEOUT,
193            #[cfg(feature = "auth")]
194            access_key: None,
195        }
196    }
197}
198
199impl NotifyRequest {
200    pub(crate) fn from_watch(
201        watch: &WatchRequest,
202        notifications: Vec<Notification>,
203        timeout: Duration,
204    ) -> Self {
205        Self {
206            app_id: watch.app_id.clone(),
207            cluster_name: watch.cluster_name.clone(),
208            notifications,
209            timeout,
210            #[cfg(feature = "auth")]
211            access_key: watch.access_key.clone(),
212        }
213    }
214}
215
216impl PerformRequest for NotifyRequest {
217    type Response = Vec<Notification>;
218
219    fn path(&self) -> String {
220        "/notifications/v2".to_string()
221    }
222
223    fn queries(&self) -> ApolloClientResult<Vec<(Cow<'_, str>, Cow<'_, str>)>> {
224        let notifications = &self.notifications;
225        Ok(vec![
226            ("appId".into(), self.app_id.clone().into()),
227            ("cluster".into(), self.cluster_name.clone().into()),
228            (
229                "notifications".into(),
230                serde_json::to_string(notifications)?.into(),
231            ),
232        ])
233    }
234
235    #[allow(unused_mut)]
236    fn request_builder(&self, mut request_builder: RequestBuilder) -> RequestBuilder {
237        //FIXME
238        //see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
239        #[cfg(feature = "auth")]
240        {
241            request_builder = self.signature(request_builder);
242        }
243        request_builder.timeout(self.timeout)
244    }
245
246    fn app_id(&self) -> Option<&str> {
247        Some(&self.app_id)
248    }
249
250    #[cfg(feature = "auth")]
251    fn access_key(&self) -> Option<&str> {
252        self.access_key.as_deref()
253    }
254}
255
256impl PerformConfRequest for NotifyRequest {}
257
258/// watch multi namespaces.
259///
260/// Can only be used in [crate::conf::ApolloConfClient::watch].
261#[derive(Clone, Debug)]
262pub struct WatchRequest {
263    pub app_id: String,
264    pub namespace_names: Vec<String>,
265    pub cluster_name: String,
266    pub ip: Option<IpValue>,
267    pub extras_queries: Vec<(String, String)>,
268    #[cfg(feature = "auth")]
269    pub access_key: Option<String>,
270}
271
272impl Default for WatchRequest {
273    fn default() -> Self {
274        WatchRequest {
275            app_id: "".to_string(),
276            namespace_names: vec![],
277            cluster_name: DEFAULT_CLUSTER_NAME.to_string(),
278            ip: None,
279            extras_queries: vec![],
280            #[cfg(feature = "auth")]
281            access_key: None,
282        }
283    }
284}
285
286impl WatchRequest {
287    pub(crate) fn create_notifications(&self) -> Vec<Notification> {
288        self.namespace_names
289            .iter()
290            .map(|namespace| Notification {
291                namespace_name: namespace.clone(),
292                ..Default::default()
293            })
294            .collect()
295    }
296}