23 Commits

Author SHA1 Message Date
Tiago Batista Cardoso
1c1f1aa193 rendu 2026-02-17 15:42:49 +01:00
Tiago Batista Cardoso
3c17b5fa1f tidy 2026-01-25 16:01:11 +01:00
Tiago Batista Cardoso
600f617c85 times & readme 2026-01-25 15:22:22 +01:00
Tiago Batista Cardoso
15bfbcd0d4 code tidy 2026-01-25 14:22:20 +01:00
TIBERGHIEN corentin
55a0eb21bb dl folder fix 2026-01-25 13:22:20 +01:00
4bb5f9033b Merge pull request 'bigfix' (#5) from bigfix into master
Reviewed-on: https://git.0001101.xyz/bob/p2p/pulls/5
2026-01-25 02:46:52 +00:00
TIBERGHIEN corentin
b4c4f8f1be Merge remote-tracking branch 'origin' into bigfix 2026-01-25 03:46:19 +01:00
TIBERGHIEN corentin
5378474397 Merge branch 'download_progress' 2026-01-25 03:37:05 +01:00
Tiago Batista Cardoso
10b77f8635 tidy 2026-01-25 03:25:54 +01:00
TIBERGHIEN corentin
fbbd8cd640 big download fixed 2026-01-25 03:19:08 +01:00
Tiago Batista Cardoso
9ecc944857 rapport link 2026-01-25 03:18:09 +01:00
Tiago Batista Cardoso
c0708fc4b9 tidy 2026-01-25 03:17:47 +01:00
Tiago Batista Cardoso
54cd6ebc41 tidy 2026-01-25 02:16:22 +01:00
Tiago Batista Cardoso
929c386b09 magnifique 2026-01-25 01:39:15 +01:00
TIBERGHIEN corentin
cc64aa1b88 wip big 2026-01-25 01:32:28 +01:00
Tiago Batista Cardoso
2283ef5f33 progress bar 2026-01-25 01:31:22 +01:00
Tiago Batista Cardoso
61edd8cd24 [feature] server selection 2026-01-25 01:31:15 +01:00
TIBERGHIEN corentin
79f523be48 wip bigfix 2026-01-25 00:55:57 +01:00
Tiago Batista Cardoso
fc7886c94c progress bar 2026-01-25 00:54:54 +01:00
Tiago Batista Cardoso
f69629cd52 [feature] better socket address fetching logic 2026-01-25 00:02:06 +01:00
TIBERGHIEN corentin
aec686b502 fix out of boudns 2026-01-24 23:59:15 +01:00
Tiago Batista Cardoso
95c2dfe83c pretty 2026-01-24 23:04:01 +01:00
Tiago Batista Cardoso
7a1155c0bd carre 2026-01-24 22:32:01 +01:00
20 changed files with 807 additions and 989 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
README.md

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,17 +1,16 @@
use client_network::{ use client_network::{
ChunkNode, MerkleNode, MerkleTree, NetworkCommand, NetworkEvent, NodeHash, ChunkNode, MerkleNode, MerkleTree, NetworkCommand, NetworkEvent, NodeHash,
big_or_chunk_to_file, filename_to_string, generate_base_tree, node_hash_to_hex_string, big_or_chunk_to_file, generate_base_tree, node_hash_to_hex_string, remove_null_bytes,
remove_null_bytes,
}; };
use crossbeam_channel::{Receiver, Sender}; use crossbeam_channel::{Receiver, Sender};
use egui::{ use egui::{
CentralPanel, CollapsingHeader, Color32, Context, CornerRadius, Frame, Response, ScrollArea, Align, CentralPanel, CollapsingHeader, Color32, Context, CornerRadius, Frame, Id, Layout,
SidePanel, Stroke, TopBottomPanel, Ui, ViewportCommand, ProgressBar, ScrollArea, SidePanel, Stroke, TopBottomPanel, Ui, ViewportCommand,
}; };
use std::collections::HashMap;
use std::collections::HashSet; use std::collections::HashSet;
use std::{collections::HashMap, fmt::format, io::Seek};
use std::fs::{File, OpenOptions, create_dir}; use std::fs::{OpenOptions, create_dir};
enum ServerStatus { enum ServerStatus {
Loading, Loading,
@@ -20,23 +19,18 @@ enum ServerStatus {
ConnectedHandshake, ConnectedHandshake,
} }
// --- Main Application Struct ---
pub struct P2PClientApp { pub struct P2PClientApp {
remaining: std::time::Duration, // temps restant remaining: std::time::Duration, // temps restant
last_update: std::time::Instant, // pour calculer delta last_update: std::time::Instant, // pour calculer delta
timer_started: bool,
// Communication channels
network_cmd_tx: Sender<NetworkCommand>, network_cmd_tx: Sender<NetworkCommand>,
network_event_rx: Receiver<NetworkEvent>, network_event_rx: Receiver<NetworkEvent>,
// GUI State
status_message: String,
known_peers: Vec<(String, bool)>, known_peers: Vec<(String, bool)>,
loading_peers: Vec<String>,
connect_address_input: String, connect_address_input: String,
connected_address: String, connected_address: String,
connect_name_input: String, connect_name_input: String,
// Key: Parent Directory Hash (String), Value: List of children FileNode
loaded_fs: HashMap<String, MerkleTree>, loaded_fs: HashMap<String, MerkleTree>,
shared_tree: MerkleTree, shared_tree: MerkleTree,
@@ -45,55 +39,60 @@ pub struct P2PClientApp {
server_status: ServerStatus, server_status: ServerStatus,
show_network_popup: bool, // gérer selon besoin error_message: Option<(String, String)>, // Some(message) -> afficher, None -> rien
success_message: Option<(String, String)>, // Some(message) -> afficher, None -> rien
error_message: Option<String>, // Some(message) -> afficher, None -> rien
success_message: Option<String>, // Some(message) -> afficher, None -> rien
active_server: String, active_server: String,
current_downloading_file_map: MerkleTree, current_downloading_file_map: MerkleTree,
remaining_chunks: HashSet<[u8; 32]>, remaining_chunks: HashSet<[u8; 32]>,
// total number of chunks expected for the current download (set when download starts)
current_total_chunks: Option<usize>,
// number of chunks received so far (count of removed remaining_chunks)
current_received_chunks: usize,
root_downloading_file: String, root_downloading_file: String,
show_network_window: bool,
show_choose_server_window: bool,
} }
impl P2PClientApp { impl P2PClientApp {
pub fn new(cmd_tx: Sender<NetworkCommand>, event_rx: Receiver<NetworkEvent>) -> Self { pub fn new(cmd_tx: Sender<NetworkCommand>, event_rx: Receiver<NetworkEvent>) -> Self {
//let (root_hash, tree_content) = MerkleNode::generate_base_tree(); let loaded_fs = HashMap::new();
let current_downloading_file_map = MerkleTree::new(HashMap::new(), [0; 32]);
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);
Self { Self {
remaining: std::time::Duration::from_secs(0), remaining: std::time::Duration::from_secs(0),
timer_started: false,
last_update: std::time::Instant::now(), last_update: std::time::Instant::now(),
network_cmd_tx: cmd_tx, network_cmd_tx: cmd_tx,
network_event_rx: event_rx, network_event_rx: event_rx,
status_message: "Client Initialized. Awaiting network status...".to_string(),
known_peers: Vec::new(), known_peers: Vec::new(),
loading_peers: Vec::new(),
connect_address_input: "https://jch.irif.fr:8443".to_string(), connect_address_input: "https://jch.irif.fr:8443".to_string(),
connected_address: "".to_string(), connected_address: "".to_string(),
loaded_fs, loaded_fs,
active_peer: None, active_peer: None,
server_status: ServerStatus::NotConnected, server_status: ServerStatus::NotConnected,
show_network_popup: false,
error_message: None, error_message: None,
success_message: None, success_message: None,
connect_name_input: "bob".to_string(), connect_name_input: "bob".to_string(),
active_server: "".to_string(), active_server: "".to_string(),
shared_tree: generate_base_tree(), shared_tree: generate_base_tree(),
current_downloading_file_map: current_downloading_file_map, current_downloading_file_map: current_downloading_file_map,
current_total_chunks: None,
current_received_chunks: 0,
root_downloading_file: "".to_string(), root_downloading_file: "".to_string(),
remaining_chunks: HashSet::new(), remaining_chunks: HashSet::new(),
show_network_window: false,
show_choose_server_window: false,
} }
} }
pub fn show_error(&mut self, msg: impl Into<String>) { pub fn show_error(&mut self, msg: impl Into<String>, peer_username: impl Into<String>) {
self.error_message = Some(msg.into()); self.error_message = Some((msg.into(), peer_username.into()));
} }
pub fn show_success(&mut self, msg: impl Into<String>) { pub fn show_success(&mut self, msg: impl Into<String>, peer_username: impl Into<String>) {
self.success_message = Some(msg.into()); self.success_message = Some((msg.into(), peer_username.into()));
} }
pub fn clear_error(&mut self) { pub fn clear_error(&mut self) {
self.error_message = None; self.error_message = None;
@@ -103,17 +102,13 @@ impl P2PClientApp {
} }
} }
// --- eframe::App Trait Implementation ---
impl eframe::App for P2PClientApp { impl eframe::App for P2PClientApp {
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) { fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
if matches!(self.server_status, ServerStatus::Connected) && !self.timer_started { if matches!(self.server_status, ServerStatus::Connected) {
self.remaining = std::time::Duration::from_secs(30 * 60); self.remaining = std::time::Duration::from_secs(30 * 60);
self.last_update = std::time::Instant::now(); self.last_update = std::time::Instant::now();
self.timer_started = true;
} }
// in update (every frame)
let now = std::time::Instant::now(); let now = std::time::Instant::now();
let delta = now.saturating_duration_since(self.last_update); let delta = now.saturating_duration_since(self.last_update);
self.last_update = now; self.last_update = now;
@@ -124,18 +119,8 @@ impl eframe::App for P2PClientApp {
self.remaining = self.remaining.saturating_sub(delta); self.remaining = self.remaining.saturating_sub(delta);
} }
// 1. Process incoming Network Events
// We poll the channel and update the GUI state for every event received.
while let Ok(event) = self.network_event_rx.try_recv() { while let Ok(event) = self.network_event_rx.try_recv() {
match event { match event {
NetworkEvent::PeerConnected(addr) => {
todo!();
self.status_message = format!("✅ Peer connected: {}", addr);
if !self.known_peers.contains(&(addr, true)) {
self.known_peers.push((addr, true));
}
}
NetworkEvent::RootRequest(addr) => { NetworkEvent::RootRequest(addr) => {
let root = self.shared_tree.root; let root = self.shared_tree.root;
let _ = self let _ = self
@@ -161,8 +146,6 @@ impl eframe::App for P2PClientApp {
} }
} }
NetworkEvent::PeerListUpdated(peers) => { NetworkEvent::PeerListUpdated(peers) => {
//todo!();
self.known_peers = peers; self.known_peers = peers;
} }
@@ -201,16 +184,8 @@ impl eframe::App for P2PClientApp {
None => {} None => {}
} }
} }
NetworkEvent::FileTreeRootReceived(peer_id, root_hash) => { NetworkEvent::FileTreeRootReceived(_, root_hash) => {
// todo!(); if let Ok(_) = ChunkNode::new(Vec::new()) {
/*self.status_message = format!(
"🔄 Received Merkle Root from {}: {}",
peer_id,
&root_hash[..8]
);*/
if let Ok(chunknode) = ChunkNode::new(Vec::new()) {
let data_map: HashMap<NodeHash, MerkleNode> = HashMap::new(); let data_map: HashMap<NodeHash, MerkleNode> = HashMap::new();
//data_map.insert(root_hash, MerkleNode::Chunk(chunknode)); //data_map.insert(root_hash, MerkleNode::Chunk(chunknode));
println!("len root: {}", data_map.len()); println!("len root: {}", data_map.len());
@@ -228,17 +203,11 @@ impl eframe::App for P2PClientApp {
println!("tree created"); println!("tree created");
} }
//self.active_peer_id = Some(peer_id.clone());
// Request the content of the root directory immediately
/*let _ = self
.network_cmd_tx
.send(NetworkCommand::RequestDirectoryContent(peer_id, root_hash));*/
} }
NetworkEvent::Connected(ip) => { NetworkEvent::Connected(ip) => {
self.server_status = ServerStatus::Connected; self.server_status = ServerStatus::Connected;
self.connected_address = ip.clone(); self.connected_address = ip.clone();
self.show_choose_server_window = true;
let _ = self.network_cmd_tx.send(NetworkCommand::FetchPeerList( let _ = self.network_cmd_tx.send(NetworkCommand::FetchPeerList(
self.connected_address.clone(), self.connected_address.clone(),
)); ));
@@ -252,13 +221,16 @@ impl eframe::App for P2PClientApp {
self.known_peers.clear(); self.known_peers.clear();
self.server_status = ServerStatus::NotConnected; self.server_status = ServerStatus::NotConnected;
} }
NetworkEvent::Error(err) => { NetworkEvent::Error(err, peer_username) => {
self.show_error(err); self.loading_peers.retain(|s| s != peer_username.as_str());
self.show_error(err, peer_username);
} }
NetworkEvent::InitDownload(hash, ip) => { NetworkEvent::InitDownload(hash, ip, name) => {
if let Some(addr) = &self.active_peer { if let Some(addr) = &self.active_peer {
if let Some(roottree) = self.loaded_fs.get(addr) { if let Some(roottree) = self.loaded_fs.get(addr) {
if let Some(root) = roottree.data.get(&hash) { if let Some(root) = roottree.data.get(&hash) {
self.current_downloading_file_map.root = hash;
self.root_downloading_file = name;
let _ = self let _ = self
.current_downloading_file_map .current_downloading_file_map
.data .data
@@ -287,66 +259,209 @@ impl eframe::App for P2PClientApp {
true, true,
)); ));
self.remaining_chunks.insert(entry); self.remaining_chunks.insert(entry);
self.current_total_chunks = Some(self.remaining_chunks.len());
} }
self.remaining_chunks.remove(&hash); self.remaining_chunks.remove(&hash);
} }
MerkleNode::Chunk(chunk) => { MerkleNode::Chunk(_) => {
self.remaining_chunks.remove(&hash); self.remaining_chunks.remove(&hash);
} }
_ => {} _ => {}
} }
if let Some(total) = self.current_total_chunks {
// recompute received (safer than incrementing)
let received = total.saturating_sub(self.remaining_chunks.len());
self.current_received_chunks = received;
}
println!("remaining chunks size: {}", self.remaining_chunks.len());
match create_dir("./Download/") {
Ok(_) => println!("Directory created successfully!"),
Err(e) => println!("Failed to create directory: {}", e),
}
if self.remaining_chunks.is_empty() { if self.remaining_chunks.is_empty() {
let file = OpenOptions::new().append(true).create(true).open(
"./Download/".to_string()
+ &remove_null_bytes(&self.root_downloading_file.clone()),
);
if let Some(current) = self
.current_downloading_file_map
.data
.get(&self.current_downloading_file_map.root)
{
match file {
Ok(mut fileok) => {
big_or_chunk_to_file(
&self.current_downloading_file_map,
current,
&mut fileok,
);
}
Err(e) => {
eprintln!("error creaation file: {}", e);
}
}
} else {
eprintln!("error root absent");
}
println!("bigfile téléchargé {}", self.root_downloading_file);
self.current_total_chunks = None;
self.current_received_chunks = 0;
println!("bigfile téléchargé"); println!("bigfile téléchargé");
} }
} }
NetworkEvent::Success(msg) => { NetworkEvent::Success(msg, peer_username) => {
self.show_success(msg); self.loading_peers.retain(|s| s != peer_username.as_str());
self.show_success(msg, peer_username);
} }
NetworkEvent::HandshakeFailed() => {} NetworkEvent::HandshakeFailed() => {}
NetworkEvent::ServerHandshakeFailed(err) => { NetworkEvent::ServerHandshakeFailed(err) => {
self.active_server = "".to_string(); self.active_server = "".to_string();
self.server_status = ServerStatus::NotConnected; self.server_status = ServerStatus::NotConnected;
let err_msg = format!("Failed to connect to the server: {}", err); 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()); match self.network_cmd_tx.send(NetworkCommand::ResetServerPeer()) {
Ok(_) => {}
Err(err) => {
println!("GUI Error : {}", err.to_string());
}
};
} }
} }
} }
if self.show_choose_server_window {
let full_rect = ctx.input(|i| i.content_rect());
let modal_size = egui::vec2(400.0, 160.0);
egui::Area::new(Id::new("modal_blocker_bg"))
.order(egui::Order::Background)
.show(ctx, |ui| {
let painter = ui.painter();
painter.rect_filled(full_rect, 0.0, egui::Color32::from_black_alpha(160));
let sense = egui::Sense::click_and_drag();
ui.allocate_exact_size(full_rect.size(), sense);
});
egui::Window::new("Choose the server")
.resizable(false)
.collapsible(false)
.title_bar(true)
.anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
.fixed_size(modal_size)
.show(ctx, |ui| {
ScrollArea::vertical()
.auto_shrink([false; 2])
.show(ui, |ui| {
ui.style_mut().visuals.widgets.inactive.bg_fill =
ui.style().visuals.widgets.inactive.bg_fill; // no-op to get mutable borrow
if self.known_peers.is_empty() {
ui.add_space(10.0);
ui.label("No active peers.");
} else {
for peer in &self.known_peers {
let is_active =
self.active_peer.as_ref().map_or(false, |id| id == &peer.0); // if peer.id == self.active_peer_id
// 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
// use resp (click handling etc.)
if resp.clicked() {
self.active_server = peer.0.to_string();
match self.network_cmd_tx.send(
NetworkCommand::ServerHandshake(
peer.0.to_string(),
self.connected_address.clone(),
),
) {
Ok(_) => {}
Err(e) => {
println!("GUI Error : {}", e.to_string());
}
};
ui.close();
self.show_choose_server_window = false;
}
});
}
}
});
});
}
// 2. Menu Bar // 2. Menu Bar
TopBottomPanel::top("top_panel").show(ctx, |ui| { TopBottomPanel::top("top_panel").show(ctx, |ui| {
egui::MenuBar::new().ui(ui, |ui| { egui::MenuBar::new().ui(ui, |ui| {
ui.menu_button("File", |ui| { ui.menu_button("File", |ui| {
if ui.button("Settings").clicked() { if ui.button("Settings").clicked() {}
//show settings
}
if ui.button("Quit").clicked() { if ui.button("Quit").clicked() {
// Use ViewportCommand to request a close
ctx.send_viewport_cmd(ViewportCommand::Close); ctx.send_viewport_cmd(ViewportCommand::Close);
} }
}); });
ui.menu_button("Network", |ui| { if ui.button("Network").clicked() {
self.show_network_window = !self.show_network_window;
}
if self.show_network_window {
match self.server_status { match self.server_status {
ServerStatus::Connected | ServerStatus::ConnectedHandshake => { ServerStatus::Connected | ServerStatus::ConnectedHandshake => {
egui::Window::new("Network")
.resizable(false)
.collapsible(false)
.title_bar(false)
.show(ctx, |ui| {
let desired = egui::vec2(300.0, 0.0); // width 300, auto-height if 0 let desired = egui::vec2(300.0, 0.0); // width 300, auto-height if 0
ui.set_min_size(desired); ui.set_min_size(desired);
ui.vertical(|ui| { ui.vertical(|ui| {
if ui.button("Disconnect").clicked() { if ui.button("Disconnect").clicked() {
println!("Disconnecting..."); println!("Disconnecting...");
let _ = self.network_cmd_tx.send(NetworkCommand::Disconnect()); let _ = self
.network_cmd_tx
.send(NetworkCommand::Disconnect());
self.server_status = ServerStatus::NotConnected; self.server_status = ServerStatus::NotConnected;
self.remaining = std::time::Duration::from_secs(0); self.remaining = std::time::Duration::from_secs(0);
self.timer_started = false; self.show_network_window = false;
ui.close(); self.loaded_fs.clear();
self.active_peer = None;
} }
}); });
});
} }
ServerStatus::NotConnected => { ServerStatus::NotConnected => {
let desired = egui::vec2(0.0, 0.0); // width 300, auto-height if 0 egui::Window::new("Network")
ui.set_min_size(desired); .resizable(false)
ui.vertical(|ui| { .collapsible(false)
.title_bar(false)
.show(ctx, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label("Server IP:"); ui.label("Server IP:");
ui.text_edit_singleline(&mut self.connect_address_input); ui.text_edit_singleline(&mut self.connect_address_input);
@@ -358,43 +473,58 @@ impl eframe::App for P2PClientApp {
if ui.button("Connect").clicked() { if ui.button("Connect").clicked() {
let addr = self.connect_address_input.clone(); let addr = self.connect_address_input.clone();
let name = self.connect_name_input.clone(); let name = self.connect_name_input.clone();
let _ = self let _ = self.network_cmd_tx.send(
.network_cmd_tx NetworkCommand::ConnectToServerPut(
.send(NetworkCommand::ConnectToServerPut(addr, name)); addr,
name.to_string(),
),
);
self.server_status = ServerStatus::Loading; self.server_status = ServerStatus::Loading;
ui.close(); ui.close();
self.show_network_window = false;
self.loaded_fs
.insert(name.to_string(), self.shared_tree.clone());
} }
}); });
} }
_ => {} _ => {}
} }
}); }
}); });
}); });
TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| { TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
match self.server_status { match self.server_status {
ServerStatus::Loading => { ServerStatus::Loading => ui.spinner(),
ui.spinner(); ServerStatus::Connected => ui.label("Registered but no server peer chosen..."),
ServerStatus::NotConnected => ui.label("No connection.."),
ServerStatus::ConnectedHandshake => ui.label("📡"),
};
ui.add_space(8.0); // small gap
// desired progress bar width
let bar_width = 220.0f32;
// push it to the right by adding space equal to remaining width minus bar width
let push = (ui.available_width() - bar_width).max(0.0);
ui.add_space(push);
if let Some(total) = self.current_total_chunks {
let received = self.current_received_chunks;
let frac = if total == 0 {
1.0
} else {
received as f32 / total as f32
};
ui.add(
ProgressBar::new(frac)
.show_percentage()
.animate(true)
.desired_height(10.0),
);
} }
ServerStatus::Connected => {
ui.label("Registered but no server peer chosen...");
}
ServerStatus::NotConnected => {
ui.label("No connection..");
}
ServerStatus::ConnectedHandshake => {
let str = format!("📡");
ui.label(str);
}
}
ui.add_space(ui.available_width() - 30.0);
// formater mm:ss
let secs = self.remaining.as_secs();
let minutes = secs / 60;
let seconds = secs % 60;
ui.label(format!("{:02}:{:02}", minutes, seconds));
}); });
}); });
@@ -425,7 +555,11 @@ impl eframe::App for P2PClientApp {
}); });
ui.separator(); ui.separator();
ScrollArea::vertical().show(ui, |ui| { ScrollArea::vertical()
.auto_shrink([false; 2])
.show(ui, |ui| {
ui.style_mut().visuals.widgets.inactive.bg_fill =
ui.style().visuals.widgets.inactive.bg_fill; // no-op to get mutable borrow
if self.known_peers.is_empty() { if self.known_peers.is_empty() {
ui.add_space(10.0); ui.add_space(10.0);
ui.label("No active peers."); ui.label("No active peers.");
@@ -433,27 +567,52 @@ impl eframe::App for P2PClientApp {
for peer in &self.known_peers { for peer in &self.known_peers {
let is_active = let is_active =
self.active_peer.as_ref().map_or(false, |id| id == &peer.0); // if peer.id == self.active_peer_id self.active_peer.as_ref().map_or(false, |id| id == &peer.0); // if peer.id == self.active_peer_id
//
if peer.0.eq(&self.connect_name_input) {
ui.horizontal(|ui| {
let resp = ui.selectable_label(
is_active,
format!("{} (you)", peer.0),
);
let selectable: Response; if resp.clicked() {
if &self.active_server == &peer.0 { self.active_peer = Some(peer.0.clone());
// Create a frame with green background and render the selectable inside it. }
// Adjust rounding, padding and stroke as desired. });
} else {
// place spinner to the right of the label
ui.horizontal(|ui| {
let resp = if &self.active_server == &peer.0 {
let frame = Frame { let frame = Frame {
fill: Color32::DARK_BLUE, fill: Color32::DARK_BLUE,
stroke: Stroke::default(), stroke: Stroke::default(),
corner_radius: CornerRadius::from(0.5), corner_radius: CornerRadius::from(0.5),
..Default::default() ..Default::default()
}; };
let internal = frame.show(ui, |ui| { frame
ui.selectable_label(is_active, format!("{}", peer.0)) .show(ui, |ui| {
}); ui.selectable_label(
selectable = internal.inner; is_active,
format!("{}", peer.0),
)
})
.inner
} else { } 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) {
ui.with_layout(
Layout::right_to_left(Align::Center),
|ui| {
ui.spinner();
},
);
} }
if selectable.clicked() { if resp.clicked() {
// switch to displaying this peer's tree
self.active_peer = Some(peer.0.clone()); self.active_peer = Some(peer.0.clone());
// Request root content if not loaded // Request root content if not loaded
if !self if !self
@@ -461,15 +620,16 @@ impl eframe::App for P2PClientApp {
.contains_key(self.active_peer.as_ref().unwrap()) .contains_key(self.active_peer.as_ref().unwrap())
{ {
//todo!(); //todo!();
let _ = self.network_cmd_tx.send(NetworkCommand::Discover( let _ = self.network_cmd_tx.send(
NetworkCommand::Discover(
peer.0.clone(), peer.0.clone(),
"root".to_string(), "root".to_string(),
self.connected_address.clone(), self.connected_address.clone(),
)); ),
);
} }
} }
selectable.context_menu(|ui| { resp.context_menu(|ui| {
// ... action
match self.server_status { match self.server_status {
ServerStatus::Connected => { ServerStatus::Connected => {
if ui if ui
@@ -477,29 +637,40 @@ impl eframe::App for P2PClientApp {
.clicked() .clicked()
{ {
self.active_server = peer.0.to_string(); self.active_server = peer.0.to_string();
let res = self.network_cmd_tx.send( match self.network_cmd_tx.send(
NetworkCommand::ServerHandshake( NetworkCommand::ServerHandshake(
peer.0.to_string(), peer.0.to_string(),
self.connected_address.clone(), self.connected_address.clone(),
), ),
); ) {
Ok(_) => {}
Err(e) => {
println!("GUI Error : {}", e.to_string());
},
};
} }
} }
_ => {} _ => {}
} }
if ui.button("Send Ping").clicked() { if ui.button("Send Ping").clicked() {
let res = self.network_cmd_tx.send(NetworkCommand::Ping( let _ = self.network_cmd_tx.send(NetworkCommand::Ping(
peer.0.to_string(), peer.0.to_string(),
self.connected_address.clone(), self.connected_address.clone(),
)); ));
self.loading_peers.push(peer.0.to_owned());
} }
if ui.button("Send Nat Traversal Request").clicked() { 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(), peer.0.to_string(),
self.connected_address.clone(), self.connected_address.clone(),
)) { ),
) {
Ok(_) => { Ok(_) => {
print!("[+] successfully sent nat traversal request") print!(
"[+] successfully sent nat traversal request"
)
} }
Err(_) => { Err(_) => {
print!("[-] failed to send nat traversal request") print!("[-] failed to send nat traversal request")
@@ -513,6 +684,8 @@ impl eframe::App for P2PClientApp {
// ... autres boutons // ... autres boutons
}); });
});
}
} }
} }
}); });
@@ -529,13 +702,17 @@ impl eframe::App for P2PClientApp {
ui.separator(); ui.separator();
if let Some(active_peer) = &self.active_peer { if let Some(active_peer) = &self.active_peer {
if let Some(tree) = self.loaded_fs.get(active_peer) { if let Some(tree) = self.loaded_fs.clone().get(active_peer) {
ScrollArea::vertical().show(ui, |ui| { ScrollArea::vertical().show(ui, |ui| {
// Start drawing the tree from the root hash // Start drawing the tree from the root hash
self.draw_file_tree(ui, tree); self.draw_file_tree(ui, tree);
}); });
} else { } else {
ui.horizontal(|ui| {
ui.label(format!("Loading root for peer: {}", active_peer)); ui.label(format!("Loading root for peer: {}", active_peer));
ui.add_space(8.0);
ui.spinner(); // or conditional: if is_loading { ui.spinner(); }
});
} }
} else { } else {
ui.label("Connect to a peer to view a file tree."); ui.label("Connect to a peer to view a file tree.");
@@ -554,7 +731,8 @@ impl eframe::App for P2PClientApp {
.resizable(false) .resizable(false)
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0]) .anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
.show(ctx, |ui| { .show(ctx, |ui| {
ui.label(&msg); ui.label(&msg.1);
ui.label(&msg.0);
if ui.button("OK").clicked() { if ui.button("OK").clicked() {
self.clear_error(); self.clear_error();
} }
@@ -568,7 +746,8 @@ impl eframe::App for P2PClientApp {
.resizable(false) .resizable(false)
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0]) .anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
.show(ctx, |ui| { .show(ctx, |ui| {
ui.label(&msg); ui.label(&msg.1);
ui.label(&msg.0);
if ui.button("OK").clicked() { if ui.button("OK").clicked() {
self.clear_success(); self.clear_success();
} }
@@ -583,7 +762,7 @@ impl eframe::App for P2PClientApp {
// --- Helper for Drawing the Recursive File Tree --- // --- Helper for Drawing the Recursive File Tree ---
impl P2PClientApp { impl P2PClientApp {
fn draw_file_tree(&self, ui: &mut Ui, tree: &MerkleTree) { fn draw_file_tree(&mut self, ui: &mut Ui, tree: &MerkleTree) {
assert!(self.active_peer.is_some()); assert!(self.active_peer.is_some());
assert!( assert!(
self.loaded_fs self.loaded_fs
@@ -600,7 +779,7 @@ impl P2PClientApp {
} }
fn draw_file_node( fn draw_file_node(
&self, &mut self,
ui: &mut Ui, ui: &mut Ui,
to_draw: NodeHash, to_draw: NodeHash,
tree: &MerkleTree, tree: &MerkleTree,
@@ -668,16 +847,22 @@ impl P2PClientApp {
} }
}); });
} }
MerkleNode::Big(node) => { MerkleNode::Big(_) => {
if ui if ui
.selectable_label(false, format!("📄 (B) {}", name)) .selectable_label(false, format!("📄 (B) {}", name))
.on_hover_text("Click to request file chunks...") .on_hover_text("Click to request file chunks...")
.clicked() .clicked()
{ {
if let Some(name) = filename {
if let Ok(nameb) = String::from_utf8(name.to_vec()) {
if let Some(addr) = &self.active_peer { if let Some(addr) = &self.active_peer {
let _ = self let _ = self.network_cmd_tx.send(NetworkCommand::InitDownload(
.network_cmd_tx to_draw,
.send(NetworkCommand::InitDownload(to_draw, addr.clone())); addr.clone(),
nameb,
));
}
}
} }
} }
} }

View File

@@ -32,7 +32,7 @@ async fn main() -> eframe::Result<()> {
eframe::run_native( eframe::run_native(
"p2p-merkle client", "p2p-merkle client",
options, options,
Box::new(|cc| { Box::new(|_| {
let app = P2PClientApp::new(network_cmd_tx, network_event_rx); let app = P2PClientApp::new(network_cmd_tx, network_event_rx);
Ok(Box::new(app)) Ok(Box::new(app))
}), }),

View File

@@ -1,11 +1,6 @@
use std::io::Read;
use bytes::Bytes; use bytes::Bytes;
use p256::EncodedPoint; use p256::EncodedPoint;
use p256::ecdsa::{ use p256::ecdsa::{Signature, SigningKey, VerifyingKey, signature::Verifier};
Signature, SigningKey, VerifyingKey,
signature::{Signer, Verifier},
};
use rand_core::OsRng; use rand_core::OsRng;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
@@ -37,15 +32,6 @@ impl CryptographicSignature {
} }
} }
///
/// returns a string representing the pub_key as a String
///
pub fn formatPubKey(crypto_pair: CryptographicSignature) -> String {
let encoded_point = crypto_pair.pub_key.to_encoded_point(false);
let pubkey_bytes = encoded_point.as_bytes();
hex::encode(pubkey_bytes)
}
pub async fn get_peer_key(username: &String) -> Result<VerifyingKey, reqwest::Error> { pub async fn get_peer_key(username: &String) -> Result<VerifyingKey, reqwest::Error> {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let uri = format!("https://jch.irif.fr:8443/peers/{}/key", username); let uri = format!("https://jch.irif.fr:8443/peers/{}/key", username);
@@ -126,34 +112,7 @@ pub fn sign_message(crypto_pair: &CryptographicSignature, message: &Vec<u8>) ->
signed_message signed_message
} }
Err(e) => { Err(e) => {
panic!("error"); panic!("error : {}", e);
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
/*
///
/// creates a cryptographic signature
///
#[test]
fn creating_cryptographic_signature() {
let username = String::from("gamixtreize");
let crypto_pair = CryptographicSignature::new(username);
let formatted_pubkey = formatPubKey(crypto_pair);
println!("pubkey : {}", formatted_pubkey);
}*/
/*#[test]
fn signing_message() {
let username = String::from("gamixtreize");
let crypto_pair = CryptographicSignature::new(username.clone());
let handshake = HandshakeMessage::hello(0, 12, username);
let ser = handshake.serialize();
let signed_message = sign_message(&crypto_pair, &ser);
println!("unsigned_message: {:?}", ser);
println!("signed_message: {:?}", signed_message);
}*/
}

View File

@@ -1,14 +1,9 @@
use rand::{Rng, rng}; use rand::{Rng, rng};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::fs::{File, OpenOptions, create_dir}; use std::fs::{File, OpenOptions, create_dir};
use std::io::{self, Write}; use std::io::Write;
use std::env;
use crate::data;
// --- Constants --- // --- Constants ---
pub const MAX_CHUNK_DATA_SIZE: usize = 1024; pub const MAX_CHUNK_DATA_SIZE: usize = 1024;
@@ -67,18 +62,12 @@ impl ChunkNode {
pub fn new_random() -> Self { pub fn new_random() -> Self {
let mut rng = rand::rng(); let mut rng = rand::rng();
// Determine a random length between 1 and MAX_CHUNK_DATA_SIZE (inclusive).
// Using +1 ensures the range is up to 1024.
let random_len = rng.random_range(1..=MAX_CHUNK_DATA_SIZE); let random_len = rng.random_range(1..=MAX_CHUNK_DATA_SIZE);
// Initialize a vector with the random length
let mut data = vec![0u8; random_len]; let mut data = vec![0u8; random_len];
// Fill the vector with random bytes
rng.fill(&mut data[..]); rng.fill(&mut data[..]);
// Since we generated the length based on MAX_CHUNK_DATA_SIZE,
// this is guaranteed to be valid and doesn't need to return a Result.
ChunkNode { data } ChunkNode { data }
} }
} }
@@ -154,8 +143,8 @@ impl MerkleNode {
match self { match self {
MerkleNode::Chunk(_) => 0, MerkleNode::Chunk(_) => 0,
MerkleNode::Directory(_) => 1, MerkleNode::Directory(_) => 1,
MerkleNode::Big(_) => 3, MerkleNode::Big(_) => 2,
MerkleNode::BigDirectory(_) => 4, MerkleNode::BigDirectory(_) => 3,
} }
} }
@@ -193,17 +182,6 @@ fn hash(data: &[u8]) -> NodeHash {
println!("root hash: {:?}", root_hash); println!("root hash: {:?}", root_hash);
let res: NodeHash = root_hash.try_into().expect("incorrect size"); let res: NodeHash = root_hash.try_into().expect("incorrect size");
res res
/*let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
let hash_u64 = hasher.finish();
let mut hash_array = [0u8; FILENAME_HASH_SIZE];
// Simple way to spread a 64-bit hash across 32 bytes for a unique-ish ID
for i in 0..8 {
hash_array[i] = (hash_u64 >> (i * 8)) as u8;
}
hash_array // The rest remains 0, satisfying the 32-byte requirement
*/
} }
fn generate_random_filename() -> [u8; FILENAME_HASH_SIZE] { fn generate_random_filename() -> [u8; FILENAME_HASH_SIZE] {
@@ -345,9 +323,9 @@ pub fn generate_base_tree() -> MerkleTree {
let oscar_content = "oscar is the opponent".to_string().into_bytes(); let oscar_content = "oscar is the opponent".to_string().into_bytes();
let mut children_nodes = Vec::new(); let mut children_nodes = Vec::new();
for i in 0..10 { for _ in 0..10 {
let mut i_nodes = Vec::new(); let mut i_nodes = Vec::new();
for j in 0..10 { for _ in 0..10 {
let node1 = MerkleNode::Chunk(ChunkNode::new(bob_content.clone()).unwrap()); let node1 = MerkleNode::Chunk(ChunkNode::new(bob_content.clone()).unwrap());
let hash = hash(&node1.serialize()); let hash = hash(&node1.serialize());
i_nodes.push(hash); i_nodes.push(hash);
@@ -368,14 +346,14 @@ pub fn generate_base_tree() -> MerkleTree {
let node2 = MerkleNode::Chunk(ChunkNode::new(alice_content).unwrap()); let node2 = MerkleNode::Chunk(ChunkNode::new(alice_content).unwrap());
let hash2 = hash(&node2.serialize()); let hash2 = hash(&node2.serialize());
//res.insert(hash1, node1); res.insert(hash1, node1);
//res.insert(hash2, node2); res.insert(hash2, node2);
res.insert(hashbig, bignode); res.insert(hashbig, bignode);
let node3 = MerkleNode::Chunk(ChunkNode::new(oscar_content).unwrap()); let node3 = MerkleNode::Chunk(ChunkNode::new(oscar_content).unwrap());
let hash3 = hash(&node3.serialize()); let hash3 = hash(&node3.serialize());
//res.insert(hash3, node3); res.insert(hash3, node3);
let dir1 = MerkleNode::Directory(DirectoryNode { let dir1 = MerkleNode::Directory(DirectoryNode {
entries: [DirectoryEntry { entries: [DirectoryEntry {
@@ -386,7 +364,7 @@ pub fn generate_base_tree() -> MerkleTree {
}); });
let hash_dir1 = hash(&dir1.serialize()); let hash_dir1 = hash(&dir1.serialize());
//res.insert(hash_dir1, dir1); res.insert(hash_dir1, dir1);
let root = MerkleNode::Directory(DirectoryNode { let root = MerkleNode::Directory(DirectoryNode {
entries: [ entries: [
@@ -394,14 +372,14 @@ pub fn generate_base_tree() -> MerkleTree {
filename: generate_random_filename(), filename: generate_random_filename(),
content_hash: hashbig, content_hash: hashbig,
}, },
/*DirectoryEntry { DirectoryEntry {
filename: generate_random_filename(), filename: generate_random_filename(),
content_hash: hash2, content_hash: hash2,
}, },
DirectoryEntry { DirectoryEntry {
filename: generate_random_filename(), filename: generate_random_filename(),
content_hash: hash_dir1, content_hash: hash_dir1,
},*/ },
] ]
.to_vec(), .to_vec(),
}); });
@@ -473,50 +451,16 @@ pub fn big_or_chunk_to_file(tree: &MerkleTree, node: &MerkleNode, file: &mut Fil
} }
} }
MerkleNode::Chunk(chunk) => { MerkleNode::Chunk(chunk) => {
println!("wrote data"); if !chunk.data.is_empty() {
let _ = file.write_all(&chunk.data); let mut data = chunk.data.clone();
data.remove(0);
let _ = file.write(&data);
} else {
println!("chunk.data is empty, nothing to write");
}
} }
_ => { _ => {
println!("invalid type of file"); println!("invalid type of file");
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
///
/// creates a cryptographic signature
///
#[test]
fn test_saving_tree() {
if let Ok(current_dir) = env::current_dir() {
println!("Current working directory: {:?}", current_dir);
}
println!("--------- tree test starts ------------");
match create_dir("../Download/") {
Ok(_) => println!("Directory created successfully!"),
Err(e) => println!("Failed to create directory: {}", e),
}
let tree = generate_base_tree();
println!("--------- test tree created ------------");
if let Some(root_node) = tree.data.get(&tree.root) {
node_to_file(&tree, root_node, "../Download/".to_string(), 0);
}
}
/*#[test]
fn signing_message() {
let username = String::from("gamixtreize");
let crypto_pair = CryptographicSignature::new(username.clone());
let handshake = HandshakeMessage::hello(0, 12, username);
let ser = handshake.serialize();
let signed_message = sign_message(&crypto_pair, &ser);
println!("unsigned_message: {:?}", ser);
println!("signed_message: {:?}", signed_message);
}*/
}

View File

@@ -1,200 +0,0 @@
use crate::data::*;
use rand::{Rng, rng};
use std::collections::HashMap;
use std::hash::{DefaultHasher, Hash, Hasher};
fn hash(data: &[u8]) -> NodeHash {
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
let hash_u64 = hasher.finish();
let mut hash_array = [0u8; FILENAME_HASH_SIZE];
// Simple way to spread a 64-bit hash across 32 bytes for a unique-ish ID
for i in 0..8 {
hash_array[i] = (hash_u64 >> (i * 8)) as u8;
}
hash_array // The rest remains 0, satisfying the 32-byte requirement
}
fn generate_random_filename() -> [u8; FILENAME_HASH_SIZE] {
let mut rng = rand::rng();
let mut filename_bytes = [0; FILENAME_HASH_SIZE];
// Generate a random length for the base name
let name_len = rng.random_range(5..21);
// Generate random alphanumeric characters
for i in 0..name_len {
let char_code = rng.random_range(97..123); // 'a' through 'z'
if i < FILENAME_HASH_SIZE {
filename_bytes[i] = char_code as u8;
}
}
// Append a common extension
let ext = if rng.random_bool(0.5) { ".txt" } else { ".dat" };
let ext_bytes = ext.as_bytes();
let start_index = name_len.min(FILENAME_HASH_SIZE - ext_bytes.len());
if start_index < FILENAME_HASH_SIZE {
filename_bytes[start_index..(start_index + ext_bytes.len())].copy_from_slice(ext_bytes);
}
filename_bytes
}
fn generate_random_file_node(
storage: &mut HashMap<NodeHash, MerkleNode>,
) -> Result<NodeHash, String> {
let mut rng = rng();
let is_big = rng.random_bool(0.2); // 20% chance of being a big file
if !is_big {
// Generate a simple Chunk Node
let node = MerkleNode::Chunk(ChunkNode::new_random());
let hash = hash(&node.serialize());
storage.insert(hash, node);
Ok(hash)
} else {
// Generate a Big Node (a file composed of chunks)
let num_children = rng.random_range(MIN_BIG_CHILDREN..=MAX_BIG_CHILDREN.min(8)); // Limit complexity
let mut children_hashes = Vec::with_capacity(num_children);
for _ in 0..num_children {
// Children must be Chunk or Big; for simplicity, we only generate Chunk children here.
let chunk_node = MerkleNode::Chunk(ChunkNode::new_random());
let chunk_hash = hash(&chunk_node.serialize());
storage.insert(chunk_hash, chunk_node);
children_hashes.push(chunk_hash);
}
let node = MerkleNode::Big(BigNode::new(children_hashes)?);
let hash = hash(&node.serialize());
storage.insert(hash, node);
Ok(hash)
}
}
fn generate_random_directory_node(
depth: u32,
max_depth: u32,
storage: &mut HashMap<NodeHash, MerkleNode>,
) -> Result<NodeHash, String> {
let mut rng = rng();
let current_depth = depth + 1;
let is_big_dir = rng.random_bool(0.3) && current_depth < max_depth;
if !is_big_dir || current_depth >= max_depth {
// Generate a simple Directory Node (leaf level directory)
let num_entries = rng.random_range(1..=MAX_DIRECTORY_ENTRIES.min(5)); // Limit directory size for testing
let mut entries = Vec::with_capacity(num_entries);
for _ in 0..num_entries {
if rng.random_bool(0.7) {
// 70% chance of creating a file (Chunk/Big)
let file_hash = generate_random_file_node(storage)?;
let entry = DirectoryEntry {
filename: generate_random_filename(),
content_hash: file_hash,
};
entries.push(entry);
} else if current_depth < max_depth {
// 30% chance of creating a subdirectory
let dir_hash = generate_random_directory_node(current_depth, max_depth, storage)?;
// Create a basic directory entry name
let mut filename_bytes = [0; 32];
let subdir_name = format!("dir_{}", current_depth);
filename_bytes[..subdir_name.len()].copy_from_slice(subdir_name.as_bytes());
let entry = DirectoryEntry {
filename: filename_bytes,
content_hash: dir_hash,
};
entries.push(entry);
}
}
let node = MerkleNode::Directory(DirectoryNode::new(entries)?);
let hash = hash(&node.serialize());
storage.insert(hash, node);
Ok(hash)
} else {
// Generate a BigDirectory Node (internal directory structure)
let num_children = rng.random_range(MIN_BIG_CHILDREN..=MAX_BIG_CHILDREN.min(4)); // Limit children count
let mut children = Vec::with_capacity(num_children);
for _ in 0..num_children {
// Children must be Directory or BigDirectory
let child_hash = generate_random_directory_node(current_depth, max_depth, storage)?;
children.push(child_hash);
}
let node = MerkleNode::BigDirectory(BigDirectoryNode::new(children)?);
let hash = hash(&node.serialize());
storage.insert(hash, node);
Ok(hash)
}
}
pub fn generate_random_tree(
max_depth: u32,
) -> Result<(NodeHash, HashMap<NodeHash, MerkleNode>), String> {
let mut storage = HashMap::new();
// Start tree generation from the root directory at depth 0
let root_hash = generate_random_directory_node(0, max_depth, &mut storage)?;
Ok((root_hash, storage))
}
pub fn generate_base_tree() -> (NodeHash, HashMap<NodeHash, MerkleNode>) {
let mut res = HashMap::new();
let node1 = MerkleNode::Chunk(ChunkNode::new_random());
let hash1 = hash(&node1.serialize());
let node2 = MerkleNode::Chunk(ChunkNode::new_random());
let hash2 = hash(&node2.serialize());
res.insert(hash1, node1);
res.insert(hash2, node2);
let node3 = MerkleNode::Chunk(ChunkNode::new_random());
let hash3 = hash(&node3.serialize());
res.insert(hash3, node3);
let dir1 = MerkleNode::Directory(DirectoryNode {
entries: [DirectoryEntry {
filename: generate_random_filename(),
content_hash: hash3,
}]
.to_vec(),
});
let hash_dir1 = hash(&dir1.serialize());
res.insert(hash_dir1, dir1);
let root = MerkleNode::Directory(DirectoryNode {
entries: [
DirectoryEntry {
filename: generate_random_filename(),
content_hash: hash1,
},
DirectoryEntry {
filename: generate_random_filename(),
content_hash: hash2,
},
DirectoryEntry {
filename: generate_random_filename(),
content_hash: hash_dir1,
},
]
.to_vec(),
});
let root_hash = hash(&root.serialize());
res.insert(root_hash, root);
(root_hash, res)
}

View File

@@ -1,4 +1,4 @@
use crate::{BigDirectoryNode, DirectoryEntry, DirectoryNode, MerkleNode, MerkleTree, NodeHash}; use crate::{BigDirectoryNode, DirectoryEntry, DirectoryNode, MerkleNode, NodeHash};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
const CHUNK: u8 = 0; const CHUNK: u8 = 0;
@@ -13,7 +13,24 @@ pub fn parse_received_datum(
let hash_name: [u8; 32] = recevied_datum[..32].try_into().expect("error"); let hash_name: [u8; 32] = recevied_datum[..32].try_into().expect("error");
let value = &recevied_datum[32..datum_length]; let value = &recevied_datum[32..datum_length];
let value_slice = value.to_vec(); let value_slice = value.to_vec();
println!("valueslice: {:?}, {}", value_slice, value_slice.len());
println!(
"((value_slice.len() - 1) / 32) {} ",
((value_slice.len() - 1) / 32)
);
// Créer une instance de Sha256
let mut hasher = Sha256::new();
// Alimenter le hasher avec les données
hasher.update(value_slice.clone());
// Obtention du résultat
let result = hasher.finalize();
if result.to_vec() != hash_name.to_vec() {
println!("{:?},{:?}", result.to_vec(), hash_name.to_vec());
None
} else {
println!("hashes equals!");
let datum_type = value_slice[0]; let datum_type = value_slice[0];
match datum_type { match datum_type {
CHUNK => Some(( CHUNK => Some((
@@ -22,7 +39,7 @@ pub fn parse_received_datum(
)), )),
DIRECTORY => { DIRECTORY => {
let mut dir_entries = Vec::new(); let mut dir_entries = Vec::new();
let mut offset = 1 as usize; let mut offset: usize;
for i in 0..((value_slice.len() - 1) / 64) as u8 { for i in 0..((value_slice.len() - 1) / 64) as u8 {
offset = (1 + 64 * i as usize) as usize; offset = (1 + 64 * i as usize) as usize;
println!("offset:{}, i:{}", offset, i); println!("offset:{}, i:{}", offset, i);
@@ -49,18 +66,28 @@ pub fn parse_received_datum(
} }
} }
BIG => { BIG => {
let mut bigdir_entries: Vec<NodeHash> = Vec::new();
let mut offset: usize;
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
bigdir_entries.push(hash.try_into().expect("incorrect size"));
}
println!("its a BIG bro"); println!("its a BIG bro");
let chlidren: Vec<NodeHash> = Vec::new();
Some(( Some((
hash_name, hash_name,
MerkleNode::Big(crate::BigNode { MerkleNode::Big(crate::BigNode {
children_hashes: chlidren, children_hashes: bigdir_entries,
}), }),
)) ))
} }
BIGDIRECTORY => { BIGDIRECTORY => {
let mut bigdir_entries: Vec<NodeHash> = Vec::new(); let mut bigdir_entries: Vec<NodeHash> = Vec::new();
let mut offset = 1 as usize; let mut offset: usize;
for i in 0..((value_slice.len() - 1) / 32) as u8 { for i in 0..((value_slice.len() - 1) / 32) as u8 {
offset = (1 + 32 * i as usize) as usize; offset = (1 + 32 * i as usize) as usize;
println!("offset:{}, i:{}", offset, i); println!("offset:{}, i:{}", offset, i);
@@ -81,4 +108,5 @@ pub fn parse_received_datum(
} }
_ => None, _ => None,
} }
}
} }

View File

@@ -1,6 +1,5 @@
mod cryptographic_signature; mod cryptographic_signature;
mod data; mod data;
mod datum_generation;
mod datum_parsing; mod datum_parsing;
mod fetchsocketaddresserror; mod fetchsocketaddresserror;
mod message_handling; mod message_handling;
@@ -21,18 +20,16 @@ use crate::{
message_handling::EventType, message_handling::EventType,
messages_channels::{MultipleSenders, start_receving_thread, start_retry_thread}, messages_channels::{MultipleSenders, start_receving_thread, start_retry_thread},
messages_structure::{ messages_structure::{
DATUM, DATUMREQUEST, NATTRAVERSALREQUEST, NATTRAVERSALREQUEST2, NODATUM, PING, ROOTREQUEST, DATUM, DATUMREQUEST, NATTRAVERSALREQUEST, NODATUM, PING, ROOTREQUEST, construct_message,
construct_message,
}, },
peers_refresh::HandshakeHistory, peers_refresh::HandshakeHistory,
registration::{parse_addresses, perform_handshake, register_with_the_server}, registration::{parse_addresses, perform_handshake, register_with_the_server},
server_communication::{generate_id, get_peer_list}, server_communication::{generate_id, get_peer_list},
threads_handling::Worker, threads_handling::Worker,
}; };
use std::collections::HashSet;
use std::{ use std::{
io::Error, io::Error,
net::{IpAddr, Ipv4Addr, UdpSocket}, net::{IpAddr, UdpSocket},
time::Duration, time::Duration,
}; };
use std::{ use std::{
@@ -73,7 +70,13 @@ impl P2PSharedData {
let mut threads = Vec::new(); let mut threads = Vec::new();
let senders = MultipleSenders::new(1, &shared_socket, cmd_tx, &mut threads); let senders = MultipleSenders::new(
5,
&shared_socket,
cmd_tx,
&mut threads,
shared_messageslist.clone(),
);
let shared_senders = Arc::new(senders); let shared_senders = Arc::new(senders);
let server_name = Arc::new(Mutex::new("".to_string())); let server_name = Arc::new(Mutex::new("".to_string()));
let server_address = Arc::new(Mutex::new("".to_string())); let server_address = Arc::new(Mutex::new("".to_string()));
@@ -185,7 +188,7 @@ pub enum NetworkCommand {
SendDatum(MerkleNode, [u8; 32], String), SendDatum(MerkleNode, [u8; 32], String),
SendNoDatum(Vec<u8>, String), SendNoDatum(Vec<u8>, String),
SendRootReply(Vec<u8>, String), SendRootReply(Vec<u8>, String),
InitDownload([u8; 32], String), InitDownload([u8; 32], String, String),
// ... // ...
} }
@@ -194,9 +197,8 @@ pub enum NetworkEvent {
Connected(String), Connected(String),
ConnectedHandshake(), ConnectedHandshake(),
Disconnected(), Disconnected(),
Error(String), Error(String, String),
Success(String), Success(String, String),
PeerConnected(String),
PeerListUpdated(Vec<(String, bool)>), PeerListUpdated(Vec<(String, bool)>),
FileTreeReceived([u8; 32], MerkleNode, String), // peer_id, content FileTreeReceived([u8; 32], MerkleNode, String), // peer_id, content
DataReceived([u8; 32], MerkleNode, String), DataReceived([u8; 32], MerkleNode, String),
@@ -205,7 +207,7 @@ pub enum NetworkEvent {
ServerHandshakeFailed(String), ServerHandshakeFailed(String),
DatumRequest([u8; 32], String), DatumRequest([u8; 32], String),
RootRequest(String), RootRequest(String),
InitDownload([u8; 32], String), InitDownload([u8; 32], String, String),
// ... // ...
} }
@@ -216,17 +218,12 @@ use crossbeam_channel::{Receiver, Sender};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
pub fn calculate_chunk_id(data: &[u8]) -> String { pub fn calculate_chunk_id(data: &[u8]) -> String {
// 1. Create a new Sha256 hasher instance
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
// 2. Write the input data into the hasher
hasher.update(data); hasher.update(data);
// 3. Finalize the hash computation and get the resulting bytes
let hash_bytes = hasher.finalize(); let hash_bytes = hasher.finalize();
// 4. Convert the hash bytes (array of u8) into a hexadecimal string
// This is the common, human-readable format for cryptographic IDs.
hex::encode(hash_bytes) hex::encode(hash_bytes)
} }
@@ -235,22 +232,21 @@ pub fn start_p2p_executor(
event_tx: Sender<NetworkEvent>, event_tx: Sender<NetworkEvent>,
mut shared_data: Option<P2PSharedData>, mut shared_data: Option<P2PSharedData>,
) -> tokio::task::JoinHandle<()> { ) -> tokio::task::JoinHandle<()> {
// Use tokio to spawn the asynchronous networking logic
tokio::task::spawn(async move { tokio::task::spawn(async move {
// P2P/Networking Setup goes here
println!("Network executor started."); println!("Network executor started.");
// Main network loop // Main network loop
loop { loop {
// Check for commands from the GUI
if let Ok(cmd) = cmd_rx.try_recv() { if let Ok(cmd) = cmd_rx.try_recv() {
match cmd { match cmd {
NetworkCommand::InitDownload(hash, ip) => { NetworkCommand::InitDownload(hash, ip, name) => {
if let Some(sd) = shared_data.as_ref() { if let Some(sd) = shared_data.as_ref() {
if let Some(res) = sd.handshake_peers.get_peer_info_username(ip) { if let Some(res) = sd.handshake_peers.get_peer_info_username(ip) {
let _ = event_tx let _ = event_tx.send(NetworkEvent::InitDownload(
.send(NetworkEvent::InitDownload(hash, res.ip.to_string())); hash,
res.ip.to_string(),
name.to_string(),
));
} }
} }
} }
@@ -266,12 +262,8 @@ pub fn start_p2p_executor(
None => {} None => {}
Some(resp_msg) => { Some(resp_msg) => {
println!("msg_sent:{:?}", resp_msg); println!("msg_sent:{:?}", resp_msg);
sd.senders_ref().send_dispatch( sd.senders_ref()
resp_msg, .send_dispatch(resp_msg, addr.clone(), false);
addr.clone(),
false,
sd.messages_list(),
);
} }
} }
} }
@@ -288,12 +280,8 @@ pub fn start_p2p_executor(
None => {} None => {}
Some(resp_msg) => { Some(resp_msg) => {
println!("msg_sent:{:?}", resp_msg); println!("msg_sent:{:?}", resp_msg);
sd.senders_ref().send_dispatch( sd.senders_ref()
resp_msg, .send_dispatch(resp_msg, addr.clone(), false);
addr.clone(),
false,
sd.messages_list(),
);
} }
} }
} }
@@ -311,12 +299,8 @@ pub fn start_p2p_executor(
None => {} None => {}
Some(resp_msg) => { Some(resp_msg) => {
println!("msg_sent:{:?}", resp_msg); println!("msg_sent:{:?}", resp_msg);
sd.senders_ref().send_dispatch( sd.senders_ref()
resp_msg, .send_dispatch(resp_msg, addr.clone(), false);
addr.clone(),
false,
sd.messages_list(),
);
} }
} }
} }
@@ -337,27 +321,70 @@ pub fn start_p2p_executor(
sd.messages_list(), sd.messages_list(),
sd.handshake_peers.get_username_peerinfo_map(), sd.handshake_peers.get_username_peerinfo_map(),
); );
let server_address = {
match get_server_address(username.to_owned(), ip.to_owned()).await {
Some(addr) => addr.to_string(),
None => {
match event_tx.send(NetworkEvent::Error(
"Couldn't fetch server socket address.".to_owned(),
username.to_owned(),
)) {
Ok(_) => {}
Err(e) => {
println!("Network Event Error : {}", e.to_string());
}
}
"".to_owned()
}
}
};
if server_address.to_owned().eq(&"".to_owned()) {
continue;
}
let res = sd.set_servername(username.to_owned());
perform_handshake(&sd, username, ip, event_tx.clone(), true).await; sd.set_serveraddress(server_address.to_string());
println!("SET SERVERADDRESS");
match perform_handshake(
&sd,
username.to_owned(),
ip,
event_tx.clone(),
(true, server_address.to_string()),
)
.await
{
true => {
match event_tx.send(NetworkEvent::Success(
"Handshake established ✔️".to_string(),
username.to_owned(),
)) {
Ok(_) => {}
Err(err) => {
println!("Network Event Error : {}", err.to_string());
}
};
}
false => {}
};
} else { } else {
println!("no shared data"); println!("no shared data");
} }
} }
NetworkCommand::ConnectPeer((username, connected)) => { NetworkCommand::ConnectPeer((username, _)) => {
println!("[Network] ConnectPeer() called"); println!("[Network] ConnectPeer() called");
println!("[Network] Attempting to connect to: {}", username); println!("[Network] Attempting to connect to: {}", username);
// Network logic to connect...
// If successful, send an event back:
// event_tx.send(NetworkEvent::PeerConnected(addr)).unwrap();
} }
NetworkCommand::RequestFileTree(_) => { NetworkCommand::RequestFileTree(_) => {
println!("[Network] RequestFileTree() called"); println!("[Network] RequestFileTree() called");
} }
NetworkCommand::Discover(username, hash, ip) => { NetworkCommand::Discover(username, _, ip) => {
// envoie un handshake au peer, puis un root request // envoie un handshake au peer, puis un root request
if let Some(sd) = shared_data.as_ref() { if let Some(sd) = shared_data.as_ref() {
let res = sd.handshake_peers.get_peer_info_username(username.clone()); let res = sd
.handshake_peers
.get_peer_info_username(username.to_owned());
match res { match res {
Some(peerinfo) => { Some(peerinfo) => {
let id = generate_id(); let id = generate_id();
@@ -385,21 +412,37 @@ pub fn start_p2p_executor(
resp_msg, resp_msg,
peerinfo.ip.to_string(), peerinfo.ip.to_string(),
false, false,
sd.messages_list(),
); );
} }
} }
} }
None => { None => {
// envoyer un handshake // envoyer un handshake
let res = perform_handshake( match perform_handshake(
&sd, &sd,
username, username.to_owned(),
ip, ip,
event_tx.clone(), event_tx.clone(),
false, (false, "".to_string()),
) )
.await; .await
{
true => {
match event_tx.send(NetworkEvent::Success(
"Handshake established ✔️".to_string(),
username.to_owned(),
)) {
Ok(_) => {}
Err(err) => {
println!(
"Network Event Error : {}",
err.to_string()
);
}
};
}
false => {}
}
} }
} }
} else { } else {
@@ -432,12 +475,7 @@ pub fn start_p2p_executor(
false, false,
); );
sd.senders_ref().send_dispatch( sd.senders_ref().send_dispatch(resp_msg, ip.clone(), false);
resp_msg,
ip.clone(),
false,
sd.messages_list(),
);
} }
} }
} }
@@ -458,8 +496,18 @@ pub fn start_p2p_executor(
Err(e) => { Err(e) => {
let mut err_msg = String::from("failed to initialize socket: "); let mut err_msg = String::from("failed to initialize socket: ");
err_msg += &e.to_string(); err_msg += &e.to_string();
let res = event_tx.send(NetworkEvent::Error(err_msg)); match event_tx.send(NetworkEvent::Error(err_msg, name.to_owned())) {
let res = event_tx.send(NetworkEvent::Disconnected()); Ok(_) => {}
Err(err) => {
println!("Network Event Error : {}", err.to_string());
}
};
match event_tx.send(NetworkEvent::Disconnected()) {
Ok(_) => {}
Err(err) => {
println!("Network Event Error : {}", err.to_string());
}
};
None None
} }
}; };
@@ -468,31 +516,41 @@ pub fn start_p2p_executor(
if let Err(e) = register_with_the_server(&sd.cryptopair(), &ip).await { if let Err(e) = register_with_the_server(&sd.cryptopair(), &ip).await {
let mut err_msg = String::from("request failed: "); let mut err_msg = String::from("request failed: ");
err_msg += &e.to_string(); err_msg += &e.to_string();
let res = event_tx.send(NetworkEvent::Error(err_msg)); match event_tx.send(NetworkEvent::Error(err_msg, name.to_owned())) {
let res = event_tx.send(NetworkEvent::Disconnected()); Ok(_) => {}
Err(err) => {
println!("Network Event Error : {}", err.to_string());
}
};
match event_tx.send(NetworkEvent::Disconnected()) {
Ok(_) => {}
Err(err) => {
println!("Network Event Error : {}", err.to_string());
}
};
} else { } else {
let res = event_tx.send(NetworkEvent::Connected(ip)); match event_tx.send(NetworkEvent::Connected(ip)) {
Ok(_) => {}
Err(err) => {
println!("Network Event Error : {}", err.to_string());
}
};
println!("username created: {}", sd.cryptopair().username); println!("username created: {}", sd.cryptopair().username);
} }
//println!("ip: {}", ip);
} }
//tokio::time::sleep(std::time::Duration::from_millis(5000)).await;
/*let res = event_tx.send(NetworkEvent::Connected());
if let Some(error) = res.err() {
println!(
"[Network] Couldn't send crossbeam message to GUI: {}",
error.to_string()
);
}*/
} }
NetworkCommand::FetchPeerList(ip) => { NetworkCommand::FetchPeerList(ip) => {
println!("[Network] FetchPeerList() called"); println!("[Network] FetchPeerList() called");
if ip == "" { if ip == "" {
let res = event_tx.send(NetworkEvent::Error( match event_tx.send(NetworkEvent::Error(
"Not registered to any server".to_string(), "Not registered to any server".to_string(),
)); "".to_owned(),
)) {
Ok(_) => {}
Err(err) => {
println!("Network Event Error : {}", err.to_string());
}
};
} else { } else {
println!("cc"); println!("cc");
match get_peer_list(ip).await { match get_peer_list(ip).await {
@@ -508,14 +566,21 @@ pub fn start_p2p_executor(
current.push(i); current.push(i);
} }
} }
let res = match event_tx.send(NetworkEvent::PeerListUpdated(peers)) {
event_tx.send(NetworkEvent::PeerListUpdated(peers)); Ok(_) => {}
Err(err) => {
println!(
"Network Event Error : {}",
err.to_string()
);
}
};
} }
Err(e) => { Err(e) => {
eprintln!("invalid UTF-8 in socket address bytes: {}", e); eprintln!("invalid UTF-8 in socket address bytes: {}", e);
} }
}, },
Err(e) => println!("error"), Err(e) => println!("error : {}", e),
} }
} }
} }
@@ -527,29 +592,17 @@ pub fn start_p2p_executor(
if let Some(sd) = shared_data.as_ref() { if let Some(sd) = shared_data.as_ref() {
let id = generate_id(); let id = generate_id();
sd.add_message(id, EventType::Ping); sd.add_message(id, EventType::Ping);
let pingrequest =
construct_message(PING, Vec::new(), id, sd.cryptopair_ref());
let peer_address = 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 { match peer_address {
Ok(addr) => { Ok(addr) => {
//if let Some(ping) = pingrequest { match event_tx.send(NetworkEvent::Success(
// sd.senders_ref().add_message_to_retry_queue( format!(
// ping.clone(),
// addr.to_string(),
// false,
// );
// sd.senders_ref().send_dispatch(
// ping,
// addr.to_string(),
// false,
// sd.messages_list(),
// );
//}
match event_tx.send(NetworkEvent::Success(format!(
"Successfully sent ping message to {}.", "Successfully sent ping message to {}.",
addr.to_string() addr.to_string(),
))) { ),
str.to_owned(),
)) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
eprintln!("NetworkEvent error : {}", e); eprintln!("NetworkEvent error : {}", e);
@@ -557,7 +610,9 @@ pub fn start_p2p_executor(
}; };
} }
Err(err_msg) => { 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(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
eprintln!("NetworkEvent error : {}", e); eprintln!("NetworkEvent error : {}", e);
@@ -620,11 +675,12 @@ pub fn start_p2p_executor(
), ),
server_addr.to_string(), server_addr.to_string(),
false, false,
sd.messages_list(),
); );
} }
Err(err_msg) => { 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(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
eprintln!("NetworkEvent error : {}", e); eprintln!("NetworkEvent error : {}", e);
@@ -637,12 +693,6 @@ pub fn start_p2p_executor(
} }
} }
// 2. Poll network for new events (e.g., an incoming connection)
// ...
// When a new peer is found:
// event_tx.send(NetworkEvent::PeerConnected("NewPeerID".to_string())).unwrap();
// Avoid spinning too fast
sleep(std::time::Duration::from_millis(50)).await; sleep(std::time::Duration::from_millis(50)).await;
} }
}) })
@@ -657,22 +707,6 @@ fn socket_addr_to_vec(addr: SocketAddr) -> Vec<u8> {
v v
} }
fn parse_pack(s: &str) -> Option<[u8; 6]> {
// split into "ip" and "port"
let mut parts = s.rsplitn(2, ':');
let port_str = parts.next()?;
let ip_str = parts.next()?; // if missing, invalid
let ip: Ipv4Addr = ip_str.parse().ok()?;
let port: u16 = port_str.parse().ok()?;
let octets = ip.octets();
let port_be = port.to_be_bytes();
Some([
octets[0], octets[1], octets[2], octets[3], port_be[0], port_be[1],
])
}
async fn quick_ping(addr: &SocketAddr, timeout_ms: u64, sd: &P2PSharedData) -> bool { async fn quick_ping(addr: &SocketAddr, timeout_ms: u64, sd: &P2PSharedData) -> bool {
let id = generate_id(); let id = generate_id();
let pingreq = construct_message(PING, Vec::new(), id, &sd.shared_cryptopair); let pingreq = construct_message(PING, Vec::new(), id, &sd.shared_cryptopair);
@@ -680,7 +714,7 @@ async fn quick_ping(addr: &SocketAddr, timeout_ms: u64, sd: &P2PSharedData) -> b
if let Some(ping) = pingreq { if let Some(ping) = pingreq {
sd.add_message(id, EventType::Ping); sd.add_message(id, EventType::Ping);
sd.senders_ref() sd.senders_ref()
.send_dispatch(ping, addr.to_string(), false, sd.messages_list()); .send_dispatch(ping, addr.to_string(), false);
} }
sleep(Duration::from_millis(timeout_ms)).await; sleep(Duration::from_millis(timeout_ms)).await;
@@ -699,7 +733,6 @@ async fn quick_ping(addr: &SocketAddr, timeout_ms: u64, sd: &P2PSharedData) -> b
/// ///
/// sends a get request to the server to get the socket address of the given peer /// sends a get request to the server to get the socket address of the given peer
/// ///
pub async fn get_socket_address( pub async fn get_socket_address(
username: String, username: String,
ip: String, ip: String,
@@ -743,7 +776,16 @@ pub async fn get_socket_address(
} }
}; };
let addresses = parse_addresses(&s); // assumes parse_addresses: &str -> Vec<SocketAddr> let addresses: Vec<SocketAddr> = {
let temp = parse_addresses(&s);
temp.iter()
.filter_map(|a| match a {
SocketAddr::V4(_) => Some(*a),
SocketAddr::V6(_) => None,
})
.collect()
};
if addresses.is_empty() { if addresses.is_empty() {
return Err(FetchSocketAddressError::NoRegisteredAddresses); return Err(FetchSocketAddressError::NoRegisteredAddresses);
} else if !addresses.iter().any(|a| matches!(a, SocketAddr::V4(_))) { } else if !addresses.iter().any(|a| matches!(a, SocketAddr::V4(_))) {
@@ -752,7 +794,7 @@ pub async fn get_socket_address(
for addr in addresses { for addr in addresses {
println!("trying address : {}", addr); println!("trying address : {}", addr);
if quick_ping(&addr, 5000, sd).await { if quick_ping(&addr, 1000, sd).await {
return Ok(addr); return Ok(addr);
} }
@@ -766,10 +808,9 @@ pub async fn get_socket_address(
natreq.expect("couldnt construct message nattraversalrequest2"), natreq.expect("couldnt construct message nattraversalrequest2"),
sd.serveraddress().to_string(), sd.serveraddress().to_string(),
false, false,
sd.messages_list(),
); );
sleep(Duration::from_millis(5000)).await; sleep(Duration::from_millis(1000)).await;
let maybe_entry = { let maybe_entry = {
let guard = sd.messages_received_ref().lock().unwrap(); let guard = sd.messages_received_ref().lock().unwrap();
@@ -784,7 +825,7 @@ pub async fn get_socket_address(
} }
} }
if quick_ping(&addr, 15000, sd).await { if quick_ping(&addr, 5000, sd).await {
return Ok(addr); return Ok(addr);
} }
} }

View File

@@ -10,7 +10,6 @@ use crate::{
}; };
use std::{ use std::{
collections::HashMap, collections::HashMap,
default,
net::{Ipv4Addr, SocketAddr}, net::{Ipv4Addr, SocketAddr},
}; };
use std::{ use std::{
@@ -61,7 +60,6 @@ const ID: usize = 4;
const TYPE: usize = 5; const TYPE: usize = 5;
const LENGTH: usize = 7; const LENGTH: usize = 7;
const EXTENSIONS: usize = 4; const EXTENSIONS: usize = 4;
const SIGNATURE: usize = 64;
pub const PING: u8 = 0; pub const PING: u8 = 0;
const OK: u8 = 128; const OK: u8 = 128;
@@ -101,7 +99,6 @@ pub fn handle_recevied_message(
let length_bytes: [u8; 2] = recevied_message[TYPE..LENGTH] let length_bytes: [u8; 2] = recevied_message[TYPE..LENGTH]
.try_into() .try_into()
.expect("Taille incorrecte"); .expect("Taille incorrecte");
let msg_length = u16::from_be_bytes(length_bytes) as usize;
let ilength = u16::from_be_bytes(length_bytes); let ilength = u16::from_be_bytes(length_bytes);
let received_name = &recevied_message[LENGTH + EXTENSIONS..LENGTH + ilength as usize]; let received_name = &recevied_message[LENGTH + EXTENSIONS..LENGTH + ilength as usize];
let name = String::from_utf8(received_name.to_vec()).expect("wrong name"); let name = String::from_utf8(received_name.to_vec()).expect("wrong name");
@@ -126,12 +123,7 @@ pub fn handle_recevied_message(
None => {} None => {}
Some(resp_msg) => { Some(resp_msg) => {
println!("msg_sent:{:?}", resp_msg); println!("msg_sent:{:?}", resp_msg);
senders.send_dispatch( senders.send_dispatch(resp_msg, ip.to_string(), is_resp_to_server_handshake);
resp_msg,
ip.to_string(),
is_resp_to_server_handshake,
messages_list.clone(),
);
} }
} }
} }
@@ -149,10 +141,6 @@ pub fn parse_message(
) -> Option<Vec<u8>> { ) -> Option<Vec<u8>> {
let cmd_tx_clone = cmd_tx.clone(); let cmd_tx_clone = cmd_tx.clone();
let id_bytes: [u8; 4] = received_message[0..ID]
.try_into()
.expect("Taille incorrecte");
let msgtype = received_message[ID]; let msgtype = received_message[ID];
messages_received messages_received
@@ -269,7 +257,6 @@ pub fn parse_message(
natreq2.expect("couldnt construct message nattraversalrequest2"), natreq2.expect("couldnt construct message nattraversalrequest2"),
address, address,
false, false,
messages_list.clone(),
); );
} }
@@ -279,10 +266,6 @@ pub fn parse_message(
let ilength = u16::from_be_bytes(length_bytes); let ilength = u16::from_be_bytes(length_bytes);
let received_address = &received_message[LENGTH..LENGTH + ilength as usize]; let received_address = &received_message[LENGTH..LENGTH + ilength as usize];
println!("received_address:{:?}", received_message);
//let addressv4 = IpAddr::V4(Ipv4Addr::from_octets(
// received_address[0..4].try_into().expect("incorrect size"),
//));
let bytes: [u8; 4] = received_address[0..4].try_into().expect("incorrect size"); let bytes: [u8; 4] = received_address[0..4].try_into().expect("incorrect size");
let addr_v4 = Ipv4Addr::from(bytes); let addr_v4 = Ipv4Addr::from(bytes);
let addressv4 = IpAddr::V4(addr_v4); let addressv4 = IpAddr::V4(addr_v4);
@@ -300,14 +283,12 @@ pub fn parse_message(
constructed_message.expect("couldnt construct message ping request"), constructed_message.expect("couldnt construct message ping request"),
ip.to_string(), ip.to_string(),
false, false,
messages_list.clone(),
); );
senders.send_dispatch( senders.send_dispatch(
pingreq.expect("couldnt construct message ping request"), pingreq.expect("couldnt construct message ping request"),
address.to_string(), address.to_string(),
false, false,
messages_list.clone(),
); );
constructed_message = None; constructed_message = None;
} }
@@ -317,10 +298,10 @@ pub fn parse_message(
String::from_utf8(received_message[LENGTH..(msg_length + LENGTH)].to_vec()) String::from_utf8(received_message[LENGTH..(msg_length + LENGTH)].to_vec())
{ {
let err_msg = format!("Error received from peer {} : {}", ip, err_received); 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 { } else {
let err_msg = format!("Error received from peer {} : N/A", ip,); 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()));
} }
} }
@@ -370,14 +351,11 @@ pub fn parse_message(
// envoyer la root request // envoyer la root request
let _ = &guard.remove_entry(&id); let _ = &guard.remove_entry(&id);
println!("message {} retiré de la liste", id); println!("message {} retiré de la liste", id);
let new_id = generate_id();
let rootrequest = construct_message( let rootrequest =
ROOTREQUEST, construct_message(ROOTREQUEST, Vec::new(), new_id, crypto_pair);
Vec::new(), let _ = &guard.insert(new_id, EventType::RootRequest);
generate_id(), println!("root requesst sent");
crypto_pair,
);
//&guard.insert(, v)
return rootrequest; return rootrequest;
} }
EventType::Hello => { EventType::Hello => {
@@ -392,6 +370,7 @@ pub fn parse_message(
} }
ROOTREPLY => { ROOTREPLY => {
// recuperer le pseudo du peers ayant repondu // recuperer le pseudo du peers ayant repondu
println!("root reply received");
let peers_exist = handhsake_history.get_peer_info_ip(ip.to_string()); let peers_exist = handhsake_history.get_peer_info_ip(ip.to_string());
match peers_exist { match peers_exist {
Some(peerinfo) => { Some(peerinfo) => {
@@ -410,11 +389,15 @@ pub fn parse_message(
[LENGTH..(32 + LENGTH)] [LENGTH..(32 + LENGTH)]
.try_into() .try_into()
.expect("incorrect size"); .expect("incorrect size");
let res = match cmd_tx_clone.send(NetworkEvent::FileTreeRootReceived(
cmd_tx_clone.send(NetworkEvent::FileTreeRootReceived(
peerinfo.username.clone(), peerinfo.username.clone(),
received_hash, received_hash,
)); )) {
Ok(_) => {}
Err(e) => {
println!("Network Event Error : {}", e.to_string());
}
};
println!("file tree sent"); println!("file tree sent");
// envoyer un datum // envoyer un datum
let mut payload = Vec::new(); let mut payload = Vec::new();
@@ -429,7 +412,9 @@ pub fn parse_message(
constructed_message = datumreqest; constructed_message = datumreqest;
guard.insert(new_id, EventType::DatumRequest); guard.insert(new_id, EventType::DatumRequest);
} }
_ => {} _ => {
println!("event not prensent");
}
} }
} }
None => {} None => {}
@@ -468,18 +453,19 @@ pub fn parse_message(
} }
} }
EventType::DatumRequestBig => { EventType::DatumRequestBig => {
let _ = &guard.remove_entry(&id);
println!("message {} retiré de la liste", id); println!("message {} retiré de la liste", id);
let received_length = u16::from_be_bytes( let received_length = u16::from_be_bytes(
received_message[TYPE..LENGTH] received_message[TYPE..LENGTH]
.try_into() .try_into()
.expect("incorrect size"), .expect("incorrect size"),
); );
println!("received length:{}", received_length);
let received_datum = &received_message[LENGTH..]; let received_datum = &received_message[LENGTH..];
let parsed_node = let parsed_node =
parse_received_datum(received_datum.to_vec(), received_length as usize); parse_received_datum(received_datum.to_vec(), received_length as usize);
match parsed_node { match parsed_node {
Some(tuple) => { Some(tuple) => {
let _ = &guard.remove_entry(&id);
let _ = cmd_tx.send(NetworkEvent::DataReceived( let _ = cmd_tx.send(NetworkEvent::DataReceived(
tuple.0, tuple.0,
tuple.1, tuple.1,
@@ -487,7 +473,9 @@ pub fn parse_message(
)); ));
println!("datareceived event sent"); println!("datareceived event sent");
} }
None => {} None => {
println!("message corrompu, nouvelle tentative");
}
} }
} }
_ => {} _ => {}

View File

@@ -1,26 +1,20 @@
use crossbeam_channel::Receiver; use crossbeam_channel::Receiver;
use tokio::sync::oneshot;
use tokio::time::sleep;
use crate::P2PSharedData; use crate::P2PSharedData;
use crate::message_handling::EventType; use crate::message_handling::EventType;
use crate::message_handling::handle_recevied_message; use crate::message_handling::handle_recevied_message;
use crate::peers_refresh::HandshakeHistory; use crate::peers_refresh::HandshakeHistory;
use crate::threads_handling::Worker; use crate::threads_handling::Worker;
use std::clone; use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::net::SocketAddr;
use std::net::UdpSocket; use std::net::UdpSocket;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::sync::mpsc::{self, Sender};
use std::thread; use std::thread;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::time::Duration;
use std::time::SystemTime; use std::time::SystemTime;
use std::time::UNIX_EPOCH; use std::time::UNIX_EPOCH;
use std::time::{Duration, Instant};
use crate::NetworkEvent; use crate::NetworkEvent;
@@ -38,10 +32,8 @@ struct RetryMessage {
pub struct MultipleSenders { pub struct MultipleSenders {
sender: crossbeam_channel::Sender<Message>, sender: crossbeam_channel::Sender<Message>,
receiver: crossbeam_channel::Receiver<Message>,
response_channel: crossbeam_channel::Sender<NetworkEvent>, response_channel: crossbeam_channel::Sender<NetworkEvent>,
retry_queue: Arc<Mutex<VecDeque<RetryMessage>>>, retry_queue: Arc<Mutex<VecDeque<RetryMessage>>>,
completed_messages: HashSet<i32>,
} }
impl MultipleSenders { impl MultipleSenders {
@@ -50,6 +42,7 @@ impl MultipleSenders {
socket: &Arc<UdpSocket>, socket: &Arc<UdpSocket>,
cmd_tx: crossbeam_channel::Sender<NetworkEvent>, cmd_tx: crossbeam_channel::Sender<NetworkEvent>,
threads: &mut Vec<Worker>, threads: &mut Vec<Worker>,
messages_list: Arc<Mutex<HashMap<i32, EventType>>>,
) -> Self { ) -> Self {
let (tx1, rx1) = crossbeam_channel::unbounded(); let (tx1, rx1) = crossbeam_channel::unbounded();
@@ -57,18 +50,22 @@ impl MultipleSenders {
let sock_clone = Arc::clone(&socket); let sock_clone = Arc::clone(&socket);
let cmd_tx_clone = cmd_tx.clone(); let cmd_tx_clone = cmd_tx.clone();
let rx: Receiver<Message> = rx1.clone(); let rx: Receiver<Message> = rx1.clone();
let msg_list_clone = messages_list.clone();
let thread = thread::spawn(move || { let thread = thread::spawn(move || {
println!("Canal d'envoi {} prêt", i); println!("Canal d'envoi {} prêt", i);
loop { loop {
// Priorité aux messages en attente prêts à être réessayés
// Si aucun retry prêt, on bloque sur rx avec timeout court, pour pouvoir traiter les timers
let msg = rx.recv().unwrap(); let msg = rx.recv().unwrap();
match sock_clone.send_to(&msg.payload, &msg.address) { match sock_clone.send_to(&msg.payload, &msg.address) {
Ok(_) => { Ok(_) => {
if msg.is_resp_to_server_handshake { if msg.is_resp_to_server_handshake {
let res = cmd_tx_clone.send(NetworkEvent::ConnectedHandshake()); match cmd_tx_clone.send(NetworkEvent::ConnectedHandshake()) {
Ok(_) => {}
Err(e) => {
println!("Network Event Error : {}", e.to_string());
}
};
} }
let message_id: [u8; 4] = let message_id: [u8; 4] =
msg.payload[0..4].try_into().expect("size error"); msg.payload[0..4].try_into().expect("size error");
@@ -84,61 +81,33 @@ impl MultipleSenders {
"Erreur d'envoi initial sur canal {}: {}, address: {}", "Erreur d'envoi initial sur canal {}: {}, address: {}",
i, e, &msg.address i, e, &msg.address
); );
let mut guard = msg_list_clone.lock().unwrap();
let message_id: [u8; 4] =
msg.payload[0..4].try_into().expect("size error");
let id = i32::from_be_bytes(message_id);
guard.remove_entry(&id);
drop(guard);
} }
} }
} }
}); });
threads.push(Worker::spawn( threads.push(Worker::spawn(thread));
thread,
crate::threads_handling::WorkerType::MSGSENDER,
));
} }
MultipleSenders { MultipleSenders {
sender: tx1, sender: tx1,
receiver: rx1,
response_channel: cmd_tx.clone(), response_channel: cmd_tx.clone(),
retry_queue: Arc::new(Mutex::new(VecDeque::new())), retry_queue: Arc::new(Mutex::new(VecDeque::new())),
completed_messages: HashSet::new(),
} }
} }
/*
/// Envoie un message via un canal spécifique (round-robin ou index précis)
pub fn send_via(
&self,
channel_idx: usize,
data: Vec<u8>,
remote_addr: String,
is_resp_to_server_handshake: bool,
messages_list: &Mutex<HashMap<i32, EventType>>,
) {
println!(
"is_resp_to_server_handshake {}",
is_resp_to_server_handshake
);
let msg_to_send = Message {
payload: data.clone(),
address: remote_addr,
is_resp_to_server_handshake,
};
if let Some(sender) = self.senders.get(channel_idx) {
let _ = sender.send(msg_to_send);
}
if !is_resp_to_server_handshake {
let mut guard = messages_list.lock().unwrap();
let message_id: [u8; 4] = data[0..4].try_into().expect("size error");
let id = i32::from_be_bytes(message_id);
guard.insert(id, EventType::SendRootRequest);
}
}*/
pub fn send_dispatch( pub fn send_dispatch(
&self, &self,
data: Vec<u8>, data: Vec<u8>,
remote_addr: String, remote_addr: String,
is_resp_to_server_handshake: bool, is_resp_to_server_handshake: bool,
messages_list: Arc<Mutex<HashMap<i32, EventType>>>,
) { ) {
let msg_to_send = Message { let msg_to_send = Message {
payload: data.clone(), payload: data.clone(),
@@ -199,8 +168,7 @@ pub fn start_retry_thread(
if guard.contains_key(&id) { if guard.contains_key(&id) {
drop(guard); drop(guard);
// si le message est n'a pas encore a etre traité, on le
// remet en queue de liste
if front.next_try if front.next_try
<= SystemTime::now() <= SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
@@ -215,9 +183,15 @@ pub fn start_retry_thread(
); );
println!("{}", str); println!("{}", str);
if front.msg.is_resp_to_server_handshake { if front.msg.is_resp_to_server_handshake {
let res = senders match senders
.response_channel .response_channel
.send(NetworkEvent::ServerHandshakeFailed(str)); .send(NetworkEvent::ServerHandshakeFailed(str))
{
Ok(_) => {}
Err(e) => {
println!("Network Event Error : {}", e.to_string());
}
};
} }
} else { } else {
let str = format!( let str = format!(
@@ -230,11 +204,11 @@ pub fn start_retry_thread(
front.msg.payload.clone(), front.msg.payload.clone(),
front.msg.address.clone(), front.msg.address.clone(),
front.msg.is_resp_to_server_handshake, front.msg.is_resp_to_server_handshake,
messages_list.clone(),
); );
let base: u64 = 2; let base: u64 = 2;
let backoff = base.saturating_pow(attempt as u32); // 2^1 == 2 seconds let backoff = base.saturating_pow(attempt as u32); // 2^1 == 2 seconds
//let backoff = 1;
let newretry = RetryMessage { let newretry = RetryMessage {
next_try: SystemTime::now() next_try: SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
@@ -245,19 +219,16 @@ pub fn start_retry_thread(
attempts: attempt, attempts: attempt,
}; };
q.push_back(newretry); // remettre en tête pour réessayer plus tôt q.push_back(newretry);
} }
} else { } else {
q.push_back(front); // remettre en tête pour réessayer plus tôt q.push_back(front);
} }
} }
} }
} }
}); });
threads.push(Worker::spawn( threads.push(Worker::spawn(thread));
thread,
crate::threads_handling::WorkerType::MSGRETRY,
));
} }
pub fn start_receving_thread( pub fn start_receving_thread(
@@ -272,13 +243,13 @@ pub fn start_receving_thread(
let messages_received_clone = shared_data.messages_received(); let messages_received_clone = shared_data.messages_received();
let servername_clone = shared_data.servername(); let servername_clone = shared_data.servername();
let thread = thread::spawn(move || { let thread = thread::spawn(move || {
let mut buf = [0u8; 1024]; let mut buf = [0u8; 1500];
loop { loop {
match sock_clone.recv_from(&mut buf) { match sock_clone.recv_from(&mut buf) {
Ok((amt, src)) => { Ok((amt, src)) => {
let received_data = buf[..amt].to_vec(); let received_data = buf[..amt].to_vec();
println!("Reçu {} octets de {}: {:?}", amt, src, received_data); println!("Reçu {} octets de {}", amt, src);
handle_recevied_message( handle_recevied_message(
&messages_clone, &messages_clone,
&messages_received_clone, &messages_received_clone,
@@ -295,8 +266,5 @@ pub fn start_receving_thread(
} }
} }
}); });
shared_data.threads.push(Worker::spawn( shared_data.threads.push(Worker::spawn(thread));
thread,
crate::threads_handling::WorkerType::MSGRECEPTION,
));
} }

View File

@@ -1,3 +1,4 @@
#![allow(unused)]
use crate::cryptographic_signature::{CryptographicSignature, sign_message}; use crate::cryptographic_signature::{CryptographicSignature, sign_message};
const ID: usize = 4; const ID: usize = 4;
@@ -163,7 +164,7 @@ impl HandshakeMessage {
} }
} }
pub fn helloReply(id: u32, length: u16, username: String) -> HandshakeMessage { pub fn hello_reply(id: u32, length: u16, username: String) -> HandshakeMessage {
let name_vec = username.trim_end_matches(char::from(0)).as_bytes().to_vec(); let name_vec = username.trim_end_matches(char::from(0)).as_bytes().to_vec();
HandshakeMessage { HandshakeMessage {
id: id, id: id,
@@ -219,28 +220,3 @@ impl HandshakeMessage {
} }
} }
} }
#[cfg(test)]
mod tests {
// Note this useful idiom: importing names from outer (for mod tests) scope.
use super::*;
/*
/// creates an handshake message
#[tokio::test]
async fn creating_handshake_msg() {
let username = String::from("charlie_kirk");
let handshake = HandshakeMessage::hello(0, 12, username);
handshake.display();
}
/// parses an handshake message
#[tokio::test]
async fn parse_handshakemessage() {
let username = String::from("charlie_kirk");
let handshake = HandshakeMessage::hello(0, 12, username);
let ser = handshake.serialize();
let parsed = HandshakeMessage::parse(ser);
handshake.display();
parsed.display();
}*/
}

View File

@@ -4,24 +4,18 @@
pub use crate::message_handling::*; pub use crate::message_handling::*;
use std::{ use std::{
collections::{HashMap, VecDeque}, collections::HashMap,
net::{AddrParseError, Ipv4Addr, SocketAddr}, net::SocketAddr,
ops::Add,
process::Command,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
thread::{self, JoinHandle}, thread::{self},
time::{self, Duration, SystemTime}, time::Duration,
}; };
use crate::{construct_message, generate_id};
use crate::{ use crate::{
NetworkEvent, cryptographic_signature::CryptographicSignature, cryptographic_signature::CryptographicSignature, messages_channels::MultipleSenders,
messages_channels::MultipleSenders, threads_handling::Worker, threads_handling::Worker,
}; };
use crate::{
P2PSharedData, construct_message, generate_id, messages_structure,
registration::perform_handshake,
};
use crossbeam_channel::{Receiver, Sender};
use p256::ecdsa::VerifyingKey; use p256::ecdsa::VerifyingKey;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -117,7 +111,7 @@ pub fn update_handshake(
let handle = thread::spawn(move || { let handle = thread::spawn(move || {
loop { loop {
let guard = map_for_thread.lock().unwrap(); let guard = map_for_thread.lock().unwrap();
for (peer, peerinfo) in guard.iter() { for (_, peerinfo) in guard.iter() {
let id = generate_id(); let id = generate_id();
let mut map = messages_list.lock().unwrap(); let mut map = messages_list.lock().unwrap();
map.insert(id, EventType::Ping); map.insert(id, EventType::Ping);
@@ -128,34 +122,12 @@ pub fn update_handshake(
peerinfo.ip.to_string(), peerinfo.ip.to_string(),
false, false,
); );
senders.send_dispatch( senders.send_dispatch(ping, peerinfo.ip.to_string(), false);
ping,
peerinfo.ip.to_string(),
false,
messages_list.clone(),
);
} }
} }
drop(guard); drop(guard);
thread::sleep(Duration::from_secs(60)); thread::sleep(Duration::from_secs(60));
} }
}); });
Worker::spawn(handle, crate::threads_handling::WorkerType::PING) Worker::spawn(handle)
}
#[cfg(test)]
mod tests {
use std::net::{IpAddr, Ipv4Addr};
use super::*;
/*#[test]
fn creating_cryptographic_signature() {
let mut hh = HandshakeHistory::new();
hh.add_new_handshake(
20,
"putain".to_string(),
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 1),
);
}*/
} }

View File

@@ -1,7 +1,7 @@
use crate::NetworkEvent; use crate::NetworkEvent;
use crate::P2PSharedData; use crate::P2PSharedData;
use crate::cryptographic_signature::CryptographicSignature; use crate::cryptographic_signature::CryptographicSignature;
use crate::get_server_address; use crate::get_socket_address;
use crate::message_handling::EventType; use crate::message_handling::EventType;
use crate::messages_structure::construct_message; use crate::messages_structure::construct_message;
use crate::server_communication::generate_id; use crate::server_communication::generate_id;
@@ -55,24 +55,48 @@ pub async fn perform_handshake(
username: String, username: String,
ip: String, ip: String,
event_tx: Sender<NetworkEvent>, event_tx: Sender<NetworkEvent>,
is_server_handshake: bool, is_server_handshake: (bool, String),
) { ) -> bool {
println!("username: {}, ip: {}", username.clone(), ip.clone()); println!("username: {}, ip: {}", username.clone(), ip.clone());
let crypto_pair = sd.cryptopair_ref(); let crypto_pair = sd.cryptopair_ref();
let senders = sd.senders_ref(); let senders = sd.senders_ref();
let id = generate_id(); let id = generate_id();
let server_addr_query = get_server_address(username.clone(), ip.clone());
match server_addr_query.await { let address = {
Some(sockaddr_bytes) => { if is_server_handshake.0 {
sd.set_servername(username); is_server_handshake.1
sd.set_serveraddress(sockaddr_bytes.to_string()); } else {
// first: &SocketAddr let server_addr_query =
get_socket_address(username.clone(), ip.clone(), Some(sd)).await;
match server_addr_query {
Ok(sockaddr_bytes) => sockaddr_bytes.to_string(),
Err(err_msg) => {
match event_tx.send(NetworkEvent::Error(
err_msg.to_string(),
username.to_owned(),
)) {
Ok(_) => {}
Err(err) => {
println!("Network Event Error : {}", err.to_string());
}
}
"".to_string()
}
}
}
};
if address.eq(&"".to_string()) {
return false;
}
let mut payload = Vec::new(); let mut payload = Vec::new();
payload.extend_from_slice(&0u32.to_be_bytes()); payload.extend_from_slice(&0u32.to_be_bytes());
payload.extend_from_slice(&crypto_pair.username.clone().as_bytes()); payload.extend_from_slice(&crypto_pair.username.clone().as_bytes());
let hello_handshake = construct_message(1, payload, id, crypto_pair); let hello_handshake = construct_message(1, payload, id, crypto_pair);
if is_server_handshake { if is_server_handshake.0 {
sd.add_message(id, EventType::Hello); sd.add_message(id, EventType::Hello);
} else { } else {
sd.add_message(id, EventType::HelloThenRootRequest); sd.add_message(id, EventType::HelloThenRootRequest);
@@ -80,69 +104,10 @@ pub async fn perform_handshake(
match hello_handshake { match hello_handshake {
Some(handshake_message) => { Some(handshake_message) => {
senders.send_dispatch( senders.send_dispatch(handshake_message, address, is_server_handshake.0);
handshake_message,
sockaddr_bytes.to_string(),
is_server_handshake,
sd.messages_list(),
);
} }
None => {} None => {}
} }
}
None => {
let err_msg = format!("failed to retreive socket address:").to_string();
let res = event_tx.send(NetworkEvent::Error(err_msg));
}
}
/*let mut list = messages_list.lock().expect("Failed to lock messages_list"); return true;
match list.get(&id) {
Some(_) => {
list.remove(&id);
}
None => {
list.insert(id, EventType::ServerHelloReply);
}
}
println!("message sent: {}", &id);*/
// 3. Perform the insertion
/*let mut buf = [0u8; 1024];
socket.recv_from(&mut buf).expect("receive failed");
let hello_handshake_received = UDPMessage::parse(buf.to_vec());
hello_handshake_received.display();*/
//TODO
}
#[cfg(test)]
mod tests {
/*///
/// does the procedure to register with the server
///
#[tokio::test]
async fn registering_with_server() {
let username = String::from("gameixtreize");
let server_uri = String::from("https://jch.irif.fr:8443");
let crypto_pair = CryptographicSignature::new(username);
if let Err(e) = register_with_the_server(crypto_pair, server_uri).await {
eprintln!("Error during registration: {}", e);
}
}*/
/*///
/// retreives the socket address of a given peer
///
#[tokio::test]
async fn retreive_socket_addr() {
let username = String::from("ipjkndqfshjldfsjlbsdfjhhj");
match get_socket_address(username).await {
Ok(body) => {
println!("{:?}", body);
}
Err(e) => {
eprintln!("Erreur HTTP: {}", e);
}
}
}*/
} }

View File

@@ -4,25 +4,16 @@ use std::sync::{
}; };
use std::thread::JoinHandle; use std::thread::JoinHandle;
pub enum WorkerType {
MSGRECEPTION,
MSGSENDER,
PING,
MSGRETRY,
}
pub struct Worker { pub struct Worker {
thread: Option<JoinHandle<()>>, thread: Option<JoinHandle<()>>,
stop: Arc<AtomicBool>, stop: Arc<AtomicBool>,
workertype: WorkerType,
} }
impl Worker { impl Worker {
pub fn spawn(thread: JoinHandle<()>, workertype: WorkerType) -> Self { pub fn spawn(thread: JoinHandle<()>) -> Self {
Worker { Worker {
stop: Arc::new(AtomicBool::new(false)), stop: Arc::new(AtomicBool::new(false)),
thread: Some(thread), thread: Some(thread),
workertype,
} }
} }

1
rapport.txt Normal file
View File

@@ -0,0 +1 @@
https://docs.google.com/document/d/1emhrAfjJyJTWpBYx4IJGcCz0_iLVjDRAAdq2EZFchKo/edit?usp=sharing