1use 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
15pub(crate) trait PerformConfRequest: PerformRequest {}
17
18#[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#[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#[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 #[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#[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}