2020-12-01 09:57:54 +00:00
|
|
|
{.push raises: [Exception, Defect].}
|
|
|
|
|
2020-11-27 07:18:48 +00:00
|
|
|
import
|
2020-12-01 09:57:54 +00:00
|
|
|
std/[tables,sequtils],
|
2020-11-27 07:18:48 +00:00
|
|
|
json_rpc/rpcserver,
|
2020-12-01 09:57:54 +00:00
|
|
|
libp2p/protocols/pubsub/pubsub,
|
2020-11-27 07:18:48 +00:00
|
|
|
eth/[common, rlp, keys, p2p],
|
2020-11-30 09:44:57 +00:00
|
|
|
../wakunode2,
|
2021-01-06 09:35:05 +00:00
|
|
|
./jsonrpc_types, ./jsonrpc_utils,
|
|
|
|
../../protocol/waku_message
|
2020-11-27 07:18:48 +00:00
|
|
|
|
2020-12-23 09:33:28 +00:00
|
|
|
export jsonrpc_types
|
|
|
|
|
2021-03-23 08:04:51 +00:00
|
|
|
logScope:
|
|
|
|
topics = "relay api"
|
|
|
|
|
2020-12-07 13:26:58 +00:00
|
|
|
const futTimeout* = 5.seconds # Max time to wait for futures
|
2021-04-09 20:47:24 +00:00
|
|
|
const maxCache* = 30 # Max number of messages cached per topic @TODO make this configurable
|
2020-12-07 13:26:58 +00:00
|
|
|
|
2020-12-23 09:33:28 +00:00
|
|
|
proc installRelayApiHandlers*(node: WakuNode, rpcsrv: RpcServer, topicCache: TopicCache) =
|
2020-12-01 09:57:54 +00:00
|
|
|
|
|
|
|
proc topicHandler(topic: string, data: seq[byte]) {.async.} =
|
2021-03-11 07:48:59 +00:00
|
|
|
trace "Topic handler triggered", topic=topic
|
2020-12-01 09:57:54 +00:00
|
|
|
let msg = WakuMessage.init(data)
|
|
|
|
if msg.isOk():
|
|
|
|
# Add message to current cache
|
2020-12-07 13:26:58 +00:00
|
|
|
trace "WakuMessage received", msg=msg, topic=topic
|
|
|
|
|
|
|
|
# Make a copy of msgs for this topic to modify
|
|
|
|
var msgs = topicCache.getOrDefault(topic, @[])
|
|
|
|
|
|
|
|
if msgs.len >= maxCache:
|
|
|
|
# Message cache on this topic exceeds maximum. Delete oldest.
|
|
|
|
# @TODO this may become a bottle neck if called as the norm rather than exception when adding messages. Performance profile needed.
|
|
|
|
msgs.delete(0,0)
|
|
|
|
msgs.add(msg[])
|
|
|
|
|
|
|
|
# Replace indexed entry with copy
|
|
|
|
# @TODO max number of topics could be limited in node
|
|
|
|
topicCache[topic] = msgs
|
2020-12-01 09:57:54 +00:00
|
|
|
else:
|
|
|
|
debug "WakuMessage received but failed to decode", msg=msg, topic=topic
|
|
|
|
# @TODO handle message decode failure
|
2021-03-11 07:48:59 +00:00
|
|
|
|
|
|
|
## Node may already be subscribed to some topics when Relay API handlers are installed. Let's add these
|
|
|
|
for topic in PubSub(node.wakuRelay).topics.keys:
|
|
|
|
debug "Adding API topic handler for existing subscription", topic=topic
|
|
|
|
|
|
|
|
node.subscribe(topic, topicHandler)
|
|
|
|
|
|
|
|
# Create message cache for this topic
|
|
|
|
debug "MessageCache for topic", topic=topic
|
|
|
|
topicCache[topic] = @[]
|
2020-11-27 07:18:48 +00:00
|
|
|
|
|
|
|
## Relay API version 1 definitions
|
2020-11-30 09:44:57 +00:00
|
|
|
|
|
|
|
rpcsrv.rpc("post_waku_v2_relay_v1_message") do(topic: string, message: WakuRelayMessage) -> bool:
|
|
|
|
## Publishes a WakuMessage to a PubSub topic
|
|
|
|
debug "post_waku_v2_relay_v1_message"
|
|
|
|
|
2020-12-02 08:40:53 +00:00
|
|
|
if (await node.publish(topic, message.toWakuMessage(version = 0)).withTimeout(futTimeout)):
|
|
|
|
# Successfully published message
|
|
|
|
return true
|
|
|
|
else:
|
|
|
|
# Failed to publish message to topic
|
|
|
|
raise newException(ValueError, "Failed to publish to topic " & topic)
|
2020-11-27 07:18:48 +00:00
|
|
|
|
2020-12-01 09:57:54 +00:00
|
|
|
rpcsrv.rpc("get_waku_v2_relay_v1_messages") do(topic: string) -> seq[WakuMessage]:
|
|
|
|
## Returns all WakuMessages received on a PubSub topic since the
|
|
|
|
## last time this method was called
|
|
|
|
## @TODO ability to specify a return message limit
|
|
|
|
debug "get_waku_v2_relay_v1_messages", topic=topic
|
|
|
|
|
|
|
|
if topicCache.hasKey(topic):
|
|
|
|
let msgs = topicCache[topic]
|
|
|
|
# Clear cache before next call
|
|
|
|
topicCache[topic] = @[]
|
|
|
|
return msgs
|
|
|
|
else:
|
|
|
|
# Not subscribed to this topic
|
|
|
|
raise newException(ValueError, "Not subscribed to topic: " & topic)
|
|
|
|
|
2020-11-27 07:18:48 +00:00
|
|
|
rpcsrv.rpc("post_waku_v2_relay_v1_subscriptions") do(topics: seq[string]) -> bool:
|
|
|
|
## Subscribes a node to a list of PubSub topics
|
|
|
|
debug "post_waku_v2_relay_v1_subscriptions"
|
|
|
|
|
|
|
|
# Subscribe to all requested topics
|
|
|
|
for topic in topics:
|
2021-03-11 07:48:59 +00:00
|
|
|
# Only subscribe to topics for which we have no subscribed topic handlers yet
|
|
|
|
if not topicCache.hasKey(topic):
|
|
|
|
node.subscribe(topic, topicHandler)
|
|
|
|
# Create message cache for this topic
|
|
|
|
trace "MessageCache for topic", topic=topic
|
|
|
|
topicCache[topic] = @[]
|
2021-02-02 11:33:59 +00:00
|
|
|
|
|
|
|
# Successfully subscribed to all requested topics
|
|
|
|
return true
|
2020-11-27 07:18:48 +00:00
|
|
|
|
|
|
|
rpcsrv.rpc("delete_waku_v2_relay_v1_subscriptions") do(topics: seq[string]) -> bool:
|
|
|
|
## Unsubscribes a node from a list of PubSub topics
|
|
|
|
debug "delete_waku_v2_relay_v1_subscriptions"
|
|
|
|
|
|
|
|
# Unsubscribe all handlers from requested topics
|
|
|
|
for topic in topics:
|
2021-02-02 11:33:59 +00:00
|
|
|
node.unsubscribeAll(topic)
|
|
|
|
# Remove message cache for topic
|
|
|
|
topicCache.del(topic)
|
2020-11-27 07:18:48 +00:00
|
|
|
|
2021-02-02 11:33:59 +00:00
|
|
|
# Successfully unsubscribed from all requested topics
|
|
|
|
return true
|