diff --git a/client-gui/src/gui_app.rs b/client-gui/src/gui_app.rs index 12f123e..c42aa48 100644 --- a/client-gui/src/gui_app.rs +++ b/client-gui/src/gui_app.rs @@ -5,8 +5,8 @@ use client_network::{ }; use crossbeam_channel::{Receiver, Sender}; use egui::{ - CentralPanel, CollapsingHeader, Color32, Context, CornerRadius, Frame, Response, ScrollArea, - SidePanel, Stroke, TopBottomPanel, Ui, ViewportCommand, + Align, CentralPanel, CollapsingHeader, Color32, Context, CornerRadius, Frame, Layout, Response, + ScrollArea, SidePanel, Stroke, TopBottomPanel, Ui, ViewportCommand, }; use std::collections::HashSet; use std::{collections::HashMap, fmt::format, io::Seek}; @@ -32,6 +32,7 @@ pub struct P2PClientApp { // GUI State status_message: String, known_peers: Vec<(String, bool)>, + loading_peers: Vec, connect_address_input: String, connected_address: String, connect_name_input: String, @@ -47,8 +48,8 @@ pub struct P2PClientApp { show_network_popup: bool, // gérer selon besoin - error_message: Option, // Some(message) -> afficher, None -> rien - success_message: Option, // Some(message) -> afficher, None -> rien + error_message: Option<(String, String)>, // Some(message) -> afficher, None -> rien + success_message: Option<(String, String)>, // Some(message) -> afficher, None -> rien active_server: String, current_downloading_file_map: MerkleTree, @@ -73,6 +74,7 @@ impl P2PClientApp { network_event_rx: event_rx, status_message: "Client Initialized. Awaiting network status...".to_string(), known_peers: Vec::new(), + loading_peers: Vec::new(), connect_address_input: "https://jch.irif.fr:8443".to_string(), connected_address: "".to_string(), loaded_fs, @@ -89,11 +91,11 @@ impl P2PClientApp { remaining_chunks: HashSet::new(), } } - pub fn show_error(&mut self, msg: impl Into) { - self.error_message = Some(msg.into()); + pub fn show_error(&mut self, msg: impl Into, peer_username: impl Into) { + self.error_message = Some((msg.into(), peer_username.into())); } - pub fn show_success(&mut self, msg: impl Into) { - self.success_message = Some(msg.into()); + pub fn show_success(&mut self, msg: impl Into, peer_username: impl Into) { + self.success_message = Some((msg.into(), peer_username.into())); } pub fn clear_error(&mut self) { self.error_message = None; @@ -252,8 +254,9 @@ impl eframe::App for P2PClientApp { self.known_peers.clear(); self.server_status = ServerStatus::NotConnected; } - NetworkEvent::Error(err) => { - self.show_error(err); + NetworkEvent::Error(err, peer_username) => { + self.loading_peers.retain(|s| s != peer_username.as_str()); + self.show_error(err, peer_username); } NetworkEvent::InitDownload(hash, ip) => { if let Some(addr) = &self.active_peer { @@ -299,15 +302,16 @@ impl eframe::App for P2PClientApp { println!("bigfile téléchargé"); } } - NetworkEvent::Success(msg) => { - self.show_success(msg); + NetworkEvent::Success(msg, peer_username) => { + self.loading_peers.retain(|s| s != peer_username.as_str()); + self.show_success(msg, peer_username); } NetworkEvent::HandshakeFailed() => {} NetworkEvent::ServerHandshakeFailed(err) => { self.active_server = "".to_string(); self.server_status = ServerStatus::NotConnected; let err_msg = format!("Failed to connect to the server: {}", err); - self.show_error(err_msg); + self.show_error(err_msg, ""); let res = self.network_cmd_tx.send(NetworkCommand::ResetServerPeer()); } } @@ -435,84 +439,201 @@ impl eframe::App for P2PClientApp { self.active_peer.as_ref().map_or(false, |id| id == &peer.0); // if peer.id == self.active_peer_id let selectable: Response; - if &self.active_server == &peer.0 { - // Create a frame with green background and render the selectable inside it. - // Adjust rounding, padding and stroke as desired. - let frame = Frame { - fill: Color32::DARK_BLUE, - stroke: Stroke::default(), - corner_radius: CornerRadius::from(0.5), - ..Default::default() - }; - let internal = frame.show(ui, |ui| { + // if &self.active_server == &peer.0 { + // // Create a frame with green background and render the selectable inside it. + // // Adjust rounding, padding and stroke as desired. + // let frame = Frame { + // fill: Color32::DARK_BLUE, + // stroke: Stroke::default(), + // corner_radius: CornerRadius::from(0.5), + // ..Default::default() + // }; + // let internal = frame.show(ui, |ui| { + // // horizontal row: label on the left, spinner on the right + // ui.horizontal(|ui| { + // // let selectable label take remaining space + // ui.with_layout(Layout::left_to_right(Align::Center), |ui| { + // ui.add_space(0.0); // ensure layout established + // return ui.selectable_label( + // is_active, + // format!("{}", peer.0), + // ); + // }) + // .inner // return Response from the inner closure if your egui version does so + // }) + // }); + // selectable = internal.inner.inner; + // } else { + // selectable = ui.selectable_label(is_active, format!("{}", peer.0)); + // } + + // place spinner to the right of the label + ui.horizontal(|ui| { + // Use same width for the label widget as the selectable we already created: + // Recreate selectable inline so both label and spinner share the same row. + let resp = if &self.active_server == &peer.0 { + // draw with frame inline + let frame = Frame { + fill: Color32::DARK_BLUE, + stroke: Stroke::default(), + corner_radius: CornerRadius::from(0.5), + ..Default::default() + }; + frame + .show(ui, |ui| { + ui.selectable_label(is_active, format!("{}", peer.0)) + }) + .inner + } else { ui.selectable_label(is_active, format!("{}", peer.0)) + }; + + ui.add_space(4.0); // small gap + + if self.loading_peers.contains(&peer.0) { + // push spinner to right by expanding a spacer before it + ui.with_layout(Layout::right_to_left(Align::Center), |ui| { + ui.spinner(); + }); + } + + // use resp (click handling etc.) + if resp.clicked() { + // switch to displaying this peer's tree + self.active_peer = Some(peer.0.clone()); + // Request root content if not loaded + if !self + .loaded_fs + .contains_key(self.active_peer.as_ref().unwrap()) + { + //todo!(); + let _ = self.network_cmd_tx.send(NetworkCommand::Discover( + peer.0.clone(), + "root".to_string(), + self.connected_address.clone(), + )); + } + } + resp.context_menu(|ui| { + // ... action + match self.server_status { + ServerStatus::Connected => { + if ui + .button("Utiliser le peer en tant que serveur") + .clicked() + { + self.active_server = peer.0.to_string(); + let res = self.network_cmd_tx.send( + NetworkCommand::ServerHandshake( + peer.0.to_string(), + self.connected_address.clone(), + ), + ); + } + } + _ => {} + } + if ui.button("Send Ping").clicked() { + let res = self.network_cmd_tx.send(NetworkCommand::Ping( + peer.0.to_string(), + self.connected_address.clone(), + )); + + self.loading_peers.push(peer.0.to_owned()); + } + if ui.button("Send Nat Traversal Request").clicked() { + match self.network_cmd_tx.send( + NetworkCommand::NatTraversal( + peer.0.to_string(), + self.connected_address.clone(), + ), + ) { + Ok(_) => { + print!( + "[+] successfully sent nat traversal request" + ) + } + Err(_) => { + print!("[-] failed to send nat traversal request") + } + } + } + if ui.button("Infos").clicked() { + // action 3 + ui.close(); + } + + // ... autres boutons }); - selectable = internal.inner; - } else { - selectable = ui.selectable_label(is_active, format!("{}", peer.0)); - } - - if selectable.clicked() { - // switch to displaying this peer's tree - self.active_peer = Some(peer.0.clone()); - // Request root content if not loaded - if !self - .loaded_fs - .contains_key(self.active_peer.as_ref().unwrap()) - { - //todo!(); - let _ = self.network_cmd_tx.send(NetworkCommand::Discover( - peer.0.clone(), - "root".to_string(), - self.connected_address.clone(), - )); - } - } - selectable.context_menu(|ui| { - // ... action - match self.server_status { - ServerStatus::Connected => { - if ui - .button("Utiliser le peer en tant que serveur") - .clicked() - { - self.active_server = peer.0.to_string(); - let res = self.network_cmd_tx.send( - NetworkCommand::ServerHandshake( - peer.0.to_string(), - self.connected_address.clone(), - ), - ); - } - } - _ => {} - } - if ui.button("Send Ping").clicked() { - let res = self.network_cmd_tx.send(NetworkCommand::Ping( - peer.0.to_string(), - self.connected_address.clone(), - )); - } - if ui.button("Send Nat Traversal Request").clicked() { - match self.network_cmd_tx.send(NetworkCommand::NatTraversal( - peer.0.to_string(), - self.connected_address.clone(), - )) { - Ok(_) => { - print!("[+] successfully sent nat traversal request") - } - Err(_) => { - print!("[-] failed to send nat traversal request") - } - } - } - if ui.button("Infos").clicked() { - // action 3 - ui.close(); - } - - // ... autres boutons }); + + // if self.loading_peers.contains(&peer.0) { + // ui.spinner(); + // } + + //if selectable.clicked() { + // switch to displaying this peer's tree + //self.active_peer = Some(peer.0.clone()); + //// Request root content if not loaded + //if !self + // .loaded_fs + // .contains_key(self.active_peer.as_ref().unwrap()) + //{ + // //todo!(); + // let _ = self.network_cmd_tx.send(NetworkCommand::Discover( + // peer.0.clone(), + // "root".to_string(), + // self.connected_address.clone(), + // )); + //} + //} + //selectable.context_menu(|ui| { + // // ... action + // match self.server_status { + // ServerStatus::Connected => { + // if ui + // .button("Utiliser le peer en tant que serveur") + // .clicked() + // { + // self.active_server = peer.0.to_string(); + // let res = self.network_cmd_tx.send( + // NetworkCommand::ServerHandshake( + // peer.0.to_string(), + // self.connected_address.clone(), + // ), + // ); + // } + // } + // _ => {} + // } + // if ui.button("Send Ping").clicked() { + // let res = self.network_cmd_tx.send(NetworkCommand::Ping( + // peer.0.to_string(), + // self.connected_address.clone(), + // )); + + // self.loading_peers.push(peer.0.to_owned()); + // } + // if ui.button("Send Nat Traversal Request").clicked() { + // match self.network_cmd_tx.send(NetworkCommand::NatTraversal( + // peer.0.to_string(), + // self.connected_address.clone(), + // )) { + // Ok(_) => { + // print!("[+] successfully sent nat traversal request") + // } + // Err(_) => { + // print!("[-] failed to send nat traversal request") + // } + // } + // } + // if ui.button("Infos").clicked() { + // // action 3 + // ui.close(); + // } + + // // ... autres boutons + //}); } } }); @@ -554,7 +675,8 @@ impl eframe::App for P2PClientApp { .resizable(false) .anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0]) .show(ctx, |ui| { - ui.label(&msg); + ui.label(&msg.1); + ui.label(&msg.0); if ui.button("OK").clicked() { self.clear_error(); } @@ -568,7 +690,8 @@ impl eframe::App for P2PClientApp { .resizable(false) .anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0]) .show(ctx, |ui| { - ui.label(&msg); + ui.label(&msg.1); + ui.label(&msg.0); if ui.button("OK").clicked() { self.clear_success(); } diff --git a/client-network/src/lib.rs b/client-network/src/lib.rs index aca1065..fefb9de 100644 --- a/client-network/src/lib.rs +++ b/client-network/src/lib.rs @@ -194,8 +194,8 @@ pub enum NetworkEvent { Connected(String), ConnectedHandshake(), Disconnected(), - Error(String), - Success(String), + Error(String, String), + Success(String, String), PeerConnected(String), PeerListUpdated(Vec<(String, bool)>), FileTreeReceived([u8; 32], MerkleNode, String), // peer_id, content @@ -458,7 +458,8 @@ pub fn start_p2p_executor( Err(e) => { let mut err_msg = String::from("failed to initialize socket: "); err_msg += &e.to_string(); - let res = event_tx.send(NetworkEvent::Error(err_msg)); + let res = + event_tx.send(NetworkEvent::Error(err_msg, name.to_owned())); let res = event_tx.send(NetworkEvent::Disconnected()); None } @@ -468,7 +469,8 @@ pub fn start_p2p_executor( if let Err(e) = register_with_the_server(&sd.cryptopair(), &ip).await { let mut err_msg = String::from("request failed: "); err_msg += &e.to_string(); - let res = event_tx.send(NetworkEvent::Error(err_msg)); + let res = + event_tx.send(NetworkEvent::Error(err_msg, name.to_owned())); let res = event_tx.send(NetworkEvent::Disconnected()); } else { let res = event_tx.send(NetworkEvent::Connected(ip)); @@ -492,6 +494,7 @@ pub fn start_p2p_executor( if ip == "" { let res = event_tx.send(NetworkEvent::Error( "Not registered to any server".to_string(), + "".to_owned(), )); } else { println!("cc"); @@ -530,7 +533,7 @@ pub fn start_p2p_executor( let pingrequest = construct_message(PING, Vec::new(), id, sd.cryptopair_ref()); let peer_address = - get_socket_address(str, ip, shared_data.as_ref()).await; + get_socket_address(str.to_owned(), ip, shared_data.as_ref()).await; match peer_address { Ok(addr) => { //if let Some(ping) = pingrequest { @@ -546,10 +549,13 @@ pub fn start_p2p_executor( // sd.messages_list(), // ); //} - match event_tx.send(NetworkEvent::Success(format!( - "Successfully sent ping message to {}.", - addr.to_string() - ))) { + match event_tx.send(NetworkEvent::Success( + format!( + "Successfully sent ping message to {}.", + addr.to_string(), + ), + str.to_owned(), + )) { Ok(_) => {} Err(e) => { eprintln!("NetworkEvent error : {}", e); @@ -557,7 +563,9 @@ pub fn start_p2p_executor( }; } Err(err_msg) => { - match event_tx.send(NetworkEvent::Error(err_msg.to_string())) { + match event_tx + .send(NetworkEvent::Error(err_msg.to_string(), str)) + { Ok(_) => {} Err(e) => { eprintln!("NetworkEvent error : {}", e); @@ -624,7 +632,9 @@ pub fn start_p2p_executor( ); } Err(err_msg) => { - match event_tx.send(NetworkEvent::Error(err_msg.to_string())) { + match event_tx + .send(NetworkEvent::Error(err_msg.to_string(), username)) + { Ok(_) => {} Err(e) => { eprintln!("NetworkEvent error : {}", e); diff --git a/client-network/src/message_handling.rs b/client-network/src/message_handling.rs index f50c660..149322f 100644 --- a/client-network/src/message_handling.rs +++ b/client-network/src/message_handling.rs @@ -317,10 +317,10 @@ pub fn parse_message( String::from_utf8(received_message[LENGTH..(msg_length + LENGTH + 4)].to_vec()) { let err_msg = format!("Error received from peer {} : {}", ip, err_received); - let _ = cmd_tx_clone.send(NetworkEvent::Error(err_msg)); + let _ = cmd_tx_clone.send(NetworkEvent::Error(err_msg, "".to_owned())); } else { let err_msg = format!("Error received from peer {} : N/A", ip,); - let _ = cmd_tx_clone.send(NetworkEvent::Error(err_msg)); + let _ = cmd_tx_clone.send(NetworkEvent::Error(err_msg, "".to_owned())); } } diff --git a/client-network/src/registration.rs b/client-network/src/registration.rs index 608a054..7df1e06 100644 --- a/client-network/src/registration.rs +++ b/client-network/src/registration.rs @@ -92,7 +92,7 @@ pub async fn perform_handshake( } None => { let err_msg = format!("failed to retreive socket address:").to_string(); - let res = event_tx.send(NetworkEvent::Error(err_msg)); + let res = event_tx.send(NetworkEvent::Error(err_msg, "".to_owned())); } }