2022-11-04 10:52:27 +01:00
|
|
|
|
when (NimMajor, NimMinor) < (1, 4):
|
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
|
else:
|
|
|
|
|
{.push raises: [].}
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
|
|
|
|
import
|
2023-02-13 15:22:24 +01:00
|
|
|
|
std/sequtils,
|
2023-11-28 07:21:41 -05:00
|
|
|
|
stew/[byteutils, results],
|
2022-06-10 13:30:51 +02:00
|
|
|
|
chronicles,
|
|
|
|
|
json_serialization,
|
|
|
|
|
json_serialization/std/options,
|
2023-02-13 15:22:24 +01:00
|
|
|
|
presto/route,
|
|
|
|
|
presto/common
|
|
|
|
|
import
|
2023-09-22 09:36:46 -04:00
|
|
|
|
../../../waku_node,
|
2023-09-01 15:03:59 +02:00
|
|
|
|
../../../waku_relay/protocol,
|
2023-09-11 12:02:31 +05:30
|
|
|
|
../../../waku_rln_relay,
|
2023-09-26 07:33:52 -04:00
|
|
|
|
../../../node/waku_node,
|
|
|
|
|
../../message_cache,
|
2023-10-27 15:43:54 -04:00
|
|
|
|
../../handlers,
|
2022-08-29 16:54:11 +02:00
|
|
|
|
../serdes,
|
2023-02-13 15:22:24 +01:00
|
|
|
|
../responses,
|
2023-11-14 16:59:53 +01:00
|
|
|
|
../rest_serdes,
|
2023-09-26 07:33:52 -04:00
|
|
|
|
./types
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
2023-09-01 15:03:59 +02:00
|
|
|
|
from std/times import getTime
|
|
|
|
|
from std/times import toUnix
|
|
|
|
|
|
2023-02-13 15:22:24 +01:00
|
|
|
|
export types
|
|
|
|
|
|
|
|
|
|
logScope:
|
2022-11-03 16:36:24 +01:00
|
|
|
|
topics = "waku node rest relay_api"
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
|
|
|
|
##### Topic cache
|
|
|
|
|
|
|
|
|
|
const futTimeout* = 5.seconds # Max time to wait for futures
|
|
|
|
|
|
|
|
|
|
#### Request handlers
|
|
|
|
|
|
|
|
|
|
const ROUTE_RELAY_SUBSCRIPTIONSV1* = "/relay/v1/subscriptions"
|
2023-09-26 15:53:46 -04:00
|
|
|
|
const ROUTE_RELAY_MESSAGESV1* = "/relay/v1/messages/{pubsubTopic}"
|
2023-09-26 07:33:52 -04:00
|
|
|
|
const ROUTE_RELAY_AUTO_SUBSCRIPTIONSV1* = "/relay/v1/auto/subscriptions"
|
2023-09-26 15:53:46 -04:00
|
|
|
|
const ROUTE_RELAY_AUTO_MESSAGESV1* = "/relay/v1/auto/messages/{contentTopic}"
|
|
|
|
|
const ROUTE_RELAY_AUTO_MESSAGESV1_NO_TOPIC* = "/relay/v1/auto/messages"
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
proc installRelayApiHandlers*(
|
|
|
|
|
router: var RestRouter, node: WakuNode, cache: MessageCache
|
|
|
|
|
) =
|
|
|
|
|
router.api(MethodPost, ROUTE_RELAY_SUBSCRIPTIONSV1) do(
|
|
|
|
|
contentBody: Option[ContentBody]
|
|
|
|
|
) -> RestApiResponse:
|
2023-11-28 07:21:41 -05:00
|
|
|
|
## Subscribes a node to a list of PubSub topics
|
2024-03-16 00:08:47 +01:00
|
|
|
|
|
2023-11-28 07:21:41 -05:00
|
|
|
|
debug "post_waku_v2_relay_v1_subscriptions"
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
|
|
|
|
# Check the request body
|
|
|
|
|
if contentBody.isNone():
|
|
|
|
|
return RestApiResponse.badRequest()
|
2023-02-13 15:22:24 +01:00
|
|
|
|
|
2023-11-14 16:59:53 +01:00
|
|
|
|
let req: seq[PubsubTopic] = decodeRequestBody[seq[PubsubTopic]](contentBody).valueOr:
|
|
|
|
|
return error
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
2023-08-23 09:53:17 -04:00
|
|
|
|
# Only subscribe to topics for which we have no subscribed topic handlers yet
|
2023-11-28 07:21:41 -05:00
|
|
|
|
let newTopics = req.filterIt(not cache.isPubsubSubscribed(it))
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
2023-09-26 07:33:52 -04:00
|
|
|
|
for pubsubTopic in newTopics:
|
2023-11-28 07:21:41 -05:00
|
|
|
|
cache.pubsubSubscribe(pubsubTopic)
|
2024-03-16 00:08:47 +01:00
|
|
|
|
node.subscribe(
|
|
|
|
|
(kind: PubsubSub, topic: pubsubTopic), some(messageCacheHandler(cache))
|
|
|
|
|
)
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
|
|
|
|
return RestApiResponse.ok()
|
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
router.api(MethodDelete, ROUTE_RELAY_SUBSCRIPTIONSV1) do(
|
|
|
|
|
contentBody: Option[ContentBody]
|
|
|
|
|
) -> RestApiResponse:
|
2022-06-10 13:30:51 +02:00
|
|
|
|
# ## Subscribes a node to a list of PubSub topics
|
|
|
|
|
# debug "delete_waku_v2_relay_v1_subscriptions"
|
|
|
|
|
|
|
|
|
|
# Check the request body
|
|
|
|
|
if contentBody.isNone():
|
|
|
|
|
return RestApiResponse.badRequest()
|
2023-02-13 15:22:24 +01:00
|
|
|
|
|
2023-11-14 16:59:53 +01:00
|
|
|
|
let req: seq[PubsubTopic] = decodeRequestBody[seq[PubsubTopic]](contentBody).valueOr:
|
|
|
|
|
return error
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
|
|
|
|
# Unsubscribe all handlers from requested topics
|
2023-09-26 07:33:52 -04:00
|
|
|
|
for pubsubTopic in req:
|
2023-11-28 07:21:41 -05:00
|
|
|
|
cache.pubsubUnsubscribe(pubsubTopic)
|
2024-03-16 00:08:47 +01:00
|
|
|
|
node.unsubscribe((kind: PubsubUnsub, topic: pubsubTopic))
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
|
|
|
|
# Successfully unsubscribed from all requested topics
|
2023-02-13 15:22:24 +01:00
|
|
|
|
return RestApiResponse.ok()
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
router.api(MethodGet, ROUTE_RELAY_MESSAGESV1) do(
|
|
|
|
|
pubsubTopic: string
|
|
|
|
|
) -> RestApiResponse:
|
2022-06-10 13:30:51 +02:00
|
|
|
|
# ## 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
|
|
|
|
|
|
2023-09-26 15:53:46 -04:00
|
|
|
|
if pubsubTopic.isErr():
|
2022-06-10 13:30:51 +02:00
|
|
|
|
return RestApiResponse.badRequest()
|
2023-09-26 15:53:46 -04:00
|
|
|
|
let pubSubTopic = pubsubTopic.get()
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
let messages = cache.getMessages(pubSubTopic, clear = true)
|
2022-06-10 13:30:51 +02:00
|
|
|
|
if messages.isErr():
|
2024-03-16 00:08:47 +01:00
|
|
|
|
debug "Not subscribed to topic", topic = pubSubTopic
|
2023-02-13 15:22:24 +01:00
|
|
|
|
return RestApiResponse.notFound()
|
|
|
|
|
|
2022-06-10 13:30:51 +02:00
|
|
|
|
let data = RelayGetMessagesResponse(messages.get().map(toRelayWakuMessage))
|
2024-03-16 00:08:47 +01:00
|
|
|
|
let resp = RestApiResponse.jsonResponse(data, status = Http200)
|
2022-06-10 13:30:51 +02:00
|
|
|
|
if resp.isErr():
|
2024-03-16 00:08:47 +01:00
|
|
|
|
debug "An error ocurred while building the json respose", error = resp.error
|
2022-06-10 13:30:51 +02:00
|
|
|
|
return RestApiResponse.internalServerError()
|
|
|
|
|
|
|
|
|
|
return resp.get()
|
2023-02-13 15:22:24 +01:00
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
router.api(MethodPost, ROUTE_RELAY_MESSAGESV1) do(
|
|
|
|
|
pubsubTopic: string, contentBody: Option[ContentBody]
|
|
|
|
|
) -> RestApiResponse:
|
2023-09-26 15:53:46 -04:00
|
|
|
|
if pubsubTopic.isErr():
|
2022-06-10 13:30:51 +02:00
|
|
|
|
return RestApiResponse.badRequest()
|
2023-09-26 15:53:46 -04:00
|
|
|
|
let pubSubTopic = pubsubTopic.get()
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
2023-09-01 15:03:59 +02:00
|
|
|
|
# ensure the node is subscribed to the topic. otherwise it risks publishing
|
|
|
|
|
# to a topic with no connected peers
|
|
|
|
|
if pubSubTopic notin node.wakuRelay.subscribedTopics():
|
2024-03-16 00:08:47 +01:00
|
|
|
|
return RestApiResponse.badRequest(
|
|
|
|
|
"Failed to publish: Node not subscribed to topic: " & pubsubTopic
|
|
|
|
|
)
|
2023-09-01 15:03:59 +02:00
|
|
|
|
|
2022-06-10 13:30:51 +02:00
|
|
|
|
# Check the request body
|
|
|
|
|
if contentBody.isNone():
|
|
|
|
|
return RestApiResponse.badRequest()
|
2023-02-13 15:22:24 +01:00
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
let reqWakuMessage: RelayWakuMessage = decodeRequestBody[RelayWakuMessage](
|
|
|
|
|
contentBody
|
|
|
|
|
).valueOr:
|
2023-11-14 16:59:53 +01:00
|
|
|
|
return error
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
2023-11-14 16:59:53 +01:00
|
|
|
|
var message: WakuMessage = reqWakuMessage.toWakuMessage(version = 0).valueOr:
|
2023-12-06 14:02:21 +01:00
|
|
|
|
return RestApiResponse.badRequest($error)
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
2023-09-01 15:03:59 +02:00
|
|
|
|
# if RLN is mounted, append the proof to the message
|
2023-09-11 12:02:31 +05:30
|
|
|
|
if not node.wakuRlnRelay.isNil():
|
|
|
|
|
# append the proof to the message
|
2024-03-16 00:08:47 +01:00
|
|
|
|
|
|
|
|
|
node.wakuRlnRelay.appendRLNProof(message, float64(getTime().toUnix())).isOkOr:
|
|
|
|
|
return RestApiResponse.internalServerError(
|
|
|
|
|
"Failed to publish: error appending RLN proof to message: " & $error
|
|
|
|
|
)
|
2023-09-11 12:02:31 +05:30
|
|
|
|
|
2024-02-01 18:16:10 +01:00
|
|
|
|
(await node.wakuRelay.validateMessage(pubsubTopic, message)).isOkOr:
|
|
|
|
|
return RestApiResponse.badRequest("Failed to publish: " & error)
|
2023-09-01 15:03:59 +02:00
|
|
|
|
|
|
|
|
|
# if we reach here its either a non-RLN message or a RLN message with a valid proof
|
2024-03-16 00:08:47 +01:00
|
|
|
|
debug "Publishing message",
|
|
|
|
|
pubSubTopic = pubSubTopic, rln = not node.wakuRlnRelay.isNil()
|
2023-10-30 16:19:49 +01:00
|
|
|
|
if not (waitFor node.publish(some(pubSubTopic), message).withTimeout(futTimeout)):
|
2024-03-16 00:08:47 +01:00
|
|
|
|
error "Failed to publish message to topic", pubSubTopic = pubSubTopic
|
2023-09-01 15:03:59 +02:00
|
|
|
|
return RestApiResponse.internalServerError("Failed to publish: timedout")
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
|
|
|
|
return RestApiResponse.ok()
|
|
|
|
|
|
2023-09-26 07:33:52 -04:00
|
|
|
|
# Autosharding API
|
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
router.api(MethodPost, ROUTE_RELAY_AUTO_SUBSCRIPTIONSV1) do(
|
|
|
|
|
contentBody: Option[ContentBody]
|
|
|
|
|
) -> RestApiResponse:
|
2023-11-28 07:21:41 -05:00
|
|
|
|
## Subscribes a node to a list of content topics.
|
2024-03-16 00:08:47 +01:00
|
|
|
|
|
2023-11-28 07:21:41 -05:00
|
|
|
|
debug "post_waku_v2_relay_v1_auto_subscriptions"
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
2023-11-14 16:59:53 +01:00
|
|
|
|
let req: seq[ContentTopic] = decodeRequestBody[seq[ContentTopic]](contentBody).valueOr:
|
|
|
|
|
return error
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
|
|
|
|
# Only subscribe to topics for which we have no subscribed topic handlers yet
|
2023-11-28 07:21:41 -05:00
|
|
|
|
let newTopics = req.filterIt(not cache.isContentSubscribed(it))
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
|
|
|
|
for contentTopic in newTopics:
|
2023-11-28 07:21:41 -05:00
|
|
|
|
cache.contentSubscribe(contentTopic)
|
2024-03-16 00:08:47 +01:00
|
|
|
|
node.subscribe(
|
|
|
|
|
(kind: ContentSub, topic: contentTopic), some(messageCacheHandler(cache))
|
|
|
|
|
)
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
|
|
|
|
return RestApiResponse.ok()
|
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
router.api(MethodDelete, ROUTE_RELAY_AUTO_SUBSCRIPTIONSV1) do(
|
|
|
|
|
contentBody: Option[ContentBody]
|
|
|
|
|
) -> RestApiResponse:
|
2023-11-28 07:21:41 -05:00
|
|
|
|
## Unsubscribes a node from a list of content topics.
|
2024-03-16 00:08:47 +01:00
|
|
|
|
|
2023-11-28 07:21:41 -05:00
|
|
|
|
debug "delete_waku_v2_relay_v1_auto_subscriptions"
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
2023-11-14 16:59:53 +01:00
|
|
|
|
let req: seq[ContentTopic] = decodeRequestBody[seq[ContentTopic]](contentBody).valueOr:
|
|
|
|
|
return error
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
|
|
|
|
for contentTopic in req:
|
2023-11-28 07:21:41 -05:00
|
|
|
|
cache.contentUnsubscribe(contentTopic)
|
2023-09-26 07:33:52 -04:00
|
|
|
|
node.unsubscribe((kind: ContentUnsub, topic: contentTopic))
|
|
|
|
|
|
|
|
|
|
return RestApiResponse.ok()
|
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
router.api(MethodGet, ROUTE_RELAY_AUTO_MESSAGESV1) do(
|
|
|
|
|
contentTopic: string
|
|
|
|
|
) -> RestApiResponse:
|
2023-11-28 07:21:41 -05:00
|
|
|
|
## Returns all WakuMessages received on a content topic since the
|
|
|
|
|
## last time this method was called.
|
2024-03-16 00:08:47 +01:00
|
|
|
|
|
|
|
|
|
debug "get_waku_v2_relay_v1_auto_messages", contentTopic = contentTopic
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
2023-11-28 07:21:41 -05:00
|
|
|
|
let contentTopic = contentTopic.valueOr:
|
|
|
|
|
return RestApiResponse.badRequest($error)
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
let messages = cache.getAutoMessages(contentTopic, clear = true).valueOr:
|
|
|
|
|
debug "Not subscribed to topic", topic = contentTopic
|
2023-11-28 07:21:41 -05:00
|
|
|
|
return RestApiResponse.notFound(contentTopic)
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
2023-11-28 07:21:41 -05:00
|
|
|
|
let data = RelayGetMessagesResponse(messages.map(toRelayWakuMessage))
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
return RestApiResponse.jsonResponse(data, status = Http200).valueOr:
|
2023-11-28 07:21:41 -05:00
|
|
|
|
debug "An error ocurred while building the json respose", error = error
|
|
|
|
|
return RestApiResponse.internalServerError($error)
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
router.api(MethodPost, ROUTE_RELAY_AUTO_MESSAGESV1_NO_TOPIC) do(
|
|
|
|
|
contentBody: Option[ContentBody]
|
|
|
|
|
) -> RestApiResponse:
|
2023-09-26 07:33:52 -04:00
|
|
|
|
# Check the request body
|
|
|
|
|
if contentBody.isNone():
|
|
|
|
|
return RestApiResponse.badRequest()
|
|
|
|
|
|
2023-11-14 16:59:53 +01:00
|
|
|
|
let req: RelayWakuMessage = decodeRequestBody[RelayWakuMessage](contentBody).valueOr:
|
|
|
|
|
return error
|
2023-09-26 07:33:52 -04:00
|
|
|
|
|
2023-11-14 16:59:53 +01:00
|
|
|
|
if req.contentTopic.isNone():
|
2023-09-26 07:33:52 -04:00
|
|
|
|
return RestApiResponse.badRequest()
|
|
|
|
|
|
2023-11-14 16:59:53 +01:00
|
|
|
|
var message: WakuMessage = req.toWakuMessage(version = 0).valueOr:
|
2023-09-26 07:33:52 -04:00
|
|
|
|
return RestApiResponse.badRequest()
|
|
|
|
|
|
2024-03-13 10:58:13 +01:00
|
|
|
|
let pubsubTopic = node.wakuSharding.getShard(message.contentTopic).valueOr:
|
2024-02-05 09:24:54 +01:00
|
|
|
|
let msg = "Autosharding error: " & error
|
2024-03-16 00:08:47 +01:00
|
|
|
|
error "publish error", msg = msg
|
2024-02-05 09:24:54 +01:00
|
|
|
|
return RestApiResponse.badRequest("Failed to publish. " & msg)
|
2024-03-16 00:08:47 +01:00
|
|
|
|
|
2023-09-26 07:33:52 -04:00
|
|
|
|
# if RLN is mounted, append the proof to the message
|
|
|
|
|
if not node.wakuRlnRelay.isNil():
|
2024-02-13 10:18:02 +05:30
|
|
|
|
node.wakuRlnRelay.appendRLNProof(message, float64(getTime().toUnix())).isOkOr:
|
2023-11-28 07:21:41 -05:00
|
|
|
|
return RestApiResponse.internalServerError(
|
2024-03-16 00:08:47 +01:00
|
|
|
|
"Failed to publish: error appending RLN proof to message: " & $error
|
|
|
|
|
)
|
2023-11-28 07:21:41 -05:00
|
|
|
|
|
2024-02-05 09:24:54 +01:00
|
|
|
|
(await node.wakuRelay.validateMessage(pubsubTopic, message)).isOkOr:
|
|
|
|
|
return RestApiResponse.badRequest("Failed to publish: " & error)
|
2024-03-16 00:08:47 +01:00
|
|
|
|
|
2023-09-26 07:33:52 -04:00
|
|
|
|
# if we reach here its either a non-RLN message or a RLN message with a valid proof
|
2024-03-16 00:08:47 +01:00
|
|
|
|
debug "Publishing message",
|
|
|
|
|
contentTopic = message.contentTopic, rln = not node.wakuRlnRelay.isNil()
|
2024-01-18 13:49:13 +01:00
|
|
|
|
|
2024-02-05 09:24:54 +01:00
|
|
|
|
var publishFut = node.publish(some(pubsubTopic), message)
|
2024-01-18 13:49:13 +01:00
|
|
|
|
if not await publishFut.withTimeout(futTimeout):
|
2024-03-16 00:08:47 +01:00
|
|
|
|
return RestApiResponse.internalServerError("Failed to publish: timedout")
|
2024-01-18 13:49:13 +01:00
|
|
|
|
|
|
|
|
|
var res = publishFut.read()
|
|
|
|
|
|
|
|
|
|
if res.isErr():
|
|
|
|
|
return RestApiResponse.badRequest("Failed to publish. " & res.error)
|
2022-06-10 13:30:51 +02:00
|
|
|
|
|
2023-10-30 16:19:49 +01:00
|
|
|
|
return RestApiResponse.ok()
|