@waku/core 0.0.33 → 0.0.34-00f2e75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/bundle/base_protocol-Bp5a9PNG.js +152 -0
  2. package/bundle/{index-BIW3qNYx.js → index-G1eRBjeI.js} +118 -204
  3. package/bundle/index.js +1895 -179
  4. package/bundle/lib/base_protocol.js +2 -2
  5. package/bundle/lib/message/version_0.js +2 -2
  6. package/bundle/{version_0-CdmZMfkQ.js → version_0-DJZG2fB2.js} +283 -45
  7. package/dist/.tsbuildinfo +1 -1
  8. package/dist/index.d.ts +1 -3
  9. package/dist/index.js +1 -3
  10. package/dist/index.js.map +1 -1
  11. package/dist/lib/base_protocol.d.ts +3 -23
  12. package/dist/lib/base_protocol.js +3 -47
  13. package/dist/lib/base_protocol.js.map +1 -1
  14. package/dist/lib/connection_manager/connection_manager.d.ts +118 -0
  15. package/dist/lib/{connection_manager.js → connection_manager/connection_manager.js} +136 -36
  16. package/dist/lib/connection_manager/connection_manager.js.map +1 -0
  17. package/dist/lib/connection_manager/index.d.ts +1 -0
  18. package/dist/lib/connection_manager/index.js +2 -0
  19. package/dist/lib/connection_manager/index.js.map +1 -0
  20. package/dist/lib/{keep_alive_manager.d.ts → connection_manager/keep_alive_manager.d.ts} +4 -2
  21. package/dist/lib/{keep_alive_manager.js → connection_manager/keep_alive_manager.js} +2 -2
  22. package/dist/lib/connection_manager/keep_alive_manager.js.map +1 -0
  23. package/dist/lib/connection_manager/utils.d.ts +7 -0
  24. package/dist/lib/connection_manager/utils.js +22 -0
  25. package/dist/lib/connection_manager/utils.js.map +1 -0
  26. package/dist/lib/filter/filter.d.ts +18 -0
  27. package/dist/lib/filter/filter.js +209 -0
  28. package/dist/lib/filter/filter.js.map +1 -0
  29. package/dist/lib/filter/index.d.ts +1 -18
  30. package/dist/lib/filter/index.js +1 -208
  31. package/dist/lib/filter/index.js.map +1 -1
  32. package/dist/lib/light_push/index.d.ts +1 -15
  33. package/dist/lib/light_push/index.js +1 -143
  34. package/dist/lib/light_push/index.js.map +1 -1
  35. package/dist/lib/light_push/light_push.d.ts +15 -0
  36. package/dist/lib/light_push/light_push.js +144 -0
  37. package/dist/lib/light_push/light_push.js.map +1 -0
  38. package/dist/lib/light_push/utils.d.ts +0 -2
  39. package/dist/lib/light_push/utils.js +9 -17
  40. package/dist/lib/light_push/utils.js.map +1 -1
  41. package/dist/lib/metadata/index.d.ts +1 -3
  42. package/dist/lib/metadata/index.js +1 -118
  43. package/dist/lib/metadata/index.js.map +1 -1
  44. package/dist/lib/metadata/metadata.d.ts +3 -0
  45. package/dist/lib/metadata/metadata.js +119 -0
  46. package/dist/lib/metadata/metadata.js.map +1 -0
  47. package/dist/lib/store/index.d.ts +1 -9
  48. package/dist/lib/store/index.js +1 -82
  49. package/dist/lib/store/index.js.map +1 -1
  50. package/dist/lib/store/store.d.ts +9 -0
  51. package/dist/lib/store/store.js +83 -0
  52. package/dist/lib/store/store.js.map +1 -0
  53. package/dist/lib/stream_manager/stream_manager.d.ts +2 -2
  54. package/dist/lib/stream_manager/stream_manager.js +16 -17
  55. package/dist/lib/stream_manager/stream_manager.js.map +1 -1
  56. package/package.json +1 -126
  57. package/src/index.ts +1 -4
  58. package/src/lib/base_protocol.ts +3 -76
  59. package/src/lib/{connection_manager.ts → connection_manager/connection_manager.ts} +168 -63
  60. package/src/lib/connection_manager/index.ts +1 -0
  61. package/src/lib/{keep_alive_manager.ts → connection_manager/keep_alive_manager.ts} +7 -3
  62. package/src/lib/connection_manager/utils.ts +25 -0
  63. package/src/lib/filter/filter.ts +315 -0
  64. package/src/lib/filter/index.ts +1 -315
  65. package/src/lib/light_push/index.ts +1 -188
  66. package/src/lib/light_push/light_push.ts +188 -0
  67. package/src/lib/light_push/utils.ts +13 -21
  68. package/src/lib/metadata/index.ts +1 -182
  69. package/src/lib/metadata/metadata.ts +182 -0
  70. package/src/lib/store/index.ts +1 -136
  71. package/src/lib/store/store.ts +136 -0
  72. package/src/lib/stream_manager/stream_manager.ts +16 -18
  73. package/bundle/base_protocol-Dzv-QHPR.js +0 -275
  74. package/dist/lib/connection_manager.d.ts +0 -62
  75. package/dist/lib/connection_manager.js.map +0 -1
  76. package/dist/lib/filterPeers.d.ts +0 -13
  77. package/dist/lib/filterPeers.js +0 -38
  78. package/dist/lib/filterPeers.js.map +0 -1
  79. package/dist/lib/health_manager.d.ts +0 -14
  80. package/dist/lib/health_manager.js +0 -70
  81. package/dist/lib/health_manager.js.map +0 -1
  82. package/dist/lib/keep_alive_manager.js.map +0 -1
  83. package/src/lib/filterPeers.ts +0 -51
  84. package/src/lib/health_manager.ts +0 -90
@@ -1,31 +1,23 @@
1
- import { ProtocolError } from "@waku/interfaces";
2
-
3
1
  // should match nwaku
4
2
  // https://github.com/waku-org/nwaku/blob/c3cb06ac6c03f0f382d3941ea53b330f6a8dd127/waku/waku_rln_relay/rln_relay.nim#L309
5
3
  // https://github.com/waku-org/nwaku/blob/c3cb06ac6c03f0f382d3941ea53b330f6a8dd127/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim#L20
6
- const RLN_GENERATION_PREFIX_ERROR = "could not generate rln-v2 proof";
4
+ const RLN_GENERATION_PREFIX_ERROR = "could not generate rln proof";
5
+ const RLN_MESSAGE_ID_PREFIX_ERROR =
6
+ "could not get new message id to generate an rln proof";
7
+
8
+ // rare case on nwaku side
9
+ // https://github.com/waku-org/nwaku/blob/a4e92a3d02448fd708857b7b6cac2a7faa7eb4f9/waku/waku_lightpush/callbacks.nim#L49
10
+ // https://github.com/waku-org/nwaku/blob/a4e92a3d02448fd708857b7b6cac2a7faa7eb4f9/waku/node/waku_node.nim#L1117
11
+ const RLN_REMOTE_VALIDATION = "RLN validation failed";
7
12
 
8
13
  export const isRLNResponseError = (info?: string): boolean => {
9
14
  if (!info) {
10
15
  return false;
11
16
  }
12
17
 
13
- return info.includes(RLN_GENERATION_PREFIX_ERROR);
14
- };
15
-
16
- export const matchRLNErrorMessage = (info: string): ProtocolError => {
17
- const rlnErrorMap: { [key: string]: ProtocolError } = {
18
- [ProtocolError.RLN_IDENTITY_MISSING]: ProtocolError.RLN_IDENTITY_MISSING,
19
- [ProtocolError.RLN_MEMBERSHIP_INDEX]: ProtocolError.RLN_MEMBERSHIP_INDEX,
20
- [ProtocolError.RLN_LIMIT_MISSING]: ProtocolError.RLN_LIMIT_MISSING
21
- };
22
-
23
- const infoLowerCase = info.toLowerCase();
24
- for (const errorKey in rlnErrorMap) {
25
- if (infoLowerCase.includes(errorKey.toLowerCase())) {
26
- return rlnErrorMap[errorKey];
27
- }
28
- }
29
-
30
- return ProtocolError.RLN_PROOF_GENERATION;
18
+ return (
19
+ info.includes(RLN_GENERATION_PREFIX_ERROR) ||
20
+ info.includes(RLN_MESSAGE_ID_PREFIX_ERROR) ||
21
+ info.includes(RLN_REMOTE_VALIDATION)
22
+ );
31
23
  };
@@ -1,182 +1 @@
1
- import type { PeerId } from "@libp2p/interface";
2
- import { IncomingStreamData } from "@libp2p/interface";
3
- import {
4
- type IMetadata,
5
- type Libp2pComponents,
6
- type MetadataQueryResult,
7
- type PeerIdStr,
8
- ProtocolError,
9
- PubsubTopic,
10
- type ShardInfo
11
- } from "@waku/interfaces";
12
- import { proto_metadata } from "@waku/proto";
13
- import { encodeRelayShard, Logger, pubsubTopicsToShardInfo } from "@waku/utils";
14
- import all from "it-all";
15
- import * as lp from "it-length-prefixed";
16
- import { pipe } from "it-pipe";
17
- import { Uint8ArrayList } from "uint8arraylist";
18
-
19
- import { BaseProtocol } from "../base_protocol.js";
20
-
21
- const log = new Logger("metadata");
22
-
23
- export const MetadataCodec = "/vac/waku/metadata/1.0.0";
24
-
25
- class Metadata extends BaseProtocol implements IMetadata {
26
- private libp2pComponents: Libp2pComponents;
27
- protected handshakesConfirmed: Map<PeerIdStr, ShardInfo> = new Map();
28
-
29
- public constructor(
30
- public pubsubTopics: PubsubTopic[],
31
- libp2p: Libp2pComponents
32
- ) {
33
- super(MetadataCodec, libp2p.components, log, pubsubTopics);
34
- this.libp2pComponents = libp2p;
35
- void libp2p.registrar.handle(MetadataCodec, (streamData) => {
36
- void this.onRequest(streamData);
37
- });
38
- }
39
-
40
- /**
41
- * Make a metadata query to a peer
42
- */
43
- public async query(peerId: PeerId): Promise<MetadataQueryResult> {
44
- const request = proto_metadata.WakuMetadataRequest.encode(
45
- pubsubTopicsToShardInfo(this.pubsubTopics)
46
- );
47
-
48
- const peer = await this.libp2pComponents.peerStore.get(peerId);
49
- if (!peer) {
50
- return {
51
- shardInfo: null,
52
- error: ProtocolError.NO_PEER_AVAILABLE
53
- };
54
- }
55
-
56
- let stream;
57
- try {
58
- stream = await this.getStream(peer);
59
- } catch (error) {
60
- log.error("Failed to get stream", error);
61
- return {
62
- shardInfo: null,
63
- error: ProtocolError.NO_STREAM_AVAILABLE
64
- };
65
- }
66
-
67
- const encodedResponse = await pipe(
68
- [request],
69
- lp.encode,
70
- stream,
71
- lp.decode,
72
- async (source) => await all(source)
73
- );
74
-
75
- const { error, shardInfo } = this.decodeMetadataResponse(encodedResponse);
76
-
77
- if (error) {
78
- return {
79
- shardInfo: null,
80
- error
81
- };
82
- }
83
-
84
- await this.savePeerShardInfo(peerId, shardInfo);
85
-
86
- return {
87
- shardInfo,
88
- error: null
89
- };
90
- }
91
-
92
- public async confirmOrAttemptHandshake(
93
- peerId: PeerId
94
- ): Promise<MetadataQueryResult> {
95
- const shardInfo = this.handshakesConfirmed.get(peerId.toString());
96
- if (shardInfo) {
97
- return {
98
- shardInfo,
99
- error: null
100
- };
101
- }
102
-
103
- return await this.query(peerId);
104
- }
105
-
106
- /**
107
- * Handle an incoming metadata request
108
- */
109
- private async onRequest(streamData: IncomingStreamData): Promise<void> {
110
- try {
111
- const { stream, connection } = streamData;
112
- const encodedShardInfo = proto_metadata.WakuMetadataResponse.encode(
113
- pubsubTopicsToShardInfo(this.pubsubTopics)
114
- );
115
-
116
- const encodedResponse = await pipe(
117
- [encodedShardInfo],
118
- lp.encode,
119
- stream,
120
- lp.decode,
121
- async (source) => await all(source)
122
- );
123
-
124
- const { error, shardInfo } = this.decodeMetadataResponse(encodedResponse);
125
-
126
- if (error) {
127
- return;
128
- }
129
-
130
- await this.savePeerShardInfo(connection.remotePeer, shardInfo);
131
- } catch (error) {
132
- log.error("Error handling metadata request", error);
133
- }
134
- }
135
-
136
- private decodeMetadataResponse(
137
- encodedResponse: Uint8ArrayList[]
138
- ): MetadataQueryResult {
139
- const bytes = new Uint8ArrayList();
140
-
141
- encodedResponse.forEach((chunk) => {
142
- bytes.append(chunk);
143
- });
144
- const response = proto_metadata.WakuMetadataResponse.decode(
145
- bytes
146
- ) as ShardInfo;
147
-
148
- if (!response) {
149
- log.error("Error decoding metadata response");
150
- return {
151
- shardInfo: null,
152
- error: ProtocolError.DECODE_FAILED
153
- };
154
- }
155
-
156
- return {
157
- shardInfo: response,
158
- error: null
159
- };
160
- }
161
-
162
- private async savePeerShardInfo(
163
- peerId: PeerId,
164
- shardInfo: ShardInfo
165
- ): Promise<void> {
166
- // add or update the shardInfo to peer store
167
- await this.libp2pComponents.peerStore.merge(peerId, {
168
- metadata: {
169
- shardInfo: encodeRelayShard(shardInfo)
170
- }
171
- });
172
-
173
- this.handshakesConfirmed.set(peerId.toString(), shardInfo);
174
- }
175
- }
176
-
177
- export function wakuMetadata(
178
- pubsubTopics: PubsubTopic[]
179
- ): (components: Libp2pComponents) => IMetadata {
180
- return (components: Libp2pComponents) =>
181
- new Metadata(pubsubTopics, components);
182
- }
1
+ export { wakuMetadata, MetadataCodec } from "./metadata.js";
@@ -0,0 +1,182 @@
1
+ import type { PeerId } from "@libp2p/interface";
2
+ import { IncomingStreamData } from "@libp2p/interface";
3
+ import {
4
+ type IMetadata,
5
+ type Libp2pComponents,
6
+ type MetadataQueryResult,
7
+ type PeerIdStr,
8
+ ProtocolError,
9
+ PubsubTopic,
10
+ type ShardInfo
11
+ } from "@waku/interfaces";
12
+ import { proto_metadata } from "@waku/proto";
13
+ import { encodeRelayShard, Logger, pubsubTopicsToShardInfo } from "@waku/utils";
14
+ import all from "it-all";
15
+ import * as lp from "it-length-prefixed";
16
+ import { pipe } from "it-pipe";
17
+ import { Uint8ArrayList } from "uint8arraylist";
18
+
19
+ import { BaseProtocol } from "../base_protocol.js";
20
+
21
+ const log = new Logger("metadata");
22
+
23
+ export const MetadataCodec = "/vac/waku/metadata/1.0.0";
24
+
25
+ class Metadata extends BaseProtocol implements IMetadata {
26
+ private libp2pComponents: Libp2pComponents;
27
+ protected handshakesConfirmed: Map<PeerIdStr, ShardInfo> = new Map();
28
+
29
+ public constructor(
30
+ public pubsubTopics: PubsubTopic[],
31
+ libp2p: Libp2pComponents
32
+ ) {
33
+ super(MetadataCodec, libp2p.components, pubsubTopics);
34
+ this.libp2pComponents = libp2p;
35
+ void libp2p.registrar.handle(MetadataCodec, (streamData) => {
36
+ void this.onRequest(streamData);
37
+ });
38
+ }
39
+
40
+ /**
41
+ * Make a metadata query to a peer
42
+ */
43
+ public async query(peerId: PeerId): Promise<MetadataQueryResult> {
44
+ const request = proto_metadata.WakuMetadataRequest.encode(
45
+ pubsubTopicsToShardInfo(this.pubsubTopics)
46
+ );
47
+
48
+ const peer = await this.libp2pComponents.peerStore.get(peerId);
49
+ if (!peer) {
50
+ return {
51
+ shardInfo: null,
52
+ error: ProtocolError.NO_PEER_AVAILABLE
53
+ };
54
+ }
55
+
56
+ let stream;
57
+ try {
58
+ stream = await this.getStream(peerId);
59
+ } catch (error) {
60
+ log.error("Failed to get stream", error);
61
+ return {
62
+ shardInfo: null,
63
+ error: ProtocolError.NO_STREAM_AVAILABLE
64
+ };
65
+ }
66
+
67
+ const encodedResponse = await pipe(
68
+ [request],
69
+ lp.encode,
70
+ stream,
71
+ lp.decode,
72
+ async (source) => await all(source)
73
+ );
74
+
75
+ const { error, shardInfo } = this.decodeMetadataResponse(encodedResponse);
76
+
77
+ if (error) {
78
+ return {
79
+ shardInfo: null,
80
+ error
81
+ };
82
+ }
83
+
84
+ await this.savePeerShardInfo(peerId, shardInfo);
85
+
86
+ return {
87
+ shardInfo,
88
+ error: null
89
+ };
90
+ }
91
+
92
+ public async confirmOrAttemptHandshake(
93
+ peerId: PeerId
94
+ ): Promise<MetadataQueryResult> {
95
+ const shardInfo = this.handshakesConfirmed.get(peerId.toString());
96
+ if (shardInfo) {
97
+ return {
98
+ shardInfo,
99
+ error: null
100
+ };
101
+ }
102
+
103
+ return await this.query(peerId);
104
+ }
105
+
106
+ /**
107
+ * Handle an incoming metadata request
108
+ */
109
+ private async onRequest(streamData: IncomingStreamData): Promise<void> {
110
+ try {
111
+ const { stream, connection } = streamData;
112
+ const encodedShardInfo = proto_metadata.WakuMetadataResponse.encode(
113
+ pubsubTopicsToShardInfo(this.pubsubTopics)
114
+ );
115
+
116
+ const encodedResponse = await pipe(
117
+ [encodedShardInfo],
118
+ lp.encode,
119
+ stream,
120
+ lp.decode,
121
+ async (source) => await all(source)
122
+ );
123
+
124
+ const { error, shardInfo } = this.decodeMetadataResponse(encodedResponse);
125
+
126
+ if (error) {
127
+ return;
128
+ }
129
+
130
+ await this.savePeerShardInfo(connection.remotePeer, shardInfo);
131
+ } catch (error) {
132
+ log.error("Error handling metadata request", error);
133
+ }
134
+ }
135
+
136
+ private decodeMetadataResponse(
137
+ encodedResponse: Uint8ArrayList[]
138
+ ): MetadataQueryResult {
139
+ const bytes = new Uint8ArrayList();
140
+
141
+ encodedResponse.forEach((chunk) => {
142
+ bytes.append(chunk);
143
+ });
144
+ const response = proto_metadata.WakuMetadataResponse.decode(
145
+ bytes
146
+ ) as ShardInfo;
147
+
148
+ if (!response) {
149
+ log.error("Error decoding metadata response");
150
+ return {
151
+ shardInfo: null,
152
+ error: ProtocolError.DECODE_FAILED
153
+ };
154
+ }
155
+
156
+ return {
157
+ shardInfo: response,
158
+ error: null
159
+ };
160
+ }
161
+
162
+ private async savePeerShardInfo(
163
+ peerId: PeerId,
164
+ shardInfo: ShardInfo
165
+ ): Promise<void> {
166
+ // add or update the shardInfo to peer store
167
+ await this.libp2pComponents.peerStore.merge(peerId, {
168
+ metadata: {
169
+ shardInfo: encodeRelayShard(shardInfo)
170
+ }
171
+ });
172
+
173
+ this.handshakesConfirmed.set(peerId.toString(), shardInfo);
174
+ }
175
+ }
176
+
177
+ export function wakuMetadata(
178
+ pubsubTopics: PubsubTopic[]
179
+ ): (components: Libp2pComponents) => IMetadata {
180
+ return (components: Libp2pComponents) =>
181
+ new Metadata(pubsubTopics, components);
182
+ }
@@ -1,136 +1 @@
1
- import type { Peer } from "@libp2p/interface";
2
- import {
3
- IDecodedMessage,
4
- IDecoder,
5
- IStoreCore,
6
- Libp2p,
7
- PubsubTopic,
8
- QueryRequestParams
9
- } from "@waku/interfaces";
10
- import { Logger } from "@waku/utils";
11
- import all from "it-all";
12
- import * as lp from "it-length-prefixed";
13
- import { pipe } from "it-pipe";
14
- import { Uint8ArrayList } from "uint8arraylist";
15
-
16
- import { BaseProtocol } from "../base_protocol.js";
17
- import { toProtoMessage } from "../to_proto_message.js";
18
-
19
- import {
20
- DEFAULT_PAGE_SIZE,
21
- MAX_PAGE_SIZE,
22
- StoreQueryRequest,
23
- StoreQueryResponse
24
- } from "./rpc.js";
25
-
26
- const log = new Logger("store");
27
-
28
- export const StoreCodec = "/vac/waku/store-query/3.0.0";
29
-
30
- export class StoreCore extends BaseProtocol implements IStoreCore {
31
- public constructor(
32
- public readonly pubsubTopics: PubsubTopic[],
33
- libp2p: Libp2p
34
- ) {
35
- super(StoreCodec, libp2p.components, log, pubsubTopics);
36
- }
37
-
38
- public async *queryPerPage<T extends IDecodedMessage>(
39
- queryOpts: QueryRequestParams,
40
- decoders: Map<string, IDecoder<T>>,
41
- peer: Peer
42
- ): AsyncGenerator<Promise<T | undefined>[]> {
43
- if (
44
- queryOpts.contentTopics.toString() !==
45
- Array.from(decoders.keys()).toString()
46
- ) {
47
- throw new Error(
48
- "Internal error, the decoders should match the query's content topics"
49
- );
50
- }
51
-
52
- let currentCursor = queryOpts.paginationCursor;
53
- while (true) {
54
- const storeQueryRequest = StoreQueryRequest.create({
55
- ...queryOpts,
56
- paginationCursor: currentCursor
57
- });
58
-
59
- let stream;
60
- try {
61
- stream = await this.getStream(peer);
62
- } catch (e) {
63
- log.error("Failed to get stream", e);
64
- break;
65
- }
66
-
67
- const res = await pipe(
68
- [storeQueryRequest.encode()],
69
- lp.encode,
70
- stream,
71
- lp.decode,
72
- async (source) => await all(source)
73
- );
74
-
75
- const bytes = new Uint8ArrayList();
76
- res.forEach((chunk) => {
77
- bytes.append(chunk);
78
- });
79
-
80
- const storeQueryResponse = StoreQueryResponse.decode(bytes);
81
-
82
- if (
83
- !storeQueryResponse.statusCode ||
84
- storeQueryResponse.statusCode >= 300
85
- ) {
86
- const errorMessage = `Store query failed with status code: ${storeQueryResponse.statusCode}, description: ${storeQueryResponse.statusDesc}`;
87
- log.error(errorMessage);
88
- throw new Error(errorMessage);
89
- }
90
-
91
- if (!storeQueryResponse.messages || !storeQueryResponse.messages.length) {
92
- log.warn("Stopping pagination due to empty messages in response");
93
- break;
94
- }
95
-
96
- log.info(
97
- `${storeQueryResponse.messages.length} messages retrieved from store`
98
- );
99
-
100
- const decodedMessages = storeQueryResponse.messages.map((protoMsg) => {
101
- if (!protoMsg.message) {
102
- return Promise.resolve(undefined);
103
- }
104
- const contentTopic = protoMsg.message.contentTopic;
105
- if (contentTopic) {
106
- const decoder = decoders.get(contentTopic);
107
- if (decoder) {
108
- return decoder.fromProtoObj(
109
- protoMsg.pubsubTopic || "",
110
- toProtoMessage(protoMsg.message)
111
- );
112
- }
113
- }
114
- return Promise.resolve(undefined);
115
- });
116
-
117
- yield decodedMessages;
118
-
119
- if (queryOpts.paginationForward) {
120
- currentCursor =
121
- storeQueryResponse.messages[storeQueryResponse.messages.length - 1]
122
- .messageHash;
123
- } else {
124
- currentCursor = storeQueryResponse.messages[0].messageHash;
125
- }
126
-
127
- if (
128
- storeQueryResponse.messages.length > MAX_PAGE_SIZE &&
129
- storeQueryResponse.messages.length <
130
- (queryOpts.paginationLimit || DEFAULT_PAGE_SIZE)
131
- ) {
132
- break;
133
- }
134
- }
135
- }
136
- }
1
+ export { StoreCore, StoreCodec } from "./store.js";
@@ -0,0 +1,136 @@
1
+ import type { PeerId } from "@libp2p/interface";
2
+ import {
3
+ IDecodedMessage,
4
+ IDecoder,
5
+ IStoreCore,
6
+ Libp2p,
7
+ PubsubTopic,
8
+ QueryRequestParams
9
+ } from "@waku/interfaces";
10
+ import { Logger } from "@waku/utils";
11
+ import all from "it-all";
12
+ import * as lp from "it-length-prefixed";
13
+ import { pipe } from "it-pipe";
14
+ import { Uint8ArrayList } from "uint8arraylist";
15
+
16
+ import { BaseProtocol } from "../base_protocol.js";
17
+ import { toProtoMessage } from "../to_proto_message.js";
18
+
19
+ import {
20
+ DEFAULT_PAGE_SIZE,
21
+ MAX_PAGE_SIZE,
22
+ StoreQueryRequest,
23
+ StoreQueryResponse
24
+ } from "./rpc.js";
25
+
26
+ const log = new Logger("store");
27
+
28
+ export const StoreCodec = "/vac/waku/store-query/3.0.0";
29
+
30
+ export class StoreCore extends BaseProtocol implements IStoreCore {
31
+ public constructor(
32
+ public readonly pubsubTopics: PubsubTopic[],
33
+ libp2p: Libp2p
34
+ ) {
35
+ super(StoreCodec, libp2p.components, pubsubTopics);
36
+ }
37
+
38
+ public async *queryPerPage<T extends IDecodedMessage>(
39
+ queryOpts: QueryRequestParams,
40
+ decoders: Map<string, IDecoder<T>>,
41
+ peerId: PeerId
42
+ ): AsyncGenerator<Promise<T | undefined>[]> {
43
+ if (
44
+ queryOpts.contentTopics.toString() !==
45
+ Array.from(decoders.keys()).toString()
46
+ ) {
47
+ throw new Error(
48
+ "Internal error, the decoders should match the query's content topics"
49
+ );
50
+ }
51
+
52
+ let currentCursor = queryOpts.paginationCursor;
53
+ while (true) {
54
+ const storeQueryRequest = StoreQueryRequest.create({
55
+ ...queryOpts,
56
+ paginationCursor: currentCursor
57
+ });
58
+
59
+ let stream;
60
+ try {
61
+ stream = await this.getStream(peerId);
62
+ } catch (e) {
63
+ log.error("Failed to get stream", e);
64
+ break;
65
+ }
66
+
67
+ const res = await pipe(
68
+ [storeQueryRequest.encode()],
69
+ lp.encode,
70
+ stream,
71
+ lp.decode,
72
+ async (source) => await all(source)
73
+ );
74
+
75
+ const bytes = new Uint8ArrayList();
76
+ res.forEach((chunk) => {
77
+ bytes.append(chunk);
78
+ });
79
+
80
+ const storeQueryResponse = StoreQueryResponse.decode(bytes);
81
+
82
+ if (
83
+ !storeQueryResponse.statusCode ||
84
+ storeQueryResponse.statusCode >= 300
85
+ ) {
86
+ const errorMessage = `Store query failed with status code: ${storeQueryResponse.statusCode}, description: ${storeQueryResponse.statusDesc}`;
87
+ log.error(errorMessage);
88
+ throw new Error(errorMessage);
89
+ }
90
+
91
+ if (!storeQueryResponse.messages || !storeQueryResponse.messages.length) {
92
+ log.warn("Stopping pagination due to empty messages in response");
93
+ break;
94
+ }
95
+
96
+ log.info(
97
+ `${storeQueryResponse.messages.length} messages retrieved from store`
98
+ );
99
+
100
+ const decodedMessages = storeQueryResponse.messages.map((protoMsg) => {
101
+ if (!protoMsg.message) {
102
+ return Promise.resolve(undefined);
103
+ }
104
+ const contentTopic = protoMsg.message.contentTopic;
105
+ if (contentTopic) {
106
+ const decoder = decoders.get(contentTopic);
107
+ if (decoder) {
108
+ return decoder.fromProtoObj(
109
+ protoMsg.pubsubTopic || "",
110
+ toProtoMessage(protoMsg.message)
111
+ );
112
+ }
113
+ }
114
+ return Promise.resolve(undefined);
115
+ });
116
+
117
+ yield decodedMessages;
118
+
119
+ if (queryOpts.paginationForward) {
120
+ currentCursor =
121
+ storeQueryResponse.messages[storeQueryResponse.messages.length - 1]
122
+ .messageHash;
123
+ } else {
124
+ currentCursor = storeQueryResponse.messages[0].messageHash;
125
+ }
126
+
127
+ if (
128
+ storeQueryResponse.messages.length > MAX_PAGE_SIZE &&
129
+ storeQueryResponse.messages.length <
130
+ (queryOpts.paginationLimit || DEFAULT_PAGE_SIZE)
131
+ ) {
132
+ break;
133
+ }
134
+ }
135
+ }
136
+ }