Skip to content

feat: Add WebSocket and WebRTC transports to relay server example #6030

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

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

5 changes: 4 additions & 1 deletion examples/relay-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ release = false
clap = { version = "4.5.6", features = ["derive"] }
tokio = { version = "1.37.0", features = ["full"] }
futures = { workspace = true }
libp2p = { path = "../../libp2p", features = ["tokio", "noise", "macros", "ping", "tcp", "identify", "yamux", "relay", "quic"] }
libp2p = { path = "../../libp2p", features = ["tokio", "noise", "macros", "ping", "tcp", "identify", "yamux", "relay", "quic", "websocket", "dns", "tls"] }
libp2p-webrtc = { workspace = true, features = ["tokio"] }
tracing-subscriber = { workspace = true, features = ["env-filter"] }
tracing = "0.1"
rand = "0.8"

[lints]
workspace = true
15 changes: 11 additions & 4 deletions examples/relay-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@ To run the example, follow these steps:
```

Replace `<port>` with the port number on which the relay node will listen for incoming connections.

Replace `<seed>` with a seed value used to generate a deterministic peer ID for the relay node.

2. The relay node will start listening for incoming connections.

Replace `<ws-port>` with the port number on which the relay node will listen for websocket incoming connections.

Replace `<wrtc-port>` with the port number on which the relay node will listen for webrtc incoming connections.

If you do **not** provide `--websocket-port` or `--webrtc-port`, the relay will **not** listen on those transports.

3. The relay node will start listening for incoming connections.
It will print the listening address once it is ready.

3. Connect other **libp2p** nodes to the relay node by specifying the relay's listening address as one of the bootstrap nodes in their configuration.
4. Connect other **libp2p** nodes to the relay node by specifying the relay's listening address as one of the bootstrap nodes in their configuration.

4. Once the connections are established, the relay node will facilitate communication between the connected peers, allowing them to exchange messages and data.
5. Once the connections are established, the relay node will facilitate communication between the connected peers, allowing them to exchange messages and data.

## Conclusion

Expand Down
67 changes: 64 additions & 3 deletions examples/relay-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ use std::{
use clap::Parser;
use futures::StreamExt;
use libp2p::{
core::{multiaddr::Protocol, Multiaddr},
core::{multiaddr::Protocol, muxing::StreamMuxerBox, Multiaddr, Transport},
identify, identity, noise, ping, relay,
swarm::{NetworkBehaviour, SwarmEvent},
tcp, yamux,
tcp, yamux, PeerId, Swarm,
};
use libp2p_webrtc as webrtc;
use rand::thread_rng;
use tracing::info;
use tracing_subscriber::EnvFilter;

#[tokio::main]
Expand All @@ -46,6 +49,8 @@ async fn main() -> Result<(), Box<dyn Error>> {

// Create a static known PeerId based on given secret
let local_key: identity::Keypair = generate_ed25519(opt.secret_key_seed);
let local_peer_id = PeerId::from(local_key.public());
info!(?local_peer_id, "Local peer id");

let mut swarm = libp2p::SwarmBuilder::with_existing_identity(local_key)
.with_tokio()
Expand All @@ -55,6 +60,16 @@ async fn main() -> Result<(), Box<dyn Error>> {
yamux::Config::default,
)?
.with_quic()
.with_other_transport(|id_keys| {
Ok(webrtc::tokio::Transport::new(
id_keys.clone(),
webrtc::tokio::Certificate::generate(&mut thread_rng())?,
)
.map(|(peer_id, conn), _| (peer_id, StreamMuxerBox::new(conn))))
})?
.with_dns()?
.with_websocket(noise::Config::new, yamux::Config::default)
.await?
.with_behaviour(|key| Behaviour {
relay: relay::Behaviour::new(key.public().to_peer_id(), Default::default()),
ping: ping::Behaviour::new(ping::Config::new()),
Expand Down Expand Up @@ -83,6 +98,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
.with(Protocol::QuicV1);
swarm.listen_on(listen_addr_quic)?;

listen_on_websocket(&mut swarm, &opt)?;
listen_on_webrtc(&mut swarm, &opt)?;

loop {
match swarm.next().await.expect("Infinite Stream.") {
SwarmEvent::Behaviour(event) => {
Expand All @@ -96,14 +114,49 @@ async fn main() -> Result<(), Box<dyn Error>> {

println!("{event:?}")
}
SwarmEvent::NewListenAddr { address, .. } => {
SwarmEvent::NewListenAddr { mut address, .. } => {
address.push(Protocol::P2p(local_peer_id));
println!("Listening on {address:?}");
}
_ => {}
}
}
}

fn listen_on_websocket(swarm: &mut Swarm<Behaviour>, opt: &Opt) -> Result<(), Box<dyn Error>> {
match opt.websocket_port {
Some(port) => {
let address = Multiaddr::from(Ipv4Addr::UNSPECIFIED)
.with(Protocol::Tcp(port))
.with(Protocol::Ws(std::borrow::Cow::Borrowed("/")));

info!(?address, "Listening on webSocket");
swarm.listen_on(address.clone())?;
}
None => {
info!("Does not use websocket");
}
}
Ok(())
}

fn listen_on_webrtc(swarm: &mut Swarm<Behaviour>, opt: &Opt) -> Result<(), Box<dyn Error>> {
match opt.webrtc_port {
Some(port) => {
let address = Multiaddr::from(Ipv4Addr::UNSPECIFIED)
.with(Protocol::Udp(port))
.with(Protocol::WebRTCDirect);

info!(?address, "Listening on webRTC");
swarm.listen_on(address.clone())?;
}
None => {
info!("Does not use webRTC");
}
}
Ok(())
}

#[derive(NetworkBehaviour)]
struct Behaviour {
relay: relay::Behaviour,
Expand Down Expand Up @@ -132,4 +185,12 @@ struct Opt {
/// The port used to listen on all interfaces
#[arg(long)]
port: u16,

/// The websocket port used to listen on all interfaces
#[arg(long)]
websocket_port: Option<u16>,

/// The webrtc port used to listen on all interfaces
#[arg(long)]
webrtc_port: Option<u16>,
}
Loading