mirror of https://github.com/waku-org/nwaku.git
Waku v2 JSON-RPC REST API: Store protocol proof of concept (#263)
* Waku V2 history query POC * Fix folder structure * Improve test clarity * Improve imports, returns and some naming * Changed naming conventions. Refactor & improve. Co-authored-by: Oskar Thorén <ot@oskarthoren.com>
This commit is contained in:
parent
e875027be4
commit
135eaae9fb
|
@ -9,4 +9,5 @@ import
|
|||
./v2/test_waku_payload,
|
||||
./v2/test_rpc_waku,
|
||||
./v2/test_waku_swap,
|
||||
./v2/test_message_store
|
||||
./v2/test_message_store,
|
||||
./v2/test_jsonrpc_waku
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
import
|
||||
std/[unittest, options, sets, tables, os, strutils],
|
||||
stew/shims/net as stewNet,
|
||||
json_rpc/[rpcserver, rpcclient],
|
||||
libp2p/standard_setup,
|
||||
libp2p/switch,
|
||||
libp2p/protobuf/minprotobuf,
|
||||
libp2p/stream/[bufferstream, connection],
|
||||
libp2p/crypto/crypto,
|
||||
libp2p/protocols/pubsub/rpc/message,
|
||||
../../waku/v2/waku_types,
|
||||
../../waku/v2/node/wakunode2,
|
||||
../../waku/v2/node/jsonrpc/[jsonrpc_types,store_api],
|
||||
../../waku/v2/protocol/[waku_store, message_notifier],
|
||||
../test_helpers
|
||||
|
||||
template sourceDir*: string = currentSourcePath.rsplit(DirSep, 1)[0]
|
||||
const sigPath = sourceDir / ParDir / ParDir / "waku" / "v2" / "node" / "jsonrpc" / "jsonrpc_callsigs.nim"
|
||||
createRpcSigs(RpcHttpClient, sigPath)
|
||||
|
||||
suite "Waku v2 JSON-RPC API":
|
||||
|
||||
asyncTest "get_waku_v2_store_v1_messages":
|
||||
const defaultTopic = "/waku/2/default-waku/proto"
|
||||
const testCodec = "/waku/2/default-waku/codec"
|
||||
|
||||
# WakuNode setup
|
||||
let
|
||||
rng = crypto.newRng()
|
||||
privkey = crypto.PrivateKey.random(Secp256k1, rng[]).tryGet()
|
||||
bindIp = ValidIpAddress.init("0.0.0.0")
|
||||
extIp = ValidIpAddress.init("127.0.0.1")
|
||||
port = Port(9000)
|
||||
node = WakuNode.init(privkey, bindIp, port, some(extIp), some(port))
|
||||
|
||||
waitFor node.start()
|
||||
|
||||
waitFor node.mountRelay(@[defaultTopic])
|
||||
|
||||
# RPC server setup
|
||||
let
|
||||
rpcPort = Port(8545)
|
||||
ta = initTAddress(bindIp, rpcPort)
|
||||
server = newRpcHttpServer([ta])
|
||||
|
||||
setupWakuJSONRPC(node, server)
|
||||
server.start()
|
||||
|
||||
# WakuStore setup
|
||||
let
|
||||
key = wakunode2.PrivateKey.random(ECDSA, rng[]).get()
|
||||
peer = PeerInfo.init(key)
|
||||
|
||||
node.mountStore()
|
||||
let
|
||||
subscription = node.wakuStore.subscription()
|
||||
|
||||
var listenSwitch = newStandardSwitch(some(key))
|
||||
discard waitFor listenSwitch.start()
|
||||
|
||||
node.wakuStore.setPeer(listenSwitch.peerInfo)
|
||||
|
||||
listenSwitch.mount(node.wakuStore)
|
||||
|
||||
var subscriptions = newTable[string, MessageNotificationSubscription]()
|
||||
subscriptions[testCodec] = subscription
|
||||
|
||||
# Now prime it with some history before tests
|
||||
var
|
||||
msgList = @[WakuMessage(payload: @[byte 0], contentTopic: ContentTopic(2)),
|
||||
WakuMessage(payload: @[byte 1], contentTopic: ContentTopic(1)),
|
||||
WakuMessage(payload: @[byte 2], contentTopic: ContentTopic(1)),
|
||||
WakuMessage(payload: @[byte 3], contentTopic: ContentTopic(1)),
|
||||
WakuMessage(payload: @[byte 4], contentTopic: ContentTopic(1)),
|
||||
WakuMessage(payload: @[byte 5], contentTopic: ContentTopic(1)),
|
||||
WakuMessage(payload: @[byte 6], contentTopic: ContentTopic(1)),
|
||||
WakuMessage(payload: @[byte 7], contentTopic: ContentTopic(1)),
|
||||
WakuMessage(payload: @[byte 8], contentTopic: ContentTopic(1)),
|
||||
WakuMessage(payload: @[byte 9], contentTopic: ContentTopic(2))]
|
||||
|
||||
for wakuMsg in msgList:
|
||||
waitFor subscriptions.notify(defaultTopic, wakuMsg)
|
||||
|
||||
let client = newRpcHttpClient()
|
||||
await client.connect("127.0.0.1", rpcPort)
|
||||
|
||||
let response = await client.get_waku_v2_store_v1_messages(@[ContentTopic(1)], some(StorePagingOptions()))
|
||||
check:
|
||||
response.messages.len() == 8
|
||||
response.pagingOptions.isNone
|
||||
|
||||
server.stop()
|
||||
server.close()
|
||||
waitfor node.stop()
|
|
@ -45,3 +45,7 @@ suite "Waku v2 Remote Procedure Calls":
|
|||
await client.connect("127.0.0.1", rpcPort)
|
||||
|
||||
check await(client.waku_version()) == WakuRelayCodec
|
||||
|
||||
server.stop()
|
||||
server.close()
|
||||
waitfor node.stop()
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
proc get_waku_v2_store_v1_messages(topics: seq[ContentTopic], pagingOptions: Option[StorePagingOptions]): StoreResponse
|
|
@ -0,0 +1,14 @@
|
|||
import
|
||||
../../waku_types,
|
||||
std/options
|
||||
|
||||
type
|
||||
StoreResponse* = object
|
||||
messages*: seq[WakuMessage]
|
||||
pagingOptions*: Option[StorePagingOptions]
|
||||
|
||||
StorePagingOptions* = object
|
||||
## This type holds some options for pagination
|
||||
pageSize*: uint64
|
||||
cursor*: Option[Index]
|
||||
forward*: bool
|
|
@ -0,0 +1,23 @@
|
|||
import
|
||||
std/options,
|
||||
../../waku_types,
|
||||
../wakunode2,
|
||||
./jsonrpc_types
|
||||
|
||||
## Conversion tools
|
||||
## Since the Waku v2 JSON-RPC API has its own defined types,
|
||||
## we need to convert between these and the types for the Nim API
|
||||
|
||||
proc toPagingInfo*(pagingOptions: StorePagingOptions): PagingInfo =
|
||||
PagingInfo(pageSize: pagingOptions.pageSize,
|
||||
cursor: if pagingOptions.cursor.isSome: pagingOptions.cursor.get else: Index(),
|
||||
direction: if pagingOptions.forward: PagingDirection.FORWARD else: PagingDirection.BACKWARD)
|
||||
|
||||
proc toPagingOptions*(pagingInfo: PagingInfo): StorePagingOptions =
|
||||
StorePagingOptions(pageSize: pagingInfo.pageSize,
|
||||
cursor: some(pagingInfo.cursor),
|
||||
forward: if pagingInfo.direction == PagingDirection.FORWARD: true else: false)
|
||||
|
||||
proc toStoreResponse*(historyResponse: HistoryResponse): StoreResponse =
|
||||
StoreResponse(messages: historyResponse.messages,
|
||||
pagingOptions: if historyResponse.pagingInfo != PagingInfo(): some(historyResponse.pagingInfo.toPagingOptions()) else: none(StorePagingOptions))
|
|
@ -0,0 +1,33 @@
|
|||
import
|
||||
std/options,
|
||||
json_rpc/rpcserver,
|
||||
../../waku_types,
|
||||
../wakunode2,
|
||||
./jsonrpc_types, ./jsonrpc_utils
|
||||
|
||||
proc setupWakuJSONRPC*(node: WakuNode, rpcsrv: RpcServer) =
|
||||
const futTimeout = 5.seconds
|
||||
|
||||
## Store API version 1 definitions
|
||||
|
||||
rpcsrv.rpc("get_waku_v2_store_v1_messages") do(topics: seq[ContentTopic], pagingOptions: Option[StorePagingOptions]) -> StoreResponse:
|
||||
## Returns history for a list of content topics with optional paging
|
||||
debug "get_waku_v2_store_v1_messages"
|
||||
|
||||
var responseFut = newFuture[StoreResponse]()
|
||||
|
||||
proc queryFuncHandler(response: HistoryResponse) {.gcsafe, closure.} =
|
||||
debug "get_waku_v2_store_v1_messages response"
|
||||
responseFut.complete(response.toStoreResponse())
|
||||
|
||||
let historyQuery = HistoryQuery(topics: topics,
|
||||
pagingInfo: if pagingOptions.isSome: pagingOptions.get.toPagingInfo() else: PagingInfo())
|
||||
|
||||
await node.query(historyQuery, queryFuncHandler)
|
||||
|
||||
if (await responseFut.withTimeout(futTimeout)):
|
||||
# Future completed
|
||||
return responseFut.read()
|
||||
else:
|
||||
# Future failed to complete
|
||||
raise newException(ValueError, "No history response received")
|
Loading…
Reference in New Issue