From 26fa7a833f0dc24b05744df5e622fcc7e41c64bd Mon Sep 17 00:00:00 2001 From: TIBERGHIEN corentin Date: Thu, 22 Jan 2026 03:19:43 +0100 Subject: [PATCH] datum parsing --- client-gui/src/gui_app.rs | 107 +++++++++---------------- client-network/src/datum_parsing.rs | 34 ++++---- client-network/src/lib.rs | 40 +++++++-- client-network/src/message_handling.rs | 7 +- project.pdf | Bin 79510 -> 79561 bytes 5 files changed, 96 insertions(+), 92 deletions(-) diff --git a/client-gui/src/gui_app.rs b/client-gui/src/gui_app.rs index 2da5513..09d3797 100644 --- a/client-gui/src/gui_app.rs +++ b/client-gui/src/gui_app.rs @@ -6,6 +6,7 @@ use crossbeam_channel::{Receiver, Sender}; use egui::{ Align, Align2, Button, CentralPanel, CollapsingHeader, Context, Id, LayerId, Layout, Order, Popup, ScrollArea, SidePanel, TextStyle, TopBottomPanel, Ui, ViewportCommand, + debug_text::print, }; use std::{collections::HashMap, fmt::format}; @@ -120,8 +121,36 @@ impl eframe::App for P2PClientApp { self.known_peers = peers; } - NetworkEvent::FileTreeReceived(node_hash, merklenode) => { - //self.status_message = "🔄 File tree updated successfully.".to_string(); + + NetworkEvent::FileTreeReceived(node_hash, merklenode, ip) => { + match &self.active_peer { + Some(active_peer) => { + if let Some(maptree) = self.loaded_fs.get_mut(active_peer) { + maptree.data.insert(node_hash, merklenode.clone()); + match merklenode { + MerkleNode::Directory(d) => { + for entry in d.entries { + let _ = self.network_cmd_tx.send( + NetworkCommand::GetChildren( + entry.content_hash, + ip.clone(), + ), + ); + } + } + MerkleNode::BigDirectory(bigd) => { + for entry in bigd.children_hashes { + let _ = self.network_cmd_tx.send( + NetworkCommand::GetChildren(entry, ip.clone()), + ); + } + } + _ => {} + } + } + } + None => {} + } } NetworkEvent::FileTreeRootReceived(peer_id, root_hash) => { // todo!(); @@ -133,8 +162,10 @@ impl eframe::App for P2PClientApp { );*/ if let Ok(chunknode) = ChunkNode::new(Vec::new()) { - let mut data_map: HashMap = HashMap::new(); - data_map.insert(root_hash, MerkleNode::Chunk(chunknode)); + let data_map: HashMap = HashMap::new(); + //data_map.insert(root_hash, MerkleNode::Chunk(chunknode)); + println!("len root: {}", data_map.len()); + println!("node hash: {:?}", root_hash.to_vec()); let tree = MerkleTree { data: data_map, root: root_hash, @@ -242,64 +273,7 @@ impl eframe::App for P2PClientApp { } _ => {} } - - /* ui.horizontal(|ui| { - ui.label("Server peer name:"); - ui.text_edit_singleline(&mut self.connect_server_name_input); - if ui.button("Connect").clicked() { - let addr = self.connect_address_input.clone(); - let serv_name = self.connect_server_name_input.clone(); - let _ = self - .network_cmd_tx - .send(NetworkCommand::ConnectToServer(addr, serv_name)); - self.server_status = ServerStatus::Loading; - ui.close(); - } - });*/ }); - - // état - - /*if ui.button("Network").clicked() { - self.show_network_popup = true; - }*/ - - /*if self.show_network_popup { - egui::Window::new("Network") - .collapsible(false) - .resizable(false) - .show(ctx, |ui| { - ui.horizontal_wrapped(|ui| { - ui.with_layout( - egui::Layout::right_to_left(egui::Align::TOP), - |ui| { - if ui.button("✕").clicked() { - self.show_network_popup = false; - } - }, - ); - }); - ui.horizontal(|ui| { - ui.label("Server IP:"); - ui.text_edit_singleline(&mut self.connect_address_input); - }); - ui.horizontal(|ui| { - ui.label("Server peer name:"); - ui.text_edit_singleline(&mut self.connect_server_name_input); - if ui.button("Connect").clicked() { - // envoyer commande... - let addr = self.connect_address_input.clone(); - let serv_name = self.connect_server_name_input.clone(); - let _ = self - .network_cmd_tx - .send(NetworkCommand::ConnectToServer(addr, serv_name)); - self.server_status = ServerStatus::Loading; - - self.show_network_popup = false; - } - }); - }); - }*/ }); }); @@ -514,11 +488,12 @@ impl P2PClientApp { if let Some(current) = tree.data.get(&to_draw) { let name = { if filename.is_some() { - filename_to_string(filename.unwrap()) + String::from_utf8(filename.unwrap().to_vec()).expect("err") } else { node_hash_to_hex_string(&to_draw) } }; + match current { MerkleNode::Chunk(node) => { if ui @@ -544,13 +519,7 @@ impl P2PClientApp { entry.content_hash, tree, depth + 1, - Some( - entry - .filename - .as_slice() - .try_into() - .expect("incorrect size"), - ), + Some(entry.filename.try_into().expect("incorrect size")), ); } }); diff --git a/client-network/src/datum_parsing.rs b/client-network/src/datum_parsing.rs index 25503f4..c22b3a6 100644 --- a/client-network/src/datum_parsing.rs +++ b/client-network/src/datum_parsing.rs @@ -11,9 +11,9 @@ pub fn parse_received_datum( datum_length: usize, ) -> Option<([u8; 32], MerkleNode)> { let hash_name: [u8; 32] = recevied_datum[..32].try_into().expect("error"); - let sigstart = datum_length - 64; - let value = &recevied_datum[32..sigstart]; + let value = &recevied_datum[32..datum_length]; let value_slice = value.to_vec(); + println!("valueslice: {:?}, {}", value_slice, value_slice.len()); let datum_type = value_slice[0]; match datum_type { CHUNK => Some(( @@ -21,14 +21,17 @@ pub fn parse_received_datum( MerkleNode::Chunk(crate::ChunkNode { data: value_slice }), )), DIRECTORY => { - let nb_entries = value_slice[1]; let mut dir_entries = Vec::new(); let mut offset = 1 as usize; - for i in 0..nb_entries { - offset = (offset as u8 + 64 * i) as usize; - let name = &recevied_datum[offset..offset + 32]; + for i in 0..((value_slice.len() - 1) / 64) as u8 { + offset = (1 + 64 * i as usize) as usize; + println!("offset:{}, i:{}", offset, i); + let name = &value_slice[offset..offset + 32]; let mut hash = [0u8; 32]; - hash.copy_from_slice(&recevied_datum[offset + 32..offset + 64]); + hash.copy_from_slice(&value_slice[offset + 32..offset + 64]); + let dp_name = String::from_utf8(name.to_vec()).expect("err"); + println!("name:{}", dp_name); + // envoyer un datum request dir_entries.push(DirectoryEntry { filename: name.try_into().expect("incorrect size"), @@ -62,19 +65,18 @@ pub fn parse_received_datum( );*/ } BIGDIRECTORY => { - let nb_entries = value_slice[1]; - let mut dir_entries = Vec::new(); + let mut bigdir_entries: Vec = Vec::new(); let mut offset = 1 as usize; - for i in 0..nb_entries { - offset = (offset as u8 + 64 * i) as usize; - let name = &recevied_datum[offset..offset + 32]; - let mut hash = [0u8; 32]; - hash.copy_from_slice(&recevied_datum[offset + 32..offset + 64]); + for i in 0..((value_slice.len() - 1) / 32) as u8 { + offset = (1 + 32 * i as usize) as usize; + println!("offset:{}, i:{}", offset, i); + let hash = &value_slice[offset..offset + 32]; + // envoyer un datum request - dir_entries.push(hash); + bigdir_entries.push(hash.try_into().expect("incorrect size")); } - let current = BigDirectoryNode::new(dir_entries); + let current = BigDirectoryNode::new(bigdir_entries); match current { Ok(current_node) => Some((hash_name, MerkleNode::BigDirectory(current_node))), Err(e) => { diff --git a/client-network/src/lib.rs b/client-network/src/lib.rs index 4f9a03d..7aa9b45 100644 --- a/client-network/src/lib.rs +++ b/client-network/src/lib.rs @@ -16,7 +16,8 @@ use crate::{ message_handling::EventType, messages_channels::{MultipleSenders, start_receving_thread, start_retry_thread}, messages_structure::{ - NATTRAVERSALREQUEST, NATTRAVERSALREQUEST2, PING, ROOTREQUEST, construct_message, + DATUMREQUEST, NATTRAVERSALREQUEST, NATTRAVERSALREQUEST2, PING, ROOTREQUEST, + construct_message, }, peers_refresh::HandshakeHistory, registration::{parse_addresses, perform_handshake, register_with_the_server}, @@ -147,7 +148,7 @@ pub enum NetworkCommand { Disconnect(), ResetServerPeer(), Discover(String, String, String), - GetChildren(String, String), + GetChildren([u8; 32], String), // ... } @@ -159,7 +160,7 @@ pub enum NetworkEvent { Error(String), PeerConnected(String), PeerListUpdated(Vec<(String, bool)>), - FileTreeReceived([u8; 32], MerkleNode), // peer_id, content + FileTreeReceived([u8; 32], MerkleNode, String), // peer_id, content DataReceived(String, MerkleNode), FileTreeRootReceived(String, NodeHash), HandshakeFailed(), @@ -289,8 +290,37 @@ pub fn start_p2p_executor( println!("no shared data"); } } - NetworkCommand::GetChildren(username, hash) => { - // envoie un datum request au peer + NetworkCommand::GetChildren(hash, ip) => { + if let Some(sd) = shared_data.as_ref() { + let mut payload = Vec::new(); + payload.extend_from_slice(&hash); + let new_id = generate_id(); + let datumreqest = construct_message( + DATUMREQUEST, + payload, + new_id, + sd.cryptopair_ref(), + ); + match datumreqest { + None => {} + Some(resp_msg) => { + sd.add_message(new_id, EventType::DatumRequest); + println!("msg_sent:{:?}", resp_msg); + sd.senders_ref().add_message_to_retry_queue( + resp_msg.clone(), + ip.clone(), + false, + ); + + sd.senders_ref().send_dispatch( + resp_msg, + ip.clone(), + false, + sd.messages_list(), + ); + } + } + } } NetworkCommand::RequestDirectoryContent(_, _) => { println!("[Network] RequestDirectoryContent() called"); diff --git a/client-network/src/message_handling.rs b/client-network/src/message_handling.rs index f5491b0..4c7a220 100644 --- a/client-network/src/message_handling.rs +++ b/client-network/src/message_handling.rs @@ -420,8 +420,11 @@ pub fn parse_message( parse_received_datum(received_datum.to_vec(), received_length as usize); match parsed_node { Some(tuple) => { - let _ = - cmd_tx.send(NetworkEvent::FileTreeReceived(tuple.0, tuple.1)); + let _ = cmd_tx.send(NetworkEvent::FileTreeReceived( + tuple.0, + tuple.1, + ip.to_string(), + )); } None => {} } diff --git a/project.pdf b/project.pdf index 4b9eea43ed5a0d924e88488c34c796b7f2438b6b..ba32a46c57d2df938bc4c59522fea6bcabf04cd3 100644 GIT binary patch delta 12644 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 delta 12560 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 Dx+zz?