use crate::address::Address;
use crate::error::{Error, Result};
use crate::identity::NodeId;
use crate::server::Server;
use core::ffi::c_char;
use core::marker::PhantomData;
use core::ptr;
use nwep_sys as sys;
#[derive(Clone, Copy)]
pub struct Bootstrap(sys::nwep_bootstrap_entry);
impl Bootstrap {
pub fn parse(input: &str) -> Result<Bootstrap> {
let mut entry = sys::nwep_bootstrap_entry {
node_id: sys::nwep_node_id {
bytes: [0; sys::NWEP_NODEID_SIZE],
},
addr: sys::nwep_address { opaque: [0; 32] },
};
Error::check(unsafe {
sys::nwep_dht_parse_bootstrap(&mut entry, input.as_ptr().cast::<c_char>(), input.len())
})?;
Ok(Bootstrap(entry))
}
pub fn new(node_id: &NodeId, addr: &Address) -> Bootstrap {
Bootstrap(sys::nwep_bootstrap_entry {
node_id: node_id.raw(),
addr: *addr.as_raw(),
})
}
}
impl core::str::FromStr for Bootstrap {
type Err = Error;
fn from_str(s: &str) -> Result<Bootstrap> {
Bootstrap::parse(s)
}
}
#[derive(Clone, Copy)]
pub struct Record(sys::nwep_dht_record);
impl Record {
pub fn node_id(&self) -> NodeId {
NodeId::from_bytes(self.0.node_id.bytes)
}
pub fn address(&self) -> Address {
Address::from_raw(self.0.addr)
}
pub fn public_key(&self) -> &[u8; sys::NWEP_PUBKEY_SIZE] {
&self.0.pubkey
}
pub fn seq(&self) -> u64 {
self.0.seq
}
pub fn timestamp(&self) -> u64 {
self.0.timestamp
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct DhtMetrics {
pub datagrams_sent: u64,
pub datagrams_received: u64,
pub bytes_sent: u64,
pub bytes_received: u64,
}
pub struct DhtBuilder<'srv> {
server: &'srv Server,
bootstraps: Vec<sys::nwep_bootstrap_entry>,
initial_seq: u64,
}
impl<'srv> DhtBuilder<'srv> {
pub fn bootstrap(mut self, contact: Bootstrap) -> Self {
self.bootstraps.push(contact.0);
self
}
pub fn bootstraps(mut self, contacts: impl IntoIterator<Item = Bootstrap>) -> Self {
self.bootstraps.extend(contacts.into_iter().map(|b| b.0));
self
}
pub fn initial_seq(mut self, seq: u64) -> Self {
self.initial_seq = seq;
self
}
pub fn attach(self) -> Result<Dht<'srv>> {
if self.bootstraps.is_empty() {
return Err(Error::ConfigMissing);
}
let mut raw: *mut sys::nwep_dht = ptr::null_mut();
Error::check(unsafe {
sys::nwep_dht_attach(
&mut raw,
self.server.as_ptr(),
self.bootstraps.as_ptr(),
self.bootstraps.len(),
self.initial_seq,
)
})?;
Ok(Dht {
raw,
_server: PhantomData,
})
}
}
pub struct Dht<'srv> {
raw: *mut sys::nwep_dht,
_server: PhantomData<&'srv Server>,
}
impl<'srv> Dht<'srv> {
pub fn builder(server: &'srv Server) -> DhtBuilder<'srv> {
DhtBuilder {
server,
bootstraps: Vec::new(),
initial_seq: 0,
}
}
pub fn join(&self, now_secs: u64) -> Result<()> {
Error::check(unsafe { sys::nwep_dht_bootstrap(self.raw, now_secs) })
}
pub fn announce(&self, service_addr: &Address, now_secs: u64) -> Result<()> {
Error::check(unsafe { sys::nwep_dht_announce(self.raw, service_addr.as_raw(), now_secs) })
}
pub fn start_lookup(&self, target: &NodeId, now_secs: u64) -> Result<()> {
Error::check(unsafe { sys::nwep_dht_start_lookup(self.raw, &target.raw(), now_secs) })
}
pub fn lookup_result(&self, target: &NodeId) -> Option<Record> {
let mut out = sys::nwep_dht_record {
node_id: sys::nwep_node_id {
bytes: [0; sys::NWEP_NODEID_SIZE],
},
addr: sys::nwep_address { opaque: [0; 32] },
pubkey: [0; sys::NWEP_PUBKEY_SIZE],
seq: 0,
timestamp: 0,
};
let rc = unsafe { sys::nwep_dht_lookup_result(self.raw, &target.raw(), &mut out) };
if rc == 0 {
Some(Record(out))
} else {
None
}
}
pub fn tick(&self, now_secs: u64) -> Result<()> {
Error::check(unsafe { sys::nwep_dht_tick(self.raw, now_secs) })
}
pub fn next_timeout(&self, now_secs: u64) -> Option<u32> {
let ms = unsafe { sys::nwep_dht_next_timeout_ms(self.raw, now_secs) };
if ms < 0 {
None
} else {
Some(ms as u32)
}
}
pub fn metrics(&self) -> DhtMetrics {
let mut m = sys::nwep_dht_metrics {
datagrams_sent: 0,
datagrams_received: 0,
bytes_sent: 0,
bytes_received: 0,
};
unsafe { sys::nwep_dht_metrics_get(self.raw, &mut m) };
DhtMetrics {
datagrams_sent: m.datagrams_sent,
datagrams_received: m.datagrams_received,
bytes_sent: m.bytes_sent,
bytes_received: m.bytes_received,
}
}
pub fn as_ptr(&self) -> *mut sys::nwep_dht {
self.raw
}
}
impl Drop for Dht<'_> {
fn drop(&mut self) {
unsafe { sys::nwep_dht_close(self.raw) };
}
}