multiformats / rust-multiaddr

multiaddr implementation in rust
https://crates.io/crates/multiaddr
Other
86 stars 45 forks source link

Add conversions between sockets and multiaddrs #99

Open jmcph4 opened 11 months ago

jmcph4 commented 11 months ago

This PR allows two type conversions involving both Multiaddr and SocketAddr:

These are certainly fairly minor changes; however, they enable some niceties such as:

match libp2p_event {
    FromSwarm::NewListenAddr { listener_id: _, addr: Multiaddr } => if let Ok(sock) = addr.try_into::<SocketAddr>() {
        do_something_with_socket(sock);
    } else {
        panic!("Something went wrong!");
    }
}
jmcph4 commented 11 months ago

We should consider Udp as well and not just Tcp.

I think these would be better served as dedicated functions so we can include the tcp bit in the name to make this clear.

I agree, I'll add the equivalent UDP methods and make the existing TCP ones dedicated methods rather than From and TryFrom implementations.

What is also not clear to me is what should happen with the remaining components of the multiaddr? Currently we just drop them. Should we return them instead?

Are you referring to the case where we need to produce a SocketAddr from a multiaddr like /ip4/192.0.2.0/tcp/4321/p2p/QmcEPrat8ShnCph8WjkREzt5CPXF2RwhYxYBALDcLC1iV6? Given we're abandoning the From and TryFrom approach, we could perhaps take an approach like:

pub fn into_tcp_socket(&self) -> Option<(SocketAddr, Multiaddr)> {
    /* snip */
    Some((sock, remaining))
}

Which would yield (sock: 192.0.2.0:4321, remaining: /p2p/QmcEPrat8ShnCph8WjkREzt5CPXF2RwhYxYBALDcLC1iV6).

The issue with this is that it implicitly assumes a left-to-right parsing approach for what it means to convert a multiaddr into a SocketAddr. I think this is the most sane approach, but it's still something to consider.

thomaseizinger commented 11 months ago

The issue with this is that it implicitly assumes a left-to-right parsing approach for what it means to convert a multiaddr into a SocketAddr. I think this is the most sane approach, but it's still something to consider.

Left-to-right is how you are meant to parse multiaddr, see https://github.com/multiformats/multiaddr?tab=readme-ov-file#interpreting-multiaddrs.

Perhaps, the functions should be called something like:

impl Multiaddr {
    pub fn pop_front_tcp_socket(&mut self) -> Option<SocketAddr>;
}

This modifies the Multiaddr instead of returning the remaining bits. Getting None would mean the multiaddr is unmodified.

thomaseizinger commented 11 months ago

Multiaddr is a very fundamental crate to the Rust libp2p ecosystem. I am a bit hesitant to include a lot of convenience functions in here if it can be implemented externally as well.

Perhaps what we should add is a pop_front function that modifies the Multiaddr.

You should then be able to implement an efficient extension trait that uses iter() to peek at the first components and if they represent the correct components, you can use pop_front to remove them.

Curious to hear what other maintainers think.