posemesh_domain_http/
lib.rs

1use futures::channel::mpsc::Receiver;
2
3#[cfg(target_family = "wasm")]
4use crate::domain_data::{UploadDomainData, upload_v1};
5use crate::domain_data::{download_by_id, download_metadata_v1, download_v1_stream, DomainData, DownloadQuery};
6
7mod auth;
8pub mod config;
9pub mod domain_data;
10pub mod discovery;
11#[cfg(target_family = "wasm")]
12pub mod wasm;
13
14use crate::discovery::DiscoveryService;
15
16#[derive(Debug, Clone)]
17pub struct DomainClient {
18    discovery_client: DiscoveryService,
19    pub client_id: String,
20}
21
22impl DomainClient {
23    fn new(api_url: &str, dds_url: &str, client_id: &str) -> Self {
24        if client_id.is_empty() {
25            panic!("client_id is empty");
26        }
27        Self {
28            discovery_client: DiscoveryService::new(api_url, dds_url, client_id),
29            client_id: client_id.to_string(),
30        }
31    }
32    
33    pub async fn new_with_app_credential(api_url: &str, dds_url: &str, client_id: &str, app_key: &str, app_secret: &str) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
34        let mut dc = DomainClient::new(api_url, dds_url, client_id);
35        let _ = dc.discovery_client.sign_in_as_auki_app(app_key, app_secret).await?;
36        Ok(dc)
37    }
38
39    pub async fn new_with_user_credential(api_url: &str, dds_url: &str, client_id: &str, email: &str, password: &str, logout: bool) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
40        let mut dc = DomainClient::new(api_url, dds_url, client_id);
41        let _ = dc.discovery_client.sign_in_with_auki_account(email, password, logout).await?;
42        Ok(dc)
43    }
44
45    pub async fn download_domain_data(&self, domain_id: &str, query: &DownloadQuery) -> Result<Receiver<Result<DomainData, Box<dyn std::error::Error + Send + Sync>>>, Box<dyn std::error::Error + Send + Sync>> {
46        let domain = self.discovery_client.auth_domain(domain_id).await?;
47        let rx = download_v1_stream(&domain.domain.domain_server.url, &self.client_id, &domain.access_token, domain_id, query).await?;
48        Ok(rx)
49    }
50
51    #[cfg(not(target_family = "wasm"))]
52    pub async fn upload_domain_data(&self, domain_id: &str, data: Receiver<domain_data::UploadDomainData>) -> Result<Vec<DomainData>, Box<dyn std::error::Error + Send + Sync>> {
53        use crate::domain_data::upload_v1_stream;
54        let domain = self.discovery_client.auth_domain(domain_id).await?;
55        upload_v1_stream(&domain.domain.domain_server.url, &domain.access_token, domain_id, data).await
56    }
57
58    #[cfg(target_family = "wasm")]
59    pub async fn upload_domain_data(&self, domain_id: &str, data: Vec<UploadDomainData>) -> Result<Vec<DomainData>, Box<dyn std::error::Error + Send + Sync>> {
60        let domain = self.discovery_client.auth_domain(domain_id).await?;
61        upload_v1(&domain.domain.domain_server.url, &domain.access_token, domain_id, data).await
62    }
63
64    pub async fn download_metadata(&self, domain_id: &str, query: &DownloadQuery) -> Result<Vec<DomainData>, Box<dyn std::error::Error + Send + Sync>> {
65        let domain = self.discovery_client.auth_domain(domain_id).await?;
66        download_metadata_v1(&domain.domain.domain_server.url, &self.client_id, &domain.access_token, domain_id, query).await
67    }
68
69    pub async fn download_domain_data_by_id(&self, domain_id: &str, id: &str) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
70        let domain = self.discovery_client.auth_domain(domain_id).await?;
71        download_by_id(&domain.domain.domain_server.url, &self.client_id, &domain.access_token, domain_id, id).await
72    }
73}
74
75#[cfg(not(target_family = "wasm"))]
76#[cfg(test)]
77mod tests {
78    use std::time::Duration;
79
80    use crate::domain_data::{UpdateDomainData, UploadDomainData};
81
82    use super::*;
83    use futures::{channel::mpsc, StreamExt};
84    use tokio::{spawn, time::sleep};
85
86    fn get_config() -> (config::Config, String) {
87        if std::path::Path::new("../.env.local").exists() {
88            dotenvy::from_filename("../.env.local").ok();
89            dotenvy::dotenv().ok();
90        }
91        let config = config::Config::from_env().unwrap();
92        (config, std::env::var("DOMAIN_ID").unwrap())
93    }
94
95    #[tokio::test]
96    async fn test_download_domain_data_with_app_credential() {
97        // Create a test client
98        let config = get_config();
99        let client = DomainClient::new_with_app_credential(&config.0.api_url, &config.0.dds_url, &config.0.client_id, &config.0.app_key.unwrap(), &config.0.app_secret.unwrap()).await.expect("Failed to create client");
100        
101        // Create a test query
102        let query = DownloadQuery {
103            ids: vec![],
104            name: None,
105            data_type: Some("dmt_accel_csv".to_string()),
106        };
107
108        // Test the download function
109        let result = client.download_domain_data(
110            &config.1,
111            &query
112        ).await;
113
114        assert!(result.is_ok(), "error message : {:?}", result.err());
115
116        let mut count = 0;
117        let mut rx = result.unwrap();
118        while let Some(Ok(_)) = rx.next().await {
119            count += 1;
120        }
121        assert!(count > 0);
122    }
123
124    #[tokio::test]
125    async fn test_upload_domain_data_with_user_credential() {
126        use futures::SinkExt;
127        let config = get_config();
128        let client = DomainClient::new_with_user_credential(&config.0.api_url, &config.0.dds_url, &config.0.client_id, &config.0.email.unwrap(), &config.0.password.unwrap(), true).await.expect("Failed to create client");
129
130        let data = vec![UploadDomainData {
131            create: None,
132            update: Some(UpdateDomainData {
133                id: "a84a36e5-312b-4f80-974a-06f5d19c1e16".to_string(),
134            }),
135            data: "{\"test\": \"test updated\"}".as_bytes().to_vec(),
136        }, UploadDomainData {
137            create: None,
138            update: Some(UpdateDomainData {
139                id: "a08dc12f-c79e-4f5e-b388-c09ad6d8cfd8".to_string(),
140            }),
141            data: "{\"test\": \"test updated\"}".as_bytes().to_vec(),
142        }];
143        let (mut tx, rx) = mpsc::channel(10);
144        spawn(async move {
145            for d in data {
146                tx.send(d).await.unwrap();
147            }
148            tx.close().await.unwrap();
149        });
150        let result = client.upload_domain_data(&config.1, rx).await;
151
152        assert!(result.is_ok(), "error message : {:?}", result.err());
153        assert_eq!(result.unwrap().len(), 2);
154
155        sleep(Duration::from_secs(5)).await;
156
157        // Create a test query
158        let query = DownloadQuery {
159            ids: vec![],
160            name: None,
161            data_type: Some("dmt_accel_csv".to_string()),
162        };
163
164        // Test the download function
165        let result = client.download_domain_data(
166            &config.1,
167            &query
168        ).await;
169
170        assert!(result.is_ok(), "error message : {:?}", result.err());
171
172        let mut count = 0;
173        let mut rx = result.unwrap();
174        while let Some(Ok(_)) = rx.next().await {
175            count += 1;
176        }
177        assert!(count > 0);
178    }
179    
180    #[tokio::test]
181    async fn test_download_domain_data_by_id() {
182        let config = get_config();
183        let client = DomainClient::new_with_app_credential(&config.0.api_url, &config.0.dds_url, &config.0.client_id, &config.0.app_key.unwrap(), &config.0.app_secret.unwrap()).await.expect("Failed to create client");
184
185        // Now test download by id
186        let download_result = client.download_domain_data_by_id(
187            &config.1,
188            "a84a36e5-312b-4f80-974a-06f5d19c1e16",
189        ).await;
190
191        assert!(download_result.is_ok(), "download by id failed: {:?}", download_result.err());
192        let downloaded_bytes = download_result.unwrap();
193        assert_eq!(downloaded_bytes, b"{\"test\": \"test updated\"}".to_vec());
194    }
195}
196