Add dumb peerstore for feedback

This commit is contained in:
Fredrik
2017-10-13 14:44:02 +01:00
committed by Pierre Krieger
parent 68f573d8ae
commit 56c19b1357
5 changed files with 229 additions and 0 deletions

View File

@@ -5,6 +5,7 @@ members = [
"datastore",
"libp2p-host",
"libp2p-peer",
"libp2p-peerstore",
"libp2p-transport",
"libp2p-tcp-transport",
]

View File

@@ -0,0 +1,9 @@
[package]
name = "libp2p-peerstore"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
error-chain = "0.11"
multiaddr = "0.2"
libp2p-peer = { path = "../libp2p-peer" }

View File

@@ -0,0 +1,6 @@
#[macro_use] extern crate error_chain;
extern crate multiaddr;
extern crate libp2p_peer as peer;
mod memory_peerstore;
mod peerstore;

View File

@@ -0,0 +1,126 @@
use std::collections::{HashMap, HashSet};
use std::collections::hash_map;
use multiaddr::Multiaddr;
use peer::PeerId;
use peerstore::*;
pub struct MemoryPeerstore<T> {
store: HashMap<PeerId, PeerInfo<T>>,
}
impl<T> MemoryPeerstore<T> {
pub fn new() -> MemoryPeerstore<T> {
MemoryPeerstore {
store: HashMap::new(),
}
}
}
impl<T> Peerstore<T> for MemoryPeerstore<T> {
/// Returns a list of peers in this Peerstore
fn peers(&self) -> Vec<&PeerId> {
// this is terrible but I honestly can't think of any other way than to hand off ownership
// through this type of allocation or handing off the entire hashmap and letting people do what they
// want with that
self.store.keys().collect()
}
/// Returns the PeerInfo for a specific peer in this peer store, or None if it doesn't exist.
fn peer_info(&self, peer_id: &PeerId) -> Option<&PeerInfo<T>> {
self.store.get(peer_id)
}
/// Try to get a property for a given peer
fn get_data(&self, peer_id: &PeerId, key: &str) -> Option<&T> {
match self.store.get(peer_id) {
None => None,
Some(peer_info) => peer_info.get_data(key),
}
}
/// Try to set a property for a given peer
fn put_data(&mut self, peer_id: &PeerId, key: String, val: T) -> Result<()> {
match self.store.get_mut(peer_id) {
None => Err(Error::from_kind(ErrorKind::NoSuchPeer((*peer_id).clone()))),
Some(mut peer_info) => {
peer_info.set_data(key, val);
Ok(())
}
}
}
/// Adds an address to a peer
fn add_addr(&mut self, peer_id: &PeerId, addr: Multiaddr, ttl: TTL) {
match self.store.get_mut(peer_id) {
None => (),
Some(peer_info) => peer_info.add_addr(addr),
}
}
// AddAddrs gives AddrManager addresses to use, with a given ttl
// (time-to-live), after which the address is no longer valid.
// If the manager has a longer TTL, the operation is a no-op for that address
fn add_addrs(&mut self, peer_id: &PeerId, addrs: Vec<Multiaddr>, ttl: TTL) {
match self.store.get_mut(peer_id) {
None => (),
Some(peer_info) => {
for addr in addrs {
peer_info.add_addr(addr)
}
},
}
}
// SetAddr calls mgr.SetAddrs(p, addr, ttl)
fn set_addr(&mut self, peer_id: &PeerId, addr: Multiaddr, ttl: TTL) {
self.set_addrs(peer_id, vec![addr], ttl)
}
// SetAddrs sets the ttl on addresses. This clears any TTL there previously.
// This is used when we receive the best estimate of the validity of an address.
fn set_addrs(&mut self, peer_id: &PeerId, addrs: Vec<Multiaddr>, ttl: TTL) {
match self.store.get_mut(peer_id) {
None => (),
Some(peer_info) => peer_info.set_addrs(addrs),
}
}
/// Returns all known (and valid) addresses for a given peer
fn addrs(&self, peer_id: &PeerId) -> &[Multiaddr] {
match self.store.get(peer_id) {
None => &[],
Some(peer_info) => peer_info.get_addrs(),
}
}
/// Removes all previously stored addresses
fn clear_addrs(&mut self, peer_id: &PeerId) {
match self.store.get_mut(peer_id) {
None => (),
Some(peer_info) => peer_info.set_addrs(vec![]),
}
}
/// Get public key for a peer
fn get_pub_key(&self, peer_id: &PeerId) -> Option<&[u8]> {
self.store.get(peer_id).map(|peer_info| peer_info.get_public_key())
}
/// Set public key for a peer
fn set_pub_key(&mut self, peer_id: &PeerId, key: Vec<u8>) {
self.store.get_mut(peer_id).map(|peer_info| peer_info.set_public_key(key));
}
}
#[cfg(test)]
mod tests {
use peer::PeerId;
use super::{Peerstore, MemoryPeerstore};
#[test]
fn insert_get_and_list() {
let peer_id = PeerId::new(vec![1,2,3]);
let mut peer_store: MemoryPeerstore<u8> = MemoryPeerstore::new();
peer_store.put(&peer_id, "test", 123u8);
let got = peer_store.get(&peer_id, "test").expect("should be able to fetch");
assert_eq!(*got, 123u8);
}
}

View File

@@ -0,0 +1,87 @@
use std::time;
use std::collections::{HashMap, HashSet};
use multiaddr::Multiaddr;
use peer::PeerId;
error_chain! {
errors {
NoSuchPeer(p: PeerId) {
description("tried operating on Peerstore with unknown PeerID")
display("invalid PeerId: '{}'", p)
}
}
}
pub type TTL = time::Duration;
pub struct PeerInfo<T> {
public_key: Vec<u8>,
addrs: Vec<Multiaddr>,
data: HashMap<String, T>,
}
impl<T> PeerInfo<T> {
pub fn get_public_key(&self) -> &[u8] {
&self.public_key
}
pub fn set_public_key(&mut self, key: Vec<u8>) {
self.public_key = key;
}
pub fn get_addrs(&self) -> &[Multiaddr] {
&self.addrs
}
pub fn set_addrs(&mut self, addrs: Vec<Multiaddr>) {
self.addrs = addrs;
}
pub fn add_addr(&mut self, addr: Multiaddr) {
self.addrs.push(addr); // TODO: This is stupid, a more advanced thing using TTLs need to be implemented
self.addrs.dedup();
}
pub fn get_data(&self, key: &str) -> Option<&T> {
self.data.get(key)
}
pub fn set_data(&mut self, key: String, val: T) -> Option<T> {
self.data.insert(key, val)
}
}
pub trait Peerstore<T> {
/// Returns a list of peers in this Peerstore
fn peers(&self) -> Vec<&PeerId>;
/// Returns the PeerInfo for a specific peer in this peer store, or None if it doesn't exist.
fn peer_info(&self, peer_id: &PeerId) -> Option<&PeerInfo<T>>;
/// Try to get a property for a given peer
fn get_data(&self, peer_id: &PeerId, key: &str) -> Option<&T>;
/// Try to set a property for a given peer
fn put_data(&mut self, peer_id: &PeerId, key: String, val: T) -> Result<()>;
/// Adds an address to a peer
fn add_addr(&mut self, peer_id: &PeerId, addr: Multiaddr, ttl: TTL);
// AddAddrs gives AddrManager addresses to use, with a given ttl
// (time-to-live), after which the address is no longer valid.
// If the manager has a longer TTL, the operation is a no-op for that address
fn add_addrs(&mut self, peer_id: &PeerId, addrs: Vec<Multiaddr>, ttl: TTL);
// SetAddr calls mgr.SetAddrs(p, addr, ttl)
fn set_addr(&mut self, peer_id: &PeerId, addr: Multiaddr, ttl: TTL);
// SetAddrs sets the ttl on addresses. This clears any TTL there previously.
// This is used when we receive the best estimate of the validity of an address.
fn set_addrs(&mut self, peer_id: &PeerId, addrs: Vec<Multiaddr>, ttl: TTL);
/// Returns all known (and valid) addresses for a given peer
fn addrs(&self, peer_id: &PeerId) -> &[Multiaddr];
/// Removes all previously stored addresses
fn clear_addrs(&mut self, peer_id: &PeerId);
/// Get public key for a peer
fn get_pub_key(&self, peer_id: &PeerId) -> Option<&[u8]>;
/// Set public key for a peer
fn set_pub_key(&mut self, peer_id: &PeerId, key: Vec<u8>);
}