Simplify the implementation of peer_info (#327)

* Simplify the implementation of peer_info
* Add Serde-Support to MultiAddr
This commit is contained in:
Pierre Krieger 2018-08-20 12:04:22 +02:00 committed by Benjamin Kampmann
parent 6c7ae04349
commit 7aa08917ea
5 changed files with 66 additions and 69 deletions

View File

@ -13,6 +13,9 @@ bs58 = "0.2.0"
byteorder = "~0.4"
multihash = { path = "../multihash" }
integer-encoding = "~1.0.3"
serde = "1.0.70"
[dev-dependencies]
data-encoding = "~1.1.2"
serde_json = "1.0"
bincode = "1.0.1"

View File

@ -6,6 +6,7 @@
extern crate bs58;
extern crate byteorder;
extern crate integer_encoding;
extern crate serde;
pub extern crate multihash;
mod protocol;
@ -14,7 +15,10 @@ mod errors;
pub use errors::{Result, Error};
pub use protocol::{Protocol, ProtocolArgSize, AddrComponent};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeserializerError};
use std::fmt;
use std::result::Result as StdResult;
use std::iter::FromIterator;
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
@ -25,6 +29,35 @@ pub struct Multiaddr {
bytes: Vec<u8>,
}
impl Serialize for Multiaddr {
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
// Serialize to a human-readable string "2015-05-15T17:01:00Z".
self.to_string().serialize(serializer)
} else {
self.to_bytes().serialize(serializer)
}
}
}
impl<'de> Deserialize<'de> for Multiaddr {
fn deserialize<D>(deserializer: D) -> StdResult<Self, D::Error>
where
D: Deserializer<'de>,
{
if deserializer.is_human_readable() {
let addr: String = Deserialize::deserialize(deserializer)?;
addr.parse::<Multiaddr>().map_err(|err| DeserializerError::custom(err))
} else {
let addr: Vec<u8> = Deserialize::deserialize(deserializer)?;
Multiaddr::from_bytes(addr).map_err(|err| DeserializerError::custom(err))
}
}
}
impl fmt::Debug for Multiaddr {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

View File

@ -1,5 +1,7 @@
extern crate multiaddr;
extern crate data_encoding;
extern crate serde_json;
extern crate bincode;
use data_encoding::hex;
use multiaddr::*;
@ -173,3 +175,24 @@ fn from_bytes_fail() {
let bytes = vec![1, 2, 3, 4];
assert!(Multiaddr::from_bytes(bytes).is_err());
}
#[test]
fn ser_and_deser_json() {
let addr : Multiaddr = "/ip4/0.0.0.0/tcp/0".parse::<Multiaddr>().unwrap();
let serialized = serde_json::to_string(&addr).unwrap();
assert_eq!(serialized, "\"/ip4/0.0.0.0/tcp/0\"");
let deserialized: Multiaddr = serde_json::from_str(&serialized).unwrap();
assert_eq!(addr, deserialized);
}
#[test]
fn ser_and_deser_bincode() {
let addr : Multiaddr = "/ip4/0.0.0.0/tcp/0".parse::<Multiaddr>().unwrap();
let serialized = bincode::serialize(&addr).unwrap();
// compact addressing
assert_eq!(serialized, vec![8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 6, 0, 0]);
let deserialized: Multiaddr = bincode::deserialize(&serialized).unwrap();
assert_eq!(addr, deserialized);
}

View File

@ -11,8 +11,8 @@ futures = "0.1.0"
owning_ref = "0.3.3"
libp2p-core = { path = "../core" }
multiaddr = { path = "../multiaddr" }
serde = "1.0"
serde_derive = "1.0"
serde = "1.0.70"
serde_derive = "1.0.70"
[dev-dependencies]
tempfile = "2.2"

View File

@ -27,15 +27,12 @@
//! more thoughts about this.
use multiaddr::Multiaddr;
use serde::de::Error as DeserializerError;
use serde::ser::SerializeStruct;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp::Ordering;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use std::time::SystemTime;
use TTL;
/// Information about a peer.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct PeerInfo {
// Adresses, and the time at which they will be considered expired.
addrs: Vec<(Multiaddr, SystemTime)>,
@ -108,67 +105,6 @@ pub enum AddAddrBehaviour {
IgnoreTtlIfInferior,
}
impl Serialize for PeerInfo {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut s = serializer.serialize_struct("PeerInfo", 2)?;
s.serialize_field(
"addrs",
&self.addrs
.iter()
.map(|&(ref addr, ref expires)| {
let addr = addr.to_string();
let from_epoch = expires.duration_since(UNIX_EPOCH)
// This `unwrap_or` case happens if the user has their system time set to
// before EPOCH. Times-to-live will be be longer than expected, but it's a very
// improbable corner case and is not attackable in any way, so we don't really
// care.
.unwrap_or(Duration::new(0, 0));
let secs = from_epoch
.as_secs()
.saturating_mul(1_000)
.saturating_add(from_epoch.subsec_nanos() as u64 / 1_000_000);
(addr, secs)
})
.collect::<Vec<_>>(),
)?;
s.end()
}
}
impl<'de> Deserialize<'de> for PeerInfo {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
// We deserialize to an intermdiate struct first, then turn that struct into a `PeerInfo`.
let interm = {
#[derive(Deserialize)]
struct Interm {
addrs: Vec<(String, u64)>,
}
Interm::deserialize(deserializer)?
};
let addrs = {
let mut out = Vec::with_capacity(interm.addrs.len());
for (addr, since_epoch) in interm.addrs {
let addr = match addr.parse::<Multiaddr>() {
Ok(a) => a,
Err(err) => return Err(DeserializerError::custom(err)),
};
let expires = UNIX_EPOCH + Duration::from_millis(since_epoch);
out.push((addr, expires));
}
out
};
Ok(PeerInfo { addrs: addrs })
}
}
// The reason why we need to implement the PartialOrd trait is that the datastore library (a
// key-value storage) which we use allows performing queries where the results can be ordered.
//
@ -181,10 +117,12 @@ impl PartialOrd for PeerInfo {
}
}
#[cfg(test)]
mod tests {
extern crate serde_json;
use super::*;
use std::time::UNIX_EPOCH;
#[test]
fn ser_and_deser() {
@ -198,4 +136,4 @@ mod tests {
let deserialized: PeerInfo = serde_json::from_str(&serialized).unwrap();
assert_eq!(peer_info, deserialized);
}
}
}