2024-06-28 10:34:57 +00:00
|
|
|
{.push raises: [].}
|
2022-10-20 16:09:40 +00:00
|
|
|
|
2024-07-09 11:14:28 +00:00
|
|
|
import std/options, results, chronicles, chronos, metrics, bearssl/rand
|
2022-10-20 16:09:40 +00:00
|
|
|
import
|
2024-04-25 13:09:52 +00:00
|
|
|
../node/peer_manager, ../utils/requests, ./protocol_metrics, ./common, ./rpc_codec
|
2022-10-20 16:09:40 +00:00
|
|
|
|
|
|
|
logScope:
|
2022-11-03 15:36:24 +00:00
|
|
|
topics = "waku store client"
|
2022-10-20 16:09:40 +00:00
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
const DefaultPageSize*: uint = 20
|
|
|
|
# A recommended default number of waku messages per page
|
2022-11-09 17:50:18 +00:00
|
|
|
|
2022-10-20 16:09:40 +00:00
|
|
|
type WakuStoreClient* = ref object
|
2024-03-15 23:08:47 +00:00
|
|
|
peerManager: PeerManager
|
|
|
|
rng: ref rand.HmacDrbgContext
|
2022-11-23 09:08:00 +00:00
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
proc new*(
|
|
|
|
T: type WakuStoreClient, peerManager: PeerManager, rng: ref rand.HmacDrbgContext
|
2024-07-09 11:14:28 +00:00
|
|
|
): T {.gcsafe.} =
|
2022-11-23 09:08:00 +00:00
|
|
|
WakuStoreClient(peerManager: peerManager, rng: rng)
|
2022-10-20 16:09:40 +00:00
|
|
|
|
2024-04-25 13:09:52 +00:00
|
|
|
proc sendStoreRequest(
|
|
|
|
self: WakuStoreClient, request: StoreQueryRequest, connection: Connection
|
|
|
|
): Future[StoreQueryResult] {.async, gcsafe.} =
|
|
|
|
var req = request
|
2022-11-21 08:36:41 +00:00
|
|
|
|
2024-08-29 20:56:14 +00:00
|
|
|
if req.requestId == "":
|
|
|
|
req.requestId = generateRequestId(self.rng)
|
2022-10-20 16:09:40 +00:00
|
|
|
|
2024-04-25 13:09:52 +00:00
|
|
|
let writeRes = catch:
|
|
|
|
await connection.writeLP(req.encode().buffer)
|
|
|
|
if writeRes.isErr():
|
|
|
|
return err(StoreError(kind: ErrorCode.BAD_REQUEST, cause: writeRes.error.msg))
|
2022-10-20 16:09:40 +00:00
|
|
|
|
2024-04-25 13:09:52 +00:00
|
|
|
let readRes = catch:
|
|
|
|
await connection.readLp(DefaultMaxRpcSize.int)
|
2022-11-09 17:50:18 +00:00
|
|
|
|
2024-04-25 13:09:52 +00:00
|
|
|
let buf = readRes.valueOr:
|
|
|
|
return err(StoreError(kind: ErrorCode.BAD_RESPONSE, cause: error.msg))
|
2022-11-09 17:50:18 +00:00
|
|
|
|
2024-04-25 13:09:52 +00:00
|
|
|
let res = StoreQueryResponse.decode(buf).valueOr:
|
|
|
|
waku_store_errors.inc(labelValues = [decodeRpcFailure])
|
|
|
|
return err(StoreError(kind: ErrorCode.BAD_RESPONSE, cause: decodeRpcFailure))
|
2022-11-09 17:50:18 +00:00
|
|
|
|
2024-04-25 13:09:52 +00:00
|
|
|
if res.statusCode != uint32(StatusCode.SUCCESS):
|
|
|
|
waku_store_errors.inc(labelValues = [res.statusDesc])
|
|
|
|
return err(StoreError.new(res.statusCode, res.statusDesc))
|
2022-11-09 17:50:18 +00:00
|
|
|
|
2024-04-25 13:09:52 +00:00
|
|
|
return ok(res)
|
2022-11-09 17:50:18 +00:00
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
proc query*(
|
2024-08-13 11:27:34 +00:00
|
|
|
self: WakuStoreClient, request: StoreQueryRequest, peer: RemotePeerInfo | PeerId
|
2024-04-25 13:09:52 +00:00
|
|
|
): Future[StoreQueryResult] {.async, gcsafe.} =
|
|
|
|
if request.paginationCursor.isSome() and request.paginationCursor.get() == EmptyCursor:
|
|
|
|
return err(StoreError(kind: ErrorCode.BAD_REQUEST, cause: "invalid cursor"))
|
|
|
|
|
|
|
|
let connection = (await self.peerManager.dialPeer(peer, WakuStoreCodec)).valueOr:
|
|
|
|
waku_store_errors.inc(labelValues = [dialFailure])
|
|
|
|
|
|
|
|
return err(StoreError(kind: ErrorCode.PEER_DIAL_FAILURE, address: $peer))
|
|
|
|
|
|
|
|
return await self.sendStoreRequest(request, connection)
|
2024-08-27 14:49:46 +00:00
|
|
|
|
|
|
|
proc queryToAny*(
|
|
|
|
self: WakuStoreClient, request: StoreQueryRequest, peerId = none(PeerId)
|
|
|
|
): Future[StoreQueryResult] {.async.} =
|
|
|
|
## This proc is similar to the query one but in this case
|
|
|
|
## we don't specify a particular peer and instead we get it from peer manager
|
|
|
|
|
|
|
|
if request.paginationCursor.isSome() and request.paginationCursor.get() == EmptyCursor:
|
|
|
|
return err(StoreError(kind: ErrorCode.BAD_REQUEST, cause: "invalid cursor"))
|
|
|
|
|
|
|
|
let peer = self.peerManager.selectPeer(WakuStoreCodec).valueOr:
|
|
|
|
return err(StoreError(kind: BAD_RESPONSE, cause: "no service store peer connected"))
|
|
|
|
|
|
|
|
let connection = (await self.peerManager.dialPeer(peer, WakuStoreCodec)).valueOr:
|
|
|
|
waku_store_errors.inc(labelValues = [dialFailure])
|
|
|
|
|
|
|
|
return err(StoreError(kind: ErrorCode.PEER_DIAL_FAILURE, address: $peer))
|
|
|
|
|
|
|
|
return await self.sendStoreRequest(request, connection)
|