hive_client/client/
mod.rs1mod api;
2mod wrapper;
3
4pub mod authentication;
6
7pub use api::actions;
8pub use api::devices;
9pub use api::products;
10pub use api::weather;
11
12pub use api::ApiError;
13pub use authentication::AuthenticationError;
14
15#[doc(hidden)]
16pub use authentication::RefreshError;
17
18use crate::authentication::HiveAuth;
19use crate::client::api::HiveApi;
20use crate::client::authentication::{Tokens, User};
21use std::sync::Arc;
22use tokio::sync::{Mutex, RwLock};
23
24#[derive(Debug)]
26pub struct Client {
27 auth: RwLock<Option<HiveAuth>>,
28 api: HiveApi,
29 user: Mutex<Option<User>>,
30 tokens: Mutex<Option<Arc<Tokens>>>,
31 friendly_name: String,
32}
33
34impl Client {
35 #[must_use]
41 pub fn new(friendly_name: &str) -> Self {
42 Self {
43 auth: RwLock::new(None),
44 api: HiveApi::new(),
45 user: Mutex::new(None),
46 tokens: Mutex::new(None),
47 friendly_name: friendly_name.to_string(),
48 }
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use dotenvy_macro::dotenv;
56
57 #[tokio::test]
58 async fn test_cognito_authentication_and_device_confirmation() {
59 let mut client = Client::new("Home Automation");
60
61 let user = User::new(dotenv!("MOCK_USER_EMAIL"), dotenv!("MOCK_USER_PASSWORD"));
62
63 let trusted_device = client
64 .login(user, None)
65 .await
66 .expect("Login should succeed")
67 .expect("A trusted device should've been returned");
68
69 assert!(!trusted_device.device_key.is_empty());
70 assert!(!trusted_device.device_group_key.is_empty());
71 assert!(!trusted_device.device_password.is_empty());
72 assert!(trusted_device.device_key.starts_with(dotenv!("REGION")));
73
74 println!("Hello: {:?}", client.get_devices().await);
75
76 client.logout().await;
77 }
78
79 #[tokio::test]
80 async fn test_cognito_authentication_refresh() {
81 let mut client = Client::new("Home Automation");
82
83 let user = User::new(dotenv!("MOCK_USER_EMAIL"), dotenv!("MOCK_USER_PASSWORD"));
84
85 client
86 .login(user, None)
87 .await
88 .expect("Login should succeed");
89
90 let current_tokens = {
91 let mut tokens = client.tokens.lock().await;
94
95 let current_tokens = tokens.clone().expect("Tokens should be present");
96
97 let replacement_tokens = Arc::new(Tokens::new(
98 current_tokens.id_token.to_string(),
99 current_tokens.access_token.to_string(),
100 current_tokens.refresh_token.to_string(),
101 -1000,
102 ));
103 tokens.replace(Arc::clone(&replacement_tokens));
104
105 replacement_tokens
106 };
107
108 let refreshed_tokens = client
109 .refresh_tokens_if_needed()
110 .await
111 .expect("Refresh tokens should succeed");
112
113 assert_ne!(current_tokens.access_token, refreshed_tokens.access_token);
114 assert_eq!(current_tokens.refresh_token, refreshed_tokens.refresh_token);
115 assert!(current_tokens.expires_at < refreshed_tokens.expires_at);
116
117 client.logout().await;
118 }
119}