From 5111a050d04da90a4d4ca35f87a47b9971d9afc0 Mon Sep 17 00:00:00 2001 From: John Turpish Date: Fri, 30 Sep 2022 15:51:43 -0400 Subject: [PATCH 1/8] Providing convenient access to the static components only --- src/lib.rs | 15 ++++++++++ src/protocol.rs | 38 ++++++++++++++++++++++++ tests/lib.rs | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index f0e2196..71a8db0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -191,6 +191,10 @@ impl Multiaddr { } self.bytes[(n - m)..] == other.bytes[..] } + + pub fn protocol_stack(&self) -> ProtoStackIter { + ProtoStackIter{ parts: self.iter() } + } } impl fmt::Debug for Multiaddr { @@ -293,6 +297,17 @@ impl<'a> Iterator for Iter<'a> { } } +pub struct ProtoStackIter<'a>{ + parts: Iter<'a> +} + +impl<'a> Iterator for ProtoStackIter<'a> { + type Item = &'static str; + fn next(&mut self) -> Option { + self.parts.next().map(|p|p.tag()) + } +} + impl<'a> From> for Multiaddr { fn from(p: Protocol<'a>) -> Multiaddr { let mut w = Vec::new(); diff --git a/src/protocol.rs b/src/protocol.rs index 59b9537..cd03c99 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -510,6 +510,44 @@ impl<'a> Protocol<'a> { Wss(cow) => Wss(Cow::Owned(cow.into_owned())), } } + + pub fn tag(&self) -> &'static str { + use self::Protocol::*; + match self { + Dccp(_) => "dccp", + Dns(_) => "dns", + Dns4(_) => "dns4", + Dns6(_) => "dns6", + Dnsaddr(_) => "dnsaddr", + Http => "http", + Https => "https", + Ip4(_) => "ip4", + Ip6(_) => "ip6", + P2pWebRtcDirect => "p2p-webrtc-direct", + P2pWebRtcStar => "p2p-webrtc-star", + WebRTC => "webrtc", + Certhash(_) => "certhash", + P2pWebSocketStar => "p2p-websocket-star", + Memory(_) => "memory", + Onion(_, _) => "onion", + Onion3(_) => "onion3", + P2p(_) =>"p2p", + P2pCircuit => "p2p-circuit", + Quic => "quic", + Sctp(_) => "sctp", + Tcp(_) => "tcp", + Tls => "tls", + Noise => "noise", + Udp(_) => "udp", + Udt => "udt", + Unix(_) => "unix", + Utp => "utp", + Ws(ref s) if s == "/" => "ws", + Ws(_) => "x-parity-ws", + Wss(ref s) if s == "/" => "wss", + Wss(_) => "x-parity-wss", + } + } } impl<'a> fmt::Display for Protocol<'a> { diff --git a/tests/lib.rs b/tests/lib.rs index f31a955..65601d0 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,3 +1,5 @@ +extern crate core; + use data_encoding::HEXUPPER; use multiaddr::*; use multihash::Multihash; @@ -527,3 +529,79 @@ fn unknown_protocol_string() { }, } } + +#[test] +fn protocol_stack() { + let addresses = [ + "/ip4/0.0.0.0", + "/ip6/::1", + "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21", + "/udp/0", + "/tcp/0", + "/sctp/0", + "/udp/1234", + "/tcp/1234", + "/sctp/1234", + "/udp/65535", + "/tcp/65535", + "/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "/udp/1234/sctp/1234", + "/udp/1234/udt", + "/udp/1234/utp", + "/tcp/1234/http", + "/tcp/1234/tls/http", + "/tcp/1234/https", + "/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", + "/ip4/127.0.0.1/udp/1234", + "/ip4/127.0.0.1/udp/0", + "/ip4/127.0.0.1/tcp/1234", + "/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", + "/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/ws/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "/p2p-webrtc-star/ip4/127.0.0.1/tcp/9090/ws/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/wss/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "/ip4/127.0.0.1/tcp/9090/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "/onion/aaimaq4ygg2iegci:80", + "/dnsaddr/sjc-1.bootstrap.libp2p.io", + "/dnsaddr/sjc-1.bootstrap.libp2p.io/tcp/1234/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", + "/ip4/127.0.0.1/tcp/127/ws", + "/ip4/127.0.0.1/tcp/127/tls", + "/ip4/127.0.0.1/tcp/127/tls/ws", + "/ip4/127.0.0.1/tcp/127/noise", + "/ip4/127.0.0.1/udp/1234/webrtc", + ]; + let argless = std::collections::HashSet::from([ + "http", + "https", + "noise", + "p2p-circuit", + "p2p-webrtc-direct", + "p2p-webrtc-star", + "p2p-websocket-star", + "quic", + "tls", + "udt", + "utp", + "webrtc", + "ws", + "wss", + ]); + for addr_str in addresses { + let ma = Multiaddr::from_str(addr_str).expect("These are supposed to be valid multiaddrs"); + let ps: Vec<&str> = ma.protocol_stack().collect(); + let mut toks: Vec<&str> = addr_str.split("/").collect(); + assert_eq!("", toks[0]); + toks.remove(0); + let mut i = 0; + while i < toks.len() { + let proto_tag = toks[i]; + i += 1; + if argless.contains(proto_tag) { + //skip + } else { + toks.remove(i); + } + } + assert_eq!(ps, toks); + } +} From f0dea3e0d799f7f482cc675bb294da0e6115b152 Mon Sep 17 00:00:00 2001 From: John Turpish Date: Fri, 30 Sep 2022 17:01:27 -0400 Subject: [PATCH 2/8] commented --- src/lib.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 71a8db0..c07c9ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -192,8 +192,11 @@ impl Multiaddr { self.bytes[(n - m)..] == other.bytes[..] } + /// Returns a &str identifiers for the protocols themselves, in order + /// This omits specific info like addresses, ports, peer IDs, and the like. + /// Example: `"/ip4/127.0.0.1/tcp/5001"` would return `["ip4", "tcp"]` pub fn protocol_stack(&self) -> ProtoStackIter { - ProtoStackIter{ parts: self.iter() } + ProtoStackIter { parts: self.iter() } } } @@ -297,14 +300,15 @@ impl<'a> Iterator for Iter<'a> { } } -pub struct ProtoStackIter<'a>{ - parts: Iter<'a> +/// Iterator over the string idtenfiers of the protocols (not addrs) in a multiaddr +pub struct ProtoStackIter<'a> { + parts: Iter<'a>, } impl<'a> Iterator for ProtoStackIter<'a> { - type Item = &'static str; + type Item = &'static str; fn next(&mut self) -> Option { - self.parts.next().map(|p|p.tag()) + self.parts.next().map(|p| p.tag()) } } From 8fb6320eafe3467ab7139bb9572af4fad93fbddc Mon Sep 17 00:00:00 2001 From: John Turpish Date: Tue, 4 Oct 2022 16:10:36 -0400 Subject: [PATCH 3/8] Refactor of fmt based on Max's suggestion. --- .gitignore | 3 ++- src/protocol.rs | 68 +++++++++++++++++++------------------------------ 2 files changed, 28 insertions(+), 43 deletions(-) diff --git a/.gitignore b/.gitignore index 5071d14..2fd3adf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target Cargo.lock -*.rs.bk \ No newline at end of file +*.rs.bk +.idea diff --git a/src/protocol.rs b/src/protocol.rs index cd03c99..e3dc5f1 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -531,7 +531,7 @@ impl<'a> Protocol<'a> { Memory(_) => "memory", Onion(_, _) => "onion", Onion3(_) => "onion3", - P2p(_) =>"p2p", + P2p(_) => "p2p", P2pCircuit => "p2p-circuit", Quic => "quic", Sctp(_) => "sctp", @@ -542,9 +542,9 @@ impl<'a> Protocol<'a> { Udt => "udt", Unix(_) => "unix", Utp => "utp", - Ws(ref s) if s == "/" => "ws", + Ws(ref s) if s == "/" => "ws", Ws(_) => "x-parity-ws", - Wss(ref s) if s == "/" => "wss", + Wss(ref s) if s == "/" => "wss", Wss(_) => "x-parity-wss", } } @@ -553,61 +553,45 @@ impl<'a> Protocol<'a> { impl<'a> fmt::Display for Protocol<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::Protocol::*; + write!(f, "/{}", self.tag())?; match self { - Dccp(port) => write!(f, "/dccp/{}", port), - Dns(s) => write!(f, "/dns/{}", s), - Dns4(s) => write!(f, "/dns4/{}", s), - Dns6(s) => write!(f, "/dns6/{}", s), - Dnsaddr(s) => write!(f, "/dnsaddr/{}", s), - Http => f.write_str("/http"), - Https => f.write_str("/https"), - Ip4(addr) => write!(f, "/ip4/{}", addr), - Ip6(addr) => write!(f, "/ip6/{}", addr), - P2pWebRtcDirect => f.write_str("/p2p-webrtc-direct"), - P2pWebRtcStar => f.write_str("/p2p-webrtc-star"), - WebRTC => f.write_str("/webrtc"), + Dccp(port) => write!(f, "/{}", port), + Dns(s) => write!(f, "/{}", s), + Dns4(s) => write!(f, "/{}", s), + Dns6(s) => write!(f, "/{}", s), + Dnsaddr(s) => write!(f, "/{}", s), + Ip4(addr) => write!(f, "/{}", addr), + Ip6(addr) => write!(f, "/{}", addr), Certhash(hash) => write!( f, - "/certhash/{}", + "{}", multibase::encode(multibase::Base::Base64Url, hash.to_bytes()) ), - P2pWebSocketStar => f.write_str("/p2p-websocket-star"), - Memory(port) => write!(f, "/memory/{}", port), + Memory(port) => write!(f, "/{}", port), Onion(addr, port) => { let s = BASE32.encode(addr.as_ref()); - write!(f, "/onion/{}:{}", s.to_lowercase(), port) + write!(f, "/{}:{}", s.to_lowercase(), port) } Onion3(addr) => { let s = BASE32.encode(addr.hash()); - write!(f, "/onion3/{}:{}", s.to_lowercase(), addr.port()) - } - P2p(c) => write!( - f, - "/p2p/{}", - multibase::Base::Base58Btc.encode(c.to_bytes()) - ), - P2pCircuit => f.write_str("/p2p-circuit"), - Quic => f.write_str("/quic"), - Sctp(port) => write!(f, "/sctp/{}", port), - Tcp(port) => write!(f, "/tcp/{}", port), - Tls => write!(f, "/tls"), - Noise => write!(f, "/noise"), - Udp(port) => write!(f, "/udp/{}", port), - Udt => f.write_str("/udt"), - Unix(s) => write!(f, "/unix/{}", s), - Utp => f.write_str("/utp"), - Ws(ref s) if s == "/" => f.write_str("/ws"), - Ws(s) => { + write!(f, "/{}:{}", s.to_lowercase(), addr.port()) + } + P2p(c) => write!(f, "/{}", multibase::Base::Base58Btc.encode(c.to_bytes())), + Sctp(port) => write!(f, "/{}", port), + Tcp(port) => write!(f, "/{}", port), + Udp(port) => write!(f, "/{}", port), + Unix(s) => write!(f, "/{}", s), + Ws(s) if s != "/" => { let encoded = percent_encoding::percent_encode(s.as_bytes(), PATH_SEGMENT_ENCODE_SET); - write!(f, "/x-parity-ws/{}", encoded) + write!(f, "/{}", encoded) } - Wss(ref s) if s == "/" => f.write_str("/wss"), - Wss(s) => { + Wss(s) if s != "/" => { let encoded = percent_encoding::percent_encode(s.as_bytes(), PATH_SEGMENT_ENCODE_SET); - write!(f, "/x-parity-wss/{}", encoded) + write!(f, "/{}", encoded) } + _ => Ok(()), } } } From 89e6efc3b00b90e4a28f65df13595919a05cfb42 Mon Sep 17 00:00:00 2001 From: John Turpish Date: Tue, 11 Oct 2022 15:11:05 -0400 Subject: [PATCH 4/8] A couple of updates from PR comments. --- .gitignore | 1 - CHANGELOG.md | 2 ++ src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 2fd3adf..5057d9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ target Cargo.lock *.rs.bk -.idea diff --git a/CHANGELOG.md b/CHANGELOG.md index d522b87..eca259e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ - Use `multibase` instead of `bs58` for base58 encoding. See [PR 56]. +- Create `protocol_stack` for Multiaddr. See [PR 60] + [PR 53]: https://github.com/multiformats/rust-multiaddr/pull/53 [PR 56]: https://github.com/multiformats/rust-multiaddr/pull/56 [PR 59]: https://github.com/multiformats/rust-multiaddr/pull/59 diff --git a/src/lib.rs b/src/lib.rs index c07c9ba..d5e6ffd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -308,7 +308,7 @@ pub struct ProtoStackIter<'a> { impl<'a> Iterator for ProtoStackIter<'a> { type Item = &'static str; fn next(&mut self) -> Option { - self.parts.next().map(|p| p.tag()) + self.parts.next().as_ref().map(Protocol::tag) } } From 04df5259c47526cc7f1bb1039fdcb086eca47bc4 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 19 Oct 2022 19:48:22 +0100 Subject: [PATCH 5/8] src/lib.rs: Fix typo --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index d5e6ffd..e79e385 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -192,7 +192,7 @@ impl Multiaddr { self.bytes[(n - m)..] == other.bytes[..] } - /// Returns a &str identifiers for the protocols themselves, in order + /// Returns &str identifiers for the protocol names themselves. /// This omits specific info like addresses, ports, peer IDs, and the like. /// Example: `"/ip4/127.0.0.1/tcp/5001"` would return `["ip4", "tcp"]` pub fn protocol_stack(&self) -> ProtoStackIter { From be6b7641e8fdc2ea05e60e89be01722aa692383d Mon Sep 17 00:00:00 2001 From: John Turpish Date: Wed, 19 Oct 2022 16:02:43 -0400 Subject: [PATCH 6/8] clippy --- tests/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib.rs b/tests/lib.rs index 65601d0..35d48e4 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -589,7 +589,7 @@ fn protocol_stack() { for addr_str in addresses { let ma = Multiaddr::from_str(addr_str).expect("These are supposed to be valid multiaddrs"); let ps: Vec<&str> = ma.protocol_stack().collect(); - let mut toks: Vec<&str> = addr_str.split("/").collect(); + let mut toks: Vec<&str> = addr_str.split('/').collect(); assert_eq!("", toks[0]); toks.remove(0); let mut i = 0; From 6aac9b43af3a061f081e201c94367cb4653ec5f2 Mon Sep 17 00:00:00 2001 From: John Turpish Date: Fri, 21 Oct 2022 12:26:21 -0400 Subject: [PATCH 7/8] bump --- CHANGELOG.md | 6 ++++-- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abd5c06..cf15eca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.16.0 [unreleased] + +- Create `protocol_stack` for Multiaddr. See [PR 60] + # 0.15.0 [2022-10-20] - Add `WebRTC` instance for `Multiaddr`. See [PR 59]. @@ -7,8 +11,6 @@ - Use `multibase` instead of `bs58` for base58 encoding. See [PR 56]. -- Create `protocol_stack` for Multiaddr. See [PR 60] - [PR 53]: https://github.com/multiformats/rust-multiaddr/pull/53 [PR 56]: https://github.com/multiformats/rust-multiaddr/pull/56 [PR 59]: https://github.com/multiformats/rust-multiaddr/pull/59 diff --git a/Cargo.toml b/Cargo.toml index 4b493f9..7d5ef9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["multiaddr", "ipfs"] license = "MIT" name = "multiaddr" readme = "README.md" -version = "0.15.0" +version = "0.16.0" [features] default = ["url"] From 5129098cd4f63c46bee0d6a075f818b485e0dc9b Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 24 Oct 2022 23:21:35 +0100 Subject: [PATCH 8/8] src/protocol.rs: Seperate tag from payload with slash --- src/protocol.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocol.rs b/src/protocol.rs index e3dc5f1..7474096 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -564,7 +564,7 @@ impl<'a> fmt::Display for Protocol<'a> { Ip6(addr) => write!(f, "/{}", addr), Certhash(hash) => write!( f, - "{}", + "/{}", multibase::encode(multibase::Base::Base64Url, hash.to_bytes()) ), Memory(port) => write!(f, "/{}", port),