iroh 0.30.0 - Slimming Down
by dignifiedquireWelcome to a new release of iroh, a library for building on direct connections between devices, putting more control in the hands of your users.
Less is more, simpler is better. This release we focused on cleaning up iroh APIs, streamlining the protocol APIs, and reducing our dependency load!
🚚 Movin’ structs into their new homes
A few crucial exports have changed locations. We’ve added many of our most-used structs to become top-line exports, such as PublicKey ,SecretKey and NodeAddr. Some exports were moved from iroh into iroh_blobs or iroh_base. Notably, NodeTicket is now iroh_base::ticket::NodeTicket and BlobTicket can now be found under iroh_blobs::ticket::BlobTicket
For a full list of those changes, check out the breaking changes below.
⌚️ New Watchable APIs
We have a few elements in the iroh Endpoint that can only be updated or created once the Endpoint does a bit of work. For example, we can’t know the home_relay or the direct_addresses that our Endpoint can be dialed on, until we do at least one run of the net-reporter. There are also elements, like conn_type, that continuously update us on the type of connection (e.g. are we talking to them through the relay or do we have a direct connection) that we have with a remote node.
To streamline and unify these APIs, we have a new Watchable type, that allows you do things like wait for a value to exist or create a stream of changes more simply.
The method iroh::Endpoint::conn_type_stream is replaced by iroh::Endpoint::conn_type and returns a Result<Watchable<ConnectionType>>. To get a stream of ConnectionType changes, use iroh::Endpoint::conn_type()?.stream() .
iroh::Endpoint::home_relay() now returns a Watcher<Option<RelayUrl>>, rather than an Option<RelayUrl>
The method iroh::Endpoint::watch_home_relay is removed and replaced by Watchable functionality iniroh::Endpoint::home_relay(). To get a stream of changes, use iroh::Endpoint::home_relay().stream(), and to wait until a home relay is established, use iroh::Endpoint::home_relay().initialized().await?.
Checkout PR#2806 for more details.
đź§ą Cleaning up protocol setup
The setup process was still quite complicated for our main protocols, so we worked on streamlining this process. Below you can see the now-required code for the different protocols.
iroh-gossip
use iroh::{protocol::Router, Endpoint};
use iroh_gossip::net::Gossip;
// create an iroh endpoint that includes the standard discovery mechanisms
// we've built at number0
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
// build gossip protocol
let gossip = Gossip::builder().spawn(endpoint.clone()).await?;
// setup router
let router = Router::builder(endpoint.clone())
.accept(iroh_gossip::ALPN, gossip.clone())
.spawn()
.await?;
iroh-blobs
use iroh::{protocol::Router, Endpoint};
use iroh_blobs::{net_protocol::Blobs, util::local_pool::LocalPool};
// create an iroh endpoint that includes the standard discovery mechanisms
// we've built at number0
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
// spawn a local pool with one thread per CPU
// for a single threaded pool use `LocalPool::single`
let local_pool = LocalPool::default();
// create an in-memory blob store
// use `iroh_blobs::net_protocol::Blobs::persistent` to load or create a
// persistent blob store from a path
let blobs = Blobs::memory().build(local_pool.handle(), &endpoint);
// turn on the "rpc" feature if you need to create blobs and tags clients
let blobs_client = blobs.client();
let tags_client = blobs_client.tags();
// build the router
let router = Router::builder(endpoint)
.accept(iroh_blobs::ALPN, blobs.clone())
.spawn()
.await?;
iroh-docs
use iroh::{protocol::Router, Endpoint};
use iroh_blobs::{
net_protocol::Blobs,
util::local_pool::LocalPool,
ALPN as BLOBS_ALPN
};
use iroh_docs::{protocol::Docs, ALPN as DOCS_ALPN};
use iroh_gossip::{net::Gossip, ALPN as GOSSIP_ALPN};
// create an iroh endpoint that includes the standard discovery mechanisms
// we've built at number0
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
// create a router builder, we will add the
// protocols to this builder and then spawn the router
let builder = Router::builder(endpoint);
// build the blobs protocol
let local_pool = LocalPool::default();
let blobs = Blobs::memory().build(local_pool.handle(), builder.endpoint());
// build the gossip protocol
let gossip = Gossip::builder().spawn(builder.endpoint().clone()).await?;
// build the docs protocol
let docs = Docs::memory().spawn(&blobs, &gossip).await?;
// setup router
let router = builder
.accept(BLOBS_ALPN, blobs)
.accept(GOSSIP_ALPN, gossip)
.accept(DOCS_ALPN, docs)
.spawn()
.await?;
📦 Reducing dependencies
Irohs dependency load is not the smallest, so while preparing the API for 1.0, we are also trying to reduce the number of required dependencies.
This work work was spread over a lot of smaller PRs and should reduce the dependencies quite a bit when adding iroh to your project.
Check out these PRs for more details:
- https://github.com/n0-computer/iroh/pull/3005
- https://github.com/n0-computer/iroh/pull/3034
- https://github.com/n0-computer/iroh/pull/3042
- https://github.com/n0-computer/iroh/pull/3047
- https://github.com/n0-computer/iroh/pull/3046
- https://github.com/n0-computer/iroh/pull/3048
- https://github.com/n0-computer/iroh/pull/3051
⌨ Simpler ProtocolHandler API
Previously the ProtocolHandler trait required using explicit Arcs, but this is no longer required, allowing for a more flexible structure in defining protocols.
Checkout PR#3010 for more details.
⚠️ Breaking Changes
MSRV has been increased from 1.76 to 1.81 for all crates.
iroh-base- removed
iroh_base::SharedSecretiroh_base::DecryptionError,iroh::DecryptionErroriroh_base::SecretKey::sharediroh_base::SecretKey::generate_with_rng, usegeneratedirectlyiroh_base::SecretKey::to_opensshiroh_base::SecretKey::from_opensshiroh_base::base32iroh_base::node_addr::AddrInfoiroh_base::node_addr::AddrInfoOptionsiroh_base::relay_map, useiroh_relay::relay_map
- changed
iroh_base::node_addr::NodeAddr->iroh_base::NodeAddriroh_base::relay_url::RelayUrl->iroh_base::RelayUrliroh_base::SecretKey::generatenow takes an rnganyhow::Erroris replaced with explicit errors forRelayUrl::from_stranyhow::Erroris replaced with explicit errors forSharedSecret::openiroh_base::PUBLIC_KEY_LENGTHis moved from a top level constant toiroh_base::PublicKey::LENGTH- keys are now formatted using
hexlowercase by default - keys still parse base32 encoded, for better backwards compatibility
- introduce
ticketfeature foriroh_base, to useiroh_base::ticket iroh_base::keyexports moved toiroh_base:iroh_base::{KeyParsingError, NodeId, PublicKey, SecretKey, SharedSecret, Signature, PUBLIC_KEY_LENGTH}
- removed
iroh-net-report- changed
net_report::Client::get_report_channelnow takes anopts: net_report::Optionsnet_report::Clientwill no longer bindUdpSockets when one is not provided for both STUN over IPv4 or STUN over IPv6.iroh_net_report::Client::get_reporttakes new parameterquic_config: net_report::QuicConfigiroh_net_report::Client::get_report_channeltakes new parameterquic_config: net_report::QuicConfig
- added
net_report::Client::get_report_with_options
- changed
iroh-relay
- changed
iroh_relay::HttpClientBuilder::address_family_selectorsignature changedserveris not a default feature iniroh-relayanymore
ClientErrorhas a number of unused variants removed.
iroh
- removed
iroh::protocol::Router::get_protocoliroh::protocol::RouterBuilder::get_protocoliroh::protocol::ProtocolMap::get_typediroh::protocol::IntoArcAnyiroh::dialer::Dialerandiroh::dialeriroh::tlsiroh::Endpoint::connect_by_node_id, useiroh::Endpoint::connectwith aNodeIdinstead.iroh::hash::{BlobFormat, Hash, HashAndFormat}, useiroh_blobs::{BlobFormat, Hash, HashAndFormat}iroh::ticket::BlobTicket, useiroh_blobs::ticket::BlobTicketiroh::endpoint::Bytes, usebytes::Bytesiroh::Endpoint::watch_home_relayTo migrate, useendpoint.home_relay().initialized().await?instead ofendpoint.watch_home_relay().next().awaitand useendpoint.home_relay().stream()instead ofendpoint.watch_home_relay().next().await.DirectAddrsStreamandConnTypeStream, useiroh::watchable::WatcherStreamfor as named types instead.
- changed
iroh::endpoint::NodeAddrmoved toiroh::NodeAddriroh::Endpoint::conn_type_streamis renamed toiroh::Endpoint::conn_typeand returnsResult<Watcher<ConnectionType>>instead ofResult<ConnectionTypeStream>To migrate, useendpoint.conn_type()?.stream()instead ofendpoint.conn_type_stream()?.iroh::Endpoint::home_relaynow returnsWatcher<Option<RelayUrl>>instead ofOption<RelayUrl>. To migrate, useendpoint.home_relay().get()?instead ofendpoint.home_relay().iroh::protocol::ProtocolHandler::acceptnow takes&selfinstead ofArc<Self>iroh::protocol::ProtocolHandler::shutdownnow takes&selfinstead ofArc<Self>iroh::protocol::RouterBuilder::acceptnow takesT: ProtocolHandlerinstead ofArc<dyn ProtocolHandler>iroh::protocol::ProtocolMapis now private- struct
iroh::config::Confighas a new fieldzone_store - struct
iroh::metrics::Metricshas a new fieldstore_packets_expired iroh::keyexports are now top-line exports
But wait, there's more!
Many bugs were squashed, and smaller features were added. For all those details, check out the full changelog: https://github.com/n0-computer/iroh/releases/tag/v0.30.0.
If you want to know what is coming up, check out the v0.31.0 milestone, and if you have any wishes, let us know about the issues! If you need help using iroh or just want to chat, please join us on discord! And to keep up with all things iroh, check out our Twitter.
To get started, take a look at our docs, dive directly into the code, or chat with us in our discord channel.