Add custom Iroh relay maps

This commit is contained in:
Eric Wendland 2026-05-16 14:28:38 +02:00
commit 280472cecb
10 changed files with 241 additions and 32 deletions

View file

@ -160,23 +160,43 @@ pub enum GethRelayMode {
Disabled,
Default,
Staging,
Custom {
name: String,
relay_urls: Vec<String>,
},
}
impl GethRelayMode {
fn to_iroh(&self) -> iroh::RelayMode {
fn to_iroh(&self) -> Result<iroh::RelayMode, IrohError> {
match self {
Self::Disabled => iroh::RelayMode::Disabled,
Self::Default => iroh::RelayMode::Default,
Self::Staging => iroh::RelayMode::Staging,
Self::Disabled => Ok(iroh::RelayMode::Disabled),
Self::Default => Ok(iroh::RelayMode::Default),
Self::Staging => Ok(iroh::RelayMode::Staging),
Self::Custom { relay_urls, .. } => {
let relay_urls = relay_urls
.iter()
.map(|url| {
url.parse::<iroh::RelayUrl>()
.map_err(|error| IrohError::InvalidRelayUrl {
url: url.clone(),
message: error.to_string(),
})
})
.collect::<Result<Vec<_>, _>>()?;
Ok(iroh::RelayMode::Custom(iroh::RelayMap::from_iter(
relay_urls,
)))
}
}
}
#[must_use]
pub fn as_str(&self) -> &'static str {
pub fn label(&self) -> String {
match self {
Self::Disabled => "disabled",
Self::Default => "default",
Self::Staging => "staging",
Self::Disabled => "disabled".to_owned(),
Self::Default => "default".to_owned(),
Self::Staging => "staging".to_owned(),
Self::Custom { name, .. } => format!("custom:{name}"),
}
}
}
@ -206,7 +226,7 @@ pub async fn start_endpoint(config: &GethIrohConfig) -> Result<GethIrohEndpoint,
let secret_key = load_or_create_secret_key(&config.secret_key_path)?;
let mut builder = iroh::Endpoint::builder()
.secret_key(secret_key)
.relay_mode(config.relay_mode.to_iroh())
.relay_mode(config.relay_mode.to_iroh()?)
.alpns(config.alpns.clone());
if let Some(bind_ipv4) = config.bind_ipv4 {
@ -220,7 +240,7 @@ pub async fn start_endpoint(config: &GethIrohConfig) -> Result<GethIrohEndpoint,
let status = EndpointStatus {
enabled: true,
endpoint_id: Some(endpoint.node_id().to_string()),
relay_mode: config.relay_mode.as_str().to_owned(),
relay_mode: config.relay_mode.label(),
note: format!(
"Iroh endpoint started with iroh 0.90.0; relay mode: {:?}",
config.relay_mode
@ -286,6 +306,8 @@ pub enum IrohError {
Hex(#[from] hex::FromHexError),
#[error("invalid iroh secret key length")]
InvalidSecretKeyLength,
#[error("invalid iroh relay URL `{url}`: {message}")]
InvalidRelayUrl { url: String, message: String },
#[error("failed to bind iroh endpoint: {0}")]
Bind(Box<iroh::endpoint::BindError>),
}
@ -370,11 +392,27 @@ mod tests {
let config = GethIrohConfig::local_with_relay("iroh.ed25519", GethRelayMode::Staging);
assert_eq!(config.relay_mode, GethRelayMode::Staging);
assert!(matches!(
config.relay_mode.to_iroh(),
config.relay_mode.to_iroh().expect("iroh relay mode"),
iroh::RelayMode::Staging
));
}
#[test]
fn custom_relay_mode_builds_iroh_relay_map() {
let mode = GethRelayMode::Custom {
name: "home".to_owned(),
relay_urls: vec!["https://relay.example.com".to_owned()],
};
let relay_mode = mode.to_iroh().expect("custom relay mode");
match relay_mode {
iroh::RelayMode::Custom(map) => {
assert_eq!(map.len(), 1);
assert_eq!(mode.label(), "custom:home");
}
other => panic!("unexpected relay mode: {other:?}"),
}
}
#[tokio::test]
async fn endpoint_status_tracks_node_id_when_bind_is_available() {
let dir = tempfile::tempdir().expect("tempdir");