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