rqbit/crates/librqbit/src/dht_utils.rs

150 lines
4.2 KiB
Rust
Raw Normal View History

2024-08-08 00:35:32 +01:00
use std::{collections::HashSet, net::SocketAddr, sync::Arc};
2021-07-13 13:16:59 +01:00
use anyhow::Context;
use buffers::ByteBufOwned;
2021-07-13 16:10:36 +01:00
use futures::{stream::FuturesUnordered, Stream, StreamExt};
2021-07-03 19:10:59 +01:00
use librqbit_core::torrent_metainfo::TorrentMetaV1Info;
2024-05-17 23:57:25 +01:00
use tracing::{debug, error_span, Instrument};
2021-09-29 19:10:32 +01:00
use crate::{
peer_connection::PeerConnectionOptions, peer_info_reader, spawn_utils::BlockingSpawner,
2024-08-08 00:35:32 +01:00
stream_connect::StreamConnector,
2021-09-29 19:10:32 +01:00
};
2023-12-24 16:53:02 -06:00
use librqbit_core::hash_id::Id20;
#[derive(Debug)]
pub enum ReadMetainfoResult<Rx> {
Found {
info: TorrentMetaV1Info<ByteBufOwned>,
info_bytes: ByteBufOwned,
rx: Rx,
seen: HashSet<SocketAddr>,
},
ChannelClosed {
2024-07-27 08:46:33 +02:00
#[allow(dead_code)]
seen: HashSet<SocketAddr>,
},
}
2021-07-13 16:10:36 +01:00
pub async fn read_metainfo_from_peer_receiver<A: Stream<Item = SocketAddr> + Unpin>(
2021-07-12 21:59:08 +01:00
peer_id: Id20,
info_hash: Id20,
initial_addrs: Vec<SocketAddr>,
addrs_stream: A,
2021-07-13 14:59:44 +01:00
peer_connection_options: Option<PeerConnectionOptions>,
2024-08-08 00:35:32 +01:00
connector: Arc<StreamConnector>,
) -> ReadMetainfoResult<A> {
let mut seen = HashSet::<SocketAddr>::new();
let mut addrs = addrs_stream;
2021-07-13 13:16:59 +01:00
let semaphore = tokio::sync::Semaphore::new(128);
let read_info_guarded = |addr| {
let semaphore = &semaphore;
2024-08-08 00:35:32 +01:00
let connector = connector.clone();
2021-07-13 13:16:59 +01:00
async move {
let token = semaphore.acquire().await?;
2021-07-13 14:59:44 +01:00
let ret = peer_info_reader::read_metainfo_from_peer(
addr,
peer_id,
info_hash,
peer_connection_options,
2021-09-29 19:10:32 +01:00
BlockingSpawner::new(true),
2024-08-08 00:35:32 +01:00
connector,
2021-07-13 14:59:44 +01:00
)
2024-05-17 23:57:25 +01:00
.instrument(error_span!("read_metainfo_from_peer", ?addr))
2021-07-13 14:59:44 +01:00
.await
.with_context(|| format!("error reading metainfo from {addr}"));
2021-07-13 13:16:59 +01:00
drop(token);
ret
}
};
let mut unordered = FuturesUnordered::new();
for a in initial_addrs {
seen.insert(a);
unordered.push(read_info_guarded(a));
}
2024-08-14 11:24:19 +01:00
let mut addrs_completed = false;
loop {
2024-08-14 11:24:19 +01:00
if addrs_completed && unordered.is_empty() {
return ReadMetainfoResult::ChannelClosed { seen };
}
tokio::select! {
done = unordered.next(), if !unordered.is_empty() => {
match done {
Some(Ok((info, info_bytes))) => return ReadMetainfoResult::Found { info, info_bytes, seen, rx: addrs },
Some(Err(e)) => {
2021-07-13 13:16:59 +01:00
debug!("{:#}", e);
},
None => unreachable!()
}
}
2024-08-14 11:24:19 +01:00
next_addr = addrs.next(), if !addrs_completed => {
match next_addr {
Some(addr) => {
if seen.insert(addr) {
unordered.push(read_info_guarded(addr));
}
continue;
},
None => {
addrs_completed = true;
},
}
}
};
}
}
#[cfg(test)]
mod tests {
2023-11-28 11:35:28 +00:00
use dht::{DhtBuilder, Id20};
2021-07-12 21:59:08 +01:00
use librqbit_core::peer_id::generate_peer_id;
2021-07-03 19:10:59 +01:00
use super::*;
2024-08-08 00:35:32 +01:00
use std::{
str::FromStr,
sync::{Arc, Once},
};
static LOG_INIT: Once = Once::new();
fn init_logging() {
#[allow(unused_must_use)]
LOG_INIT.call_once(|| {
2023-11-19 12:50:11 +00:00
// pretty_env_logger::try_init();
})
}
#[tokio::test]
2023-12-16 11:15:42 +00:00
#[ignore]
async fn read_metainfo_from_dht() {
init_logging();
2023-12-03 12:14:50 +00:00
let info_hash = Id20::from_str("cab507494d02ebb1178b38f2e9d7be299c86b862").unwrap();
let dht = DhtBuilder::new().await.unwrap();
let peer_rx = dht.get_peers(info_hash, None);
2025-05-24 03:57:23 -04:00
let peer_id = generate_peer_id(b"-xx1234-");
2024-08-08 00:35:32 +01:00
match read_metainfo_from_peer_receiver(
peer_id,
info_hash,
Vec::new(),
peer_rx,
None,
Arc::new(Default::default()),
)
.await
{
2021-07-13 13:16:59 +01:00
ReadMetainfoResult::Found { info, .. } => dbg!(info),
ReadMetainfoResult::ChannelClosed { .. } => todo!("should not have happened"),
2021-07-12 21:59:08 +01:00
};
}
}