1use dioxus::prelude::*;
7
8#[server]
10async fn get_local_addr() -> Result<String, ServerFnError> {
11 use crate::state::LOCAL_APP_STATE;
12 let state = LOCAL_APP_STATE.lock().await;
13 Ok(state.get_site_addr_as_string())
14}
15
16#[server]
18async fn get_site_id() -> Result<String, ServerFnError> {
19 use crate::state::LOCAL_APP_STATE;
20 let state = LOCAL_APP_STATE.lock().await;
21 Ok(state.get_site_id().to_string())
22}
23
24#[server]
26async fn get_peers() -> Result<Vec<String>, ServerFnError> {
27 use crate::state::LOCAL_APP_STATE;
28 let state = LOCAL_APP_STATE.lock().await;
29 Ok(state.get_cli_peers_addrs_as_string())
30}
31
32#[server]
34async fn get_lamport() -> Result<i64, ServerFnError> {
35 use crate::state::LOCAL_APP_STATE;
36 let state = LOCAL_APP_STATE.lock().await;
37 Ok(*state.get_clock().get_lamport())
38}
39
40#[server]
42async fn get_vector_clock() -> Result<String, ServerFnError> {
43 use crate::state::LOCAL_APP_STATE;
44 let state = LOCAL_APP_STATE.lock().await;
45 let vector_clock = state.get_clock().get_vector_clock_values();
46 let vector_clock_string = vector_clock
47 .iter()
48 .map(|x| x.to_string())
49 .collect::<Vec<String>>()
50 .join(", ");
51 Ok(vector_clock_string)
52}
53
54#[server]
56async fn get_db_path() -> Result<String, ServerFnError> {
57 let conn = crate::db::DB_CONN.lock().unwrap();
58 let path = conn.path().unwrap();
59 Ok(path.to_string().split("/").last().unwrap().to_string())
61}
62
63#[server]
65async fn get_nb_connected_neighbours() -> Result<i64, ServerFnError> {
66 use crate::state::LOCAL_APP_STATE;
67 let state = LOCAL_APP_STATE.lock().await;
68 Ok(state.get_nb_connected_neighbours())
69}
70
71#[server]
73async fn get_nb_cli_peers() -> Result<i64, ServerFnError> {
74 use crate::state::LOCAL_APP_STATE;
75 let state = LOCAL_APP_STATE.lock().await;
76 Ok(state.get_cli_peers_addrs().len() as i64)
77}
78
79#[server]
81async fn get_connected_neighbours() -> Result<Vec<String>, ServerFnError> {
82 use crate::state::LOCAL_APP_STATE;
83 let state = LOCAL_APP_STATE.lock().await;
84 Ok(state.get_connected_nei_addr_string())
85}
86
87#[server]
89async fn get_peer_addrs() -> Result<Vec<String>, ServerFnError> {
90 use crate::state::LOCAL_APP_STATE;
91 let state = LOCAL_APP_STATE.lock().await;
92 Ok(state.get_cli_peers_addrs_as_string())
93}
94
95#[server]
97async fn ask_for_snapshot() -> Result<(), ServerFnError> {
98 if let Err(e) =
99 crate::control::enqueue_critical(crate::control::CriticalCommands::FileSnapshot).await
100 {
101 return Err(ServerFnError::new(format!(
102 "[SERVER] Failed make the local snapshot: {e}"
103 )));
104 }
105 Ok(())
106}
107
108#[server]
110async fn get_snapshot_content() -> Result<Option<String>, ServerFnError> {
111 use crate::snapshot::LOCAL_SNAPSHOT_MANAGER;
112 use tokio::fs::File;
113 use tokio::io::AsyncReadExt;
114
115 let maybe_filename = {
116 let state = LOCAL_SNAPSHOT_MANAGER.lock().await;
117 state.path.clone()
118 };
119
120 if let Some(filename) = maybe_filename {
121 let mut file = File::open(&filename).await?;
122 let mut contents = String::new();
123 file.read_to_string(&mut contents).await?;
124 Ok(Some(contents))
125 } else {
126 Ok(None)
127 }
128}
129
130#[component]
142pub fn Info() -> Element {
143 let mut local_addr = use_signal(|| "".to_string());
144 let mut site_id = use_signal(|| "".to_string());
145 let mut peers_addr = use_signal(|| Vec::new());
146 let mut connected_neighbours = use_signal(|| Vec::new());
147 let mut lamport = use_signal(|| 0i64);
148 let mut vector_clock = use_signal(|| "".to_string());
149 let mut nb_neighbours = use_signal(|| 0i64);
150 let mut nb_peers = use_signal(|| 0i64);
151 let mut db_path = use_signal(|| "".to_string());
152 let mut snapshot_content = use_signal(|| None::<String>);
153
154 use_future(move || async move {
155 if let Ok(data) = get_local_addr().await {
157 local_addr.set(data);
158 } else {
159 local_addr.set("Error fetching local address".to_string());
161 }
162
163 if let Ok(data) = get_site_id().await {
165 site_id.set(data);
166 } else {
167 site_id.set("Error fetching site ID".to_string());
168 }
169
170 if let Ok(data) = get_peers().await {
172 peers_addr.set(data);
173 } if let Ok(data) = get_connected_neighbours().await {
177 connected_neighbours.set(data);
178 } if let Ok(data) = get_lamport().await {
182 lamport.set(data);
183 } if let Ok(data) = get_vector_clock().await {
187 vector_clock.set(data);
188 } if let Ok(data) = get_nb_connected_neighbours().await {
192 nb_neighbours.set(data);
193 } if let Ok(data) = get_nb_cli_peers().await {
197 nb_peers.set(data);
198 } if let Ok(data) = get_db_path().await {
202 db_path.set(data);
203 } if let Ok(data) = get_snapshot_content().await {
207 snapshot_content.set(data);
208 } });
210
211 rsx! {
212 div { class: "info-panel", h2 { "System Information" }
214
215 div { class: "info-item",
216 strong { "💾 Database : " }
217 span { "{db_path}" }
218 }
219
220 div { class: "info-item",
221 strong { "🌐 Site Address: " }
222 span { "{local_addr}" }
223 }
224 div { class: "info-item",
225 strong { "🆔 Site ID: " }
226 span { "{site_id}" }
227 }
228 div { class: "info-item",
229 strong { "⏰ Lamport Timestamp: " }
230 span { "{lamport}" }
231 }
232 div { class: "info-item",
233 strong { "⏱️ Vector Clock : " }
234 span { "{vector_clock}" }
235 }
236 div { class: "info-item",
237 strong { "🌍 Number of connected neighbours: " }
238 span { "{nb_neighbours}" }
239 }
240
241 div { class: "info-item",
242 strong { "🤝 Connected Neighbours: " }
243 if connected_neighbours.read().is_empty() {
244 span { "No peers currently connected." }
245 } else {
246 ul { class: "peer-list",
247 for adr in connected_neighbours.read().iter() {
248 li { key: "{adr}", "{adr}" }
249 }
250 }
251 }
252 }
253
254 div { class: "info-item",
255 strong { "🌍 Number of CLI peers: " }
256 span { "{nb_peers}" }
257 }
258
259 div { class: "info-item",
260 strong { "🤝 CLI peers adresses: " }
261 if peers_addr.read().is_empty() {
262 span { "No peers currently connected." }
263 } else {
264 ul { class: "peer-list",
265 for adr in peers_addr.read().iter() {
266 li { key: "{adr}", "{adr}" }
267 }
268 }
269 }
270 }
271
272 div {
273 class: "info-item",
274 style: "display: flex; justify-content: center;",
275 form {
276 button {
277 class: "snapshot",
278 r#type: "submit",
279 onclick: move |_| {
280 async move {
281 if let Err(e) = ask_for_snapshot().await {
282 log::error!("Error taking snapshot: {e}");
283 }
284 }
285 },
286 "Take a snapshot"
287 }
288 }
289 }
290
291 div { class: "info-item",
292 strong { "📄 Last Snapshot Content:" }
293 if let Some(content) = snapshot_content.read().as_ref() {
294 pre { "{content}" }
295 } else {
296 span { "No snapshot available." }
297 }
298 }
299 }
300 }
301}