2024-06-28 16:04:57 +05:30
|
|
|
{.push raises: [].}
|
2022-10-25 14:55:31 +02:00
|
|
|
|
2024-11-29 15:31:08 +01:00
|
|
|
import std/options, results, chronicles, chronos, metrics, bearssl/rand, stew/byteutils
|
2025-09-11 20:40:01 +05:30
|
|
|
import libp2p/peerid, libp2p/stream/connection
|
2022-10-25 14:55:31 +02:00
|
|
|
import
|
2024-11-29 15:31:08 +01:00
|
|
|
../waku_core/peers,
|
2023-04-18 15:22:10 +02:00
|
|
|
../node/peer_manager,
|
2024-08-27 16:49:46 +02:00
|
|
|
../node/delivery_monitor/publish_observer,
|
2023-04-18 15:22:10 +02:00
|
|
|
../utils/requests,
|
2023-04-19 13:29:23 +02:00
|
|
|
../waku_core,
|
2024-01-30 07:28:21 -05:00
|
|
|
./common,
|
2022-10-25 14:55:31 +02:00
|
|
|
./protocol_metrics,
|
|
|
|
|
./rpc,
|
|
|
|
|
./rpc_codec
|
|
|
|
|
|
|
|
|
|
logScope:
|
2022-11-03 16:36:24 +01:00
|
|
|
topics = "waku lightpush client"
|
2022-10-25 14:55:31 +02:00
|
|
|
|
|
|
|
|
type WakuLightPushClient* = ref object
|
2024-03-16 00:08:47 +01:00
|
|
|
peerManager*: PeerManager
|
|
|
|
|
rng*: ref rand.HmacDrbgContext
|
2024-08-27 16:49:46 +02:00
|
|
|
publishObservers: seq[PublishObserver]
|
2022-10-25 14:55:31 +02:00
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
proc new*(
|
|
|
|
|
T: type WakuLightPushClient, peerManager: PeerManager, rng: ref rand.HmacDrbgContext
|
|
|
|
|
): T =
|
2022-10-25 14:55:31 +02:00
|
|
|
WakuLightPushClient(peerManager: peerManager, rng: rng)
|
|
|
|
|
|
2024-08-27 16:49:46 +02:00
|
|
|
proc addPublishObserver*(wl: WakuLightPushClient, obs: PublishObserver) =
|
|
|
|
|
wl.publishObservers.add(obs)
|
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
proc sendPushRequest(
|
2025-09-11 20:40:01 +05:30
|
|
|
wl: WakuLightPushClient,
|
|
|
|
|
req: LightPushRequest,
|
|
|
|
|
peer: PeerId | RemotePeerInfo,
|
|
|
|
|
conn: Option[Connection] = none(Connection),
|
2025-03-05 12:07:56 +01:00
|
|
|
): Future[WakuLightPushResult] {.async.} =
|
2025-09-11 20:40:01 +05:30
|
|
|
let connection = conn.valueOr:
|
|
|
|
|
(await wl.peerManager.dialPeer(peer, WakuLightPushCodec)).valueOr:
|
|
|
|
|
waku_lightpush_v3_errors.inc(labelValues = [dialFailure])
|
|
|
|
|
return lighpushErrorResult(
|
|
|
|
|
LightPushErrorCode.NO_PEERS_TO_RELAY,
|
|
|
|
|
dialFailure & ": " & $peer & " is not accessible",
|
|
|
|
|
)
|
2022-10-25 14:55:31 +02:00
|
|
|
|
2025-10-03 14:42:46 +02:00
|
|
|
defer:
|
|
|
|
|
await connection.closeWithEOF()
|
2025-11-21 23:15:12 +05:30
|
|
|
try:
|
|
|
|
|
await connection.writeLP(req.encode().buffer)
|
|
|
|
|
except CatchableError:
|
|
|
|
|
error "failed to send push request", error = getCurrentExceptionMsg()
|
|
|
|
|
return lightpushResultInternalError(
|
|
|
|
|
"failed to send push request: " & getCurrentExceptionMsg()
|
|
|
|
|
)
|
2022-10-25 14:55:31 +02:00
|
|
|
|
2024-02-06 17:37:42 +01:00
|
|
|
var buffer: seq[byte]
|
|
|
|
|
try:
|
2024-04-20 09:10:52 +05:30
|
|
|
buffer = await connection.readLp(DefaultMaxRpcSize.int)
|
2024-02-06 17:37:42 +01:00
|
|
|
except LPStreamRemoteClosedError:
|
2025-07-10 10:56:02 +10:00
|
|
|
error "Failed to read response from peer", error = getCurrentExceptionMsg()
|
2025-03-05 12:07:56 +01:00
|
|
|
return lightpushResultInternalError(
|
|
|
|
|
"Failed to read response from peer: " & getCurrentExceptionMsg()
|
|
|
|
|
)
|
|
|
|
|
let response = LightpushResponse.decode(buffer).valueOr:
|
2025-11-21 23:15:12 +05:30
|
|
|
error "failed to decode response", error = $error
|
2025-03-05 12:07:56 +01:00
|
|
|
waku_lightpush_v3_errors.inc(labelValues = [decodeRpcFailure])
|
|
|
|
|
return lightpushResultInternalError(decodeRpcFailure)
|
2022-10-25 14:55:31 +02:00
|
|
|
|
2025-03-05 12:07:56 +01:00
|
|
|
if response.requestId != req.requestId and
|
2025-07-10 10:56:02 +10:00
|
|
|
response.statusCode != LightPushErrorCode.TOO_MANY_REQUESTS:
|
2025-03-05 12:07:56 +01:00
|
|
|
error "response failure, requestId mismatch",
|
|
|
|
|
requestId = req.requestId, responseRequestId = response.requestId
|
|
|
|
|
return lightpushResultInternalError("response failure, requestId mismatch")
|
2022-10-25 14:55:31 +02:00
|
|
|
|
2025-03-05 12:07:56 +01:00
|
|
|
return toPushResult(response)
|
2022-10-25 14:55:31 +02:00
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
proc publish*(
|
|
|
|
|
wl: WakuLightPushClient,
|
2025-03-05 12:07:56 +01:00
|
|
|
pubSubTopic: Option[PubsubTopic] = none(PubsubTopic),
|
2025-04-17 13:03:56 +02:00
|
|
|
wakuMessage: WakuMessage,
|
2025-03-05 12:07:56 +01:00
|
|
|
peer: PeerId | RemotePeerInfo,
|
|
|
|
|
): Future[WakuLightPushResult] {.async, gcsafe.} =
|
2025-04-17 13:03:56 +02:00
|
|
|
var message = wakuMessage
|
|
|
|
|
if message.timestamp == 0:
|
|
|
|
|
message.timestamp = getNowInNanosecondTime()
|
|
|
|
|
|
2025-03-05 12:07:56 +01:00
|
|
|
when peer is PeerId:
|
|
|
|
|
info "publish",
|
|
|
|
|
peerId = shortLog(peer),
|
|
|
|
|
msg_hash = computeMessageHash(pubsubTopic.get(""), message).to0xHex
|
|
|
|
|
else:
|
|
|
|
|
info "publish",
|
|
|
|
|
peerId = shortLog(peer.peerId),
|
|
|
|
|
msg_hash = computeMessageHash(pubsubTopic.get(""), message).to0xHex
|
|
|
|
|
|
|
|
|
|
let pushRequest = LightpushRequest(
|
|
|
|
|
requestId: generateRequestId(wl.rng), pubSubTopic: pubSubTopic, message: message
|
|
|
|
|
)
|
|
|
|
|
let publishedCount = ?await wl.sendPushRequest(pushRequest, peer)
|
2024-08-27 16:49:46 +02:00
|
|
|
|
|
|
|
|
for obs in wl.publishObservers:
|
2025-03-05 12:07:56 +01:00
|
|
|
obs.onMessagePublished(pubSubTopic.get(""), message)
|
2025-01-08 20:52:44 +01:00
|
|
|
|
2025-03-05 12:07:56 +01:00
|
|
|
return lightpushSuccessResult(publishedCount)
|
2024-08-27 16:49:46 +02:00
|
|
|
|
|
|
|
|
proc publishToAny*(
|
2025-04-17 13:03:56 +02:00
|
|
|
wl: WakuLightPushClient, pubSubTopic: PubsubTopic, wakuMessage: WakuMessage
|
2025-03-05 12:07:56 +01:00
|
|
|
): Future[WakuLightPushResult] {.async, gcsafe.} =
|
2024-08-27 16:49:46 +02:00
|
|
|
## This proc is similar to the publish one but in this case
|
|
|
|
|
## we don't specify a particular peer and instead we get it from peer manager
|
|
|
|
|
|
2025-04-17 13:03:56 +02:00
|
|
|
var message = wakuMessage
|
|
|
|
|
if message.timestamp == 0:
|
|
|
|
|
message.timestamp = getNowInNanosecondTime()
|
|
|
|
|
|
2024-08-27 16:49:46 +02:00
|
|
|
let peer = wl.peerManager.selectPeer(WakuLightPushCodec).valueOr:
|
2025-03-05 12:07:56 +01:00
|
|
|
# TODO: check if it is matches the situation - shall we distinguish client side missing peers from server side?
|
2025-07-10 10:56:02 +10:00
|
|
|
return lighpushErrorResult(
|
|
|
|
|
LightPushErrorCode.NO_PEERS_TO_RELAY, "no suitable remote peers"
|
|
|
|
|
)
|
2024-08-27 16:49:46 +02:00
|
|
|
|
2025-09-11 20:40:01 +05:30
|
|
|
info "publishToAny",
|
|
|
|
|
my_peer_id = wl.peerManager.switch.peerInfo.peerId,
|
|
|
|
|
peer_id = peer.peerId,
|
|
|
|
|
msg_hash = computeMessageHash(pubsubTopic, message).to0xHex,
|
|
|
|
|
sentTime = getNowInNanosecondTime()
|
|
|
|
|
|
2025-03-05 12:07:56 +01:00
|
|
|
let pushRequest = LightpushRequest(
|
|
|
|
|
requestId: generateRequestId(wl.rng),
|
|
|
|
|
pubSubTopic: some(pubSubTopic),
|
|
|
|
|
message: message,
|
|
|
|
|
)
|
|
|
|
|
let publishedCount = ?await wl.sendPushRequest(pushRequest, peer)
|
2024-08-27 16:49:46 +02:00
|
|
|
|
|
|
|
|
for obs in wl.publishObservers:
|
|
|
|
|
obs.onMessagePublished(pubSubTopic, message)
|
|
|
|
|
|
2025-03-05 12:07:56 +01:00
|
|
|
return lightpushSuccessResult(publishedCount)
|
2025-09-11 20:40:01 +05:30
|
|
|
|
|
|
|
|
proc publishWithConn*(
|
|
|
|
|
wl: WakuLightPushClient,
|
|
|
|
|
pubSubTopic: PubsubTopic,
|
|
|
|
|
message: WakuMessage,
|
|
|
|
|
conn: Connection,
|
|
|
|
|
destPeer: PeerId,
|
|
|
|
|
): Future[WakuLightPushResult] {.async, gcsafe.} =
|
|
|
|
|
info "publishWithConn",
|
|
|
|
|
my_peer_id = wl.peerManager.switch.peerInfo.peerId,
|
|
|
|
|
peer_id = destPeer,
|
|
|
|
|
msg_hash = computeMessageHash(pubsubTopic, message).to0xHex,
|
|
|
|
|
sentTime = getNowInNanosecondTime()
|
|
|
|
|
|
|
|
|
|
let pushRequest = LightpushRequest(
|
|
|
|
|
requestId: generateRequestId(wl.rng),
|
|
|
|
|
pubSubTopic: some(pubSubTopic),
|
|
|
|
|
message: message,
|
|
|
|
|
)
|
|
|
|
|
#TODO: figure out how to not pass destPeer as this is just a hack
|
|
|
|
|
let publishedCount =
|
|
|
|
|
?await wl.sendPushRequest(pushRequest, destPeer, conn = some(conn))
|
|
|
|
|
|
|
|
|
|
for obs in wl.publishObservers:
|
|
|
|
|
obs.onMessagePublished(pubSubTopic, message)
|
|
|
|
|
|
|
|
|
|
return lightpushSuccessResult(publishedCount)
|