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 Arc
s, 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::SharedSecret
iroh_base::DecryptionError
,iroh::DecryptionError
iroh_base::SecretKey::shared
iroh_base::SecretKey::generate_with_rng
, usegenerate
directlyiroh_base::SecretKey::to_openssh
iroh_base::SecretKey::from_openssh
iroh_base::base32
iroh_base::node_addr::AddrInfo
iroh_base::node_addr::AddrInfoOptions
iroh_base::relay_map
, useiroh_relay::relay_map
- changed
iroh_base::node_addr::NodeAddr
->iroh_base::NodeAddr
iroh_base::relay_url::RelayUrl
->iroh_base::RelayUrl
iroh_base::SecretKey::generate
now takes an rnganyhow::Error
is replaced with explicit errors forRelayUrl::from_str
anyhow::Error
is replaced with explicit errors forSharedSecret::open
iroh_base::PUBLIC_KEY_LENGTH
is moved from a top level constant toiroh_base::PublicKey::LENGTH
- keys are now formatted using
hex
lowercase by default - keys still parse base32 encoded, for better backwards compatibility
- introduce
ticket
feature foriroh_base
, to useiroh_base::ticket
iroh_base::key
exports moved toiroh_base
:iroh_base::{KeyParsingError, NodeId, PublicKey, SecretKey, SharedSecret, Signature, PUBLIC_KEY_LENGTH}
- removed
iroh-net-report
- changed
net_report::Client::get_report_channel
now takes anopts: net_report::Options
net_report::Client
will no longer bindUdpSocket
s when one is not provided for both STUN over IPv4 or STUN over IPv6.iroh_net_report::Client::get_report
takes new parameterquic_config: net_report::QuicConfig
iroh_net_report::Client::get_report_channel
takes new parameterquic_config: net_report::QuicConfig
- added
net_report::Client::get_report_with_options
- changed
iroh-relay
- changed
iroh_relay::HttpClientBuilder::address_family_selector
signature changedserver
is not a default feature iniroh-relay
anymore
ClientError
has a number of unused variants removed.
iroh
- removed
iroh::protocol::Router::get_protocol
iroh::protocol::RouterBuilder::get_protocol
iroh::protocol::ProtocolMap::get_typed
iroh::protocol::IntoArcAny
iroh::dialer::Dialer
andiroh::dialer
iroh::tls
iroh::Endpoint::connect_by_node_id
, useiroh::Endpoint::connect
with aNodeId
instead.iroh::hash::{BlobFormat, Hash, HashAndFormat}
, useiroh_blobs::{BlobFormat, Hash, HashAndFormat}
iroh::ticket::BlobTicket
, useiroh_blobs::ticket::BlobTicket
iroh::endpoint::Bytes
, usebytes::Bytes
iroh::Endpoint::watch_home_relay
To migrate, useendpoint.home_relay().initialized().await?
instead ofendpoint.watch_home_relay().next().await
and useendpoint.home_relay().stream()
instead ofendpoint.watch_home_relay().next().await
.DirectAddrsStream
andConnTypeStream
, useiroh::watchable::WatcherStream
for as named types instead.
- changed
iroh::endpoint::NodeAddr
moved toiroh::NodeAddr
iroh::Endpoint::conn_type_stream
is renamed toiroh::Endpoint::conn_type
and returnsResult<Watcher<ConnectionType>>
instead ofResult<ConnectionTypeStream>
To migrate, useendpoint.conn_type()?.stream()
instead ofendpoint.conn_type_stream()?
.iroh::Endpoint::home_relay
now returnsWatcher<Option<RelayUrl>>
instead ofOption<RelayUrl>
. To migrate, useendpoint.home_relay().get()?
instead ofendpoint.home_relay()
.iroh::protocol::ProtocolHandler::accept
now takes&self
instead ofArc<Self>
iroh::protocol::ProtocolHandler::shutdown
now takes&self
instead ofArc<Self>
iroh::protocol::RouterBuilder::accept
now takesT: ProtocolHandler
instead ofArc<dyn ProtocolHandler>
iroh::protocol::ProtocolMap
is now private- struct
iroh::config::Config
has a new fieldzone_store
- struct
iroh::metrics::Metrics
has a new fieldstore_packets_expired
iroh::key
exports 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.