Skip to content

Commit 94c46d7

Browse files
tlongwell-blockMax
andcommitted
Add embedded SDK knobs: disable iroh relays + join-token on running node
Two opt-in, default-false seams the Sprout v1 mesh integration needs: - disable_iroh_relays(bool): when true, bind_mesh_endpoint uses RelayMode::Disabled instead of the existing Custom relay path. Lets a consumer say "no public relay" explicitly; default false preserves existing behavior byte-for-byte. - EmbeddedNodeHandle::join_token(token): forwards an invite token over the existing RuntimeControl channel to node.join_with_retry, so an already-running embedded node can dial a new EndpointAddr without restart (the call-me-now primitive). Purely additive, defaults preserve current behavior for all other consumers. Co-authored-by: Max <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
1 parent bd16da4 commit 94c46d7

6 files changed

Lines changed: 87 additions & 9 deletions

File tree

‎crates/mesh-llm-host-runtime/src/api/state.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ impl Serialize for PublicationState {
4343
}
4444

4545
pub enum RuntimeControlRequest {
46+
Join {
47+
invite_token: String,
48+
resp: tokio::sync::oneshot::Sender<anyhow::Result<()>>,
49+
},
4650
Load {
4751
spec: String,
4852
resp: tokio::sync::oneshot::Sender<anyhow::Result<RuntimeLoadResponse>>,

‎crates/mesh-llm-host-runtime/src/cli/mod.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,10 @@ pub(crate) struct Cli {
512512
#[arg(long = "relay-auth", value_parser = parse_relay_auth_pair, hide = true)]
513513
pub(crate) relay_auth: Vec<(String, String)>,
514514

515+
/// Disable iroh relay registration. Direct addresses and explicit EndpointAddr dials still work.
516+
#[arg(long, hide = true)]
517+
pub(crate) disable_iroh_relays: bool,
518+
515519
/// Bind QUIC to a fixed UDP port (for NAT port forwarding).
516520
#[arg(long, hide = true)]
517521
pub(crate) bind_port: Option<u16>,

‎crates/mesh-llm-host-runtime/src/mesh/mod.rs‎

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ pub struct QuicBindSelection {
265265
pub struct RelayConfig<'a> {
266266
pub urls: &'a [String],
267267
pub auths: &'a std::collections::HashMap<String, String>,
268+
pub disabled: bool,
268269
}
269270

270271
fn quic_bind_addr(bind: QuicBindSelection) -> Option<SocketAddr> {
@@ -1772,6 +1773,7 @@ async fn bind_mesh_endpoint(
17721773
secret_key: SecretKey,
17731774
relay_urls: &[String],
17741775
relay_auths: &std::collections::HashMap<String, String>,
1776+
relay_disabled: bool,
17751777
quic_bind: QuicBindSelection,
17761778
) -> Result<Endpoint> {
17771779
let mut builder = Endpoint::builder(iroh::endpoint::presets::Minimal)
@@ -1782,12 +1784,17 @@ async fn bind_mesh_endpoint(
17821784
])
17831785
.transport_config(startup_transport_config());
17841786

1785-
let urls = effective_relay_urls(relay_urls);
1786-
tracing::info!("Relay: {:?}", urls);
1787-
builder = builder.relay_mode(iroh::endpoint::RelayMode::Custom(relay_map_from_urls(
1788-
&urls,
1789-
relay_auths,
1790-
)));
1787+
if relay_disabled {
1788+
tracing::info!("Relay: disabled");
1789+
builder = builder.relay_mode(iroh::endpoint::RelayMode::Disabled);
1790+
} else {
1791+
let urls = effective_relay_urls(relay_urls);
1792+
tracing::info!("Relay: {:?}", urls);
1793+
builder = builder.relay_mode(iroh::endpoint::RelayMode::Custom(relay_map_from_urls(
1794+
&urls,
1795+
relay_auths,
1796+
)));
1797+
}
17911798

17921799
if let Some(addr) = quic_bind_addr(quic_bind) {
17931800
tracing::info!("Binding QUIC to {addr}");
@@ -3265,9 +3272,16 @@ impl Node {
32653272
) -> Result<(Self, TunnelChannels)> {
32663273
let relay_urls = relay.urls;
32673274
let relay_auths = relay.auths;
3275+
let relay_disabled = relay.disabled;
32683276
let secret_key = startup_secret_key(&role).await?;
3269-
let endpoint =
3270-
bind_mesh_endpoint(secret_key.clone(), relay_urls, relay_auths, quic_bind).await?;
3277+
let endpoint = bind_mesh_endpoint(
3278+
secret_key.clone(),
3279+
relay_urls,
3280+
relay_auths,
3281+
relay_disabled,
3282+
quic_bind,
3283+
)
3284+
.await?;
32713285
// Wait briefly for relay connection so the invite token includes the relay URL.
32723286
// On sinkholed networks this times out and we proceed without relay (direct UDP only).
32733287
wait_for_endpoint_online(

‎crates/mesh-llm-host-runtime/src/runtime/mod.rs‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ pub(crate) struct EmbeddedRuntimeOptions {
167167
pub(crate) discovery_mode: EmbeddedRuntimeDiscoveryMode,
168168
pub(crate) relay: Vec<String>,
169169
pub(crate) relay_auth: Vec<(String, String)>,
170+
pub(crate) disable_iroh_relays: bool,
170171
pub(crate) nostr_relay: Vec<String>,
171172
pub(crate) region: Option<String>,
172173
pub(crate) node_name: Option<String>,
@@ -3283,6 +3284,7 @@ fn cli_from_embedded_options(options: EmbeddedRuntimeOptions) -> Cli {
32833284
};
32843285
cli.relay = options.relay;
32853286
cli.relay_auth = options.relay_auth;
3287+
cli.disable_iroh_relays = options.disable_iroh_relays;
32863288
cli.nostr_relay = options.nostr_relay;
32873289
cli.region = options.region;
32883290
cli.name = options.node_name;
@@ -5267,8 +5269,13 @@ async fn start_run_auto_node_and_plugins(
52675269
let (node, channels) = mesh::Node::start(
52685270
role,
52695271
mesh::RelayConfig {
5270-
urls: &cli.relay,
5272+
urls: if cli.disable_iroh_relays {
5273+
&[]
5274+
} else {
5275+
&cli.relay
5276+
},
52715277
auths: &relay_auths,
5278+
disabled: cli.disable_iroh_relays,
52725279
},
52735280
mesh::QuicBindSelection {
52745281
ip: cli.bind_ip,
@@ -6711,6 +6718,11 @@ async fn run_auto_handle_control_request(
67116718
cmd: api::RuntimeControlRequest,
67126719
) -> bool {
67136720
match cmd {
6721+
api::RuntimeControlRequest::Join { invite_token, resp } => {
6722+
let result = ctx.node.join_with_retry(&invite_token).await;
6723+
let _ = resp.send(result);
6724+
false
6725+
}
67146726
api::RuntimeControlRequest::Load { spec, resp } => {
67156727
let result = run_auto_load_runtime_model(ctx, spec).await;
67166728
let _ = resp.send(result);

‎crates/mesh-llm-host-runtime/src/sdk.rs‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ pub struct EmbeddedMeshNetworkConfig {
9797
pub node_name: Option<String>,
9898
pub iroh_relays: Vec<String>,
9999
pub iroh_relay_auth: BTreeMap<String, String>,
100+
pub disable_iroh_relays: bool,
100101
pub nostr_relays: Vec<String>,
101102
pub bind_ip: Option<IpAddr>,
102103
pub bind_port: Option<u16>,
@@ -116,6 +117,7 @@ impl Default for EmbeddedMeshNetworkConfig {
116117
node_name: None,
117118
iroh_relays: Vec::new(),
118119
iroh_relay_auth: BTreeMap::new(),
120+
disable_iroh_relays: false,
119121
nostr_relays: Vec::new(),
120122
bind_ip: None,
121123
bind_port: None,
@@ -296,6 +298,11 @@ impl EmbeddedMeshNodeBuilder {
296298
self
297299
}
298300

301+
pub fn disable_iroh_relays(mut self, disabled: bool) -> Self {
302+
self.config.network.disable_iroh_relays = disabled;
303+
self
304+
}
305+
299306
pub fn nostr_relay(mut self, url: impl Into<String>) -> Self {
300307
self.config.network.nostr_relays.push(url.into());
301308
self
@@ -369,6 +376,7 @@ pub struct EmbeddedServeConfig {
369376
pub discovery_mode: EmbeddedMeshDiscoveryMode,
370377
pub relay: Vec<String>,
371378
pub relay_auth: BTreeMap<String, String>,
379+
pub disable_iroh_relays: bool,
372380
pub nostr_relay: Vec<String>,
373381
pub region: Option<String>,
374382
pub node_name: Option<String>,
@@ -398,6 +406,7 @@ impl Default for EmbeddedServeConfig {
398406
discovery_mode: EmbeddedMeshDiscoveryMode::Nostr,
399407
relay: Vec::new(),
400408
relay_auth: BTreeMap::new(),
409+
disable_iroh_relays: false,
401410
nostr_relay: Vec::new(),
402411
region: None,
403412
node_name: None,
@@ -437,6 +446,7 @@ impl From<EmbeddedServeConfig> for EmbeddedMeshNodeConfig {
437446
node_name: config.node_name,
438447
iroh_relays: config.relay,
439448
iroh_relay_auth: config.relay_auth,
449+
disable_iroh_relays: config.disable_iroh_relays,
440450
nostr_relays: config.nostr_relay,
441451
bind_ip: config.bind_ip,
442452
bind_port: config.bind_port,
@@ -468,6 +478,7 @@ impl From<EmbeddedMeshNodeConfig> for EmbeddedServeConfig {
468478
discovery_mode: config.network.discovery_mode,
469479
relay: config.network.iroh_relays,
470480
relay_auth: config.network.iroh_relay_auth,
481+
disable_iroh_relays: config.network.disable_iroh_relays,
471482
nostr_relay: config.network.nostr_relays,
472483
region: config.network.region,
473484
node_name: config.network.node_name,
@@ -528,6 +539,22 @@ impl EmbeddedServeHandle {
528539
})
529540
}
530541

542+
pub async fn join_token(&self, invite_token: impl Into<String>) -> Result<()> {
543+
let control_tx = self
544+
.control_tx
545+
.as_ref()
546+
.context("embedded mesh runtime control channel is unavailable")?;
547+
let (resp, rx) = tokio::sync::oneshot::channel();
548+
control_tx
549+
.send(crate::api::RuntimeControlRequest::Join {
550+
invite_token: invite_token.into(),
551+
resp,
552+
})
553+
.map_err(|_| anyhow::anyhow!("embedded mesh runtime control channel is closed"))?;
554+
rx.await
555+
.context("embedded mesh runtime join response dropped")?
556+
}
557+
531558
pub async fn stop(mut self) -> Result<()> {
532559
if !self.request_shutdown("sdk") && !self.task_finished() {
533560
anyhow::bail!("embedded mesh runtime control channel is unavailable");
@@ -646,6 +673,7 @@ fn embedded_runtime_options(
646673
EmbeddedMeshDiscoveryMode::Mdns => crate::runtime::EmbeddedRuntimeDiscoveryMode::Mdns,
647674
},
648675
relay: config.network.iroh_relays.clone(),
676+
disable_iroh_relays: config.network.disable_iroh_relays,
649677
relay_auth: config
650678
.network
651679
.iroh_relay_auth
@@ -1093,6 +1121,7 @@ mod tests {
10931121
.max_vram_gb(3.0)
10941122
.iroh_relay("https://relay.example")
10951123
.iroh_relay_auth("https://relay.example", "token")
1124+
.disable_iroh_relays(true)
10961125
.nostr_relay("wss://nostr.example")
10971126
.bind_port(17777)
10981127
.build();
@@ -1109,6 +1138,7 @@ mod tests {
11091138
options.relay_auth,
11101139
vec![("https://relay.example".to_string(), "token".to_string())]
11111140
);
1141+
assert!(options.disable_iroh_relays);
11121142
assert_eq!(options.nostr_relay, vec!["wss://nostr.example".to_string()]);
11131143
assert_eq!(options.bind_port, Some(17777));
11141144
assert_eq!(options.log_format, crate::cli::LogFormat::Json);

‎crates/mesh-llm-sdk/src/lib.rs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ pub struct NetworkConfig {
4949
pub node_name: Option<String>,
5050
pub iroh_relays: Vec<String>,
5151
pub iroh_relay_auth: BTreeMap<String, String>,
52+
pub disable_iroh_relays: bool,
5253
pub nostr_relays: Vec<String>,
5354
pub bind_ip: Option<IpAddr>,
5455
pub bind_port: Option<u16>,
@@ -68,6 +69,7 @@ impl Default for NetworkConfig {
6869
node_name: None,
6970
iroh_relays: Vec::new(),
7071
iroh_relay_auth: BTreeMap::new(),
72+
disable_iroh_relays: false,
7173
nostr_relays: Vec::new(),
7274
bind_ip: None,
7375
bind_port: None,
@@ -186,6 +188,11 @@ macro_rules! impl_common_builder_methods {
186188
self
187189
}
188190

191+
pub fn disable_iroh_relays(mut self, disabled: bool) -> Self {
192+
self.config.network.disable_iroh_relays = disabled;
193+
self
194+
}
195+
189196
pub fn nostr_relay(mut self, url: impl Into<String>) -> Self {
190197
self.config.network.nostr_relays.push(url.into());
191198
self
@@ -265,6 +272,10 @@ impl EmbeddedNodeHandle {
265272
self.inner.status().await.map(EmbeddedNodeStatus::from)
266273
}
267274

275+
pub async fn join_token(&self, token: impl Into<String>) -> Result<()> {
276+
self.inner.join_token(token).await
277+
}
278+
268279
pub async fn stop(self) -> Result<()> {
269280
self.inner.stop().await
270281
}
@@ -489,6 +500,7 @@ fn host_config(parts: EmbeddedNodeParts) -> mesh_llm_host_runtime::sdk::Embedded
489500
node_name: parts.network.node_name,
490501
iroh_relays: parts.network.iroh_relays,
491502
iroh_relay_auth: parts.network.iroh_relay_auth,
503+
disable_iroh_relays: parts.network.disable_iroh_relays,
492504
nostr_relays: parts.network.nostr_relays,
493505
bind_ip: parts.network.bind_ip,
494506
bind_port: parts.network.bind_port,
@@ -520,6 +532,7 @@ mod tests {
520532
.api_port(19337)
521533
.console_port(13131)
522534
.discovery_mode(MeshDiscoveryMode::Mdns)
535+
.disable_iroh_relays(true)
523536
.log_format(LogFormat::Pretty)
524537
.build();
525538

@@ -528,6 +541,7 @@ mod tests {
528541
assert_eq!(config.http.api_port, 19337);
529542
assert_eq!(config.http.console_port, 13131);
530543
assert_eq!(config.network.discovery_mode, MeshDiscoveryMode::Mdns);
544+
assert!(config.network.disable_iroh_relays);
531545
assert_eq!(config.log_format, LogFormat::Pretty);
532546
}
533547

0 commit comments

Comments
 (0)