use std::net::SocketAddr;
use std::time::{Duration, Instant};
use std::cmp::Ordering;
use toxcore::crypto_core::*;
use toxcore::dht::packed_node::*;
use toxcore::dht::kbucket::*;
use toxcore::dht::server::*;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum NodeStatus {
Good,
Bad,
}
pub trait ReplaceOrder {
fn replace_order(&self, &DhtNode, &DhtNode, Duration) -> Ordering;
}
impl ReplaceOrder for PublicKey {
fn replace_order(&self,
node1: &DhtNode,
node2: &DhtNode,
bad_node_timeout: Duration) -> Ordering {
trace!(target: "Distance", "Comparing distance between PKs. and status of node");
match node1.calc_status(bad_node_timeout) {
NodeStatus::Good => {
match node2.calc_status(bad_node_timeout) {
NodeStatus::Good => { self.distance(&node1.pk, &node2.pk)
},
NodeStatus::Bad => { Ordering::Less },
}
},
NodeStatus::Bad => {
match node2.calc_status(bad_node_timeout) {
NodeStatus::Good => { Ordering::Greater },
NodeStatus::Bad => { self.distance(&node1.pk, &node2.pk)
},
}
},
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DhtNode {
pub saddr: SocketAddr,
pub pk: PublicKey,
pub last_resp_time: Instant,
}
impl DhtNode {
pub fn new(pn: PackedNode) -> DhtNode {
DhtNode {
pk: pn.pk,
saddr: pn.saddr,
last_resp_time: Instant::now(),
}
}
pub fn calc_status(&self, bad_node_timeout: Duration) -> NodeStatus {
if self.last_resp_time.elapsed() > bad_node_timeout {
NodeStatus::Bad
} else {
NodeStatus::Good
}
}
pub fn is_bad_node_timed_out(&self, server: &Server) -> bool {
self.last_resp_time.elapsed() > Duration::from_secs(server.config.bad_node_timeout)
}
}
#[cfg(test)]
mod tests {
use super::*;
use quickcheck::quickcheck;
#[test]
fn dht_node_clonable() {
let pn = PackedNode {
pk: gen_keypair().0,
saddr: "127.0.0.1:33445".parse().unwrap(),
};
let dht_node = DhtNode::new(pn);
let _ = dht_node.clone();
}
#[test]
fn dht_node_bucket_try_add_test() {
fn with_nodes(n1: PackedNode, n2: PackedNode, n3: PackedNode,
n4: PackedNode, n5: PackedNode, n6: PackedNode,
n7: PackedNode, n8: PackedNode) {
let pk = PublicKey([0; PUBLICKEYBYTES]);
let mut bucket = Bucket::new(None);
assert_eq!(true, bucket.try_add(&pk, &n1));
assert_eq!(true, bucket.try_add(&pk, &n2));
assert_eq!(true, bucket.try_add(&pk, &n3));
assert_eq!(true, bucket.try_add(&pk, &n4));
assert_eq!(true, bucket.try_add(&pk, &n5));
bucket.set_bad_node_timeout(0);
assert_eq!(true, bucket.try_add(&pk, &n6));
assert_eq!(true, bucket.try_add(&pk, &n7));
assert_eq!(true, bucket.try_add(&pk, &n8));
assert_eq!(true, bucket.try_add(&pk, &n1));
}
quickcheck(with_nodes as fn(PackedNode, PackedNode, PackedNode, PackedNode,
PackedNode, PackedNode, PackedNode, PackedNode));
}
}