MudEngine Part 11: Peer-to-Peer (Hybrid)
Spawn iroh from the App component
The host needs to start the iroh endpoint, gossip, and (optionally) the relay. Desktop clients need to connect to the host's endpoint.
Use use_effect to spawn async tasks when the component mounts. The signals
(players, rooms, chat_messages) are written from the iroh message loop,
just like they were from the WebSocket receive loop before.
// ── Inside App component, after the connection screen ── if *mode.read() == "host" { let name = player_name.read().clone(); use_effect(move || { tokio::spawn(async move { let engine = Arc::new(GameEngine::load("game.toml")); let (endpoint, sink, _handle) = p2p::start_host(engine.clone(), true).await?; println!("🔗 Share this EndpointId with players:"); println!(" {}", endpoint.node_id()); // If relay feature is enabled, spawn the WebSocket bridge #[cfg(feature = "relay")] if let Err(e) = p2p::spawn_relay( sink.clone(), broadcast_receiver, 9090, ).await { eprintln!("Relay error: {e}"); } Ok::<_, anyhow::Error>(()) }); }); }
// ── Inside App component, when joining ── if *mode.read() == "join" { let host_id = host_id_input.read().clone(); use_effect(move || { tokio::spawn(async move { let (_endpoint, sink, mut rx) = p2p::connect_to_host(&host_id).await?; // Join the game p2p::broadcast(&sink, &ServerMessage::State { players: vec![], your_id: String::new(), rooms: vec![], quest_active: false, quest_completed: false, }).await; // Forward server messages to Dioxus signals while let Some(msg) = rx.recv().await { // Write to signals — same pattern as Part 7-9 receive loop } Ok::<_, anyhow::Error>(()) }); }); }
The Blitz renderer uses tokio internally. When you spawn a tokio task from
use_effect, it runs on the same runtime that drives the UI. This means
iroh's async operations and the Dioxus render loop coexist in the same
threadpool — no special wiring needed.
If you see tokio runtime panics, make sure the iroh tasks are spawned from
within a Dioxus component (which guarantees a tokio context). Never call
tokio::spawn before dioxus_native::launch.