|
|
@@ -32,7 +32,7 @@ use log::{debug, warn};
|
|
|
use crate::{net::P2pPtr, Result};
|
|
|
|
|
|
/// Networked HashMap
|
|
|
-mod net_hashmap;
|
|
|
+pub mod net_hashmap;
|
|
|
use net_hashmap::NetHashMap;
|
|
|
|
|
|
/// Maximum size of a stored chunk (2 MiB)
|
|
|
@@ -388,130 +388,9 @@ impl Dht {
|
|
|
|
|
|
#[cfg(test)]
|
|
|
mod tests {
|
|
|
- use super::{
|
|
|
- net_hashmap::{NetHashMapInsert, NetHashMapRemove},
|
|
|
- *,
|
|
|
- };
|
|
|
- use crate::{
|
|
|
- net,
|
|
|
- net::{
|
|
|
- transport::TransportName, ChannelPtr, MessageSubscription, P2p, ProtocolBase,
|
|
|
- ProtocolBasePtr, ProtocolJobsManager,
|
|
|
- },
|
|
|
- util::async_util::sleep,
|
|
|
- };
|
|
|
- use async_std::{net::TcpListener, sync::Arc};
|
|
|
- use async_trait::async_trait;
|
|
|
- use log::error;
|
|
|
+ use super::*;
|
|
|
+ use crate::{net, net::P2p};
|
|
|
use rand::{rngs::OsRng, RngCore};
|
|
|
- use smol::Executor;
|
|
|
- use url::Url;
|
|
|
-
|
|
|
- async fn create_p2p_net(n_peers: usize) -> Result<Vec<P2pPtr>> {
|
|
|
- let mut ret = vec![];
|
|
|
- let mut addrs = vec![];
|
|
|
-
|
|
|
- for i in 0..n_peers {
|
|
|
- // Find an available port
|
|
|
- let listener = TcpListener::bind("127.0.0.1:0").await?;
|
|
|
- let sockaddr = listener.local_addr()?;
|
|
|
- let url = Url::parse(&format!("tcp://127.0.0.1:{}", sockaddr.port()))?;
|
|
|
- drop(listener);
|
|
|
-
|
|
|
- let mut settings = net::Settings::default();
|
|
|
- settings.inbound = vec![url.clone()];
|
|
|
- settings.peers = addrs.clone();
|
|
|
- settings.outbound_transports = vec![TransportName::try_from("tcp").unwrap()];
|
|
|
- settings.localnet = true;
|
|
|
- settings.channel_log = true;
|
|
|
-
|
|
|
- addrs.push(url);
|
|
|
-
|
|
|
- let p2p = P2p::new(settings).await;
|
|
|
- let registry = p2p.protocol_registry();
|
|
|
- registry
|
|
|
- .register(net::SESSION_ALL, move |channel, p2p| async move {
|
|
|
- ProtoDht::init(i, channel, p2p).await.unwrap()
|
|
|
- })
|
|
|
- .await;
|
|
|
-
|
|
|
- ret.push(p2p);
|
|
|
- }
|
|
|
-
|
|
|
- Ok(ret)
|
|
|
- }
|
|
|
-
|
|
|
- struct ProtoDht {
|
|
|
- jobsman: net::ProtocolJobsManagerPtr,
|
|
|
- node_id: usize,
|
|
|
- _channel: ChannelPtr,
|
|
|
- _p2p: P2pPtr,
|
|
|
- insert_sub: MessageSubscription<NetHashMapInsert<blake3::Hash, Vec<blake3::Hash>>>,
|
|
|
- remove_sub: MessageSubscription<NetHashMapRemove<blake3::Hash>>,
|
|
|
- }
|
|
|
-
|
|
|
- impl ProtoDht {
|
|
|
- pub async fn init(
|
|
|
- node_id: usize,
|
|
|
- channel: ChannelPtr,
|
|
|
- p2p: P2pPtr,
|
|
|
- ) -> Result<ProtocolBasePtr> {
|
|
|
- let msg_subsystem = channel.get_message_subsystem();
|
|
|
- msg_subsystem.add_dispatch::<NetHashMapInsert<blake3::Hash, Vec<blake3::Hash>>>().await;
|
|
|
- msg_subsystem.add_dispatch::<NetHashMapRemove<blake3::Hash>>().await;
|
|
|
-
|
|
|
- let insert_sub = channel.subscribe_msg().await?;
|
|
|
- let remove_sub = channel.subscribe_msg().await?;
|
|
|
-
|
|
|
- Ok(Arc::new(Self {
|
|
|
- jobsman: ProtocolJobsManager::new("DHTProto", channel.clone()),
|
|
|
- node_id,
|
|
|
- _channel: channel,
|
|
|
- _p2p: p2p,
|
|
|
- insert_sub,
|
|
|
- remove_sub,
|
|
|
- }))
|
|
|
- }
|
|
|
-
|
|
|
- async fn handle_insert(self: Arc<Self>) -> Result<()> {
|
|
|
- debug!("[Node {}] ProtoDht::handle_insert START", self.node_id);
|
|
|
- loop {
|
|
|
- let insert_message = match self.insert_sub.receive().await {
|
|
|
- Ok(v) => v,
|
|
|
- Err(_) => continue,
|
|
|
- };
|
|
|
-
|
|
|
- println!("[Node {}] {:?}", self.node_id, insert_message);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- async fn handle_remove(self: Arc<Self>) -> Result<()> {
|
|
|
- debug!("[Node {}] ProtoDht::handle_remove START", self.node_id);
|
|
|
- loop {
|
|
|
- let remove_message = match self.remove_sub.receive().await {
|
|
|
- Ok(v) => v,
|
|
|
- Err(_) => continue,
|
|
|
- };
|
|
|
-
|
|
|
- println!("[Node {}] {:?}", self.node_id, remove_message);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- #[async_trait]
|
|
|
- impl ProtocolBase for ProtoDht {
|
|
|
- async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
|
|
|
- debug!("ProtoDht::start()");
|
|
|
- self.jobsman.clone().start(executor.clone());
|
|
|
- self.jobsman.clone().spawn(self.clone().handle_insert(), executor.clone()).await;
|
|
|
- self.jobsman.clone().spawn(self.clone().handle_remove(), executor.clone()).await;
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- fn name(&self) -> &'static str {
|
|
|
- "ProtoDHT"
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
#[async_std::test]
|
|
|
async fn dht_local_get_insert() -> Result<()> {
|
|
|
@@ -559,82 +438,4 @@ mod tests {
|
|
|
fs::remove_dir_all(base_path).await?;
|
|
|
Ok(())
|
|
|
}
|
|
|
-
|
|
|
- async fn dht_remote_get_insert_real(executor: Arc<Executor<'_>>) -> Result<()> {
|
|
|
- const NET_SIZE: usize = 5;
|
|
|
-
|
|
|
- let peers = create_p2p_net(NET_SIZE).await?;
|
|
|
-
|
|
|
- for p2p in &peers {
|
|
|
- p2p.clone().start(executor.clone()).await?;
|
|
|
-
|
|
|
- let _p2p = p2p.clone();
|
|
|
- let _ex = executor.clone();
|
|
|
- executor
|
|
|
- .spawn(async move {
|
|
|
- if let Err(e) = _p2p.run(_ex).await {
|
|
|
- error!("Failed starting P2P network: {}", e);
|
|
|
- assert!(false);
|
|
|
- }
|
|
|
- })
|
|
|
- .detach();
|
|
|
-
|
|
|
- p2p.clone().wait_for_outbound(executor.clone()).await?;
|
|
|
- }
|
|
|
- sleep(2).await;
|
|
|
-
|
|
|
- let mut dhts = vec![];
|
|
|
- let mut base_path = std::env::temp_dir();
|
|
|
- base_path.push("dht");
|
|
|
-
|
|
|
- for i in 0..NET_SIZE {
|
|
|
- let mut node_path = base_path.clone();
|
|
|
- node_path.push(format!("node_{}", i));
|
|
|
-
|
|
|
- let mut dht = Dht::new(&node_path.into(), peers[i].clone()).await?;
|
|
|
- dht.garbage_collect().await?;
|
|
|
- dhts.push(dht);
|
|
|
- }
|
|
|
-
|
|
|
- let dht = &mut dhts[2];
|
|
|
-
|
|
|
- let rng = &mut OsRng;
|
|
|
- let mut data = vec![0u8; MAX_CHUNK_SIZE];
|
|
|
- rng.fill_bytes(&mut data);
|
|
|
- let (file_hash, chunk_hashes) = dht.insert(&data).await?;
|
|
|
-
|
|
|
- fs::remove_dir_all(base_path).await?;
|
|
|
-
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn dht_remote_get_insert() -> Result<()> {
|
|
|
- // Logging
|
|
|
- let mut cfg = simplelog::ConfigBuilder::new();
|
|
|
- cfg.add_filter_ignore("net::protocol_version".to_string());
|
|
|
- cfg.add_filter_ignore("net::protocol_ping".to_string());
|
|
|
-
|
|
|
- simplelog::TermLogger::init(
|
|
|
- //simplelog::LevelFilter::Debug,
|
|
|
- simplelog::LevelFilter::Info,
|
|
|
- cfg.build(),
|
|
|
- simplelog::TerminalMode::Mixed,
|
|
|
- simplelog::ColorChoice::Auto,
|
|
|
- )?;
|
|
|
-
|
|
|
- let ex = Arc::new(Executor::new());
|
|
|
- let (signal, shutdown) = async_std::channel::unbounded::<()>();
|
|
|
-
|
|
|
- easy_parallel::Parallel::new()
|
|
|
- .each(0..4, |_| smol::block_on(ex.run(shutdown.recv())))
|
|
|
- .finish(|| {
|
|
|
- smol::block_on(async {
|
|
|
- dht_remote_get_insert_real(ex.clone()).await.unwrap();
|
|
|
- drop(signal);
|
|
|
- })
|
|
|
- });
|
|
|
-
|
|
|
- Ok(())
|
|
|
- }
|
|
|
}
|