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
15use crate::authentication::HiveAuth;
16use crate::client::api::HiveApi;
17use crate::client::authentication::{Tokens, User};
18use std::sync::Arc;
19use tokio::sync::Mutex;
20
21#[derive(Debug)]
23pub struct Client {
24 auth: HiveAuth,
25 api: HiveApi,
26 user: Mutex<Option<User>>,
27 tokens: Mutex<Option<Arc<Tokens>>>,
28 friendly_name: String,
29}
30
31impl Client {
32 pub async fn new(friendly_name: &str) -> Self {
38 Self {
39 auth: HiveAuth::new().await,
40 api: HiveApi::new(),
41 user: Mutex::new(None),
42 tokens: Mutex::new(None),
43 friendly_name: friendly_name.to_string(),
44 }
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use dotenvy_macro::dotenv;
52
53 #[tokio::test]
54 async fn test_cognito_authentication_and_device_confirmation() {
55 let mut client = Client::new("Home Automation").await;
56
57 let user = User::new(
58 dotenv!("MOCK_USER_EMAIL"),
59 dotenv!("MOCK_USER_PASSWORD"),
60 None,
61 );
62
63 let trusted_device = client
64 .login(user)
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 client.logout().await;
75 }
76
77 #[tokio::test]
78 async fn test_cognito_authentication_refresh() {
79 let mut client = Client::new("Home Automation").await;
80
81 let user = User::new(
82 dotenv!("MOCK_USER_EMAIL"),
83 dotenv!("MOCK_USER_PASSWORD"),
84 None,
85 );
86
87 client.login(user).await.expect("Login should succeed");
88
89 let current_tokens = {
90 let mut tokens = client.tokens.lock().await;
93
94 let current_tokens = tokens.clone().unwrap();
95
96 let replacement_tokens = Arc::new(Tokens::new(
97 current_tokens.id_token.to_string(),
98 current_tokens.access_token.to_string(),
99 current_tokens.refresh_token.to_string(),
100 -1000,
101 ));
102 tokens.replace(Arc::clone(&replacement_tokens));
103
104 replacement_tokens
105 };
106
107 let refreshed_tokens = client
108 .refresh_tokens_if_needed()
109 .await
110 .expect("Refresh tokens should succeed");
111
112 assert_ne!(current_tokens.access_token, refreshed_tokens.access_token);
113 assert_eq!(current_tokens.refresh_token, refreshed_tokens.refresh_token);
114 assert!(current_tokens.expires_at < refreshed_tokens.expires_at);
115
116 client.logout().await;
117 }
118}