mirror of https://github.com/waku-org/nwaku.git
feat: /admin rest api endpoint (#2094)
/admin rest api implementation and tests * open api doc * Add rest admin test to all tests * Enrich /admin get peers interface, group protocols by peers in response
This commit is contained in:
parent
1042cacd3f
commit
7b5c36b1c6
|
@ -38,6 +38,7 @@ import
|
||||||
../../waku/waku_api/rest/lightpush/handlers as rest_lightpush_api,
|
../../waku/waku_api/rest/lightpush/handlers as rest_lightpush_api,
|
||||||
../../waku/waku_api/rest/store/handlers as rest_store_api,
|
../../waku/waku_api/rest/store/handlers as rest_store_api,
|
||||||
../../waku/waku_api/rest/health/handlers as rest_health_api,
|
../../waku/waku_api/rest/health/handlers as rest_health_api,
|
||||||
|
../../waku/waku_api/rest/admin/handlers as rest_admin_api,
|
||||||
../../waku/waku_api/jsonrpc/admin/handlers as rpc_admin_api,
|
../../waku/waku_api/jsonrpc/admin/handlers as rpc_admin_api,
|
||||||
../../waku/waku_api/jsonrpc/debug/handlers as rpc_debug_api,
|
../../waku/waku_api/jsonrpc/debug/handlers as rpc_debug_api,
|
||||||
../../waku/waku_api/jsonrpc/filter/handlers as rpc_filter_api,
|
../../waku/waku_api/jsonrpc/filter/handlers as rpc_filter_api,
|
||||||
|
@ -567,6 +568,9 @@ proc startApp*(app: App): Future[AppResult[void]] {.async.} =
|
||||||
proc startRestServer(app: App, address: ValidIpAddress, port: Port, conf: WakuNodeConf): AppResult[RestServerRef] =
|
proc startRestServer(app: App, address: ValidIpAddress, port: Port, conf: WakuNodeConf): AppResult[RestServerRef] =
|
||||||
let server = ? newRestHttpServer(address, port)
|
let server = ? newRestHttpServer(address, port)
|
||||||
|
|
||||||
|
## Admin REST API
|
||||||
|
installAdminApiHandlers(server.router, app.node)
|
||||||
|
|
||||||
## Debug REST API
|
## Debug REST API
|
||||||
installDebugApiHandlers(server.router, app.node)
|
installDebugApiHandlers(server.router, app.node)
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,8 @@ import
|
||||||
./wakunode_rest/test_rest_store,
|
./wakunode_rest/test_rest_store,
|
||||||
./wakunode_rest/test_rest_filter,
|
./wakunode_rest/test_rest_filter,
|
||||||
./wakunode_rest/test_rest_legacy_filter,
|
./wakunode_rest/test_rest_legacy_filter,
|
||||||
./wakunode_rest/test_rest_lightpush
|
./wakunode_rest/test_rest_lightpush,
|
||||||
|
./wakunode_rest/test_rest_admin
|
||||||
|
|
||||||
import
|
import
|
||||||
./waku_rln_relay/test_waku_rln_relay,
|
./waku_rln_relay/test_waku_rln_relay,
|
||||||
|
|
|
@ -9,4 +9,5 @@ import
|
||||||
./test_rest_relay_serdes,
|
./test_rest_relay_serdes,
|
||||||
./test_rest_relay,
|
./test_rest_relay,
|
||||||
./test_rest_serdes,
|
./test_rest_serdes,
|
||||||
./test_rest_store
|
./test_rest_store,
|
||||||
|
./test_rest_admin
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
{.used.}
|
||||||
|
|
||||||
|
import
|
||||||
|
std/sequtils,
|
||||||
|
stew/shims/net,
|
||||||
|
testutils/unittests,
|
||||||
|
presto, presto/client as presto_client,
|
||||||
|
libp2p/crypto/crypto
|
||||||
|
|
||||||
|
import
|
||||||
|
../../waku/waku_core,
|
||||||
|
../../waku/waku_node,
|
||||||
|
../../waku/node/peer_manager,
|
||||||
|
../../waku/waku_api/rest/server,
|
||||||
|
../../waku/waku_api/rest/client,
|
||||||
|
../../waku/waku_api/rest/responses,
|
||||||
|
../../waku/waku_api/rest/admin/types,
|
||||||
|
../../waku/waku_api/rest/admin/handlers as admin_api,
|
||||||
|
../../waku/waku_api/rest/admin/client as admin_api_client,
|
||||||
|
../../waku/waku_relay,
|
||||||
|
../testlib/wakucore,
|
||||||
|
../testlib/wakunode,
|
||||||
|
../testlib/testasync
|
||||||
|
|
||||||
|
suite "Waku v2 Rest API - Admin":
|
||||||
|
var node1 {.threadvar.}: WakuNode
|
||||||
|
var node2 {.threadvar.}: WakuNode
|
||||||
|
var node3 {.threadvar.}: WakuNode
|
||||||
|
var peerInfo2 {.threadvar.}: RemotePeerInfo
|
||||||
|
var peerInfo3 {.threadvar.}: RemotePeerInfo
|
||||||
|
var restServer {.threadvar.}: RestServerRef
|
||||||
|
var client{.threadvar.}: RestClientRef
|
||||||
|
|
||||||
|
asyncSetup:
|
||||||
|
node1 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("127.0.0.1"), Port(60600))
|
||||||
|
node2 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("127.0.0.1"), Port(60602))
|
||||||
|
peerInfo2 = node2.switch.peerInfo
|
||||||
|
node3 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("127.0.0.1"), Port(60604))
|
||||||
|
peerInfo3 = node3.switch.peerInfo
|
||||||
|
|
||||||
|
await allFutures(node1.start(), node2.start(), node3.start())
|
||||||
|
await allFutures(node1.mountRelay(), node2.mountRelay(), node3.mountRelay())
|
||||||
|
|
||||||
|
let restPort = Port(58011)
|
||||||
|
let restAddress = ValidIpAddress.init("127.0.0.1")
|
||||||
|
restServer = RestServerRef.init(restAddress, restPort).tryGet()
|
||||||
|
|
||||||
|
installAdminApiHandlers(restServer.router, node1)
|
||||||
|
|
||||||
|
restServer.start()
|
||||||
|
|
||||||
|
client = newRestHttpClient(initTAddress(restAddress, restPort))
|
||||||
|
|
||||||
|
asyncTearDown:
|
||||||
|
await restServer.stop()
|
||||||
|
await restServer.closeWait()
|
||||||
|
await allFutures(node1.stop(), node2.stop(), node3.stop())
|
||||||
|
|
||||||
|
asyncTest "Set and get remote peers":
|
||||||
|
# Connect to nodes 2 and 3 using the Admin API
|
||||||
|
let postRes = await client.postPeers(@[constructMultiaddrStr(peerInfo2),
|
||||||
|
constructMultiaddrStr(peerInfo3)])
|
||||||
|
|
||||||
|
check:
|
||||||
|
postRes.status == 200
|
||||||
|
|
||||||
|
# Verify that newly connected peers are being managed
|
||||||
|
let getRes = await client.getPeers()
|
||||||
|
|
||||||
|
check:
|
||||||
|
getRes.status == 200
|
||||||
|
$getRes.contentType == $MIMETYPE_JSON
|
||||||
|
getRes.data.len() == 2
|
||||||
|
# Check peer 2
|
||||||
|
getRes.data.anyIt(it.protocols.find(WakuRelayCodec) >= 0 and
|
||||||
|
it.multiaddr == constructMultiaddrStr(peerInfo2))
|
||||||
|
# Check peer 3
|
||||||
|
getRes.data.anyIt(it.protocols.find(WakuRelayCodec) >= 0 and
|
||||||
|
it.multiaddr == constructMultiaddrStr(peerInfo3))
|
||||||
|
|
||||||
|
asyncTest "Set wrong peer":
|
||||||
|
let nonExistentPeer = "/ip4/0.0.0.0/tcp/10000/p2p/16Uiu2HAm6HZZr7aToTvEBPpiys4UxajCTU97zj5v7RNR2gbniy1D"
|
||||||
|
let postRes = await client.postPeers(@[nonExistentPeer])
|
||||||
|
|
||||||
|
check:
|
||||||
|
postRes.status == 400
|
||||||
|
$postRes.contentType == $MIMETYPE_TEXT
|
||||||
|
postRes.data == "Failed to connect to peer at index: 0 - " & nonExistentPeer
|
||||||
|
|
||||||
|
# Verify that newly connected peers are being managed
|
||||||
|
let getRes = await client.getPeers()
|
||||||
|
|
||||||
|
check:
|
||||||
|
getRes.status == 200
|
||||||
|
$getRes.contentType == $MIMETYPE_JSON
|
||||||
|
getRes.data.len() == 0
|
|
@ -14,30 +14,13 @@ import
|
||||||
../../../waku_relay,
|
../../../waku_relay,
|
||||||
../../../waku_node,
|
../../../waku_node,
|
||||||
../../../node/peer_manager,
|
../../../node/peer_manager,
|
||||||
|
../../../waku_core,
|
||||||
./types
|
./types
|
||||||
|
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "waku node jsonrpc admin_api"
|
topics = "waku node jsonrpc admin_api"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc constructMultiaddrStr*(wireaddr: MultiAddress, peerId: PeerId): string =
|
|
||||||
# Constructs a multiaddress with both wire address and p2p identity
|
|
||||||
$wireaddr & "/p2p/" & $peerId
|
|
||||||
|
|
||||||
proc constructMultiaddrStr*(peerInfo: PeerInfo): string =
|
|
||||||
# Constructs a multiaddress with both location (wire) address and p2p identity
|
|
||||||
if peerInfo.listenAddrs.len == 0:
|
|
||||||
return ""
|
|
||||||
constructMultiaddrStr(peerInfo.listenAddrs[0], peerInfo.peerId)
|
|
||||||
|
|
||||||
proc constructMultiaddrStr*(remotePeerInfo: RemotePeerInfo): string =
|
|
||||||
# Constructs a multiaddress with both location (wire) address and p2p identity
|
|
||||||
if remotePeerInfo.addrs.len == 0:
|
|
||||||
return ""
|
|
||||||
constructMultiaddrStr(remotePeerInfo.addrs[0], remotePeerInfo.peerId)
|
|
||||||
|
|
||||||
proc installAdminApiHandlers*(node: WakuNode, rpcsrv: RpcServer) =
|
proc installAdminApiHandlers*(node: WakuNode, rpcsrv: RpcServer) =
|
||||||
|
|
||||||
rpcsrv.rpc("post_waku_v2_admin_v1_peers") do (peers: seq[string]) -> bool:
|
rpcsrv.rpc("post_waku_v2_admin_v1_peers") do (peers: seq[string]) -> bool:
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
when (NimMajor, NimMinor) < (1, 4):
|
||||||
|
{.push raises: [Defect].}
|
||||||
|
else:
|
||||||
|
{.push raises: [].}
|
||||||
|
|
||||||
|
import
|
||||||
|
chronicles,
|
||||||
|
json_serialization,
|
||||||
|
json_serialization/std/options,
|
||||||
|
presto/[route, client],
|
||||||
|
stew/byteutils
|
||||||
|
|
||||||
|
import
|
||||||
|
../serdes,
|
||||||
|
../responses,
|
||||||
|
./types
|
||||||
|
|
||||||
|
export types
|
||||||
|
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
topics = "waku node rest admin api"
|
||||||
|
|
||||||
|
proc decodeBytes*(t: typedesc[seq[WakuPeer]], data: openArray[byte],
|
||||||
|
contentType: Opt[ContentTypeData]): RestResult[seq[WakuPeer]] =
|
||||||
|
if MediaType.init($contentType) != MIMETYPE_JSON:
|
||||||
|
error "Unsupported response contentType value", contentType = contentType
|
||||||
|
return err("Unsupported response contentType")
|
||||||
|
|
||||||
|
let decoded = decodeFromJsonBytes(seq[WakuPeer], data).valueOr:
|
||||||
|
return err("Invalid response from server, could not decode.")
|
||||||
|
|
||||||
|
return ok(decoded)
|
||||||
|
|
||||||
|
proc decodeBytes*(t: typedesc[string], value: openArray[byte],
|
||||||
|
contentType: Opt[ContentTypeData]): RestResult[string] =
|
||||||
|
if MediaType.init($contentType) != MIMETYPE_TEXT:
|
||||||
|
error "Unsupported contentType value", contentType = contentType
|
||||||
|
return err("Unsupported contentType")
|
||||||
|
|
||||||
|
var res: string
|
||||||
|
if len(value) > 0:
|
||||||
|
res = newString(len(value))
|
||||||
|
copyMem(addr res[0], unsafeAddr value[0], len(value))
|
||||||
|
return ok(res)
|
||||||
|
|
||||||
|
proc encodeBytes*(value: seq[string],
|
||||||
|
contentType: string): RestResult[seq[byte]] =
|
||||||
|
if MediaType.init(contentType) != MIMETYPE_JSON:
|
||||||
|
error "Unsupported contentType value", contentType = contentType
|
||||||
|
return err("Unsupported contentType")
|
||||||
|
|
||||||
|
let encoded = ?encodeIntoJsonBytes(value)
|
||||||
|
return ok(encoded)
|
||||||
|
|
||||||
|
proc getPeers*():
|
||||||
|
RestResponse[seq[WakuPeer]]
|
||||||
|
{.rest, endpoint: "/admin/v1/peers", meth: HttpMethod.MethodGet.}
|
||||||
|
|
||||||
|
proc postPeers*(body: seq[string]):
|
||||||
|
RestResponse[string]
|
||||||
|
{.rest, endpoint: "/admin/v1/peers", meth: HttpMethod.MethodPost.}
|
|
@ -0,0 +1,113 @@
|
||||||
|
when (NimMajor, NimMinor) < (1, 4):
|
||||||
|
{.push raises: [Defect].}
|
||||||
|
else:
|
||||||
|
{.push raises: [].}
|
||||||
|
|
||||||
|
import
|
||||||
|
std/strformat,
|
||||||
|
std/sequtils,
|
||||||
|
stew/byteutils,
|
||||||
|
chronicles,
|
||||||
|
json_serialization,
|
||||||
|
presto/route,
|
||||||
|
libp2p/[peerinfo, switch]
|
||||||
|
|
||||||
|
import
|
||||||
|
../../../waku_core,
|
||||||
|
../../../waku_store,
|
||||||
|
../../../waku_filter,
|
||||||
|
../../../waku_relay,
|
||||||
|
../../../waku_node,
|
||||||
|
../../../node/peer_manager,
|
||||||
|
../responses,
|
||||||
|
../serdes,
|
||||||
|
./types
|
||||||
|
|
||||||
|
export types
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
topics = "waku node rest admin api"
|
||||||
|
|
||||||
|
const ROUTE_ADMIN_V1_PEERS* = "/admin/v1/peers"
|
||||||
|
|
||||||
|
type PeerProtocolTuple = tuple[multiaddr: string, protocol: string, connected: bool]
|
||||||
|
|
||||||
|
func decodeRequestBody[T](contentBody: Option[ContentBody]) : Result[T, RestApiResponse] =
|
||||||
|
if contentBody.isNone():
|
||||||
|
return err(RestApiResponse.badRequest("Missing content body"))
|
||||||
|
|
||||||
|
let reqBodyContentType = MediaType.init($contentBody.get().contentType)
|
||||||
|
if reqBodyContentType != MIMETYPE_JSON:
|
||||||
|
return err(RestApiResponse.badRequest("Wrong Content-Type, expected application/json"))
|
||||||
|
|
||||||
|
let reqBodyData = contentBody.get().data
|
||||||
|
|
||||||
|
let requestResult = decodeFromJsonBytes(T, reqBodyData)
|
||||||
|
if requestResult.isErr():
|
||||||
|
return err(RestApiResponse.badRequest("Invalid content body, could not decode. " &
|
||||||
|
$requestResult.error))
|
||||||
|
|
||||||
|
return ok(requestResult.get())
|
||||||
|
|
||||||
|
proc tuplesToWakuPeers(peers: var WakuPeers, peersTup: seq[PeerProtocolTuple]) =
|
||||||
|
for peer in peersTup:
|
||||||
|
peers.add(peer.multiaddr, peer.protocol, peer.connected)
|
||||||
|
|
||||||
|
|
||||||
|
proc installAdminV1GetPeersHandler(router: var RestRouter, node: WakuNode) =
|
||||||
|
router.api(MethodGet, ROUTE_ADMIN_V1_PEERS) do () -> RestApiResponse:
|
||||||
|
var peers: WakuPeers = @[]
|
||||||
|
|
||||||
|
if not node.wakuRelay.isNil():
|
||||||
|
# Map managed peers to WakuPeers and add to return list
|
||||||
|
let relayPeers = node.peerManager
|
||||||
|
.peerStore.peers(WakuRelayCodec)
|
||||||
|
.mapIt((
|
||||||
|
multiaddr: constructMultiaddrStr(it),
|
||||||
|
protocol: WakuRelayCodec,
|
||||||
|
connected: it.connectedness == Connectedness.Connected)
|
||||||
|
)
|
||||||
|
tuplesToWakuPeers(peers, relayPeers)
|
||||||
|
|
||||||
|
if not node.wakuFilterLegacy.isNil():
|
||||||
|
# Map WakuFilter peers to WakuPeers and add to return list
|
||||||
|
let filterPeers = node.peerManager.peerStore.peers(WakuLegacyFilterCodec)
|
||||||
|
.mapIt((multiaddr: constructMultiaddrStr(it),
|
||||||
|
protocol: WakuLegacyFilterCodec,
|
||||||
|
connected: it.connectedness == Connectedness.Connected))
|
||||||
|
tuplesToWakuPeers(peers, filterPeers)
|
||||||
|
|
||||||
|
if not node.wakuStore.isNil():
|
||||||
|
# Map WakuStore peers to WakuPeers and add to return list
|
||||||
|
let storePeers = node.peerManager.peerStore
|
||||||
|
.peers(WakuStoreCodec)
|
||||||
|
.mapIt((multiaddr: constructMultiaddrStr(it),
|
||||||
|
protocol: WakuStoreCodec,
|
||||||
|
connected: it.connectedness == Connectedness.Connected))
|
||||||
|
tuplesToWakuPeers(peers, storePeers)
|
||||||
|
|
||||||
|
let resp = RestApiResponse.jsonResponse(peers, status=Http200)
|
||||||
|
if resp.isErr():
|
||||||
|
error "An error ocurred while building the json respose: ", error=resp.error
|
||||||
|
return RestApiResponse.internalServerError(fmt("An error ocurred while building the json respose: {resp.error}"))
|
||||||
|
|
||||||
|
return resp.get()
|
||||||
|
|
||||||
|
proc installAdminV1PostPeersHandler(router: var RestRouter, node: WakuNode) =
|
||||||
|
router.api(MethodPost, ROUTE_ADMIN_V1_PEERS) do (contentBody: Option[ContentBody]) -> RestApiResponse:
|
||||||
|
|
||||||
|
let peers: seq[string] = decodeRequestBody[seq[string]](contentBody).valueOr:
|
||||||
|
return RestApiResponse.badRequest(fmt("Failed to decode request: {error}"))
|
||||||
|
|
||||||
|
for i, peer in peers:
|
||||||
|
let peerInfo = parsePeerInfo(peer).valueOr:
|
||||||
|
return RestApiResponse.badRequest(fmt("Couldn't parse remote peer info: {error}"))
|
||||||
|
|
||||||
|
if not (await node.peerManager.connectRelay(peerInfo, source="rest")):
|
||||||
|
return RestApiResponse.badRequest(fmt("Failed to connect to peer at index: {i} - {peer}"))
|
||||||
|
|
||||||
|
return RestApiResponse.ok()
|
||||||
|
|
||||||
|
proc installAdminApiHandlers*(router: var RestRouter, node: WakuNode) =
|
||||||
|
installAdminV1GetPeersHandler(router, node)
|
||||||
|
installAdminV1PostPeersHandler(router, node)
|
|
@ -0,0 +1,74 @@
|
||||||
|
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: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
'400':
|
||||||
|
description: Cannot connect to one or more peers.
|
||||||
|
'5XX':
|
||||||
|
description: Unexpected error.
|
||||||
|
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
WakuPeer:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- multiaddr
|
||||||
|
- protocols
|
||||||
|
properties:
|
||||||
|
multiaddr:
|
||||||
|
type: string
|
||||||
|
protocols:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- protocol
|
||||||
|
- connected
|
||||||
|
properties:
|
||||||
|
protocol:
|
||||||
|
type: string
|
||||||
|
connected:
|
||||||
|
type: boolean
|
|
@ -0,0 +1,132 @@
|
||||||
|
when (NimMajor, NimMinor) < (1, 4):
|
||||||
|
{.push raises: [Defect].}
|
||||||
|
else:
|
||||||
|
{.push raises: [].}
|
||||||
|
|
||||||
|
import
|
||||||
|
chronicles,
|
||||||
|
json_serialization,
|
||||||
|
json_serialization/std/options,
|
||||||
|
json_serialization/lexer
|
||||||
|
import
|
||||||
|
../serdes
|
||||||
|
|
||||||
|
#### Types
|
||||||
|
|
||||||
|
type
|
||||||
|
ProtocolState* = object
|
||||||
|
protocol*: string
|
||||||
|
connected*: bool
|
||||||
|
|
||||||
|
type
|
||||||
|
WakuPeer* = object
|
||||||
|
multiaddr*: string
|
||||||
|
protocols*: seq[ProtocolState]
|
||||||
|
|
||||||
|
type WakuPeers* = seq[WakuPeer]
|
||||||
|
|
||||||
|
#### Serialization and deserialization
|
||||||
|
|
||||||
|
proc writeValue*(writer: var JsonWriter[RestJson], value: ProtocolState)
|
||||||
|
{.raises: [IOError].} =
|
||||||
|
writer.beginRecord()
|
||||||
|
writer.writeField("protocol", value.protocol)
|
||||||
|
writer.writeField("connected", value.connected)
|
||||||
|
writer.endRecord()
|
||||||
|
|
||||||
|
proc writeValue*(writer: var JsonWriter[RestJson], value: WakuPeer)
|
||||||
|
{.raises: [IOError].} =
|
||||||
|
writer.beginRecord()
|
||||||
|
writer.writeField("multiaddr", value.multiaddr)
|
||||||
|
writer.writeField("protocols", value.protocols)
|
||||||
|
writer.endRecord()
|
||||||
|
|
||||||
|
proc readValue*(reader: var JsonReader[RestJson], value: var ProtocolState)
|
||||||
|
{.gcsafe, raises: [SerializationError, IOError].} =
|
||||||
|
var
|
||||||
|
protocol: Option[string]
|
||||||
|
connected: Option[bool]
|
||||||
|
|
||||||
|
for fieldName in readObjectFields(reader):
|
||||||
|
case fieldName
|
||||||
|
of "protocol":
|
||||||
|
if protocol.isSome():
|
||||||
|
reader.raiseUnexpectedField("Multiple `protocol` fields found", "ProtocolState")
|
||||||
|
protocol = some(reader.readValue(string))
|
||||||
|
of "connected":
|
||||||
|
if connected.isSome():
|
||||||
|
reader.raiseUnexpectedField("Multiple `connected` fields found", "ProtocolState")
|
||||||
|
connected = some(reader.readValue(bool))
|
||||||
|
else:
|
||||||
|
unrecognizedFieldWarning()
|
||||||
|
|
||||||
|
if connected.isNone():
|
||||||
|
reader.raiseUnexpectedValue("Field `connected` is missing")
|
||||||
|
|
||||||
|
if protocol.isNone():
|
||||||
|
reader.raiseUnexpectedValue("Field `protocol` is missing")
|
||||||
|
|
||||||
|
value = ProtocolState(
|
||||||
|
protocol: protocol.get(),
|
||||||
|
connected: connected.get()
|
||||||
|
)
|
||||||
|
|
||||||
|
proc readValue*(reader: var JsonReader[RestJson], value: var WakuPeer)
|
||||||
|
{.gcsafe, raises: [SerializationError, IOError].} =
|
||||||
|
var
|
||||||
|
multiaddr: Option[string]
|
||||||
|
protocols: Option[seq[ProtocolState]]
|
||||||
|
|
||||||
|
for fieldName in readObjectFields(reader):
|
||||||
|
case fieldName
|
||||||
|
of "multiaddr":
|
||||||
|
if multiaddr.isSome():
|
||||||
|
reader.raiseUnexpectedField("Multiple `multiaddr` fields found", "WakuPeer")
|
||||||
|
multiaddr = some(reader.readValue(string))
|
||||||
|
of "protocols":
|
||||||
|
if protocols.isSome():
|
||||||
|
reader.raiseUnexpectedField("Multiple `protocols` fields found", "WakuPeer")
|
||||||
|
protocols = some(reader.readValue(seq[ProtocolState]))
|
||||||
|
else:
|
||||||
|
unrecognizedFieldWarning()
|
||||||
|
|
||||||
|
if multiaddr.isNone():
|
||||||
|
reader.raiseUnexpectedValue("Field `multiaddr` is missing")
|
||||||
|
|
||||||
|
if protocols.isNone():
|
||||||
|
reader.raiseUnexpectedValue("Field `protocols` are missing")
|
||||||
|
|
||||||
|
value = WakuPeer(
|
||||||
|
multiaddr: multiaddr.get(),
|
||||||
|
protocols: protocols.get()
|
||||||
|
)
|
||||||
|
|
||||||
|
## Utility for populating WakuPeers and ProtocolState
|
||||||
|
func `==`*(a, b: ProtocolState): bool {.inline.} =
|
||||||
|
return a.protocol == b.protocol
|
||||||
|
|
||||||
|
func `==`*(a: ProtocolState, b: string): bool {.inline.} =
|
||||||
|
return a.protocol == b
|
||||||
|
|
||||||
|
func `==`*(a, b: WakuPeer): bool {.inline.} =
|
||||||
|
return a.multiaddr == b.multiaddr
|
||||||
|
|
||||||
|
proc add*(peers: var WakuPeers, multiaddr: string, protocol: string, connected: bool) =
|
||||||
|
var
|
||||||
|
peer: WakuPeer = WakuPeer(
|
||||||
|
multiaddr: multiaddr,
|
||||||
|
protocols: @[ProtocolState(
|
||||||
|
protocol: protocol,
|
||||||
|
connected: connected
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
let idx = peers.find(peer)
|
||||||
|
|
||||||
|
if idx < 0:
|
||||||
|
peers.add(peer)
|
||||||
|
else:
|
||||||
|
peers[idx].protocols.add(ProtocolState(
|
||||||
|
protocol: protocol,
|
||||||
|
connected: connected
|
||||||
|
))
|
||||||
|
|
|
@ -3,11 +3,13 @@ import
|
||||||
./waku_core/time,
|
./waku_core/time,
|
||||||
./waku_core/message,
|
./waku_core/message,
|
||||||
./waku_core/peers,
|
./waku_core/peers,
|
||||||
./waku_core/subscription
|
./waku_core/subscription,
|
||||||
|
./waku_core/multiaddrstr
|
||||||
|
|
||||||
export
|
export
|
||||||
topics,
|
topics,
|
||||||
time,
|
time,
|
||||||
message,
|
message,
|
||||||
peers,
|
peers,
|
||||||
subscription
|
subscription,
|
||||||
|
multiaddrstr
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
when (NimMajor, NimMinor) < (1, 4):
|
||||||
|
{.push raises: [Defect].}
|
||||||
|
else:
|
||||||
|
{.push raises: [].}
|
||||||
|
|
||||||
|
import
|
||||||
|
libp2p/[peerinfo, switch]
|
||||||
|
|
||||||
|
import
|
||||||
|
./peers
|
||||||
|
|
||||||
|
proc constructMultiaddrStr*(wireaddr: MultiAddress, peerId: PeerId): string =
|
||||||
|
# Constructs a multiaddress with both wire address and p2p identity
|
||||||
|
return $wireaddr & "/p2p/" & $peerId
|
||||||
|
|
||||||
|
proc constructMultiaddrStr*(peerInfo: PeerInfo): string =
|
||||||
|
# Constructs a multiaddress with both location (wire) address and p2p identity
|
||||||
|
if peerInfo.listenAddrs.len == 0:
|
||||||
|
return ""
|
||||||
|
return constructMultiaddrStr(peerInfo.listenAddrs[0], peerInfo.peerId)
|
||||||
|
|
||||||
|
proc constructMultiaddrStr*(remotePeerInfo: RemotePeerInfo): string =
|
||||||
|
# Constructs a multiaddress with both location (wire) address and p2p identity
|
||||||
|
if remotePeerInfo.addrs.len == 0:
|
||||||
|
return ""
|
||||||
|
return constructMultiaddrStr(remotePeerInfo.addrs[0], remotePeerInfo.peerId)
|
||||||
|
|
Loading…
Reference in New Issue