2021-07-12 19:55:23 +01:00
|
|
|
use std::{collections::HashSet, net::SocketAddr};
|
2021-07-03 15:22:17 +01:00
|
|
|
|
2021-07-03 19:10:59 +01:00
|
|
|
use buffers::ByteString;
|
2021-07-12 19:55:23 +01:00
|
|
|
use futures::{stream::FuturesUnordered, StreamExt};
|
2021-07-03 19:10:59 +01:00
|
|
|
use librqbit_core::torrent_metainfo::TorrentMetaV1Info;
|
2021-07-03 15:52:39 +01:00
|
|
|
use log::debug;
|
2021-07-03 15:22:17 +01:00
|
|
|
|
2021-07-03 19:10:59 +01:00
|
|
|
use crate::peer_info_reader;
|
2021-07-03 15:22:17 +01:00
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2021-07-12 19:55:23 +01:00
|
|
|
pub enum ReadMetainfoResult<Rx> {
|
2021-07-03 15:22:17 +01:00
|
|
|
Found {
|
|
|
|
|
info: TorrentMetaV1Info<ByteString>,
|
2021-07-12 19:55:23 +01:00
|
|
|
rx: Rx,
|
|
|
|
|
seen: HashSet<SocketAddr>,
|
2021-07-03 15:22:17 +01:00
|
|
|
},
|
|
|
|
|
ChannelClosed {
|
2021-07-12 19:55:23 +01:00
|
|
|
seen: HashSet<SocketAddr>,
|
2021-07-03 15:22:17 +01:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 19:55:23 +01:00
|
|
|
pub async fn read_metainfo_from_peer_receiver<A: StreamExt<Item = SocketAddr> + Unpin>(
|
2021-07-03 15:22:17 +01:00
|
|
|
peer_id: [u8; 20],
|
|
|
|
|
info_hash: [u8; 20],
|
2021-07-12 19:55:23 +01:00
|
|
|
mut addrs: A,
|
|
|
|
|
) -> ReadMetainfoResult<A> {
|
|
|
|
|
let mut seen = HashSet::<SocketAddr>::new();
|
2021-07-12 19:42:48 +01:00
|
|
|
let first_addr = match addrs.next().await {
|
2021-07-03 15:22:17 +01:00
|
|
|
Some(addr) => addr,
|
|
|
|
|
None => return ReadMetainfoResult::ChannelClosed { seen },
|
|
|
|
|
};
|
2021-07-12 19:55:23 +01:00
|
|
|
seen.insert(first_addr);
|
2021-07-03 15:22:17 +01:00
|
|
|
|
|
|
|
|
let mut unordered = FuturesUnordered::new();
|
|
|
|
|
unordered.push(peer_info_reader::read_metainfo_from_peer(
|
|
|
|
|
first_addr, peer_id, info_hash,
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
tokio::select! {
|
2021-07-12 19:42:48 +01:00
|
|
|
next_addr = addrs.next() => {
|
2021-07-03 15:22:17 +01:00
|
|
|
match next_addr {
|
|
|
|
|
Some(addr) => {
|
2021-07-12 19:55:23 +01:00
|
|
|
if seen.insert(addr) {
|
|
|
|
|
unordered.push(peer_info_reader::read_metainfo_from_peer(addr, peer_id, info_hash));
|
|
|
|
|
}
|
2021-07-03 15:22:17 +01:00
|
|
|
},
|
|
|
|
|
None => return ReadMetainfoResult::ChannelClosed { seen },
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
done = unordered.next(), if !unordered.is_empty() => {
|
|
|
|
|
match done {
|
|
|
|
|
Some(Ok(info)) => return ReadMetainfoResult::Found { info, seen, rx: addrs },
|
|
|
|
|
Some(Err(e)) => {
|
2021-07-03 15:52:39 +01:00
|
|
|
debug!("error in peer_info_reader::read_metainfo_from_peer: {}", e);
|
2021-07-03 15:22:17 +01:00
|
|
|
},
|
|
|
|
|
None => unreachable!()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
2021-07-03 19:10:59 +01:00
|
|
|
use librqbit_core::{info_hash::decode_info_hash, peer_id::generate_peer_id};
|
2021-07-12 19:55:23 +01:00
|
|
|
use tokio_stream::wrappers::UnboundedReceiverStream;
|
2021-07-03 19:10:59 +01:00
|
|
|
|
|
|
|
|
use crate::dht::jsdht::JsDht;
|
|
|
|
|
|
2021-07-03 15:22:17 +01:00
|
|
|
use super::*;
|
|
|
|
|
use std::sync::Once;
|
|
|
|
|
|
|
|
|
|
static LOG_INIT: Once = Once::new();
|
|
|
|
|
|
|
|
|
|
fn init_logging() {
|
|
|
|
|
LOG_INIT.call_once(pretty_env_logger::init)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn read_metainfo_from_dht() {
|
|
|
|
|
init_logging();
|
|
|
|
|
|
|
|
|
|
let info_hash = decode_info_hash("9905f844e5d8787ecd5e08fb46b2eb0a42c131d7").unwrap();
|
|
|
|
|
let peer_rx = JsDht::new(info_hash).start_peer_discovery().unwrap();
|
|
|
|
|
let peer_id = generate_peer_id();
|
2021-07-12 19:55:23 +01:00
|
|
|
dbg!(
|
|
|
|
|
read_metainfo_from_peer_receiver(
|
|
|
|
|
peer_id,
|
|
|
|
|
info_hash,
|
|
|
|
|
UnboundedReceiverStream::new(peer_rx)
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
);
|
2021-07-03 15:22:17 +01:00
|
|
|
}
|
|
|
|
|
}
|