Feat: implement admin rest api (#827)

* feat: implement Admin rest API to fetch and add peers
This commit is contained in:
Prem Chaitanya Prathi 2023-10-25 00:55:04 +05:30 committed by GitHub
parent 9b9fc634cb
commit 3d69e78cf3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 236 additions and 18 deletions

View File

@ -505,7 +505,7 @@ func Execute(options NodeOptions) error {
var restServer *rest.WakuRest var restServer *rest.WakuRest
if options.RESTServer.Enable { if options.RESTServer.Enable {
wg.Add(1) wg.Add(1)
restServer = rest.NewWakuRest(wakuNode, options.RESTServer.Address, options.RESTServer.Port, options.PProf, options.RESTServer.RelayCacheCapacity, logger) restServer = rest.NewWakuRest(wakuNode, options.RESTServer.Address, options.RESTServer.Port, options.PProf, options.RESTServer.Admin, options.RESTServer.RelayCacheCapacity, logger)
restServer.Start(ctx, &wg) restServer.Start(ctx, &wg)
} }

View File

@ -0,0 +1,120 @@
package rest
import (
"encoding/json"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/protocol"
ma "github.com/multiformats/go-multiaddr"
"github.com/waku-org/go-waku/cmd/waku/server"
"github.com/waku-org/go-waku/logging"
"github.com/waku-org/go-waku/waku/v2/node"
"github.com/waku-org/go-waku/waku/v2/peerstore"
waku_proto "github.com/waku-org/go-waku/waku/v2/protocol"
"go.uber.org/zap"
)
type AdminService struct {
node *node.WakuNode
mux *chi.Mux
log *zap.Logger
}
type WakuPeer struct {
ID string `json:"id"`
MultiAddrs []string `json:"multiaddrs"`
Protocols []string `json:"protocols"`
Connected bool `json:"connected"`
}
type WakuPeerInfo struct {
MultiAddr string `json:"multiaddr"`
Shards []int `json:"shards"`
Protocols []string `json:"protocols"`
}
const routeAdminV1Peers = "/admin/v1/peers"
func NewAdminService(node *node.WakuNode, m *chi.Mux, log *zap.Logger) *AdminService {
d := &AdminService{
node: node,
mux: m,
log: log,
}
m.Get(routeAdminV1Peers, d.getV1Peers)
m.Post(routeAdminV1Peers, d.postV1Peer)
return d
}
func (a *AdminService) getV1Peers(w http.ResponseWriter, req *http.Request) {
peers, err := a.node.Peers()
if err != nil {
writeErrOrResponse(w, err, nil)
return
}
response := make([]WakuPeer, 0)
for _, peer := range peers {
wPeer := WakuPeer{
ID: peer.ID.Pretty(),
Connected: peer.Connected,
}
for _, addr := range peer.Addrs {
wPeer.MultiAddrs = append(wPeer.MultiAddrs, addr.String())
}
for _, proto := range peer.Protocols {
if !server.IsWakuProtocol(proto) {
continue
}
wPeer.Protocols = append(wPeer.Protocols, string(proto))
}
response = append(response, wPeer)
}
writeErrOrResponse(w, nil, response)
}
func (a *AdminService) postV1Peer(w http.ResponseWriter, req *http.Request) {
var pInfo WakuPeerInfo
var topics []string
var protos []protocol.ID
decoder := json.NewDecoder(req.Body)
if err := decoder.Decode(&pInfo); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
defer req.Body.Close()
addr, err := ma.NewMultiaddr(pInfo.MultiAddr)
if err != nil {
a.log.Error("building multiaddr", zap.Error(err))
writeErrOrResponse(w, err, nil)
return
}
for _, shard := range pInfo.Shards {
topic := waku_proto.NewStaticShardingPubsubTopic(waku_proto.ClusterIndex, uint16(shard))
topics = append(topics, topic.String())
}
id, err := a.node.AddPeer(addr, peerstore.Static, topics, protos...)
if err != nil {
a.log.Error("failed to add peer", zap.Error(err))
writeErrOrResponse(w, err, nil)
return
}
a.log.Info("add peer successful", logging.HostID("peerID", id))
pi := peer.AddrInfo{ID: id, Addrs: []ma.Multiaddr{addr}}
err = a.node.Host().Connect(req.Context(), pi)
if err != nil {
a.log.Error("failed to connect to peer", logging.HostID("peerID", id), zap.Error(err))
writeErrOrResponse(w, err, nil)
return
}
writeErrOrResponse(w, nil, nil)
}

View File

@ -0,0 +1,88 @@
openapi: 3.0.3
info:
title: Waku V2 node REST API
version: 1.0.0
contact:
name: VAC Team
url: https://forum.vac.dev/
tags:
- name: admin
description: Admin REST API for WakuV2 node
paths:
/admin/v1/peers:
get:
summary: Get connected peers info
description: Retrieve information about connected peers.
operationId: getPeerInfo
tags:
- admin
responses:
'200':
description: Information about a Waku v2 node.
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/WakuPeer'
'5XX':
description: Unexpected error.
post:
summary: Adds new peer(s) to connect with
description: Adds new peer(s) to connect with.
operationId: postPeerInfo
tags:
- admin
requestBody:
content:
application/json:
schema:
type: object
items:
$ref: '#/components/schemas/WakuPeerInfo'
responses:
'200':
description: Ok
'400':
description: Cannot connect to one or more peers.
'5XX':
description: Unexpected error.
components:
schemas:
WakuPeerInfo:
type: object
required:
- multiaddr
- shards
- protocols
protocols:
type: array
items:
type: string
shards:
type: array
items:
type: integer
WakuPeer:
type: object
required:
- id
- addrs
- protocols
- connected
properties:
connected:
type: string
addrs:
type: array
items:
type: string
protocols:
type: array
items:
type: string
connected:
type: boolean

View File

@ -21,7 +21,7 @@ type WakuRest struct {
relayService *RelayService relayService *RelayService
} }
func NewWakuRest(node *node.WakuNode, address string, port int, enablePProf bool, relayCacheCapacity int, log *zap.Logger) *WakuRest { func NewWakuRest(node *node.WakuNode, address string, port int, enablePProf bool, enableAdmin bool, relayCacheCapacity int, log *zap.Logger) *WakuRest {
wrpc := new(WakuRest) wrpc := new(WakuRest)
wrpc.log = log.Named("rest") wrpc.log = log.Named("rest")
@ -56,6 +56,10 @@ func NewWakuRest(node *node.WakuNode, address string, port int, enablePProf bool
wrpc.relayService = relayService wrpc.relayService = relayService
} }
if enableAdmin {
_ = NewAdminService(node, mux, wrpc.log)
}
return wrpc return wrpc
} }

View File

@ -13,7 +13,7 @@ func TestWakuRest(t *testing.T) {
n, err := node.New(options) n, err := node.New(options)
require.NoError(t, err) require.NoError(t, err)
rpc := NewWakuRest(n, "127.0.0.1", 8080, false, 10, utils.Logger()) rpc := NewWakuRest(n, "127.0.0.1", 8080, false, false, 10, utils.Logger())
require.NotNil(t, rpc.server) require.NotNil(t, rpc.server)
require.Equal(t, rpc.server.Addr, "127.0.0.1:8080") require.Equal(t, rpc.server.Addr, "127.0.0.1:8080")
} }

View File

@ -7,12 +7,8 @@ import (
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
"go.uber.org/zap" "go.uber.org/zap"
"github.com/waku-org/go-waku/cmd/waku/server"
"github.com/waku-org/go-waku/waku/v2/node" "github.com/waku-org/go-waku/waku/v2/node"
"github.com/waku-org/go-waku/waku/v2/protocol/filter"
"github.com/waku-org/go-waku/waku/v2/protocol/legacy_filter"
"github.com/waku-org/go-waku/waku/v2/protocol/lightpush"
"github.com/waku-org/go-waku/waku/v2/protocol/relay"
"github.com/waku-org/go-waku/waku/v2/protocol/store"
) )
type AdminService struct { type AdminService struct {
@ -54,15 +50,6 @@ func (a *AdminService) PostV1Peers(req *http.Request, args *PeersArgs, reply *Su
return nil return nil
} }
func isWakuProtocol(protocol protocol.ID) bool {
return protocol == legacy_filter.FilterID_v20beta1 ||
protocol == filter.FilterPushID_v20beta1 ||
protocol == filter.FilterSubscribeID_v20beta1 ||
protocol == relay.WakuRelayID_v200 ||
protocol == lightpush.LightPushID_v20beta1 ||
protocol == store.StoreID_v20beta4
}
func (a *AdminService) GetV1Peers(req *http.Request, args *GetPeersArgs, reply *PeersReply) error { func (a *AdminService) GetV1Peers(req *http.Request, args *GetPeersArgs, reply *PeersReply) error {
peers, err := a.node.Peers() peers, err := a.node.Peers()
if err != nil { if err != nil {
@ -72,7 +59,7 @@ func (a *AdminService) GetV1Peers(req *http.Request, args *GetPeersArgs, reply *
for _, peer := range peers { for _, peer := range peers {
for _, addr := range peer.Addrs { for _, addr := range peer.Addrs {
for _, proto := range peer.Protocols { for _, proto := range peer.Protocols {
if !isWakuProtocol(proto) { if !server.IsWakuProtocol(proto) {
continue continue
} }
*reply = append(*reply, PeerReply{ *reply = append(*reply, PeerReply{

19
cmd/waku/server/utils.go Normal file
View File

@ -0,0 +1,19 @@
package server
import (
"github.com/libp2p/go-libp2p/core/protocol"
"github.com/waku-org/go-waku/waku/v2/protocol/filter"
"github.com/waku-org/go-waku/waku/v2/protocol/legacy_filter"
"github.com/waku-org/go-waku/waku/v2/protocol/lightpush"
"github.com/waku-org/go-waku/waku/v2/protocol/relay"
"github.com/waku-org/go-waku/waku/v2/protocol/store"
)
func IsWakuProtocol(protocol protocol.ID) bool {
return protocol == legacy_filter.FilterID_v20beta1 ||
protocol == filter.FilterPushID_v20beta1 ||
protocol == filter.FilterSubscribeID_v20beta1 ||
protocol == relay.WakuRelayID_v200 ||
protocol == lightpush.LightPushID_v20beta1 ||
protocol == store.StoreID_v20beta4
}