From fb6a2c4950020d80fed0dfe8eb0be99a4d69e3b7 Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Quiros Date: Mon, 3 Oct 2022 19:04:08 +0200 Subject: [PATCH] Implemented peers --- waku/src/node/peers.rs | 168 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 waku/src/node/peers.rs diff --git a/waku/src/node/peers.rs b/waku/src/node/peers.rs new file mode 100644 index 0000000..59188b4 --- /dev/null +++ b/waku/src/node/peers.rs @@ -0,0 +1,168 @@ +// std +use std::ffi::{c_char, CStr, CString}; +use std::time::Duration; +// crates +use multiaddr::Multiaddr; +use serde::Deserialize; +// internal +use crate::general::{JsonResponse, PeerId, Result}; + +/// Add a node multiaddress and protocol to the waku node’s peerstore. +/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_add_peerchar-address-char-protocolid) +pub fn waku_add_peers(address: Multiaddr, protocol_id: usize) -> Result { + let response = unsafe { + CStr::from_ptr(waku_sys::waku_add_peer( + CString::new(address.to_string()) + .expect("CString should build properly from the address") + .into_raw(), + CString::new(protocol_id.to_string()) + .expect("CString should build properly from the protocol id") + .into_raw(), + )) + } + .to_str() + .expect("&str should build properly from the returning response"); + + let result: JsonResponse = + serde_json::from_str(response).expect("JsonResponse should always succeed to deserialize"); + + result.into() +} + +/// Dial peer using a multiaddress +/// If `timeout` as milliseconds doesn't fit into a `i32` it is clamped to [`i32::MAX`] +/// If the function execution takes longer than `timeout` value, the execution will be canceled and an error returned. +/// Use 0 for no timeout +/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_connect_peerchar-address-int-timeoutms) +pub fn waku_connect_peer_with_address(address: Multiaddr, timeout: Option) -> Result<()> { + let response = unsafe { + CStr::from_ptr(waku_sys::waku_connect( + CString::new(address.to_string()) + .expect("CString should build properly from multiaddress") + .into_raw(), + timeout + .map(|duration| duration.as_millis().try_into().unwrap_or(i32::MAX)) + .unwrap_or(0), + )) + } + .to_str() + .expect("&str should build properly from the returning response"); + + let result: JsonResponse = + serde_json::from_str(response).expect("JsonResponse should always succeed to deserialize"); + + Result::from(result).map(|_| ()) +} + +/// Dial peer using a peer id +/// If `timeout` as milliseconds doesn't fit into a `i32` it is clamped to [`i32::MAX`] +/// The peer must be already known. +/// It must have been added before with [`waku_add_peer`] or previously dialed with [`waku_connect_peer_with_address`] +/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_connect_peeridchar-peerid-int-timeoutms) +pub fn waku_connect_peer_with_id(peer_id: PeerId, timeout: Option) -> Result<()> { + let response = unsafe { + CStr::from_ptr(waku_sys::waku_connect( + CString::new(peer_id) + .expect("CString should build properly from peer id") + .into_raw(), + timeout + .map(|duration| duration.as_millis().try_into().unwrap_or(i32::MAX)) + .unwrap_or(0), + )) + } + .to_str() + .expect("&str should build properly from the returning response"); + + let result: JsonResponse = + serde_json::from_str(response).expect("JsonResponse should always succeed to deserialize"); + + Result::from(result).map(|_| ()) +} + +/// Disconnect a peer using its peer id +/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_disconnect_peerchar-peerid) +pub fn waku_disconnect_peer_with_id(peer_id: PeerId) -> Result<()> { + let response = unsafe { + CStr::from_ptr(waku_sys::waku_disconnect( + CString::new(peer_id) + .expect("CString should build properly from peer id") + .into_raw(), + )) + } + .to_str() + .expect("&str should build properly from the returning response"); + + let result: JsonResponse = + serde_json::from_str(response).expect("JsonResponse should always succeed to deserialize"); + + Result::from(result).map(|_| ()) +} + +/// Get number of connected peers +/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_peer_count) +pub fn waku_peer_count() -> Result { + let response = unsafe { CStr::from_ptr(waku_sys::waku_peer_cnt()) } + .to_str() + .expect("&str should build properly from the returning response"); + + let result: JsonResponse = + serde_json::from_str(response).expect("JsonResponse should always succeed to deserialize"); + + result.into() +} + +pub type Protocol = String; + +/// Peer data from known/connected waku nodes +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct WakuPeerData { + /// Waku peer id + #[serde(alias = "peerID")] + peer_id: PeerId, + /// Supported node protocols + protocols: Vec, + /// Node available addresses + #[serde(alias = "addrs")] + addresses: Vec, + /// Already connected flag + connected: bool, +} + +/// List of [`WakuPeerData`], return value from [`waku_peers`] funtion +pub type WakuPeers = Vec; + +/// Retrieve the list of peers known by the Waku node +/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_peers) +pub fn waku_peers() -> Result { + let response = unsafe { CStr::from_ptr(waku_sys::waku_peers()) } + .to_str() + .expect("&str should build properly from the returning response"); + + let result: JsonResponse = + serde_json::from_str(response).expect("JsonResponse should always succeed to deserialize"); + + result.into() +} + +#[cfg(test)] +mod tests { + use crate::node::peers::WakuPeerData; + + #[test] + fn deserialize_waku_peer_data() { + let json_str = r#"{ + "peerID": "16Uiu2HAmJb2e28qLXxT5kZxVUUoJt72EMzNGXB47RedcBafeDCBA", + "protocols": [ + "/ipfs/id/1.0.0", + "/vac/waku/relay/2.0.0", + "/ipfs/ping/1.0.0" + ], + "addrs": [ + "/ip4/1.2.3.4/tcp/30303" + ], + "connected": true + }"#; + let data: WakuPeerData = serde_json::from_str(json_str).unwrap(); + } +}