mirror of https://github.com/waku-org/nwaku.git
feature/mount-filter-node-api (#181)
* started working on filter mount * fixes * fix indentation * fixes * save * change * rm * Update waku_types.nim * Update waku_filter.nim * fixes * fix * using new filter * did some testing stuff * rm * fix * updated * update doc * fix * fix * unasynced * fix * w -> node * rename * move to content filter * fix * method * rename * renamed contentFilter -> contentFilters * readded * moved * first test fix * readded * no more need * fixes * fix * fix * fixes * todo * removes mother fuck * Update waku_types.nim
This commit is contained in:
parent
75be455272
commit
a975bf6d70
|
@ -25,14 +25,11 @@ method subscribe*(w: WakuNode, topic: Topic, handler: TopicHandler)
|
||||||
## NOTE The data field SHOULD be decoded as a WakuMessage.
|
## NOTE The data field SHOULD be decoded as a WakuMessage.
|
||||||
## Status: Implemented.
|
## Status: Implemented.
|
||||||
|
|
||||||
method subscribe*(w: WakuNode, contentFilter: ContentFilter, handler: ContentFilterHandler)
|
method subscribe*(w: WakuNode, filter: FilterRequest, handler: ContentFilterHandler)
|
||||||
## Subscribes to a ContentFilter. Triggers handler when receiving messages on
|
## Registers for messages that match a specific filter. Triggers the handler whenever a message is received.
|
||||||
## this content filter. ContentFilter is a method that takes some content
|
## FilterHandler is a method that takes a MessagePush.
|
||||||
## filter, specifically with `ContentTopic`, and a `Message`. The `Message`
|
##
|
||||||
## has to match the `ContentTopic`.
|
## Status: Implemented.
|
||||||
|
|
||||||
## Status: Not yet implemented.
|
|
||||||
## TODO Implement as wrapper around `waku_filter` and `subscribe` above.
|
|
||||||
|
|
||||||
method unsubscribe*(w: WakuNode, topic: Topic)
|
method unsubscribe*(w: WakuNode, topic: Topic)
|
||||||
## Unsubscribe from a topic.
|
## Unsubscribe from a topic.
|
||||||
|
|
|
@ -29,20 +29,21 @@ procSuite "Waku Filter":
|
||||||
var listenSwitch = newStandardSwitch(some(key))
|
var listenSwitch = newStandardSwitch(some(key))
|
||||||
discard await listenSwitch.start()
|
discard await listenSwitch.start()
|
||||||
|
|
||||||
var completionFut = newFuture[bool]()
|
var responseRequestIdFuture = newFuture[string]()
|
||||||
proc handle(msg: MessagePush) {.async, gcsafe, closure.} =
|
proc handle(requestId: string, msg: MessagePush) {.gcsafe, closure.} =
|
||||||
check:
|
check:
|
||||||
msg.messages.len() == 1
|
msg.messages.len() == 1
|
||||||
msg.messages[0] == post
|
msg.messages[0] == post
|
||||||
completionFut.complete(true)
|
responseRequestIdFuture.complete(requestId)
|
||||||
|
|
||||||
let
|
let
|
||||||
proto = WakuFilter.init(dialSwitch, crypto.newRng(), handle)
|
proto = WakuFilter.init(dialSwitch, crypto.newRng(), handle)
|
||||||
rpc = FilterRequest(contentFilter: @[ContentFilter(topics: @["pew", "pew2"])], topic: "topic")
|
rpc = FilterRequest(contentFilters: @[ContentFilter(topics: @["pew", "pew2"])], topic: "topic")
|
||||||
|
|
||||||
dialSwitch.mount(proto)
|
dialSwitch.mount(proto)
|
||||||
|
proto.setPeer(listenSwitch.peerInfo)
|
||||||
|
|
||||||
proc emptyHandle(msg: MessagePush) {.async, gcsafe, closure.} =
|
proc emptyHandle(requestId: string, msg: MessagePush) {.gcsafe, closure.} =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
let
|
let
|
||||||
|
@ -53,11 +54,11 @@ procSuite "Waku Filter":
|
||||||
subscriptions["test"] = subscription
|
subscriptions["test"] = subscription
|
||||||
listenSwitch.mount(proto2)
|
listenSwitch.mount(proto2)
|
||||||
|
|
||||||
await proto.subscribe(listenSwitch.peerInfo, rpc)
|
let id = await proto.subscribe(rpc)
|
||||||
|
|
||||||
await sleepAsync(2.seconds)
|
await sleepAsync(2.seconds)
|
||||||
|
|
||||||
await subscriptions.notify("topic", post)
|
await subscriptions.notify("topic", post)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
(await completionFut.withTimeout(5.seconds)) == true
|
(await responseRequestIdFuture) == id
|
||||||
|
|
|
@ -7,7 +7,7 @@ import
|
||||||
libp2p/crypto/secp,
|
libp2p/crypto/secp,
|
||||||
libp2p/switch,
|
libp2p/switch,
|
||||||
eth/keys,
|
eth/keys,
|
||||||
../../waku/protocol/v2/[waku_relay, waku_store, message_notifier],
|
../../waku/protocol/v2/[waku_relay, waku_store, waku_filter, message_notifier],
|
||||||
../../waku/node/v2/[wakunode2, waku_types],
|
../../waku/node/v2/[wakunode2, waku_types],
|
||||||
../test_helpers
|
../test_helpers
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ procSuite "WakuNode":
|
||||||
Port(60000))
|
Port(60000))
|
||||||
pubSubTopic = "chat"
|
pubSubTopic = "chat"
|
||||||
contentTopic = "foobar"
|
contentTopic = "foobar"
|
||||||
contentFilter = ContentFilter(topics: @[contentTopic])
|
filterRequest = FilterRequest(topic: pubSubTopic, contentFilters: @[ContentFilter(topics: @[contentTopic])])
|
||||||
message = WakuMessage(payload: "hello world".toBytes(),
|
message = WakuMessage(payload: "hello world".toBytes(),
|
||||||
contentTopic: contentTopic)
|
contentTopic: contentTopic)
|
||||||
|
|
||||||
|
@ -31,24 +31,28 @@ procSuite "WakuNode":
|
||||||
if msg.isOk():
|
if msg.isOk():
|
||||||
check:
|
check:
|
||||||
topic == "chat"
|
topic == "chat"
|
||||||
node.filters.notify(msg[])
|
node.filters.notify(msg.value(), topic)
|
||||||
|
|
||||||
var completionFut = newFuture[bool]()
|
var completionFut = newFuture[bool]()
|
||||||
|
|
||||||
# This would be the actual application handler
|
# This would be the actual application handler
|
||||||
proc contentHandler(message: seq[byte]) {.gcsafe, closure.} =
|
proc contentHandler(msg: WakuMessage) {.gcsafe, closure.} =
|
||||||
let msg = string.fromBytes(message)
|
let message = string.fromBytes(msg.payload)
|
||||||
check:
|
check:
|
||||||
msg == "hello world"
|
message == "hello world"
|
||||||
completionFut.complete(true)
|
completionFut.complete(true)
|
||||||
|
|
||||||
await node.start()
|
await node.start()
|
||||||
|
|
||||||
# Subscribe our node to the pubSubTopic where all chat data go onto.
|
# Subscribe our node to the pubSubTopic where all chat data go onto.
|
||||||
await node.subscribe(pubSubTopic, relayHandler)
|
await node.subscribe(pubSubTopic, relayHandler)
|
||||||
|
|
||||||
# Subscribe a contentFilter to trigger a specific application handler when
|
# Subscribe a contentFilter to trigger a specific application handler when
|
||||||
# WakuMessages with that content are received
|
# WakuMessages with that content are received
|
||||||
await node.subscribe(contentFilter, contentHandler)
|
# node2.wakuFilter.setPeer(node1.peerInfo)
|
||||||
|
await node.subscribe(filterRequest, contentHandler)
|
||||||
|
|
||||||
|
await sleepAsync(2000.millis)
|
||||||
|
|
||||||
node.publish(pubSubTopic, message)
|
node.publish(pubSubTopic, message)
|
||||||
|
|
||||||
|
@ -67,7 +71,7 @@ procSuite "WakuNode":
|
||||||
Port(60002))
|
Port(60002))
|
||||||
pubSubTopic = "chat"
|
pubSubTopic = "chat"
|
||||||
contentTopic = "foobar"
|
contentTopic = "foobar"
|
||||||
contentFilter = ContentFilter(topics: @[contentTopic])
|
filterRequest = FilterRequest(topic: pubSubTopic, contentFilters: @[ContentFilter(topics: @[contentTopic])])
|
||||||
message = WakuMessage(payload: "hello world".toBytes(),
|
message = WakuMessage(payload: "hello world".toBytes(),
|
||||||
contentTopic: contentTopic)
|
contentTopic: contentTopic)
|
||||||
|
|
||||||
|
@ -80,13 +84,13 @@ procSuite "WakuNode":
|
||||||
if msg.isOk():
|
if msg.isOk():
|
||||||
check:
|
check:
|
||||||
topic == "chat"
|
topic == "chat"
|
||||||
node1.filters.notify(msg[])
|
node1.filters.notify(msg.value(), topic)
|
||||||
|
|
||||||
# This would be the actual application handler
|
# This would be the actual application handler
|
||||||
proc contentHandler1(message: seq[byte]) {.gcsafe, closure.} =
|
proc contentHandler(msg: WakuMessage) {.gcsafe, closure.} =
|
||||||
let msg = string.fromBytes(message)
|
let message = string.fromBytes(msg.payload)
|
||||||
check:
|
check:
|
||||||
msg == "hello world"
|
message == "hello world"
|
||||||
completionFut.complete(true)
|
completionFut.complete(true)
|
||||||
|
|
||||||
await allFutures([node1.start(), node2.start()])
|
await allFutures([node1.start(), node2.start()])
|
||||||
|
@ -95,10 +99,13 @@ procSuite "WakuNode":
|
||||||
await node1.subscribe(pubSubTopic, relayHandler)
|
await node1.subscribe(pubSubTopic, relayHandler)
|
||||||
# Subscribe a contentFilter to trigger a specific application handler when
|
# Subscribe a contentFilter to trigger a specific application handler when
|
||||||
# WakuMessages with that content are received
|
# WakuMessages with that content are received
|
||||||
await node1.subscribe(contentFilter, contentHandler1)
|
node1.wakuFilter.setPeer(node2.peerInfo)
|
||||||
|
await node1.subscribe(filterRequest, contentHandler)
|
||||||
|
await sleepAsync(2000.millis)
|
||||||
|
|
||||||
# Connect peers by dialing from node2 to node1
|
# Connect peers by dialing from node2 to node1
|
||||||
let conn = await node2.switch.dial(node1.peerInfo, WakuRelayCodec)
|
let conn = await node2.switch.dial(node1.peerInfo, WakuRelayCodec)
|
||||||
#
|
|
||||||
# We need to sleep to allow the subscription to go through
|
# We need to sleep to allow the subscription to go through
|
||||||
info "Going to sleep to allow subscribe to go through"
|
info "Going to sleep to allow subscribe to go through"
|
||||||
await sleepAsync(2000.millis)
|
await sleepAsync(2000.millis)
|
||||||
|
@ -144,3 +151,39 @@ procSuite "WakuNode":
|
||||||
(await completionFut.withTimeout(5.seconds)) == true
|
(await completionFut.withTimeout(5.seconds)) == true
|
||||||
await node1.stop()
|
await node1.stop()
|
||||||
await node2.stop()
|
await node2.stop()
|
||||||
|
|
||||||
|
asyncTest "Filter protocol returns expected message":
|
||||||
|
let
|
||||||
|
nodeKey1 = crypto.PrivateKey.random(Secp256k1, rng[])[]
|
||||||
|
node1 = WakuNode.init(nodeKey1, ValidIpAddress.init("0.0.0.0"),
|
||||||
|
Port(60000))
|
||||||
|
nodeKey2 = crypto.PrivateKey.random(Secp256k1, rng[])[]
|
||||||
|
node2 = WakuNode.init(nodeKey2, ValidIpAddress.init("0.0.0.0"),
|
||||||
|
Port(60002))
|
||||||
|
contentTopic = "foobar"
|
||||||
|
message = WakuMessage(payload: "hello world".toBytes(), contentTopic: contentTopic)
|
||||||
|
|
||||||
|
var completionFut = newFuture[bool]()
|
||||||
|
|
||||||
|
await node1.start()
|
||||||
|
await node2.start()
|
||||||
|
|
||||||
|
node1.wakuFilter.setPeer(node2.peerInfo)
|
||||||
|
|
||||||
|
proc handler(msg: WakuMessage) {.gcsafe, closure.} =
|
||||||
|
check:
|
||||||
|
msg == message
|
||||||
|
completionFut.complete(true)
|
||||||
|
|
||||||
|
await node1.subscribe(FilterRequest(topic: "waku", contentFilters: @[ContentFilter(topics: @[contentTopic])]), handler)
|
||||||
|
|
||||||
|
await sleepAsync(2000.millis)
|
||||||
|
|
||||||
|
await node2.subscriptions.notify("waku", message)
|
||||||
|
|
||||||
|
await sleepAsync(2000.millis)
|
||||||
|
|
||||||
|
check:
|
||||||
|
(await completionFut.withTimeout(5.seconds)) == true
|
||||||
|
await node1.stop()
|
||||||
|
await node2.stop()
|
||||||
|
|
|
@ -6,6 +6,7 @@ proc waku_publish(topic: string, message: seq[byte]): bool
|
||||||
proc waku_publish2(topic: string, message: seq[byte]): bool
|
proc waku_publish2(topic: string, message: seq[byte]): bool
|
||||||
proc waku_subscribe(topic: string): bool
|
proc waku_subscribe(topic: string): bool
|
||||||
proc waku_query(topics: seq[string]): bool
|
proc waku_query(topics: seq[string]): bool
|
||||||
|
proc waku_subscribe_filter(topic: string, contentFilters: seq[seq[string]]): bool
|
||||||
#proc waku_subscribe(topic: string, handler: Topichandler): bool
|
#proc waku_subscribe(topic: string, handler: Topichandler): bool
|
||||||
|
|
||||||
# NYI
|
# NYI
|
||||||
|
|
|
@ -75,3 +75,17 @@ proc setupWakuRPC*(node: WakuNode, rpcsrv: RpcServer) =
|
||||||
|
|
||||||
await node.query(HistoryQuery(topics: topics), handler)
|
await node.query(HistoryQuery(topics: topics), handler)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
rpcsrv.rpc("waku_subscribe_filter") do(topic: string, contentFilters: seq[seq[string]]) -> bool:
|
||||||
|
debug "waku_subscribe_filter"
|
||||||
|
|
||||||
|
# XXX: Hacky in-line handler
|
||||||
|
proc handler(msg: WakuMessage) {.gcsafe, closure.} =
|
||||||
|
info "Hit subscribe response", message=msg
|
||||||
|
|
||||||
|
var filters = newSeq[ContentFilter]()
|
||||||
|
for topics in contentFilters:
|
||||||
|
filters.add(ContentFilter(topics: topics))
|
||||||
|
|
||||||
|
await node.subscribe(FilterRequest(topic: topic, contentFilters: filters), handler)
|
||||||
|
return true
|
||||||
|
|
|
@ -18,20 +18,6 @@ type
|
||||||
Topic* = string
|
Topic* = string
|
||||||
Message* = seq[byte]
|
Message* = seq[byte]
|
||||||
|
|
||||||
# TODO: these filter structures can be simplified but like this for now to
|
|
||||||
# match Node API
|
|
||||||
# Also, should reuse in filter/wakufilter code, but cyclic imports right now.
|
|
||||||
ContentFilter* = object
|
|
||||||
topics*: seq[string]
|
|
||||||
|
|
||||||
ContentFilterHandler* = proc(message: seq[byte]) {.gcsafe, closure.}
|
|
||||||
|
|
||||||
Filter* = object
|
|
||||||
contentFilter*: ContentFilter
|
|
||||||
handler*: ContentFilterHandler
|
|
||||||
|
|
||||||
Filters* = Table[string, Filter]
|
|
||||||
|
|
||||||
WakuMessage* = object
|
WakuMessage* = object
|
||||||
payload*: seq[byte]
|
payload*: seq[byte]
|
||||||
contentTopic*: string
|
contentTopic*: string
|
||||||
|
@ -67,7 +53,7 @@ type
|
||||||
messages*: seq[WakuMessage]
|
messages*: seq[WakuMessage]
|
||||||
|
|
||||||
FilterRequest* = object
|
FilterRequest* = object
|
||||||
contentFilter*: seq[ContentFilter]
|
contentFilters*: seq[ContentFilter]
|
||||||
topic*: string
|
topic*: string
|
||||||
|
|
||||||
MessagePush* = object
|
MessagePush* = object
|
||||||
|
@ -83,14 +69,30 @@ type
|
||||||
requestId*: string
|
requestId*: string
|
||||||
filter*: FilterRequest # @TODO MAKE THIS A SEQUENCE AGAIN?
|
filter*: FilterRequest # @TODO MAKE THIS A SEQUENCE AGAIN?
|
||||||
|
|
||||||
MessagePushHandler* = proc(msg: MessagePush): Future[void] {.gcsafe, closure.}
|
MessagePushHandler* = proc(requestId: string, msg: MessagePush) {.gcsafe, closure.}
|
||||||
|
|
||||||
|
FilterPeer* = object
|
||||||
|
peerInfo*: PeerInfo
|
||||||
|
|
||||||
WakuFilter* = ref object of LPProtocol
|
WakuFilter* = ref object of LPProtocol
|
||||||
rng*: ref BrHmacDrbgContext
|
rng*: ref BrHmacDrbgContext
|
||||||
switch*: Switch
|
switch*: Switch
|
||||||
|
peers*: seq[FilterPeer]
|
||||||
subscribers*: seq[Subscriber]
|
subscribers*: seq[Subscriber]
|
||||||
pushHandler*: MessagePushHandler
|
pushHandler*: MessagePushHandler
|
||||||
|
|
||||||
|
ContentFilter* = object
|
||||||
|
topics*: seq[string]
|
||||||
|
|
||||||
|
ContentFilterHandler* = proc(msg: WakuMessage) {.gcsafe, closure.}
|
||||||
|
|
||||||
|
Filter* = object
|
||||||
|
contentFilters*: seq[ContentFilter]
|
||||||
|
handler*: ContentFilterHandler
|
||||||
|
|
||||||
|
# @TODO MAYBE MORE INFO?
|
||||||
|
Filters* = Table[string, Filter]
|
||||||
|
|
||||||
# NOTE based on Eth2Node in NBC eth2_network.nim
|
# NOTE based on Eth2Node in NBC eth2_network.nim
|
||||||
WakuNode* = ref object of RootObj
|
WakuNode* = ref object of RootObj
|
||||||
switch*: Switch
|
switch*: Switch
|
||||||
|
@ -125,13 +127,23 @@ proc encode*(message: WakuMessage): ProtoBuffer =
|
||||||
result.write(1, message.payload)
|
result.write(1, message.payload)
|
||||||
result.write(2, message.contentTopic)
|
result.write(2, message.contentTopic)
|
||||||
|
|
||||||
proc notify*(filters: Filters, msg: WakuMessage) =
|
proc notify*(filters: Filters, msg: WakuMessage, requestId: string = "") =
|
||||||
for filter in filters.values:
|
for key in filters.keys:
|
||||||
|
let filter = filters[key]
|
||||||
|
# We do this because the key for the filter is set to the requestId received from the filter protocol.
|
||||||
|
# This means we do not need to check the content filter explicitly as all MessagePushs already contain
|
||||||
|
# the requestId of the coresponding filter.
|
||||||
|
if requestId != "" and requestId == key:
|
||||||
|
filter.handler(msg)
|
||||||
|
continue
|
||||||
|
|
||||||
# TODO: In case of no topics we should either trigger here for all messages,
|
# TODO: In case of no topics we should either trigger here for all messages,
|
||||||
# or we should not allow such filter to exist in the first place.
|
# or we should not allow such filter to exist in the first place.
|
||||||
if filter.contentFilter.topics.len > 0:
|
for contentFilter in filter.contentFilters:
|
||||||
if msg.contentTopic in filter.contentFilter.topics:
|
if contentFilter.topics.len > 0:
|
||||||
filter.handler(msg.payload)
|
if msg.contentTopic in contentFilter.topics:
|
||||||
|
filter.handler(msg)
|
||||||
|
break
|
||||||
|
|
||||||
proc generateRequestId*(rng: ref BrHmacDrbgContext): string =
|
proc generateRequestId*(rng: ref BrHmacDrbgContext): string =
|
||||||
var bytes: array[10, byte]
|
var bytes: array[10, byte]
|
||||||
|
|
|
@ -88,7 +88,8 @@ proc init*(T: type WakuNode, nodeKey: crypto.PrivateKey,
|
||||||
rng: crypto.newRng(),
|
rng: crypto.newRng(),
|
||||||
peerInfo: peerInfo,
|
peerInfo: peerInfo,
|
||||||
wakuRelay: wakuRelay,
|
wakuRelay: wakuRelay,
|
||||||
subscriptions: newTable[string, MessageNotificationSubscription]()
|
subscriptions: newTable[string, MessageNotificationSubscription](),
|
||||||
|
filters: initTable[string, Filter]()
|
||||||
)
|
)
|
||||||
|
|
||||||
for topic in topics:
|
for topic in topics:
|
||||||
|
@ -108,17 +109,19 @@ proc start*(node: WakuNode) {.async.} =
|
||||||
node.switch.mount(node.wakuStore)
|
node.switch.mount(node.wakuStore)
|
||||||
node.subscriptions.subscribe(WakuStoreCodec, node.wakuStore.subscription())
|
node.subscriptions.subscribe(WakuStoreCodec, node.wakuStore.subscription())
|
||||||
|
|
||||||
proc pushHandler(msg: MessagePush) {.async, gcsafe.} =
|
proc filterHandler(requestId: string, msg: MessagePush) {.gcsafe.} =
|
||||||
info "push received"
|
info "push received"
|
||||||
|
for message in msg.messages:
|
||||||
|
node.filters.notify(message, requestId)
|
||||||
|
|
||||||
node.wakuFilter = WakuFilter.init(node.switch, node.rng, pushHandler)
|
node.wakuFilter = WakuFilter.init(node.switch, node.rng, filterHandler)
|
||||||
node.switch.mount(node.wakuFilter)
|
node.switch.mount(node.wakuFilter)
|
||||||
node.subscriptions.subscribe(WakuFilterCodec, node.wakuFilter.subscription())
|
node.subscriptions.subscribe(WakuFilterCodec, node.wakuFilter.subscription())
|
||||||
|
|
||||||
proc relayHandler(topic: string, data: seq[byte]) {.async, gcsafe.} =
|
proc relayHandler(topic: string, data: seq[byte]) {.async, gcsafe.} =
|
||||||
let msg = WakuMessage.init(data)
|
let msg = WakuMessage.init(data)
|
||||||
if msg.isOk():
|
if msg.isOk():
|
||||||
await node.subscriptions.notify(topic, msg.value())
|
node.filters.notify(msg.value(), "")
|
||||||
|
|
||||||
await node.wakuRelay.subscribe("waku", relayHandler)
|
await node.wakuRelay.subscribe("waku", relayHandler)
|
||||||
|
|
||||||
|
@ -146,15 +149,16 @@ proc subscribe*(node: WakuNode, topic: Topic, handler: TopicHandler) {.async.} =
|
||||||
let wakuRelay = node.wakuRelay
|
let wakuRelay = node.wakuRelay
|
||||||
await wakuRelay.subscribe(topic, handler)
|
await wakuRelay.subscribe(topic, handler)
|
||||||
|
|
||||||
proc subscribe*(node: WakuNode, contentFilter: waku_types.ContentFilter, handler: ContentFilterHandler) {.async.} =
|
proc subscribe*(node: WakuNode, request: FilterRequest, handler: ContentFilterHandler) {.async, gcsafe.} =
|
||||||
## Subscribes to a ContentFilter. Triggers handler when receiving messages on
|
## Registers for messages that match a specific filter. Triggers the handler whenever a message is received.
|
||||||
## this content filter. ContentFilter is a method that takes some content
|
## FilterHandler is a method that takes a MessagePush.
|
||||||
## filter, specifically with `ContentTopic`, and a `Message`. The `Message`
|
##
|
||||||
## has to match the `ContentTopic`.
|
## Status: Implemented.
|
||||||
info "subscribe content", contentFilter=contentFilter
|
info "subscribe content", filter=request
|
||||||
|
|
||||||
# TODO: get some random id, or use the Filter directly as key
|
# @TODO: ERROR HANDLING
|
||||||
node.filters.add("some random id", Filter(contentFilter: contentFilter, handler: handler))
|
let id = await node.wakuFilter.subscribe(request)
|
||||||
|
node.filters[id] = Filter(contentFilters: request.contentFilters, handler: handler)
|
||||||
|
|
||||||
proc unsubscribe*(w: WakuNode, topic: Topic) =
|
proc unsubscribe*(w: WakuNode, topic: Topic) =
|
||||||
echo "NYI"
|
echo "NYI"
|
||||||
|
|
|
@ -32,7 +32,7 @@ proc encode*(filter: ContentFilter): ProtoBuffer =
|
||||||
proc encode*(rpc: FilterRequest): ProtoBuffer =
|
proc encode*(rpc: FilterRequest): ProtoBuffer =
|
||||||
result = initProtoBuffer()
|
result = initProtoBuffer()
|
||||||
|
|
||||||
for filter in rpc.contentFilter:
|
for filter in rpc.contentFilters:
|
||||||
result.write(1, filter.encode())
|
result.write(1, filter.encode())
|
||||||
|
|
||||||
result.write(2, rpc.topic)
|
result.write(2, rpc.topic)
|
||||||
|
@ -46,14 +46,14 @@ proc init*(T: type ContentFilter, buffer: seq[byte]): ProtoResult[T] =
|
||||||
ok(ContentFilter(topics: topics))
|
ok(ContentFilter(topics: topics))
|
||||||
|
|
||||||
proc init*(T: type FilterRequest, buffer: seq[byte]): ProtoResult[T] =
|
proc init*(T: type FilterRequest, buffer: seq[byte]): ProtoResult[T] =
|
||||||
var rpc = FilterRequest(contentFilter: @[], topic: "")
|
var rpc = FilterRequest(contentFilters: @[], topic: "")
|
||||||
let pb = initProtoBuffer(buffer)
|
let pb = initProtoBuffer(buffer)
|
||||||
|
|
||||||
var buffs: seq[seq[byte]]
|
var buffs: seq[seq[byte]]
|
||||||
discard ? pb.getRepeatedField(1, buffs)
|
discard ? pb.getRepeatedField(1, buffs)
|
||||||
|
|
||||||
for buf in buffs:
|
for buf in buffs:
|
||||||
rpc.contentFilter.add(? ContentFilter.init(buf))
|
rpc.contentFilters.add(? ContentFilter.init(buf))
|
||||||
|
|
||||||
discard ? pb.getField(2, rpc.topic)
|
discard ? pb.getField(2, rpc.topic)
|
||||||
|
|
||||||
|
@ -81,13 +81,15 @@ proc init*(T: type FilterRPC, buffer: seq[byte]): ProtoResult[T] =
|
||||||
var rpc = FilterRPC()
|
var rpc = FilterRPC()
|
||||||
let pb = initProtoBuffer(buffer)
|
let pb = initProtoBuffer(buffer)
|
||||||
|
|
||||||
|
discard ? pb.getField(1, rpc.requestId)
|
||||||
|
|
||||||
var requestBuffer: seq[byte]
|
var requestBuffer: seq[byte]
|
||||||
discard ? pb.getField(1, requestBuffer)
|
discard ? pb.getField(2, requestBuffer)
|
||||||
|
|
||||||
rpc.request = ? FilterRequest.init(requestBuffer)
|
rpc.request = ? FilterRequest.init(requestBuffer)
|
||||||
|
|
||||||
var pushBuffer: seq[byte]
|
var pushBuffer: seq[byte]
|
||||||
discard ? pb.getField(2, pushBuffer)
|
discard ? pb.getField(3, pushBuffer)
|
||||||
|
|
||||||
rpc.push = ? MessagePush.init(pushBuffer)
|
rpc.push = ? MessagePush.init(pushBuffer)
|
||||||
|
|
||||||
|
@ -96,8 +98,9 @@ proc init*(T: type FilterRPC, buffer: seq[byte]): ProtoResult[T] =
|
||||||
proc encode*(rpc: FilterRPC): ProtoBuffer =
|
proc encode*(rpc: FilterRPC): ProtoBuffer =
|
||||||
result = initProtoBuffer()
|
result = initProtoBuffer()
|
||||||
|
|
||||||
result.write(1, rpc.request.encode())
|
result.write(1, rpc.requestId)
|
||||||
result.write(2, rpc.push.encode())
|
result.write(2, rpc.request.encode())
|
||||||
|
result.write(3, rpc.push.encode())
|
||||||
|
|
||||||
method init*(wf: WakuFilter) =
|
method init*(wf: WakuFilter) =
|
||||||
proc handle(conn: Connection, proto: string) {.async, gcsafe, closure.} =
|
proc handle(conn: Connection, proto: string) {.async, gcsafe, closure.} =
|
||||||
|
@ -107,9 +110,11 @@ method init*(wf: WakuFilter) =
|
||||||
error "failed to decode rpc"
|
error "failed to decode rpc"
|
||||||
return
|
return
|
||||||
|
|
||||||
|
info "filter message received"
|
||||||
|
|
||||||
let value = res.value
|
let value = res.value
|
||||||
if value.push != MessagePush():
|
if value.push != MessagePush():
|
||||||
await wf.pushHandler(value.push)
|
wf.pushHandler(value.requestId, value.push)
|
||||||
if value.request != FilterRequest():
|
if value.request != FilterRequest():
|
||||||
wf.subscribers.add(Subscriber(peer: conn.peerInfo, requestId: value.requestId, filter: value.request))
|
wf.subscribers.add(Subscriber(peer: conn.peerInfo, requestId: value.requestId, filter: value.request))
|
||||||
|
|
||||||
|
@ -123,6 +128,10 @@ proc init*(T: type WakuFilter, switch: Switch, rng: ref BrHmacDrbgContext, handl
|
||||||
result.pushHandler = handler
|
result.pushHandler = handler
|
||||||
result.init()
|
result.init()
|
||||||
|
|
||||||
|
# @TODO THIS SHOULD PROBABLY BE AN ADD FUNCTION AND APPEND THE PEER TO AN ARRAY
|
||||||
|
proc setPeer*(wf: WakuFilter, peer: PeerInfo) =
|
||||||
|
wf.peers.add(FilterPeer(peerInfo: peer))
|
||||||
|
|
||||||
proc subscription*(proto: WakuFilter): MessageNotificationSubscription =
|
proc subscription*(proto: WakuFilter): MessageNotificationSubscription =
|
||||||
## Returns a Filter for the specific protocol
|
## Returns a Filter for the specific protocol
|
||||||
## This filter can then be used to send messages to subscribers that match conditions.
|
## This filter can then be used to send messages to subscribers that match conditions.
|
||||||
|
@ -131,7 +140,7 @@ proc subscription*(proto: WakuFilter): MessageNotificationSubscription =
|
||||||
if subscriber.filter.topic != topic:
|
if subscriber.filter.topic != topic:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for filter in subscriber.filter.contentFilter:
|
for filter in subscriber.filter.contentFilters:
|
||||||
if msg.contentTopic in filter.topics:
|
if msg.contentTopic in filter.topics:
|
||||||
let push = FilterRPC(requestId: subscriber.requestId, push: MessagePush(messages: @[msg]))
|
let push = FilterRPC(requestId: subscriber.requestId, push: MessagePush(messages: @[msg]))
|
||||||
let conn = await proto.switch.dial(subscriber.peer.peerId, subscriber.peer.addrs, WakuFilterCodec)
|
let conn = await proto.switch.dial(subscriber.peer.peerId, subscriber.peer.addrs, WakuFilterCodec)
|
||||||
|
@ -140,6 +149,11 @@ proc subscription*(proto: WakuFilter): MessageNotificationSubscription =
|
||||||
|
|
||||||
MessageNotificationSubscription.init(@[], handle)
|
MessageNotificationSubscription.init(@[], handle)
|
||||||
|
|
||||||
proc subscribe*(wf: WakuFilter, peer: PeerInfo, request: FilterRequest) {.async, gcsafe.} =
|
proc subscribe*(wf: WakuFilter, request: FilterRequest): Future[string] {.async, gcsafe.} =
|
||||||
let conn = await wf.switch.dial(peer.peerId, peer.addrs, WakuFilterCodec)
|
let id = generateRequestId(wf.rng)
|
||||||
await conn.writeLP(FilterRPC(requestId: generateRequestId(wf.rng), request: request).encode().buffer)
|
if wf.peers.len >= 1:
|
||||||
|
let peer = wf.peers[0].peerInfo
|
||||||
|
# @TODO: THERE SHOULD BE ERROR HANDLING HERE, WHAT IF A PEER IS GONE? WHAT IF THERE IS A TIMEOUT ETC.
|
||||||
|
let conn = await wf.switch.dial(peer.peerId, peer.addrs, WakuFilterCodec)
|
||||||
|
await conn.writeLP(FilterRPC(requestId: id, request: request).encode().buffer)
|
||||||
|
result = id
|
||||||
|
|
Loading…
Reference in New Issue