Skip to content

Instantly share code, notes, and snippets.

@sireliah
Created December 21, 2021 23:01
Show Gist options
  • Select an option

  • Save sireliah/2d5924e65ed71d62c9acad2ccd516793 to your computer and use it in GitHub Desktop.

Select an option

Save sireliah/2d5924e65ed71d62c9acad2ccd516793 to your computer and use it in GitHub Desktop.
Rendezvous in wasm
use libp2p::{
core::transport::upgrade,
futures::StreamExt,
identity, mplex, noise,
ping::{Ping, PingConfig, PingEvent},
rendezvous,
swarm::{AddressScore, SwarmBuilder, SwarmEvent},
Multiaddr, NetworkBehaviour, PeerId, Swarm, Transport,
};
use libp2p::wasm_ext;
use std::time::Duration;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
mod utils;
macro_rules! console_log {
// Note that this is using the `log` function imported above during
// `bare_bones`
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
#[derive(Debug)]
enum MyEvent {
Ping(PingEvent),
Rendezvous(rendezvous::client::Event),
}
impl From<PingEvent> for MyEvent {
fn from(event: PingEvent) -> Self {
MyEvent::Ping(event)
}
}
#[derive(NetworkBehaviour)]
#[behaviour(out_event = "MyEvent")]
struct MyBehaviour {
rendezvous: rendezvous::client::Behaviour,
ping: Ping,
}
impl From<rendezvous::client::Event> for MyEvent {
fn from(event: rendezvous::client::Event) -> Self {
MyEvent::Rendezvous(event)
}
}
fn build_ws_swarm(local_keys: identity::Keypair) -> Swarm<MyBehaviour> {
let local_peer_id = PeerId::from(&local_keys.public());
console_log!("I am peer {:?}", local_peer_id);
let transport = {
let transport_base = wasm_ext::ffi::websocket_transport();
let transport_base = wasm_ext::ExtTransport::new(transport_base);
let noise_keys = noise::Keypair::<noise::X25519Spec>::new()
.into_authentic(&local_keys)
.expect("Failed to produce noise keys");
let mut mplex_config = mplex::MplexConfig::new();
let mp = mplex_config
.set_max_buffer_size(40960)
.set_split_send_size(1024 * 512);
let noise = noise::NoiseConfig::xx(noise_keys).into_authenticated();
transport_base
.upgrade(upgrade::Version::V1Lazy)
.authenticate(noise)
.multiplex(mp.clone())
.timeout(std::time::Duration::from_secs(20))
.boxed()
};
let behaviour = MyBehaviour {
rendezvous: rendezvous::client::Behaviour::new(local_keys),
ping: Ping::new(PingConfig::new().with_interval(Duration::from_secs(1))),
};
let swarm = SwarmBuilder::new(transport, behaviour, local_peer_id);
swarm.build()
}
#[wasm_bindgen]
pub fn info(message: &str) {
log(message);
}
#[wasm_bindgen]
pub async fn listen(peer_address: String) {
utils::set_panic_hook();
let local_keys = identity::Keypair::generate_ed25519();
let local_keys_clone = local_keys.clone();
let mut swarm = build_ws_swarm(local_keys);
let rendezvous_addr = "/ip4/127.0.0.1/tcp/45555/ws".parse::<Multiaddr>().unwrap();
swarm.add_external_address(rendezvous_addr.clone(), AddressScore::Infinite);
swarm
.dial(rendezvous_addr)
.expect("Dialing rendezvous failed");
let sw = async move {
while let Some(event) = swarm.next().await {
match event {
SwarmEvent::NewListenAddr {
listener_id,
address,
} => {
console_log!("New listener: {:?}, Address: {:?}", listener_id, address);
if peer_address.len() > 0 {
let addr = peer_address
.parse::<Multiaddr>()
.expect("Parsing address failed");
swarm.dial(addr).expect("Dialing failed");
}
}
SwarmEvent::ConnectionEstablished { peer_id, .. } => {
console_log!("Connection established: {:?}", peer_id);
// TODO: check if this is rendezvous server
let behaviour = swarm.behaviour_mut();
let namespace = rendezvous::Namespace::new("discovery".to_string())
.expect("Failed to create namespace");
let namespace_c = namespace.clone();
console_log!("Registering");
behaviour.rendezvous.register(namespace, peer_id, None);
console_log!("Discovering");
behaviour
.rendezvous
.discover(Some(namespace_c), None, None, peer_id);
}
SwarmEvent::Behaviour(MyEvent::Rendezvous(
rendezvous::client::Event::Registered { namespace, .. },
)) => {
console_log!("Registered in {:?}", namespace);
}
other => console_log!("Event: {:?}", other),
}
}
swarm
};
sw.await;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment