apollo_client/conf/
meta.rs

1//! Configuration api metadata.
2
3use crate::{
4    conf::requests::{FetchRequest, WatchRequest},
5    utils::canonicalize_namespace,
6};
7use serde::{Deserialize, Serialize};
8use std::{
9    borrow::Cow,
10    fmt::{self, Display},
11};
12
13pub(crate) const UNINITIALIZED_NOTIFICATION_ID: i32 = -1;
14
15/// Notification for request and response, default notification_id is `-1`.
16#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
17#[serde(rename_all = "camelCase")]
18pub struct Notification {
19    pub namespace_name: String,
20    pub notification_id: i32,
21}
22
23impl Default for Notification {
24    fn default() -> Self {
25        Self {
26            namespace_name: "".to_string(),
27            notification_id: UNINITIALIZED_NOTIFICATION_ID,
28        }
29    }
30}
31
32impl Notification {
33    #[inline]
34    pub(crate) fn is_uninitialized(&self) -> bool {
35        self.notification_id == UNINITIALIZED_NOTIFICATION_ID
36    }
37
38    // pub(crate) fn canonicalize(mut self) -> Self {
39    //     self.namespace_name = if self.namespace_name.ends_with(".properties") {
40    //         (&self.namespace_name[..self.namespace_name.len() - ".properties".len()])
41    //             .to_string()
42    //             .into()
43    //     } else {
44    //         self.namespace_name.into()
45    //     };
46    //     self
47    // }
48
49    pub(crate) fn update_notifications(older: &mut [Self], newer: &[Self]) {
50        for newer_item in newer {
51            let newer_namespace_name = canonicalize_namespace(&newer_item.namespace_name);
52            for older_item in older.iter_mut() {
53                if canonicalize_namespace(&older_item.namespace_name) == newer_namespace_name {
54                    older_item.notification_id = newer_item.notification_id;
55                }
56            }
57        }
58    }
59
60    pub(crate) fn create_fetch_requests(
61        notifications: impl IntoIterator<Item = Self>,
62        watch: &WatchRequest,
63    ) -> Vec<FetchRequest> {
64        notifications
65            .into_iter()
66            .map(|notification| FetchRequest::from_watch(watch, notification.namespace_name))
67            .collect()
68    }
69}
70
71implement_json_perform_response_for! { Vec<Notification> }
72
73/// Apollo config api `ip` param value.
74#[derive(Debug, Clone, PartialEq)]
75pub enum IpValue {
76    /// Get the hostname of the machine.
77    #[cfg(feature = "host-name")]
78    #[cfg_attr(docsrs, doc(cfg(feature = "host-name")))]
79    HostName,
80
81    /// Get the first ip of the machine generally.
82    #[cfg(feature = "host-ip")]
83    #[cfg_attr(docsrs, doc(cfg(feature = "host-ip")))]
84    HostIp,
85
86    /// Get the first ip of the machine match the cidr, such as '10.2.0.0/16'.
87    #[cfg(feature = "host-ip")]
88    #[cfg_attr(docsrs, doc(cfg(feature = "host-ip")))]
89    HostCidr(cidr_utils::cidr::IpCidr),
90
91    /// Specify your own IP address or other text.
92    Custom(String),
93}
94
95impl IpValue {
96    #[cfg(feature = "host-name")]
97    fn get_host_name() -> &'static str {
98        cfg_if::cfg_if! {
99            if #[cfg(test)] {
100                "test-host-name"
101            } else {
102                crate::utils::get_host_name()
103            }
104        }
105    }
106
107    #[cfg(feature = "host-ip")]
108    fn get_all_addrs() -> &'static [std::net::IpAddr] {
109        cfg_if::cfg_if! {
110            if #[cfg(test)] {
111                static TEST_IPS: [std::net::IpAddr; 2] = [
112                    std::net::IpAddr::V4(std::net::Ipv4Addr::new(10, 2, 0, 1)),
113                    std::net::IpAddr::V4(std::net::Ipv4Addr::new(10, 3, 0, 1)),
114                ];
115                &TEST_IPS
116            } else {
117                crate::utils::get_all_addrs()
118            }
119        }
120    }
121}
122
123impl Display for IpValue {
124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125        write!(
126            f,
127            "{}",
128            match self {
129                #[cfg(feature = "host-name")]
130                IpValue::HostName => Cow::Borrowed(Self::get_host_name()),
131
132                #[cfg(feature = "host-ip")]
133                IpValue::HostIp => {
134                    Self::get_all_addrs()
135                        .first()
136                        .map(|s| Cow::Owned(s.to_string()))
137                        .unwrap_or(Cow::Borrowed("127.0.0.1"))
138                }
139
140                #[cfg(feature = "host-ip")]
141                IpValue::HostCidr(cidr) => {
142                    Self::get_all_addrs()
143                        .iter()
144                        .find(|addr| cidr.contains(*addr))
145                        .map(|s| Cow::Owned(s.to_string()))
146                        .unwrap_or(Cow::Borrowed("127.0.0.1"))
147                }
148
149                IpValue::Custom(s) => Cow::Borrowed(s.as_ref()),
150            }
151        )
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158    use std::str::FromStr;
159
160    #[test]
161    fn test_notification_new() {
162        let notification = Notification {
163            namespace_name: "foo.properties".to_string(),
164            ..Default::default()
165        };
166        assert_eq!(notification.namespace_name, "foo.properties");
167        assert_eq!(notification.notification_id, -1);
168
169        let notification = Notification {
170            namespace_name: "foo.yaml".to_string(),
171            notification_id: 10,
172        };
173        assert_eq!(notification.namespace_name, "foo.yaml");
174        assert_eq!(notification.notification_id, 10);
175    }
176
177    #[test]
178    fn test_update_notifications() {
179        let mut notifications = [
180            Notification {
181                namespace_name: "foo".to_string(),
182                ..Default::default()
183            },
184            Notification {
185                namespace_name: "bar".to_string(),
186                notification_id: 10,
187            },
188        ];
189        Notification::update_notifications(
190            &mut notifications,
191            &[Notification {
192                namespace_name: "foo".to_string(),
193                notification_id: 100,
194            }],
195        );
196        assert_eq!(
197            notifications,
198            [
199                Notification {
200                    namespace_name: "foo".to_string(),
201                    notification_id: 100,
202                },
203                Notification {
204                    namespace_name: "bar".to_string(),
205                    notification_id: 10,
206                },
207            ]
208        );
209    }
210
211    #[test]
212    fn test_ip_value_display() {
213        #[cfg(feature = "host-name")]
214        assert_eq!(IpValue::HostName.to_string(), "test-host-name");
215
216        #[cfg(feature = "host-ip")]
217        assert_eq!(IpValue::HostIp.to_string(), "10.2.0.1");
218
219        #[cfg(feature = "host-ip")]
220        assert_eq!(
221            IpValue::HostCidr(cidr_utils::cidr::IpCidr::from_str("10.3.0.0/16").unwrap())
222                .to_string(),
223            "10.3.0.1"
224        );
225
226        assert_eq!(
227            IpValue::Custom("custom-ip".to_owned()).to_string(),
228            "custom-ip"
229        );
230    }
231}