use super::super::bencode::Value;
use super::super::transport::{Transport, Udp};
use super::fake::ignores;
use super::*;
use crate::test_support::clock::FakeClock;
use std::cell::Cell;
const HUNG: Duration = Duration::from_mins(1);
struct Steered {
udp: Udp,
moods: Vec<(SocketAddr, Mood)>,
clock: FakeClock,
owed: Cell<usize>,
}
impl Steered {
fn ignored(&self, to: SocketAddr, bytes: &[u8]) -> bool {
let verb = Value::decode(bytes).unwrap();
let verb = verb.get("q").unwrap().as_bytes().unwrap();
self.moods
.iter()
.any(|(at, mood)| *at == to && ignores(*mood, verb))
}
}
impl Transport for Steered {
fn send(&self, to: SocketAddr, bytes: &[u8]) -> io::Result<()> {
self.udp.send(to, bytes)?;
let owed = usize::from(!self.ignored(to, bytes));
self.owed.set(self.owed.get() + owed);
Ok(())
}
fn recv(&self, wait: Duration) -> io::Result<Option<(SocketAddr, Vec<u8>)>> {
if self.owed.get() == 0 {
self.clock.advance(wait);
return Ok(None);
}
let got = self.udp.recv(HUNG)?.expect("an answering node answers");
self.owed.set(self.owed.get() - 1);
Ok(Some(got))
}
}
pub(super) fn steered(
bootstrap: Vec<SocketAddr>,
config: Config,
fakes: &[&FakeNode],
) -> (Dht, FakeClock) {
let clock = FakeClock::new();
let transport = Steered {
udp: Udp::bind("127.0.0.1:0".parse().unwrap()).unwrap(),
moods: fakes.iter().map(|n| (n.addr, n.mood.unwrap())).collect(),
clock: clock.clone(),
owed: Cell::new(0),
};
let mut dht = Dht::new(Box::new(transport), bootstrap, config).unwrap();
dht.clock = clock.arc();
(dht, clock)
}