Skip to content

Commit

Permalink
feat(iroh-base, iroh-net-report)!: intro net-report as a crate (#2921)
Browse files Browse the repository at this point in the history
## Description

Introduces net-report as its own crate. For this, introduces a new
feature flag `relay` in `iroh-base` for the relay topology types.

- in `iroh-base`, the `RelayUrl` is moved to its own file. It can still
be used as before, this is not a breaking change.
- `RelayMap`, `RelayNode` are moved to `iroh-base` under the `relay`
feature flag.
- `RelayMode` is moved to `endpoint`. See the NOTES section about this.
- net-report now has metrics as a feature flag. I'm not sure how is that
this was not feature flagged before but still worked.
- ping is moved without changes from `iroh-net` to `iroh-net-report`.
This is the only place where it's used so it should have probably been
part of `netcheck` as a module from the beginig.
- Adds missing license files


## Breaking Changes

- `iroh-net`'s `NetcheckMetrics` are now called `NetReportMetrics`

## Notes & open questions

- `RelayMode` remains in `iroh-net` instead of moving to `iroh-base`
with other relay related because this is coupled with the staging and
prod configuration of relay urls. Since this is more configuration than
concept I think it's best to keep it in iroh-net.
- The crate is called `iroh-net-report` because -at least currently- it
depends on relay concepts. For example, the tests depend heavily on the
internal order of the `RelayMap`. Can we change this? yes. Should we
change this? we can discuss it. Is this PR the place for any of that?
No.
- The api needs some love. Some types that are supposed to be internal
are used by dependents (in this case `iroh-net`) It's not terrible but
it could be improved.

## Change checklist

- [x] Self-review.
- [x] Documentation updates following the [style
guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text),
if relevant.
- [ ] ~Tests if relevant.~
- [ ] ~All breaking changes documented.~
  • Loading branch information
divagant-martian authored Nov 21, 2024
1 parent 4e58b1f commit a5e9283
Show file tree
Hide file tree
Showing 34 changed files with 918 additions and 384 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ jobs:
# uses: obi1kenobi/cargo-semver-checks-action@v2
uses: n0-computer/cargo-semver-checks-action@feat-baseline
with:
package: iroh, iroh-base, iroh-cli, iroh-dns-server, iroh-metrics, iroh-net, iroh-net-bench, iroh-node-util, iroh-router, netwatch, portmapper, iroh-relay
package: iroh, iroh-base, iroh-cli, iroh-dns-server, iroh-metrics, iroh-net, iroh-net-bench, iroh-node-util, iroh-router, netwatch, portmapper, iroh-relay, iroh-net-report
baseline-rev: ${{ env.HEAD_COMMIT_SHA }}
use-cache: false

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ env:
RUSTFLAGS: -Dwarnings
RUSTDOCFLAGS: -Dwarnings
SCCACHE_CACHE_SIZE: "50G"
CRATES_LIST: "iroh,iroh-node-util,iroh-metrics,iroh-net,iroh-net-bench,iroh-test,iroh-cli,iroh-dns-server,iroh-router,netwatch,portmapper,iroh-relay"
CRATES_LIST: "iroh,iroh-node-util,iroh-metrics,iroh-net,iroh-net-bench,iroh-test,iroh-cli,iroh-dns-server,iroh-router,netwatch,portmapper,iroh-relay,iroh-net-report"
IROH_FORCE_STAGING_RELAYS: "1"

jobs:
Expand Down
32 changes: 32 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ members = [
"iroh-router",
"net-tools/netwatch",
"net-tools/portmapper",
"iroh-net-report",
"iroh-node-util",
]
resolver = "2"
Expand Down
3 changes: 2 additions & 1 deletion iroh-base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ serde_json = "1.0.107"
serde_test = "1.0.176"

[features]
default = ["hash", "base32"]
default = ["hash", "base32", "relay"]
hash = ["dep:blake3", "dep:data-encoding", "dep:postcard", "dep:derive_more", "base32"]
base32 = ["dep:data-encoding", "dep:postcard"]
redb = ["dep:redb"]
key = ["dep:ed25519-dalek", "dep:once_cell", "dep:rand", "dep:rand_core", "dep:ssh-key", "dep:ttl_cache", "dep:aead", "dep:crypto_box", "dep:zeroize", "dep:url", "dep:derive_more", "dep:getrandom"]
wasm = ["getrandom?/js"]
relay = ["dep:url", "dep:derive_more"]

[package.metadata.docs.rs]
all-features = true
Expand Down
5 changes: 5 additions & 0 deletions iroh-base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ pub mod key;
#[cfg(feature = "key")]
#[cfg_attr(iroh_docsrs, doc(cfg(feature = "key")))]
pub mod node_addr;
#[cfg(feature = "relay")]
#[cfg_attr(iroh_docsrs, doc(cfg(feature = "relay")))]
pub mod relay_map;
#[cfg(any(feature = "relay", feature = "key"))]
mod relay_url;
#[cfg(feature = "base32")]
#[cfg_attr(iroh_docsrs, doc(cfg(feature = "base32")))]
pub mod ticket;
122 changes: 2 additions & 120 deletions iroh-base/src/node_addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
//!
//! The primary way of addressing a node is by using the [`NodeAddr`].
use std::{collections::BTreeSet, fmt, net::SocketAddr, ops::Deref, str::FromStr};
use std::{collections::BTreeSet, net::SocketAddr};

use anyhow::Context;
use serde::{Deserialize, Serialize};
use url::Url;

use crate::key::{NodeId, PublicKey};
pub use crate::relay_url::RelayUrl;

/// Network-level addressing information for an iroh-net node.
///
Expand Down Expand Up @@ -199,120 +198,3 @@ pub enum AddrInfoOptions {
/// Includes the Node ID and the direct addresses.
Addresses,
}

/// A URL identifying a relay server.
///
/// This is but a wrapper around [`Url`], with a few custom tweaks:
///
/// - A relay URL is never a relative URL, so an implicit `.` is added at the end of the
/// domain name if missing.
///
/// - [`fmt::Debug`] is implemented so it prints the URL rather than the URL struct fields.
/// Useful when logging e.g. `Option<RelayUrl>`.
///
/// To create a [`RelayUrl`] use the `From<Url>` implementation.
#[derive(
Clone, derive_more::Display, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
pub struct RelayUrl(Url);

impl From<Url> for RelayUrl {
fn from(mut url: Url) -> Self {
if let Some(domain) = url.domain() {
if !domain.ends_with('.') {
let domain = String::from(domain) + ".";

// This can fail, though it is unlikely the resulting URL is usable as a
// relay URL, probably it has the wrong scheme or is not a base URL or the
// like. We don't do full URL validation however, so just silently leave
// this bad URL in place. Something will fail later.
url.set_host(Some(&domain)).ok();
}
}
Self(url)
}
}

/// Support for parsing strings directly.
///
/// If you need more control over the error first create a [`Url`] and use [`RelayUrl::from`]
/// instead.
impl FromStr for RelayUrl {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let inner = Url::from_str(s).context("invalid URL")?;
Ok(RelayUrl::from(inner))
}
}

impl From<RelayUrl> for Url {
fn from(value: RelayUrl) -> Self {
value.0
}
}

/// Dereferences to the wrapped [`Url`].
///
/// Note that [`DerefMut`] is not implemented on purpose, so this type has more flexibility
/// to change the inner later.
///
/// [`DerefMut`]: std::ops::DerefMut
impl Deref for RelayUrl {
type Target = Url;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl fmt::Debug for RelayUrl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("RelayUrl")
.field(&DbgStr(self.0.as_str()))
.finish()
}
}

/// Helper struct to format a &str without allocating a String.
///
/// Maybe this is entirely unneeded and the compiler would be smart enough to never allocate
/// the String anyway. Who knows. Writing this was faster than checking the assembler
/// output.
struct DbgStr<'a>(&'a str);

impl<'a> fmt::Debug for DbgStr<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, r#""{}""#, self.0)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_relay_url_debug_display() {
let url = RelayUrl::from(Url::parse("https://example.com").unwrap());

assert_eq!(format!("{url:?}"), r#"RelayUrl("https://example.com./")"#);

assert_eq!(format!("{url}"), "https://example.com./");
}

#[test]
fn test_relay_url_absolute() {
let url = RelayUrl::from(Url::parse("https://example.com").unwrap());

assert_eq!(url.domain(), Some("example.com."));

let url1 = RelayUrl::from(Url::parse("https://example.com.").unwrap());
assert_eq!(url, url1);

let url2 = RelayUrl::from(Url::parse("https://example.com./").unwrap());
assert_eq!(url, url2);

let url3 = RelayUrl::from(Url::parse("https://example.com/").unwrap());
assert_eq!(url, url3);
}
}
33 changes: 4 additions & 29 deletions iroh-net/src/relay_map.rs → iroh-base/src/relay_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,14 @@
use std::{collections::BTreeMap, fmt, sync::Arc};

use anyhow::{ensure, Result};
pub use iroh_relay::RelayUrl;
use serde::{Deserialize, Serialize};

use crate::defaults::DEFAULT_STUN_PORT;
pub use crate::relay_url::RelayUrl;

/// Configuration of the relay servers for an [`Endpoint`].
/// The default STUN port used by the Relay server.
///
/// [`Endpoint`]: crate::endpoint::Endpoint
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RelayMode {
/// Disable relay servers completely.
Disabled,
/// Use the default relay map, with production relay servers from n0.
///
/// See [`crate::defaults::prod`] for the severs used.
Default,
/// Use the staging relay servers from n0.
Staging,
/// Use a custom relay map.
Custom(RelayMap),
}

impl RelayMode {
/// Returns the relay map for this mode.
pub fn relay_map(&self) -> RelayMap {
match self {
RelayMode::Disabled => RelayMap::empty(),
RelayMode::Default => crate::defaults::prod::default_relay_map(),
RelayMode::Staging => crate::defaults::staging::default_relay_map(),
RelayMode::Custom(relay_map) => relay_map.clone(),
}
}
}
/// The STUN port as defined by [RFC 8489](<https://www.rfc-editor.org/rfc/rfc8489#section-18.6>)
const DEFAULT_STUN_PORT: u16 = 3478;

/// Configuration of all the relay servers that can be used.
#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down
Loading

0 comments on commit a5e9283

Please sign in to comment.