diff --git a/waku/common/peers.go b/waku/common/peers.go new file mode 100644 index 0000000..43064c2 --- /dev/null +++ b/waku/common/peers.go @@ -0,0 +1,68 @@ +package common + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/protocol" + "github.com/multiformats/go-multiaddr" +) + +type PeersData map[peer.ID]PeerInfo +type PeerInfo struct { + Protocols []protocol.ID `json:"protocols"` + Addresses []multiaddr.Multiaddr `json:"addresses"` +} + +func ParsePeerInfoFromJSON(jsonStr string) (PeersData, error) { + // Create a temporary map to unmarshal the JSON data + var rawMap map[string]struct { + Protocols []string `json:"protocols"` + Addresses []string `json:"addresses"` + } + + // Unmarshal the JSON string to our temporary map + if err := json.Unmarshal([]byte(jsonStr), &rawMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal JSON: %w", err) + } + + // Create the result map + result := make(PeersData) + + // Process each peer entry + for peerIDStr, rawPeer := range rawMap { + // Parse the peer ID + peerID, err := peer.Decode(peerIDStr) + if err != nil { + return nil, fmt.Errorf("failed to decode peer ID %s: %w", peerIDStr, err) + } + + // Convert protocols to libp2pproto.ID + protocols := make([]protocol.ID, len(rawPeer.Protocols)) + for i, protoStr := range rawPeer.Protocols { + protocols[i] = protocol.ID(protoStr) + } + + // Convert addresses to multiaddr.Multiaddr + addresses := make([]multiaddr.Multiaddr, 0, len(rawPeer.Addresses)) + for _, addrStr := range rawPeer.Addresses { + addr, err := multiaddr.NewMultiaddr(addrStr) + if err != nil { + // Log the error but continue with other addresses + log.Printf("failed to parse multiaddress %s: %v", addrStr, err) + continue + } + addresses = append(addresses, addr) + } + + // Add the peer to the result map + result[peerID] = PeerInfo{ + Protocols: protocols, + Addresses: addresses, + } + } + + return result, nil +} diff --git a/waku/nwaku.go b/waku/nwaku.go index b5f3eb6..9402785 100644 --- a/waku/nwaku.go +++ b/waku/nwaku.go @@ -239,6 +239,10 @@ package waku waku_get_peerids_from_peerstore(wakuCtx, (WakuCallBack) GoCallback, resp); } + static void cGoWakuGetConnectedPeersInfo(void* wakuCtx, void* resp) { + waku_get_connected_peers_info(wakuCtx, (WakuCallBack) GoCallback, resp); + } + static void cGoWakuLightpushPublish(void* wakuCtx, const char* pubSubTopic, const char* jsonWakuMessage, @@ -1176,6 +1180,33 @@ func (n *WakuNode) GetPeerIDsFromPeerStore() (peer.IDSlice, error) { return nil, fmt.Errorf("GetPeerIdsFromPeerStore: %s", errMsg) } +func (n *WakuNode) GetConnectedPeersInfo() (common.PeersData, error) { + wg := sync.WaitGroup{} + + var resp = C.allocResp(unsafe.Pointer(&wg)) + defer C.freeResp(resp) + + wg.Add(1) + C.cGoWakuGetConnectedPeersInfo(n.wakuCtx, resp) + wg.Wait() + if C.getRet(resp) == C.RET_OK { + jsonStr := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp))) + if jsonStr == "" { + return nil, nil + } + + peerData, err := common.ParsePeerInfoFromJSON(jsonStr) + + if err != nil { + return nil, fmt.Errorf("GetConnectedPeersInfo - failed parsing JSON: %w", err) + } + + return peerData, nil + } + errMsg := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp))) + return nil, fmt.Errorf("GetConnectedPeersInfo: %s", errMsg) +} + func (n *WakuNode) GetPeerIDsByProtocol(protocol libp2pproto.ID) (peer.IDSlice, error) { wg := sync.WaitGroup{} diff --git a/waku/peer_connections_test.go b/waku/peer_connections_test.go index 095a4ab..3fba754 100644 --- a/waku/peer_connections_test.go +++ b/waku/peer_connections_test.go @@ -144,6 +144,62 @@ func TestConnectUsingMultipleStaticPeers(t *testing.T) { Debug("Test passed: multiple nodes connected to a single node using Static Peers") } +func TestPeerData(t *testing.T) { + Debug("Starting TestPeerData") + + node1, err := StartWakuNode("node1", nil) + require.NoError(t, err, "Failed to start Node 1") + + node2, err := StartWakuNode("node2", nil) + require.NoError(t, err, "Failed to start Node 2") + + node3, err := StartWakuNode("node3", nil) + require.NoError(t, err, "Failed to start Node 3") + + addr1, err := node1.ListenAddresses() + require.NoError(t, err, "Failed to get listen addresses for Node 1") + + addr2, err := node2.ListenAddresses() + require.NoError(t, err, "Failed to get listen addresses for Node 2") + + addr3, err := node3.ListenAddresses() + require.NoError(t, err, "Failed to get listen addresses for Node 3") + + node4Config := DefaultWakuConfig + node4Config.Discv5Discovery = false + node4Config.Staticnodes = []string{addr1[0].String(), addr2[0].String(), addr3[0].String()} + + node4, err := StartWakuNode("node4", &node4Config) + require.NoError(t, err, "Failed to start Node 4") + + defer func() { + Debug("Stopping and destroying all Waku nodes") + node1.StopAndDestroy() + node2.StopAndDestroy() + node3.StopAndDestroy() + node4.StopAndDestroy() + }() + + Debug("Verifying connected peers for Node 4") + connectedPeers, err := node4.GetConnectedPeers() + require.NoError(t, err, "Failed to get connected peers for Node 4") + + node1PeerID, err := node1.PeerID() + require.NoError(t, err, "Failed to get PeerID for Node 1") + node2PeerID, err := node2.PeerID() + require.NoError(t, err, "Failed to get PeerID for Node 2") + node3PeerID, err := node3.PeerID() + require.NoError(t, err, "Failed to get PeerID for Node 3") + + require.True(t, slices.Contains(connectedPeers, node1PeerID), "Node 1 should be a peer of Node 4") + require.True(t, slices.Contains(connectedPeers, node2PeerID), "Node 2 should be a peer of Node 4") + require.True(t, slices.Contains(connectedPeers, node3PeerID), "Node 3 should be a peer of Node 4") + + node4.GetConnectedPeersInfo() + + Debug("Test passed: multiple nodes connected to a single node using Static Peers") +} + func TestDiscv5PeerMeshCount(t *testing.T) { Debug("Starting test to verify peer count in mesh using Discv5 after topic subscription")