Skip to main content

rice/
client.rs

1use rice_core::config::RiceConfig;
2use rice_core::error::RiceError;
3use rice_state::client::StateClient;
4use rice_storage::client::StorageClient;
5
6pub struct Client {
7    pub storage: Option<StorageClient>,
8    pub state: Option<StateClient>,
9}
10
11impl Client {
12    pub async fn new(config: RiceConfig) -> Result<Self, RiceError> {
13        let storage = if let Some(storage_config) = config.storage {
14            if storage_config.enabled {
15                let url = storage_config
16                    .base_url
17                    .unwrap_or_else(|| "http://localhost:50051".to_string());
18                let token = storage_config.auth_token;
19
20                // Heuristic: If URL contains "grpc", treat as gRPC. Otherwise HTTP.
21                // Or if it matches typical REST ports?
22                // For now, let's assume if it doesn't say "grpc", it might be HTTP if it fails?
23                // Better: Explicitly check scheme or keyword.
24                // The provided URLs: `grpc...` vs `api...`.
25
26                if url.contains("grpc") {
27                    if let Some(t) = token {
28                        Some(StorageClient::connect_with_token(url, t).await?)
29                    } else {
30                        Some(StorageClient::connect(url).await?)
31                    }
32                } else {
33                    // Assume HTTP
34                    let valid_url = if url.starts_with("http://") || url.starts_with("https://") {
35                        url
36                    } else {
37                        format!("http://{}", url)
38                    };
39                    let mut client = StorageClient::connect_http_url(valid_url, token.clone())?;
40
41                    // Auto-login mirroring Node SDK behavior:
42                    // If username is present and auth_token (used as password) is present, attempt login.
43                    if let Some(user) = &storage_config.username {
44                        if let Some(pwd) = &token {
45                            // We ignore errors here to allow partial functionality if auth fails/is not needed for some ops
46                            let _ = client.login(user.clone(), pwd.clone()).await;
47                        }
48                    }
49                    Some(client)
50                }
51            } else {
52                None
53            }
54        } else {
55            None
56        };
57
58        let state = if let Some(state_config) = config.state {
59            if state_config.enabled {
60                let url = state_config
61                    .base_url
62                    .unwrap_or_else(|| "http://localhost:50051".to_string());
63                if let Some(token) = state_config.auth_token {
64                    Some(StateClient::connect_with_token(url, token).await?)
65                } else {
66                    Some(StateClient::connect(url).await?)
67                }
68            } else {
69                None
70            }
71        } else {
72            None
73        };
74
75        Ok(Self { storage, state })
76    }
77}