drogue_client/discovery/v1/
client.rs1use super::data::*;
2use crate::core::CoreClient;
3use crate::error::ClientError;
4use crate::openid::{NoTokenProvider, TokenProvider};
5use std::fmt::Debug;
6use std::sync::Arc;
7use tracing::instrument;
8use url::Url;
9
10#[derive(Clone, Debug)]
12pub struct Client {
13 client: reqwest::Client,
14 api_url: Url,
15 token_provider: Arc<dyn TokenProvider>,
16}
17
18type ClientResult<T> = Result<T, ClientError>;
19
20impl CoreClient for Client {
21 fn client(&self) -> &reqwest::Client {
22 &self.client
23 }
24
25 fn token_provider(&self) -> &dyn TokenProvider {
26 self.token_provider.as_ref()
27 }
28}
29
30impl Client {
31 pub fn new_anonymous(client: reqwest::Client, api_url: Url) -> Self {
33 Self {
34 client,
35 api_url,
36 token_provider: Arc::new(NoTokenProvider),
37 }
38 }
39
40 pub fn new_authenticated(
42 client: reqwest::Client,
43 api_url: Url,
44 token_provider: impl TokenProvider + 'static,
45 ) -> Self {
46 Self {
47 client,
48 api_url,
49 token_provider: Arc::new(token_provider),
50 }
51 }
52
53 fn url(&self, authenticated: bool) -> ClientResult<Url> {
54 let mut url = self.api_url.clone();
55
56 {
57 let mut path = url
58 .path_segments_mut()
59 .map_err(|_| ClientError::Request("Failed to get paths".into()))?;
60
61 if authenticated {
62 path.extend(&["api", "console", "v1alpha1", "info"]);
63 } else {
64 path.extend(&[".well-known", "drogue-endpoints"]);
65 }
66 }
67
68 Ok(url)
69 }
70
71 #[instrument]
74 pub async fn get_public_endpoints(&self) -> ClientResult<Option<Endpoints>> {
75 let req = self.client().get(self.url(false)?);
76
77 Self::read_response(req.send().await?).await
78 }
79
80 #[instrument]
82 pub async fn get_authenticated_endpoints(&self) -> ClientResult<Option<Endpoints>> {
83 self.read(self.url(true)?).await
84 }
85
86 #[instrument]
88 pub async fn get_drogue_cloud_version(&self) -> ClientResult<Option<DrogueVersion>> {
89 let url = self.api_url.join(".well-known/drogue-version")?;
90 let req = self.client().get(url);
91
92 Self::read_response(req.send().await?).await
93 }
94
95 #[instrument]
97 pub async fn get_sso_url(&self) -> ClientResult<Option<Url>> {
98 self.get_authenticated_endpoints().await.map(|r| {
99 r.and_then(|endpoints| {
100 endpoints
101 .issuer_url
102 .and_then(|url| Url::parse(url.as_str()).ok())
103 })
104 })
105 }
106}
107
108#[cfg(test)]
109mod test {
110 use crate::discovery::v1::Client;
111 use url::Url;
112
113 #[tokio::test]
114 async fn test_get_drogue_version() {
115 let client: Client = Client::new_anonymous(
116 reqwest::Client::new(),
117 Url::parse("https://api.sandbox.drogue.cloud").unwrap(),
118 );
119
120 let version = client.get_drogue_cloud_version().await;
121 assert!(version.is_ok());
122 let version = version.unwrap();
123
124 assert!(version.is_some());
125 let version = version.unwrap();
126 assert!(!version.version.is_empty());
127 }
128
129 #[tokio::test]
130 async fn test_get_drogue_public_endpoints() {
131 let client: Client = Client::new_anonymous(
132 reqwest::Client::new(),
133 Url::parse("https://api.sandbox.drogue.cloud").unwrap(),
134 );
135
136 let endpoints = client.get_public_endpoints().await;
137 assert!(endpoints.is_ok());
138 let endpoints = endpoints.unwrap();
139
140 assert!(endpoints.is_some());
141 let endpoints = endpoints.unwrap();
142
143 assert!(endpoints.issuer_url.is_some());
144 assert!(endpoints.api.is_some());
145 assert!(endpoints.registry.is_some());
146 assert!(endpoints.sso.is_some());
147 assert!(endpoints.http.is_some());
148 assert!(endpoints.mqtt.is_some());
149 assert!(endpoints.kafka_bootstrap_servers.is_some());
150 assert!(endpoints.mqtt_integration.is_some());
151 }
152}