const MAX_RELAY : usize = 100;
pub struct RelayMap {
relay_map: ::std::collections::BTreeMap<::routing_core::ConnectionName, ::peer::Peer>,
lookup_map: ::std::collections::HashMap<::crust::Connection, ::routing_core::ConnectionName>,
}
#[allow(unused)]
impl RelayMap {
pub fn new() -> RelayMap {
RelayMap {
relay_map: ::std::collections::BTreeMap::new(),
lookup_map: ::std::collections::HashMap::new()
}
}
pub fn add_peer(&mut self,
identity: ::routing_core::ConnectionName,
connection: ::crust::Connection,
public_id: Option<::public_id::PublicId>)
-> bool {
match identity {
::routing_core::ConnectionName::Routing(_) => return false,
_ => {}
};
if !self.relay_map.contains_key(&identity) && self.relay_map.len() >= MAX_RELAY {
error!("REJECTED because of MAX_RELAY");
return false;
}
if self.lookup_map.contains_key(&connection) {
return false;
}
if self.relay_map.contains_key(&identity) {
return false;
}
let _ = self.lookup_map.entry(connection.clone()).or_insert(identity.clone());
let new_peer = || ::peer::Peer::new(identity.clone(), connection, public_id);
let _ = self.relay_map.entry(identity.clone()).or_insert_with(new_peer);
true
}
pub fn drop_connection(&mut self, connection_to_drop: &::crust::Connection) -> Option<::peer::Peer> {
match self.lookup_map.remove(connection_to_drop) {
Some(identity) => self.relay_map.remove(&identity),
None => None,
}
}
pub fn drop_connection_name(&mut self, connection_name: &::routing_core::ConnectionName)
-> Option<::peer::Peer> {
match self.relay_map.remove(connection_name) {
Some(peer) => {
let _ = self.lookup_map.remove(peer.connection());
Some(peer)
}
None => None,
}
}
#[allow(dead_code)]
pub fn contains_identity(&self, identity: &::routing_core::ConnectionName) -> bool {
self.relay_map.contains_key(identity)
}
#[allow(dead_code)]
pub fn contains_connection(&self, connection: &::crust::Connection) -> bool {
self.lookup_map.contains_key(connection)
}
pub fn lookup_connection(&self, connection: &::crust::Connection) -> Option<&::peer::Peer> {
match self.lookup_map.get(connection) {
Some(identity) => self.relay_map.get(&identity),
None => None,
}
}
pub fn lookup_name(&self, name: &::NameType) -> Option<::routing_core::ConnectionName> {
let relay_name = match self.relay_map.get(
&::routing_core::ConnectionName::Relay(::types::Address::Node(name.clone()))) {
Some(peer) => Some(peer.identity().clone()),
None => None,
};
match relay_name {
None => match self.relay_map.get(
&::routing_core::ConnectionName::Bootstrap(name.clone())) {
Some(peer) => Some(peer.identity().clone()),
None => None,
},
Some(found_name) => Some(found_name),
}
}
pub fn lookup_connection_name(&self, identity: &::routing_core::ConnectionName)
-> Option<&::peer::Peer> {
self.relay_map.get(identity)
}
pub fn is_full(&self) -> bool {
self.relay_map.len() >= MAX_RELAY
}
pub fn bootstrap_connections(&self) -> Vec<::peer::Peer> {
let mut bootstrap_connections : Vec<::peer::Peer> = Vec::new();
for (_, peer) in self.relay_map.iter()
.filter(|ref entry| match *entry.1.identity() {
::routing_core::ConnectionName::Bootstrap(_) => true, _ => false }) {
bootstrap_connections.push(peer.clone());
}
bootstrap_connections
}
pub fn has_bootstrap_connections(&self) -> bool {
for _ in self.relay_map.iter()
.filter(|ref entry| match *entry.1.identity() {
::routing_core::ConnectionName::Bootstrap(_) => true, _ => false }) {
return true;
}
false
}
}
#[cfg(test)]
mod test {
use test_utils::test;
#[test]
fn add_max_peers() {
let mut relay_map = super::RelayMap::new();
for i in 0..super::MAX_RELAY {
let id = ::id::Id::new();
let public_id = ::public_id::PublicId::new(&id);
let identity = ::routing_core::ConnectionName::Relay(
::types::Address::Client(public_id.signing_public_key()));
let connection = test::random_connection();
assert!(relay_map.add_peer(identity.clone(), connection.clone(),
Some(public_id.clone())));
assert!(relay_map.contains_identity(&identity));
assert!(relay_map.contains_connection(&connection));
assert!(relay_map.lookup_connection_name(&identity).is_some());
assert!(relay_map.lookup_connection(&connection).is_some());
let peer = ::peer::Peer::new(identity.clone(), connection.clone(), Some(public_id));
let relay_peer = relay_map.lookup_connection_name(&identity).unwrap();
assert_eq!(peer.identity(), relay_peer.identity());
assert_eq!(peer.connection(), relay_peer.connection());
assert_eq!(peer.public_id(), relay_peer.public_id());
let relay_peer = relay_map.lookup_connection(&connection).unwrap();
assert_eq!(peer.identity(), relay_peer.identity());
assert_eq!(peer.connection(), relay_peer.connection());
assert_eq!(peer.public_id(), relay_peer.public_id());
assert!(!relay_map.has_bootstrap_connections());
if i != super::MAX_RELAY-1 {
assert!(!relay_map.is_full());
} else {
assert!(relay_map.is_full());
}
}
let id = ::id::Id::new();
let public_id = ::public_id::PublicId::new(&id);
let identity = ::routing_core::ConnectionName::Relay(
::types::Address::Client(public_id.signing_public_key()));
let connection = test::random_connection();
assert!(!relay_map.add_peer(identity.clone(), connection.clone(), Some(public_id)));
assert!(!relay_map.contains_identity(&identity));
assert!(!relay_map.contains_connection(&connection));
assert!(relay_map.lookup_connection_name(&identity).is_none());
assert!(relay_map.lookup_connection(&connection).is_none());
assert!(!relay_map.has_bootstrap_connections());
assert!(relay_map.is_full());
}
#[test]
fn drop_connection() {
let mut relay_map = super::RelayMap::new();
let public_id = ::public_id::PublicId::new(&::id::Id::new());
let identity = ::routing_core::ConnectionName::Relay(
::types::Address::Client(public_id.signing_public_key()));
let connection = test::random_connection();
assert!(relay_map.add_peer(identity.clone(), connection.clone(), Some(public_id)));
assert!(relay_map.contains_identity(&identity));
assert!(relay_map.contains_connection(&connection));
let _ = relay_map.drop_connection(&connection);
assert!(!relay_map.contains_identity(&identity));
assert!(!relay_map.contains_connection(&connection));
}
#[test]
fn drop_connection_name() {
let mut relay_map = super::RelayMap::new();
let public_id = ::public_id::PublicId::new(&::id::Id::new());
let identity = ::routing_core::ConnectionName::Relay(
::types::Address::Client(public_id.signing_public_key()));
let endpoint = test::random_connection();
assert!(relay_map.add_peer(identity.clone(), endpoint.clone(), Some(public_id)));
assert!(relay_map.contains_identity(&identity));
assert!(relay_map.contains_connection(&endpoint));
let _ = relay_map.drop_connection_name(&identity);
assert!(!relay_map.contains_identity(&identity));
assert!(!relay_map.contains_connection(&endpoint));
}
#[test]
fn add_conflicting_identity() {
let mut relay_map = super::RelayMap::new();
let public_id = ::public_id::PublicId::new(&::id::Id::new());
let identity = ::routing_core::ConnectionName::Relay(
::types::Address::Client(public_id.signing_public_key()));
let endpoint = test::random_connection();
let conflicting_public_id = ::public_id::PublicId::new(&::id::Id::new());
let conflicting_identity = ::routing_core::ConnectionName::Relay(
::types::Address::Client(conflicting_public_id.signing_public_key()));
assert!(relay_map.add_peer(identity.clone(), endpoint.clone(), Some(public_id)));
assert!(relay_map.contains_identity(&identity));
assert!(relay_map.contains_connection(&endpoint));
assert!(!relay_map.add_peer(
conflicting_identity.clone(), endpoint.clone(), Some(conflicting_public_id)));
assert!(!relay_map.contains_identity(&conflicting_identity));
assert!(relay_map.contains_connection(&endpoint));
}
#[test]
fn check_bootstrap_connections() {
let mut relay_map = super::RelayMap::new();
let public_id = ::public_id::PublicId::new(&::id::Id::new());
let identity = ::routing_core::ConnectionName::Relay(
::types::Address::Client(public_id.signing_public_key()));
let connection = test::random_connection();
assert!(relay_map.add_peer(identity.clone(), connection.clone(), Some(public_id)));
assert!(relay_map.contains_identity(&identity));
assert!(relay_map.contains_connection(&connection));
let name: ::NameType = ::test_utils::Random::generate_random();
let bootstrap_identity = ::routing_core::ConnectionName::Bootstrap(name.clone());
let bootstrap_endpoint = test::random_connection();
assert!(relay_map.add_peer(bootstrap_identity.clone(), bootstrap_endpoint.clone(), None));
assert!(relay_map.contains_identity(&bootstrap_identity));
assert!(relay_map.contains_connection(&bootstrap_endpoint));
let connection = test::random_connection();
let identity = ::routing_core::ConnectionName::Unidentified(connection.clone(), false);
assert!(relay_map.add_peer(identity.clone(), connection.clone(), None));
assert!(relay_map.contains_identity(&identity));
assert!(relay_map.contains_connection(&connection));
assert!(relay_map.lookup_name(&name).is_some());
let identity = relay_map.lookup_name(&name).unwrap();
assert_eq!(identity, ::routing_core::ConnectionName::Bootstrap(name.clone()));
assert!(relay_map.has_bootstrap_connections());
let bootstrap_connections = relay_map.bootstrap_connections();
assert_eq!(1, bootstrap_connections.len());
assert_eq!(bootstrap_connections[0].identity(), &bootstrap_identity);
assert_eq!(bootstrap_connections[0].connection(), &bootstrap_endpoint);
assert_eq!(bootstrap_connections[0].public_id(), &None);
}
#[test]
fn add_routing_peer() {
let mut relay_map = super::RelayMap::new();
let name: ::NameType = ::test_utils::Random::generate_random();
let identity = ::routing_core::ConnectionName::Routing(name.clone());
let connection = test::random_connection();
assert!(!relay_map.add_peer(identity.clone(), connection.clone(), None));
assert!(!relay_map.contains_identity(&identity));
assert!(!relay_map.contains_connection(&connection));
}
#[test]
fn lookup_relay_node() {
let mut relay_map = super::RelayMap::new();
let name: ::NameType = ::test_utils::Random::generate_random();
let identity = ::routing_core::ConnectionName::Relay(
::types::Address::Node(name.clone()));
let connection = test::random_connection();
assert!(relay_map.add_peer(identity.clone(), connection.clone(), None));
assert!(relay_map.contains_identity(&identity));
assert!(relay_map.contains_connection(&connection));
assert!(relay_map.lookup_name(&name).is_some());
let relay_identity = relay_map.lookup_name(&name).unwrap();
assert_eq!(identity, relay_identity);
}
}