Skip to content

Commit 2a4c0f1

Browse files
chore: Enabling to use a full node for lightpush via rest api without lightpush client configured (#2626)
* Enabling to use a full node for lightpush via rest api without light push client configured
1 parent 1d7ff28 commit 2a4c0f1

File tree

4 files changed

+110
-29
lines changed

4 files changed

+110
-29
lines changed

waku/node/waku_node.nim

+38-21
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import
4444
../waku_lightpush/client as lightpush_client,
4545
../waku_lightpush/common,
4646
../waku_lightpush/protocol,
47+
../waku_lightpush/self_req_handler,
4748
../waku_enr,
4849
../waku_peer_exchange,
4950
../waku_rln_relay,
@@ -913,7 +914,7 @@ proc mountLightPush*(
913914

914915
if publishedCount == 0:
915916
## Agreed change expected to the lightpush protocol to better handle such case. https://github.com/waku-org/pm/issues/93
916-
debug("Lightpush request has not been published to any peers")
917+
debug "Lightpush request has not been published to any peers"
917918

918919
return ok()
919920

@@ -942,15 +943,30 @@ proc lightpushPublish*(
942943
## Returns whether relaying was successful or not.
943944
## `WakuMessage` should contain a `contentTopic` field for light node
944945
## functionality.
945-
if node.wakuLightpushClient.isNil():
946-
return err("waku lightpush client is nil")
946+
if node.wakuLightpushClient.isNil() and node.wakuLightPush.isNil():
947+
error "failed to publish message as lightpush not available"
948+
return err("Waku lightpush not available")
949+
950+
let internalPublish = proc(
951+
node: WakuNode,
952+
pubsubTopic: PubsubTopic,
953+
message: WakuMessage,
954+
peer: RemotePeerInfo,
955+
): Future[WakuLightPushResult[void]] {.async, gcsafe.} =
956+
if not node.wakuLightpushClient.isNil():
957+
debug "publishing message with lightpush",
958+
pubsubTopic = pubsubTopic,
959+
contentTopic = message.contentTopic,
960+
peer = peer.peerId
961+
return await node.wakuLightpushClient.publish(pubsubTopic, message, peer)
962+
963+
if not node.wakuLightPush.isNil():
964+
debug "publishing message with self hosted lightpush",
965+
pubsubTopic = pubsubTopic, contentTopic = message.contentTopic
966+
return await node.wakuLightPush.handleSelfLightPushRequest(pubsubTopic, message)
947967

948968
if pubsubTopic.isSome():
949-
debug "publishing message with lightpush",
950-
pubsubTopic = pubsubTopic.get(),
951-
contentTopic = message.contentTopic,
952-
peer = peer.peerId
953-
return await node.wakuLightpushClient.publish(pubsubTopic.get(), message, peer)
969+
return await internalPublish(node, pubsubTopic.get(), message, peer)
954970

955971
let topicMapRes = node.wakuSharding.parseSharding(pubsubTopic, message.contentTopic)
956972

@@ -961,26 +977,27 @@ proc lightpushPublish*(
961977
topicMapRes.get()
962978

963979
for pubsub, _ in topicMap.pairs: # There's only one pair anyway
964-
debug "publishing message with lightpush",
965-
pubsubTopic = pubsub, contentTopic = message.contentTopic, peer = peer.peerId
966-
return await node.wakuLightpushClient.publish($pubsub, message, peer)
980+
return await internalPublish(node, $pubsub, message, peer)
967981

968982
# TODO: Move to application module (e.g., wakunode2.nim)
969983
proc lightpushPublish*(
970984
node: WakuNode, pubsubTopic: Option[PubsubTopic], message: WakuMessage
971985
): Future[WakuLightPushResult[void]] {.
972986
async, gcsafe, deprecated: "Use 'node.lightpushPublish()' instead"
973987
.} =
974-
if node.wakuLightpushClient.isNil():
975-
let msg = "waku lightpush client is nil"
976-
error "failed to publish message", msg = msg
977-
return err(msg)
978-
979-
let peerOpt = node.peerManager.selectPeer(WakuLightPushCodec)
980-
if peerOpt.isNone():
981-
let msg = "no suitable remote peers"
982-
error "failed to publish message", msg = msg
983-
return err(msg)
988+
if node.wakuLightpushClient.isNil() and node.wakuLightPush.isNil():
989+
error "failed to publish message as lightpush not available"
990+
return err("waku lightpush not available")
991+
992+
var peerOpt: Option[RemotePeerInfo] = none(RemotePeerInfo)
993+
if not node.wakuLightpushClient.isNil():
994+
peerOpt = node.peerManager.selectPeer(WakuLightPushCodec)
995+
if peerOpt.isNone():
996+
let msg = "no suitable remote peers"
997+
error "failed to publish message", msg = msg
998+
return err(msg)
999+
elif not node.wakuLightPush.isNil():
1000+
peerOpt = some(RemotePeerInfo.init($node.switch.peerInfo.peerId))
9841001

9851002
let publishRes =
9861003
await node.lightpushPublish(pubsubTopic, message, peer = peerOpt.get())

waku/waku_api/rest/builder.nim

+4-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,10 @@ proc startRestServerProtocolSupport*(
177177
rest_store_legacy_api.installStoreApiHandlers(router, node, storeDiscoHandler)
178178

179179
## Light push API
180-
if conf.lightpushnode != "" and node.wakuLightpushClient != nil:
180+
## Install it either if lightpushnode (lightpush service node) is configured and client is mounted)
181+
## or install it to be used with self-hosted lightpush service
182+
if (conf.lightpushnode != "" and node.wakuLightpushClient != nil) or
183+
(conf.lightpush and node.wakuLightPush != nil and node.wakuRelay != nil):
181184
let lightDiscoHandler =
182185
if wakuDiscv5.isSome():
183186
some(defaultDiscoveryHandler(wakuDiscv5.get(), Lightpush))

waku/waku_api/rest/lightpush/handlers.nim

+15-7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import
1616
../../waku/node/peer_manager,
1717
../../../waku_node,
1818
../../waku/waku_lightpush/common,
19+
../../waku/waku_lightpush/self_req_handler,
1920
../../handlers,
2021
../serdes,
2122
../responses,
@@ -35,6 +36,9 @@ const NoPeerNoDiscoError =
3536
const NoPeerNoneFoundError =
3637
RestApiResponse.serviceUnavailable("No suitable service peer & none discovered")
3738

39+
proc useSelfHostedLightPush(node: WakuNode): bool =
40+
return node.wakuLightPush != nil and node.wakuLightPushClient == nil
41+
3842
#### Request handlers
3943

4044
const ROUTE_LIGHTPUSH* = "/lightpush/v1/message"
@@ -60,15 +64,19 @@ proc installLightPushRequestHandler*(
6064
let msg = req.message.toWakuMessage().valueOr:
6165
return RestApiResponse.badRequest("Invalid message: " & $error)
6266

63-
let peer = node.peerManager.selectPeer(WakuLightPushCodec).valueOr:
64-
let handler = discHandler.valueOr:
65-
return NoPeerNoDiscoError
67+
var peer = RemotePeerInfo.init($node.switch.peerInfo.peerId)
68+
if useSelfHostedLightPush(node):
69+
discard
70+
else:
71+
peer = node.peerManager.selectPeer(WakuLightPushCodec).valueOr:
72+
let handler = discHandler.valueOr:
73+
return NoPeerNoDiscoError
6674

67-
let peerOp = (await handler()).valueOr:
68-
return RestApiResponse.internalServerError("No value in peerOp: " & $error)
75+
let peerOp = (await handler()).valueOr:
76+
return RestApiResponse.internalServerError("No value in peerOp: " & $error)
6977

70-
peerOp.valueOr:
71-
return NoPeerNoneFoundError
78+
peerOp.valueOr:
79+
return NoPeerNoneFoundError
7280

7381
let subFut = node.lightpushPublish(req.pubsubTopic, msg, peer)
7482

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
when (NimMajor, NimMinor) < (1, 4):
2+
{.push raises: [Defect].}
3+
else:
4+
{.push raises: [].}
5+
6+
## Notice that the REST /lightpush requests normally assume that the node
7+
## is acting as a lightpush-client that will trigger the service provider node
8+
## to relay the message.
9+
## In this module, we allow that a lightpush service node (full node) can be
10+
## triggered directly through the REST /lightpush endpoint.
11+
## The typical use case for that is when using `nwaku-compose`,
12+
## which spawn a full service Waku node
13+
## that could be used also as a lightpush client, helping testing and development.
14+
15+
import stew/results, chronos, chronicles, std/options, metrics
16+
import
17+
../waku_core,
18+
./protocol,
19+
./common,
20+
./rpc,
21+
./rpc_codec,
22+
./protocol_metrics,
23+
../utils/requests
24+
25+
proc handleSelfLightPushRequest*(
26+
self: WakuLightPush, pubSubTopic: PubsubTopic, message: WakuMessage
27+
): Future[WakuLightPushResult[void]] {.async.} =
28+
## Handles the lightpush requests made by the node to itself.
29+
## Normally used in REST-lightpush requests
30+
31+
try:
32+
# provide self peerId as now this node is used directly, thus there is no light client sender peer.
33+
let selfPeerId = self.peerManager.switch.peerInfo.peerId
34+
35+
let req = PushRequest(pubSubTopic: pubSubTopic, message: message)
36+
let rpc = PushRPC(requestId: generateRequestId(self.rng), request: some(req))
37+
38+
let respRpc = await self.handleRequest(selfPeerId, rpc.encode().buffer)
39+
40+
if respRpc.response.isNone():
41+
waku_lightpush_errors.inc(labelValues = [emptyResponseBodyFailure])
42+
return err(emptyResponseBodyFailure)
43+
44+
let response = respRpc.response.get()
45+
if not response.isSuccess:
46+
if response.info.isSome():
47+
return err(response.info.get())
48+
else:
49+
return err("unknown failure")
50+
51+
return ok()
52+
except Exception:
53+
return err("exception in handleSelfLightPushRequest: " & getCurrentExceptionMsg())

0 commit comments

Comments
 (0)