pub mod store;
pub use store::{Error, Store};
use std::cell::RefCell;
use std::ops::{Deref, DerefMut};
use std::{hash, net};
use cyphernet::addr::HostName;
use localtime::LocalTime;
use nonempty::NonEmpty;
use crate::collections::RandomMap;
use crate::node::{Address, Alias, Penalty, UserAgent};
use crate::prelude::Timestamp;
use crate::{node, profile};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct AddressBook<K: hash::Hash + Eq, V> {
inner: RandomMap<K, V>,
#[serde(skip)]
rng: RefCell<fastrand::Rng>,
}
impl<K: hash::Hash + Eq, V> AddressBook<K, V> {
pub fn new(rng: fastrand::Rng) -> Self {
Self {
inner: RandomMap::with_hasher(rng.clone().into()),
rng: RefCell::new(rng),
}
}
pub fn sample(&self) -> Option<(&K, &V)> {
self.sample_with(|_, _| true)
}
pub fn sample_with(&self, mut predicate: impl FnMut(&K, &V) -> bool) -> Option<(&K, &V)> {
if let Some(pairs) = NonEmpty::from_vec(
self.inner
.iter()
.filter(|(k, v)| predicate(*k, *v))
.collect(),
) {
let ix = self.rng.borrow_mut().usize(..pairs.len());
let pair = pairs[ix];
Some(pair)
} else {
None
}
}
pub fn with(self, rng: fastrand::Rng) -> Self {
Self {
inner: self.inner,
rng: RefCell::new(rng),
}
}
}
impl<K: hash::Hash + Eq + Ord + Copy, V> AddressBook<K, V> {
pub fn shuffled(&self) -> std::vec::IntoIter<(&K, &V)> {
let mut items = self.inner.iter().collect::<Vec<_>>();
items.sort_by_key(|(k, _)| *k);
self.rng.borrow_mut().shuffle(&mut items);
items.into_iter()
}
pub fn into_shuffled(self) -> impl Iterator<Item = (K, V)> {
let mut items = self.inner.into_iter().collect::<Vec<_>>();
items.sort_by_key(|(k, _)| *k);
self.rng.borrow_mut().shuffle(&mut items);
items.into_iter()
}
pub fn cycle(&self) -> impl Iterator<Item = &K> {
self.shuffled().map(|(k, _)| k).cycle()
}
}
impl<K: hash::Hash + Eq, V> FromIterator<(K, V)> for AddressBook<K, V> {
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
let rng = profile::env::rng();
let mut inner = RandomMap::with_hasher(rng.clone().into());
for (k, v) in iter {
inner.insert(k, v);
}
Self {
inner,
rng: RefCell::new(rng),
}
}
}
impl<K: hash::Hash + Eq, V> Deref for AddressBook<K, V> {
type Target = RandomMap<K, V>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<K: hash::Hash + Eq, V> DerefMut for AddressBook<K, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Node {
pub version: u8,
pub alias: Alias,
pub features: node::Features,
pub addrs: Vec<KnownAddress>,
pub pow: u32,
pub timestamp: Timestamp,
pub agent: UserAgent,
pub penalty: Penalty,
pub banned: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct KnownAddress {
pub addr: Address,
pub source: Source,
pub last_success: Option<LocalTime>,
pub last_attempt: Option<LocalTime>,
pub banned: bool,
}
impl KnownAddress {
pub fn new(addr: Address, source: Source) -> Self {
Self {
addr,
source,
last_success: None,
last_attempt: None,
banned: false,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum Source {
Peer,
Bootstrap,
Imported,
}
impl std::fmt::Display for Source {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Peer => write!(f, "Peer"),
Self::Bootstrap => write!(f, "Bootstrap"),
Self::Imported => write!(f, "Imported"),
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AddressType {
Ipv4 = 1,
Ipv6 = 2,
Dns = 3,
Onion = 4,
}
impl From<AddressType> for u8 {
fn from(other: AddressType) -> Self {
other as u8
}
}
impl From<&Address> for AddressType {
fn from(a: &Address) -> Self {
match a.host {
HostName::Ip(net::IpAddr::V4(_)) => AddressType::Ipv4,
HostName::Ip(net::IpAddr::V6(_)) => AddressType::Ipv6,
HostName::Dns(_) => AddressType::Dns,
HostName::Tor(_) => AddressType::Onion,
_ => todo!(), }
}
}
impl TryFrom<u8> for AddressType {
type Error = u8;
fn try_from(other: u8) -> Result<Self, Self::Error> {
match other {
1 => Ok(AddressType::Ipv4),
2 => Ok(AddressType::Ipv6),
3 => Ok(AddressType::Dns),
4 => Ok(AddressType::Onion),
_ => Err(other),
}
}
}
pub fn is_routable(addr: &net::IpAddr) -> bool {
match addr {
net::IpAddr::V4(addr) => ipv4_is_routable(addr),
net::IpAddr::V6(addr) => ipv6_is_routable(addr),
}
}
pub fn is_local(addr: &net::IpAddr) -> bool {
match addr {
net::IpAddr::V4(addr) => {
addr.is_private() || addr.is_loopback() || addr.is_link_local() || addr.is_unspecified()
}
net::IpAddr::V6(addr) => {
addr.is_loopback() || addr.is_unicast_link_local() || addr.is_unspecified()
}
}
}
fn ipv4_is_routable(addr: &net::Ipv4Addr) -> bool {
if *addr == net::Ipv4Addr::new(192, 0, 0, 9) {
return true;
}
if *addr == net::Ipv4Addr::new(192, 0, 0, 10) {
return true;
}
if addr.octets()[0] == 0 {
return false;
}
!addr.is_private()
&& !addr.is_loopback()
&& !addr.is_link_local()
&& !addr.is_broadcast()
&& !addr.is_documentation()
}
fn ipv6_is_routable(addr: &net::Ipv6Addr) -> bool {
!addr.is_loopback() && !addr.is_unicast_link_local() && !addr.is_unspecified()
}