This commit is contained in:
Tiago Batista Cardoso
2026-01-24 23:04:01 +01:00
parent 7a1155c0bd
commit 95c2dfe83c
4 changed files with 237 additions and 104 deletions

View File

@@ -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<String>,
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<String>, // Some(message) -> afficher, None -> rien
success_message: Option<String>, // 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<String>) {
self.error_message = Some(msg.into());
pub fn show_error(&mut self, msg: impl Into<String>, peer_username: impl Into<String>) {
self.error_message = Some((msg.into(), peer_username.into()));
}
pub fn show_success(&mut self, msg: impl Into<String>) {
self.success_message = Some(msg.into());
pub fn show_success(&mut self, msg: impl Into<String>, peer_username: impl Into<String>) {
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,24 +439,66 @@ 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.
// 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()
};
let internal = frame.show(ui, |ui| {
frame
.show(ui, |ui| {
ui.selectable_label(is_active, format!("{}", peer.0))
});
selectable = internal.inner;
})
.inner
} else {
selectable = ui.selectable_label(is_active, format!("{}", peer.0));
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();
});
}
if selectable.clicked() {
// 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
@@ -468,7 +514,7 @@ impl eframe::App for P2PClientApp {
));
}
}
selectable.context_menu(|ui| {
resp.context_menu(|ui| {
// ... action
match self.server_status {
ServerStatus::Connected => {
@@ -492,14 +538,20 @@ impl eframe::App for P2PClientApp {
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(
match self.network_cmd_tx.send(
NetworkCommand::NatTraversal(
peer.0.to_string(),
self.connected_address.clone(),
)) {
),
) {
Ok(_) => {
print!("[+] successfully sent nat traversal request")
print!(
"[+] successfully sent nat traversal request"
)
}
Err(_) => {
print!("[-] failed to send nat traversal request")
@@ -513,6 +565,75 @@ impl eframe::App for P2PClientApp {
// ... 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();
}

View File

@@ -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!(
match event_tx.send(NetworkEvent::Success(
format!(
"Successfully sent ping message to {}.",
addr.to_string()
))) {
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);

View File

@@ -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()));
}
}

View File

@@ -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()));
}
}