1use std::sync::Arc;
2
3use anyhow::anyhow;
4use fxhash::FxHashMap;
5use rsa::{pss::BlindedSigningKey, sha2::Sha256};
6
7use crate::{
8 client_config::ParsedConfig,
9 client_polling::{self},
10 client_registration,
11 client_types::types::DeviceCapabilityStatus,
12};
13
14const RSA_KEY_SIZE: usize = 2048;
16const POLLING_INTERVAL: u64 = 500;
17
18pub type ThreadSafeMutable<T> = Arc<std::sync::Mutex<T>>;
19
20pub struct NoshpClient<S: UserDefinedState> {
21 callbacks: FxHashMap<String, Box<Callback<S>>>,
22 client_state: ClientState<S>,
23 server_ip: Option<String>,
24}
25impl<S> NoshpClient<S>
30where
31 S: UserDefinedState + 'static,
32{
33 pub fn new() -> Self {
34 let has_update = ThreadSafeMutable::new(std::sync::Mutex::new(false));
35 Self {
36 callbacks: FxHashMap::default(),
37 client_state: ClientState::new(has_update),
38 server_ip: None,
39 }
40 }
41 pub fn add_callback(mut self, capabillity: &str, callback: Box<Callback<S>>) -> Self {
43 self.callbacks.insert(String::from(capabillity), callback);
44 self
45 }
46 pub fn set_state(mut self, state: S) -> Self {
48 self.client_state.user_state = state;
49 self
50 }
51 pub fn set_server_ip(mut self, server_ip: String) -> Self {
53 self.server_ip = Some(server_ip);
54 self
55 }
56 pub async fn run(mut self, config: ParsedConfig) -> anyhow::Result<()> {
58 if let (None, None) = (self.server_ip.clone(), config.server_ip.clone()) {
60 return Err(anyhow!("Did not receive a server ip from the config or using set_server_ip, one of them needs to be set"));
61 }
62
63 let server_ip = match self.server_ip {
65 Some(v) => v,
66 None => config.server_ip.unwrap(),
67 };
68
69 let capabilities = config.capabilities;
70
71 let capabilities: ThreadSafeMutable<Vec<DeviceCapabilityStatus>> =
72 Arc::new(std::sync::Mutex::new(capabilities));
73
74 self.client_state.capabilities = capabilities.clone();
75 let (private_key, signing_key) = {
76 let mut rng = rand::thread_rng();
77 let private_key = rsa::RsaPrivateKey::new(&mut rng, RSA_KEY_SIZE).unwrap();
78 let signing_key = BlindedSigningKey::<Sha256>::new(private_key.clone());
79 (private_key, signing_key)
80 };
81
82 let client_connection_details = client_registration::repeated_register_self(
83 &private_key.to_public_key(),
84 capabilities.clone(),
85 config.device_name,
86 server_ip.clone(),
87 )
88 .await;
89
90 {
91 let certificate = client_connection_details.security_certificate.clone();
92 let uuid = client_connection_details.uuid.clone();
93
94 let mut interval =
95 tokio::time::interval(std::time::Duration::from_millis(POLLING_INTERVAL));
96
97 let update_client = client_polling::polling::request_update_service_client
98 ::RequestUpdateServiceClient::connect(server_ip).await?;
99
100 let mut polling_service = client_polling::PollingService::new(
101 update_client,
102 capabilities.clone(),
103 self.client_state.has_update.clone(),
104 client_connection_details,
105 signing_key,
106 );
107
108 loop {
109 interval.tick().await;
110 let updates = polling_service
111 .get_updates(certificate.clone(), uuid.clone())
112 .await;
113 let updates = match updates {
114 Some(v) => v,
115 None => {
116 continue;
118 }
119 };
120 for update in updates.into_iter() {
121 let callback = self.callbacks.get(&update.capability);
122 let empty_request = Request::new(update.value);
124 match callback {
125 Some(callback) => callback(&mut self.client_state, empty_request),
126 None => println!("Received signal to {}", update.capability),
127 }
128 }
129 }
130 }
131 }
132}
133
134pub trait UserDefinedState: Default {}
135pub struct ClientState<S: UserDefinedState> {
137 pub user_state: S,
138 capabilities: Arc<std::sync::Mutex<Vec<DeviceCapabilityStatus>>>,
139 has_update: Arc<std::sync::Mutex<bool>>,
140}
141impl<S: UserDefinedState> ClientState<S> {
142 fn new(has_update: Arc<std::sync::Mutex<bool>>) -> Self {
143 return Self {
144 capabilities: Arc::default(),
145 user_state: S::default(),
146 has_update,
147 };
148 }
149 pub fn update_capability_availabillity(
150 &self,
151 capability_name: &str,
152 available: bool,
153 ) -> anyhow::Result<()> {
154 {
155 let has_update = self.has_update.lock();
156 let mut has_update = match has_update {
157 Ok(v) => v,
158 Err(e) => return Err(anyhow!("Unable to get lock, error: {}", e)),
159 };
160
161 *has_update = true;
162 }
163 {
164 let capabilities = self.capabilities.lock();
165 let mut capabilities = match capabilities {
166 Ok(v) => v,
167 Err(e) => return Err(anyhow!("Unable to get lock, error: {}", e)),
168 };
169 for capability in capabilities.iter_mut() {
170 if capability.capability == capability_name {
171 capability.available = available;
172 return Ok(());
173 }
174 }
175 }
176 Err(anyhow!(
177 "Unable to find specified capability with name: {}",
178 capability_name
179 ))
180 }
181}
182
183pub type Callback<S> = fn(&mut ClientState<S>, Request);
184
185pub struct Request {
186 pub value: Option<f32>,
187}
188impl Request {
189 pub fn new(value: Option<f32>) -> Self {
190 Self { value }
191 }
192}