diff --git a/.gitignore b/.gitignore index c41cc9e..f1dad79 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/target \ No newline at end of file +/target +target/ diff --git a/client-gui/src/gui_app.rs b/client-gui/src/gui_app.rs index 34b95fb..d279c07 100644 --- a/client-gui/src/gui_app.rs +++ b/client-gui/src/gui_app.rs @@ -9,6 +9,7 @@ use egui::{ Popup, ScrollArea, SidePanel, TextStyle, TopBottomPanel, Ui, ViewportCommand, debug_text::print, }; +use std::collections::HashSet; use std::{collections::HashMap, fmt::format, io::Seek}; use std::fs::{File, OpenOptions, create_dir}; @@ -48,8 +49,11 @@ pub struct P2PClientApp { show_network_popup: bool, // gérer selon besoin error_message: Option, // Some(message) -> afficher, None -> rien - // active_server: String, + + current_downloading_file_map: MerkleTree, + remaining_chunks: HashSet<[u8; 32]>, + root_downloading_file: String, } impl P2PClientApp { @@ -57,6 +61,7 @@ impl P2PClientApp { //let (root_hash, tree_content) = MerkleNode::generate_base_tree(); let mut loaded_fs = HashMap::new(); + let mut current_downloading_file_map = MerkleTree::new(HashMap::new(), [0; 32]); //let tree = MerkleTree::new(tree_content, root_hash); //loaded_fs.insert("bob".to_string(), tree); @@ -78,6 +83,9 @@ impl P2PClientApp { connect_name_input: "bob".to_string(), active_server: "".to_string(), shared_tree: generate_base_tree(), + current_downloading_file_map: current_downloading_file_map, + root_downloading_file: "".to_string(), + remaining_chunks: HashSet::new(), } } pub fn show_error(&mut self, msg: impl Into) { @@ -163,6 +171,7 @@ impl eframe::App for P2PClientApp { NetworkCommand::GetChildren( entry.content_hash, ip.clone(), + false, ), ); } @@ -170,7 +179,11 @@ impl eframe::App for P2PClientApp { MerkleNode::BigDirectory(bigd) => { for entry in bigd.children_hashes { let _ = self.network_cmd_tx.send( - NetworkCommand::GetChildren(entry, ip.clone()), + NetworkCommand::GetChildren( + entry, + ip.clone(), + false, + ), ); } } @@ -235,7 +248,50 @@ impl eframe::App for P2PClientApp { NetworkEvent::Error(err) => { self.show_error(err); } - NetworkEvent::DataReceived(_, merkle_node) => todo!(), + NetworkEvent::InitDownload(hash, ip) => { + if let Some(addr) = &self.active_peer { + if let Some(roottree) = self.loaded_fs.get(addr) { + if let Some(root) = roottree.data.get(&hash) { + let _ = self + .current_downloading_file_map + .data + .insert(hash, root.clone()); + let _ = self + .network_cmd_tx + .send(NetworkCommand::GetChildren(hash, ip, true)); + } + } + } + } + NetworkEvent::DataReceived(hash, merkle_node, ip) => { + let _ = self + .current_downloading_file_map + .data + .insert(hash, merkle_node.clone()); + + println!("merkle:{}", merkle_node.get_type_byte()); + match merkle_node { + MerkleNode::Big(bigfile) => { + for entry in bigfile.children_hashes { + println!("entry: {:?}", entry); + let _ = self.network_cmd_tx.send(NetworkCommand::GetChildren( + entry, + ip.clone(), + true, + )); + self.remaining_chunks.insert(entry); + } + self.remaining_chunks.remove(&hash); + } + MerkleNode::Chunk(chunk) => { + self.remaining_chunks.remove(&hash); + } + _ => {} + } + if self.remaining_chunks.is_empty() { + println!("bigfile téléchargé"); + } + } NetworkEvent::HandshakeFailed() => {} NetworkEvent::ServerHandshakeFailed(err) => { self.active_server = "".to_string(); @@ -350,6 +406,11 @@ impl eframe::App for P2PClientApp { error.to_string() ); } + if let Some(active_peer) = &self.active_peer { + if let Some(tree) = self.loaded_fs.get(active_peer) { + println!("{}", tree.data.len()); + } + } } }); @@ -530,7 +591,7 @@ impl P2PClientApp { .on_hover_text("Click to request file chunks...") .clicked() { - match create_dir("../Download/") { + match create_dir("./Download/") { Ok(_) => println!("Directory created successfully!"), Err(e) => println!("Failed to create directory: {}", e), } @@ -573,25 +634,16 @@ impl P2PClientApp { }); } MerkleNode::Big(node) => { - /*CollapsingHeader::new(format!("📄 (B) {}", name)) - .default_open(false) - .enabled(true) - .show(ui, |ui| { - for child in &node.children_hashes { - self.draw_file_node(ui, child.clone(), tree, depth + 1, None); - } - });*/ if ui .selectable_label(false, format!("📄 (B) {}", name)) .on_hover_text("Click to request file chunks...") .clicked() { - /*self.network_cmd_tx.send(NetworkCommand::GetChildren(node.children_hashes, ))*/ - todo!(); - // if let Some(peer_id) = active_peer_id.clone() { - // let _ = self.network_cmd_tx.send(NetworkCommand::RequestChunk(peer_id, entry_hash.clone())); - // // self.status_message = format!("Requested file chunks for: {}...", &entry_hash[..8]); - // } + if let Some(addr) = &self.active_peer { + let _ = self + .network_cmd_tx + .send(NetworkCommand::InitDownload(to_draw, addr.clone())); + } } } MerkleNode::BigDirectory(node) => { diff --git a/client-network/src/data.rs b/client-network/src/data.rs index 47c0c68..8729574 100644 --- a/client-network/src/data.rs +++ b/client-network/src/data.rs @@ -8,6 +8,8 @@ use std::io::{self, Write}; use std::env; +use crate::data; + // --- Constants --- pub const MAX_CHUNK_DATA_SIZE: usize = 1024; pub const MAX_DIRECTORY_ENTRIES: usize = 16; @@ -30,9 +32,9 @@ pub enum MerkleNode { // 0 to 16 directory entries. Directory(DirectoryNode) = 1, // list of 2 to 32 hashes pointing to Chunk or Big nodes. - Big(BigNode) = 3, + Big(BigNode) = 2, // list of 2 to 32 hashes pointing to Directory or BigDirectory nodes. - BigDirectory(BigDirectoryNode) = 4, + BigDirectory(BigDirectoryNode) = 3, } #[derive(Debug, Clone)] @@ -45,6 +47,9 @@ impl MerkleTree { pub fn new(data: HashMap, root: NodeHash) -> MerkleTree { MerkleTree { data, root } } + pub fn clear_data(&mut self) { + self.data.clear(); + } } #[derive(Debug, Clone)] diff --git a/client-network/src/datum_parsing.rs b/client-network/src/datum_parsing.rs index c22b3a6..84e456d 100644 --- a/client-network/src/datum_parsing.rs +++ b/client-network/src/datum_parsing.rs @@ -49,6 +49,7 @@ pub fn parse_received_datum( } } BIG => { + println!("its a BIG bro"); let chlidren: Vec = Vec::new(); Some(( hash_name, @@ -56,13 +57,6 @@ pub fn parse_received_datum( children_hashes: chlidren, }), )) - /*let chlidren: Vec = Vec::new(); - tree.data.insert( - hash_name, - MerkleNode::Big(crate::BigNode { - children_hashes: chlidren, - }), - );*/ } BIGDIRECTORY => { let mut bigdir_entries: Vec = Vec::new(); diff --git a/client-network/src/lib.rs b/client-network/src/lib.rs index d897624..8604f1b 100644 --- a/client-network/src/lib.rs +++ b/client-network/src/lib.rs @@ -25,6 +25,7 @@ use crate::{ server_communication::{generate_id, get_peer_list}, threads_handling::Worker, }; +use std::collections::HashSet; use std::{ clone, io::Error, @@ -149,10 +150,11 @@ pub enum NetworkCommand { Disconnect(), ResetServerPeer(), Discover(String, String, String), - GetChildren([u8; 32], String), + GetChildren([u8; 32], String, bool), SendDatum(MerkleNode, [u8; 32], String), SendNoDatum(Vec, String), SendRootReply(Vec, String), + InitDownload([u8; 32], String), // ... } @@ -165,12 +167,13 @@ pub enum NetworkEvent { PeerConnected(String), PeerListUpdated(Vec<(String, bool)>), FileTreeReceived([u8; 32], MerkleNode, String), // peer_id, content - DataReceived(String, MerkleNode), + DataReceived([u8; 32], MerkleNode, String), FileTreeRootReceived(String, NodeHash), HandshakeFailed(), ServerHandshakeFailed(String), DatumRequest([u8; 32], String), RootRequest(String), + InitDownload([u8; 32], String), // ... } @@ -211,6 +214,14 @@ pub fn start_p2p_executor( // Check for commands from the GUI if let Ok(cmd) = cmd_rx.try_recv() { match cmd { + NetworkCommand::InitDownload(hash, ip) => { + if let Some(sd) = shared_data.as_ref() { + if let Some(res) = sd.handshake_peers.get_peer_info_username(ip) { + let _ = event_tx + .send(NetworkEvent::InitDownload(hash, res.ip.to_string())); + } + } + } NetworkCommand::SendRootReply(node_hash, addr) => { if let Some(sd) = shared_data.as_mut() { let mut payload = Vec::new(); @@ -363,7 +374,7 @@ pub fn start_p2p_executor( println!("no shared data"); } } - NetworkCommand::GetChildren(hash, ip) => { + NetworkCommand::GetChildren(hash, ip, is_file) => { if let Some(sd) = shared_data.as_ref() { let mut payload = Vec::new(); payload.extend_from_slice(&hash); @@ -377,7 +388,11 @@ pub fn start_p2p_executor( match datumreqest { None => {} Some(resp_msg) => { - sd.add_message(new_id, EventType::DatumRequest); + if is_file { + sd.add_message(new_id, EventType::DatumRequestBig); + } else { + sd.add_message(new_id, EventType::DatumRequest); + } println!("msg_sent:{:?}", resp_msg); sd.senders_ref().add_message_to_retry_queue( resp_msg.clone(), diff --git a/client-network/src/message_handling.rs b/client-network/src/message_handling.rs index 376721f..cd7896a 100644 --- a/client-network/src/message_handling.rs +++ b/client-network/src/message_handling.rs @@ -28,6 +28,7 @@ pub enum EventType { Ping, NatTraversal, DatumRequest, + DatumRequestBig, } const ID: usize = 4; @@ -429,6 +430,29 @@ pub fn parse_message( None => {} } } + EventType::DatumRequestBig => { + let _ = &guard.remove_entry(&id); + println!("message {} retiré de la liste", id); + let received_length = u16::from_be_bytes( + received_message[TYPE..LENGTH] + .try_into() + .expect("incorrect size"), + ); + let received_datum = &received_message[LENGTH..]; + let parsed_node = + parse_received_datum(received_datum.to_vec(), received_length as usize); + match parsed_node { + Some(tuple) => { + let _ = cmd_tx.send(NetworkEvent::DataReceived( + tuple.0, + tuple.1, + ip.to_string(), + )); + println!("datareceived event sent"); + } + None => {} + } + } _ => {} }, None => {} diff --git a/client-network/src/peers_refresh.rs b/client-network/src/peers_refresh.rs index 1684324..369fca8 100644 --- a/client-network/src/peers_refresh.rs +++ b/client-network/src/peers_refresh.rs @@ -137,7 +137,7 @@ pub fn update_handshake( } } drop(guard); - thread::sleep(Duration::from_secs(240)); + thread::sleep(Duration::from_secs(60)); } }); Worker::spawn(handle, crate::threads_handling::WorkerType::PING)