use crate::{DhtClient, DhtConfig, NameResolver, NameSystem};
use anyhow::Result;
use async_trait::async_trait;
use libp2p::Multiaddr;
use noosphere_core::{
authority::generate_ed25519_key,
data::{Did, LinkRecord},
};
use std::collections::HashMap;
use tokio::sync::Mutex;
use ucan::store::UcanJwtStore;
pub struct NameSystemNetwork {
nodes: Vec<NameSystem>,
address: Multiaddr,
}
impl NameSystemNetwork {
pub fn nodes(&self) -> &Vec<NameSystem> {
&self.nodes
}
pub fn nodes_mut(&mut self) -> &mut Vec<NameSystem> {
&mut self.nodes
}
pub fn get(&self, index: usize) -> Option<&NameSystem> {
self.nodes.get(index)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut NameSystem> {
self.nodes.get_mut(index)
}
pub fn address(&self) -> &Multiaddr {
&self.address
}
pub async fn generate<S: UcanJwtStore + Clone + 'static>(
node_count: usize,
store: Option<S>,
) -> Result<Self> {
let mut bootstrap_address: Option<Multiaddr> = None;
let mut nodes = vec![];
for _ in 0..node_count {
let key = generate_ed25519_key();
let node = NameSystem::new(&key, DhtConfig::default(), store.clone())?;
let address = node.listen("/ip4/127.0.0.1/tcp/0".parse()?).await?;
if let Some(address) = bootstrap_address.as_ref() {
node.add_peers(vec![address.to_owned()]).await?;
} else {
bootstrap_address = Some(address);
}
nodes.push(node);
}
Ok(NameSystemNetwork {
nodes,
address: bootstrap_address.unwrap(),
})
}
}
pub struct KeyValueNameResolver {
store: Mutex<HashMap<Did, LinkRecord>>,
}
impl KeyValueNameResolver {
pub fn new() -> Self {
KeyValueNameResolver {
store: Mutex::new(HashMap::new()),
}
}
}
impl Default for KeyValueNameResolver {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl NameResolver for KeyValueNameResolver {
async fn publish(&self, record: LinkRecord) -> Result<()> {
let mut store = self.store.lock().await;
let did_id = Did(record.to_sphere_identity().into());
store.insert(did_id, record);
Ok(())
}
async fn resolve(&self, identity: &Did) -> Result<Option<LinkRecord>> {
let store = self.store.lock().await;
Ok(store.get(identity).map(|record| record.to_owned()))
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::name_resolver_tests;
async fn before_name_resolver_tests() -> Result<KeyValueNameResolver> {
Ok(KeyValueNameResolver::new())
}
name_resolver_tests!(KeyValueNameResolver, before_name_resolver_tests);
}