From 978bedfafa83047407b56133fd60561308dafeab Mon Sep 17 00:00:00 2001 From: Anthony Laibe Date: Wed, 10 Nov 2021 14:36:51 +0100 Subject: [PATCH] feat: add admin rpc methods --- waku/v2/node/connectedness.go | 2 +- waku/v2/node/wakunode2.go | 30 ++++++++++++++- waku/v2/rpc/admin.go | 71 +++++++++++++++++++++++++++++++++++ waku/v2/rpc/admin_test.go | 62 ++++++++++++++++++++++++++++++ waku/v2/rpc/relay.go | 5 --- waku/v2/rpc/rpc_type.go | 6 +++ waku/v2/rpc/waku_rpc.go | 5 +++ waku/v2/utils/peer_test.go | 2 - 8 files changed, 174 insertions(+), 9 deletions(-) create mode 100644 waku/v2/rpc/admin.go create mode 100644 waku/v2/rpc/admin_test.go create mode 100644 waku/v2/rpc/rpc_type.go diff --git a/waku/v2/node/connectedness.go b/waku/v2/node/connectedness.go index 4a72f4b3..0a20d0e8 100644 --- a/waku/v2/node/connectedness.go +++ b/waku/v2/node/connectedness.go @@ -77,7 +77,7 @@ func (c ConnectionNotifier) Close() { func (w *WakuNode) sendConnStatus() { isOnline, hasHistory := w.Status() if w.connStatusChan != nil { - connStatus := ConnStatus{IsOnline: isOnline, HasHistory: hasHistory, Peers: w.Peers()} + connStatus := ConnStatus{IsOnline: isOnline, HasHistory: hasHistory, Peers: w.PeerStats()} w.connStatusChan <- connStatus } diff --git a/waku/v2/node/wakunode2.go b/waku/v2/node/wakunode2.go index 32b3de51..81cd882c 100644 --- a/waku/v2/node/wakunode2.go +++ b/waku/v2/node/wakunode2.go @@ -10,6 +10,7 @@ import ( "github.com/libp2p/go-libp2p-core/event" "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peerstore" p2pproto "github.com/libp2p/go-libp2p-core/protocol" @@ -32,6 +33,13 @@ var log = logging.Logger("wakunode") type Message []byte +type Peer struct { + ID peer.ID + Protocols []string + Addrs []ma.Multiaddr + Connected bool +} + type WakuNode struct { host host.Host opts *WakuNodeParameters @@ -383,7 +391,7 @@ func (w *WakuNode) PeerCount() int { return len(w.host.Network().Peers()) } -func (w *WakuNode) Peers() PeerStats { +func (w *WakuNode) PeerStats() PeerStats { p := make(PeerStats) for _, peerID := range w.host.Network().Peers() { protocols, err := w.host.Peerstore().GetProtocols(peerID) @@ -395,6 +403,26 @@ func (w *WakuNode) Peers() PeerStats { return p } +func (w *WakuNode) Peers() ([]*Peer, error) { + var peers []*Peer + for _, peerId := range w.host.Peerstore().Peers() { + connected := w.host.Network().Connectedness(peerId) == network.Connected + protocols, err := w.host.Peerstore().GetProtocols(peerId) + if err != nil { + return nil, err + } + + addrs := w.host.Peerstore().Addrs(peerId) + peers = append(peers, &Peer{ + ID: peerId, + Protocols: protocols, + Connected: connected, + Addrs: addrs, + }) + } + return peers, nil +} + // startKeepAlive creates a go routine that periodically pings connected peers. // This is necessary because TCP connections are automatically closed due to inactivity, // and doing a ping will avoid this (with a small bandwidth cost) diff --git a/waku/v2/rpc/admin.go b/waku/v2/rpc/admin.go new file mode 100644 index 00000000..32d6a9f3 --- /dev/null +++ b/waku/v2/rpc/admin.go @@ -0,0 +1,71 @@ +package rpc + +import ( + "net/http" + + ma "github.com/multiformats/go-multiaddr" + + "github.com/status-im/go-waku/waku/v2/node" +) + +type AdminService struct { + node *node.WakuNode +} + +type GetPeersArgs struct { +} + +type PeersArgs struct { + Peers []string `json:"peers,omitempty"` +} + +type PeerReply struct { + Multiaddr string `json:"mutliaddr,omitempty"` + Protocol string `json:"protocol,omitempty"` + Connected bool `json:"connected,omitempty"` +} + +type PeersReply struct { + Peers []PeerReply `json:"peers,omitempty"` +} + +func (a *AdminService) PostV1Peers(req *http.Request, args *PeersArgs, reply *SuccessReply) error { + for _, peer := range args.Peers { + addr, err := ma.NewMultiaddr(peer) + if err != nil { + log.Error("Error building multiaddr", err) + reply.Success = false + reply.Error = err.Error() + return nil + } + + err = a.node.DialPeerWithMultiAddress(req.Context(), addr) + if err != nil { + log.Error("Error dialing peers", err) + reply.Success = false + reply.Error = err.Error() + return nil + } + } + + reply.Success = true + return nil +} + +func (a *AdminService) GetV1Peers(req *http.Request, args *GetPeersArgs, reply *PeersReply) error { + peers, err := a.node.Peers() + if err != nil { + log.Error("Error getting peers", err) + return nil + } + for _, peer := range peers { + for idx, addr := range peer.Addrs { + reply.Peers = append(reply.Peers, PeerReply{ + Multiaddr: addr.String(), + Protocol: peer.Protocols[idx], + Connected: peer.Connected, + }) + } + } + return nil +} diff --git a/waku/v2/rpc/admin_test.go b/waku/v2/rpc/admin_test.go new file mode 100644 index 00000000..9110f6e6 --- /dev/null +++ b/waku/v2/rpc/admin_test.go @@ -0,0 +1,62 @@ +package rpc + +import ( + "bytes" + "context" + "crypto/rand" + "fmt" + "net/http" + "testing" + + "github.com/multiformats/go-multiaddr" + + "github.com/status-im/go-waku/tests" + "github.com/status-im/go-waku/waku/v2/node" + "github.com/stretchr/testify/require" +) + +func makeAdminService(t *testing.T) *AdminService { + options := node.WithWakuRelay() + n, err := node.New(context.Background(), options) + require.NoError(t, err) + err = n.Start() + require.NoError(t, err) + return &AdminService{n} +} + +func TestV1Peers(t *testing.T) { + port, err := tests.FindFreePort(t, "", 5) + require.NoError(t, err) + + host, err := tests.MakeHost(context.Background(), port, rand.Reader) + require.NoError(t, err) + + var reply PeersReply + + request, err := http.NewRequest(http.MethodPost, "url", bytes.NewReader([]byte(""))) + require.NoError(t, err) + + a := makeAdminService(t) + + err = a.GetV1Peers(request, &GetPeersArgs{}, &reply) + require.NoError(t, err) + require.Len(t, reply.Peers, 0) + + var reply2 SuccessReply + + hostInfo, err := multiaddr.NewMultiaddr(fmt.Sprintf("/p2p/%s", host.ID().Pretty())) + require.NoError(t, err) + + var addr multiaddr.Multiaddr + for _, a := range host.Addrs() { + addr = a.Encapsulate(hostInfo) + break + } + err = a.PostV1Peers(request, &PeersArgs{Peers: []string{addr.String()}}, &reply2) + require.NoError(t, err) + require.True(t, reply2.Success) + + err = a.GetV1Peers(request, &GetPeersArgs{}, &reply) + require.NoError(t, err) + require.Len(t, reply.Peers, 2) +} diff --git a/waku/v2/rpc/relay.go b/waku/v2/rpc/relay.go index 145f8f83..fd1a52da 100644 --- a/waku/v2/rpc/relay.go +++ b/waku/v2/rpc/relay.go @@ -21,11 +21,6 @@ type TopicsArgs struct { Topics []string `json:"topics,omitempty"` } -type SuccessReply struct { - Success bool `json:"success,omitempty"` - Error string `json:"error,omitempty"` -} - func (r *RelayService) PostV1Message(req *http.Request, args *RelayMessageArgs, reply *SuccessReply) error { _, err := r.node.Relay().Publish(req.Context(), &args.Message, (*relay.Topic)(&args.Topic)) if err != nil { diff --git a/waku/v2/rpc/rpc_type.go b/waku/v2/rpc/rpc_type.go new file mode 100644 index 00000000..f2d8c10a --- /dev/null +++ b/waku/v2/rpc/rpc_type.go @@ -0,0 +1,6 @@ +package rpc + +type SuccessReply struct { + Success bool `json:"success,omitempty"` + Error string `json:"error,omitempty"` +} diff --git a/waku/v2/rpc/waku_rpc.go b/waku/v2/rpc/waku_rpc.go index a4b9fa4a..1cd045ab 100644 --- a/waku/v2/rpc/waku_rpc.go +++ b/waku/v2/rpc/waku_rpc.go @@ -38,6 +38,11 @@ func NewWakuRpc(node *node.WakuNode, address string, port int) *WakuRpc { log.Error(err) } + err = s.RegisterService(&AdminService{node}, "Admin") + if err != nil { + log.Error(err) + } + mux := http.NewServeMux() mux.HandleFunc("/jsonrpc", func(w http.ResponseWriter, r *http.Request) { t := time.Now() diff --git a/waku/v2/utils/peer_test.go b/waku/v2/utils/peer_test.go index 011bd11d..f32ae92b 100644 --- a/waku/v2/utils/peer_test.go +++ b/waku/v2/utils/peer_test.go @@ -3,7 +3,6 @@ package utils import ( "context" "crypto/rand" - "fmt" "testing" "time" @@ -71,7 +70,6 @@ func TestSelectPeerWithLowestRTT(t *testing.T) { // No peers with selected protocol _, err = SelectPeerWithLowestRTT(ctx, h1, proto) - fmt.Println(err) require.Error(t, ErrNoPeersAvailable, err) // Peers with selected protocol