@waku/core 0.0.26 → 0.0.27
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.
- package/CHANGELOG.md +26 -0
- package/bundle/{base_protocol-pDODy0G6.js → base_protocol-LhsIWF3-.js} +137 -89
- package/bundle/{browser-mTOOnVZp.js → browser-BQyFvtq6.js} +501 -700
- package/bundle/{index-cmONXM-V.js → index-8YyfzF9R.js} +96 -41
- package/bundle/index.js +3033 -21649
- package/bundle/lib/base_protocol.js +3 -3
- package/bundle/lib/message/version_0.js +3 -3
- package/bundle/lib/predefined_bootstrap_nodes.js +1 -1
- package/bundle/{version_0-LQTFNC7k.js → version_0-FXfzO8Km.js} +1246 -2444
- package/dist/.tsbuildinfo +1 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.js +1 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/base_protocol.d.ts +13 -10
- package/dist/lib/base_protocol.js +38 -22
- package/dist/lib/base_protocol.js.map +1 -1
- package/dist/lib/connection_manager.d.ts +2 -2
- package/dist/lib/connection_manager.js +16 -6
- package/dist/lib/connection_manager.js.map +1 -1
- package/dist/lib/filter/index.d.ts +1 -1
- package/dist/lib/filter/index.js +140 -82
- package/dist/lib/filter/index.js.map +1 -1
- package/dist/lib/filterPeers.d.ts +8 -5
- package/dist/lib/filterPeers.js +12 -5
- package/dist/lib/filterPeers.js.map +1 -1
- package/dist/lib/keep_alive_manager.d.ts +2 -3
- package/dist/lib/keep_alive_manager.js.map +1 -1
- package/dist/lib/light_push/index.js +3 -6
- package/dist/lib/light_push/index.js.map +1 -1
- package/dist/lib/metadata/index.d.ts +2 -2
- package/dist/lib/metadata/index.js +25 -11
- package/dist/lib/metadata/index.js.map +1 -1
- package/dist/lib/store/index.js +1 -3
- package/dist/lib/store/index.js.map +1 -1
- package/dist/lib/stream_manager.d.ts +2 -2
- package/dist/lib/stream_manager.js.map +1 -1
- package/dist/lib/wait_for_remote_peer.d.ts +1 -1
- package/dist/lib/wait_for_remote_peer.js +40 -10
- package/dist/lib/wait_for_remote_peer.js.map +1 -1
- package/package.json +14 -12
- package/src/index.ts +1 -6
- package/src/lib/base_protocol.ts +59 -34
- package/src/lib/connection_manager.ts +17 -10
- package/src/lib/filter/index.ts +228 -137
- package/src/lib/filterPeers.ts +15 -7
- package/src/lib/keep_alive_manager.ts +2 -3
- package/src/lib/light_push/index.ts +11 -10
- package/src/lib/metadata/index.ts +51 -19
- package/src/lib/store/index.ts +3 -6
- package/src/lib/stream_manager.ts +2 -3
- package/src/lib/wait_for_remote_peer.ts +58 -12
- package/dist/lib/waku.d.ts +0 -57
- package/dist/lib/waku.js +0 -130
- package/dist/lib/waku.js.map +0 -1
- package/src/lib/waku.ts +0 -214
package/src/lib/filter/index.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
import { Stream } from "@libp2p/interface
|
2
|
-
import type { Peer } from "@libp2p/interface
|
3
|
-
import type { IncomingStreamData } from "@libp2p/interface-internal
|
1
|
+
import { Stream } from "@libp2p/interface";
|
2
|
+
import type { Peer } from "@libp2p/interface";
|
3
|
+
import type { IncomingStreamData } from "@libp2p/interface-internal";
|
4
4
|
import type {
|
5
5
|
Callback,
|
6
6
|
ContentTopic,
|
@@ -11,13 +11,13 @@ import type {
|
|
11
11
|
IProtoMessage,
|
12
12
|
IReceiver,
|
13
13
|
Libp2p,
|
14
|
-
PeerIdStr,
|
15
14
|
ProtocolCreateOptions,
|
16
15
|
PubsubTopic,
|
17
16
|
SingleShardInfo,
|
18
17
|
Unsubscribe
|
19
18
|
} from "@waku/interfaces";
|
20
19
|
import { DefaultPubsubTopic } from "@waku/interfaces";
|
20
|
+
import { messageHashStr } from "@waku/message-hash";
|
21
21
|
import { WakuMessage } from "@waku/proto";
|
22
22
|
import {
|
23
23
|
ensurePubsubTopicIsConfigured,
|
@@ -50,10 +50,14 @@ export const FilterCodecs = {
|
|
50
50
|
PUSH: "/vac/waku/filter-push/2.0.0-beta1"
|
51
51
|
};
|
52
52
|
|
53
|
+
/**
|
54
|
+
* A subscription object refers to a subscription to a given pubsub topic.
|
55
|
+
*/
|
53
56
|
class Subscription {
|
54
|
-
|
57
|
+
readonly peers: Peer[];
|
55
58
|
private readonly pubsubTopic: PubsubTopic;
|
56
59
|
private newStream: (peer: Peer) => Promise<Stream>;
|
60
|
+
readonly receivedMessagesHashStr: string[] = [];
|
57
61
|
|
58
62
|
private subscriptionCallbacks: Map<
|
59
63
|
ContentTopic,
|
@@ -62,10 +66,10 @@ class Subscription {
|
|
62
66
|
|
63
67
|
constructor(
|
64
68
|
pubsubTopic: PubsubTopic,
|
65
|
-
|
69
|
+
remotePeers: Peer[],
|
66
70
|
newStream: (peer: Peer) => Promise<Stream>
|
67
71
|
) {
|
68
|
-
this.
|
72
|
+
this.peers = remotePeers;
|
69
73
|
this.pubsubTopic = pubsubTopic;
|
70
74
|
this.newStream = newStream;
|
71
75
|
this.subscriptionCallbacks = new Map();
|
@@ -89,53 +93,59 @@ class Subscription {
|
|
89
93
|
const decodersGroupedByCT = groupByContentTopic(decodersArray);
|
90
94
|
const contentTopics = Array.from(decodersGroupedByCT.keys());
|
91
95
|
|
92
|
-
const
|
96
|
+
const promises = this.peers.map(async (peer) => {
|
97
|
+
const stream = await this.newStream(peer);
|
93
98
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
);
|
98
|
-
|
99
|
-
try {
|
100
|
-
const res = await pipe(
|
101
|
-
[request.encode()],
|
102
|
-
lp.encode,
|
103
|
-
stream,
|
104
|
-
lp.decode,
|
105
|
-
async (source) => await all(source)
|
99
|
+
const request = FilterSubscribeRpc.createSubscribeRequest(
|
100
|
+
this.pubsubTopic,
|
101
|
+
contentTopics
|
106
102
|
);
|
107
103
|
|
108
|
-
|
109
|
-
|
110
|
-
|
104
|
+
try {
|
105
|
+
const res = await pipe(
|
106
|
+
[request.encode()],
|
107
|
+
lp.encode,
|
108
|
+
stream,
|
109
|
+
lp.decode,
|
110
|
+
async (source) => await all(source)
|
111
111
|
);
|
112
|
-
}
|
113
112
|
|
114
|
-
|
115
|
-
|
113
|
+
if (!res || !res.length) {
|
114
|
+
throw Error(
|
115
|
+
`No response received for request ${request.requestId}: ${res}`
|
116
|
+
);
|
117
|
+
}
|
118
|
+
|
119
|
+
const { statusCode, requestId, statusDesc } =
|
120
|
+
FilterSubscribeResponse.decode(res[0].slice());
|
121
|
+
|
122
|
+
if (statusCode < 200 || statusCode >= 300) {
|
123
|
+
throw new Error(
|
124
|
+
`Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
|
125
|
+
);
|
126
|
+
}
|
116
127
|
|
117
|
-
|
128
|
+
log.info(
|
129
|
+
"Subscribed to peer ",
|
130
|
+
peer.id.toString(),
|
131
|
+
"for content topics",
|
132
|
+
contentTopics
|
133
|
+
);
|
134
|
+
} catch (e) {
|
118
135
|
throw new Error(
|
119
|
-
|
136
|
+
"Error subscribing to peer: " +
|
137
|
+
peer.id.toString() +
|
138
|
+
" for content topics: " +
|
139
|
+
contentTopics +
|
140
|
+
": " +
|
141
|
+
e
|
120
142
|
);
|
121
143
|
}
|
144
|
+
});
|
122
145
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
"for content topics",
|
127
|
-
contentTopics
|
128
|
-
);
|
129
|
-
} catch (e) {
|
130
|
-
throw new Error(
|
131
|
-
"Error subscribing to peer: " +
|
132
|
-
this.peer.id.toString() +
|
133
|
-
" for content topics: " +
|
134
|
-
contentTopics +
|
135
|
-
": " +
|
136
|
-
e
|
137
|
-
);
|
138
|
-
}
|
146
|
+
const results = await Promise.allSettled(promises);
|
147
|
+
|
148
|
+
this.handleErrors(results, "subscribe");
|
139
149
|
|
140
150
|
// Save the callback functions by content topics so they
|
141
151
|
// can easily be removed (reciprocally replaced) if `unsubscribe` (reciprocally `subscribe`)
|
@@ -155,133 +165,206 @@ class Subscription {
|
|
155
165
|
}
|
156
166
|
|
157
167
|
async unsubscribe(contentTopics: ContentTopic[]): Promise<void> {
|
158
|
-
const
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
168
|
+
const promises = this.peers.map(async (peer) => {
|
169
|
+
const stream = await this.newStream(peer);
|
170
|
+
const unsubscribeRequest = FilterSubscribeRpc.createUnsubscribeRequest(
|
171
|
+
this.pubsubTopic,
|
172
|
+
contentTopics
|
173
|
+
);
|
163
174
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
175
|
+
try {
|
176
|
+
await pipe([unsubscribeRequest.encode()], lp.encode, stream.sink);
|
177
|
+
} catch (error) {
|
178
|
+
throw new Error("Error unsubscribing: " + error);
|
179
|
+
}
|
169
180
|
|
170
|
-
|
171
|
-
|
181
|
+
contentTopics.forEach((contentTopic: string) => {
|
182
|
+
this.subscriptionCallbacks.delete(contentTopic);
|
183
|
+
});
|
172
184
|
});
|
185
|
+
|
186
|
+
const results = await Promise.allSettled(promises);
|
187
|
+
|
188
|
+
this.handleErrors(results, "unsubscribe");
|
173
189
|
}
|
174
190
|
|
175
191
|
async ping(): Promise<void> {
|
176
|
-
const
|
192
|
+
const promises = this.peers.map(async (peer) => {
|
193
|
+
const stream = await this.newStream(peer);
|
194
|
+
|
195
|
+
const request = FilterSubscribeRpc.createSubscriberPingRequest();
|
196
|
+
|
197
|
+
try {
|
198
|
+
const res = await pipe(
|
199
|
+
[request.encode()],
|
200
|
+
lp.encode,
|
201
|
+
stream,
|
202
|
+
lp.decode,
|
203
|
+
async (source) => await all(source)
|
204
|
+
);
|
177
205
|
|
178
|
-
|
206
|
+
if (!res || !res.length) {
|
207
|
+
throw Error(
|
208
|
+
`No response received for request ${request.requestId}: ${res}`
|
209
|
+
);
|
210
|
+
}
|
179
211
|
|
180
|
-
|
181
|
-
|
182
|
-
[request.encode()],
|
183
|
-
lp.encode,
|
184
|
-
stream,
|
185
|
-
lp.decode,
|
186
|
-
async (source) => await all(source)
|
187
|
-
);
|
212
|
+
const { statusCode, requestId, statusDesc } =
|
213
|
+
FilterSubscribeResponse.decode(res[0].slice());
|
188
214
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
215
|
+
if (statusCode < 200 || statusCode >= 300) {
|
216
|
+
throw new Error(
|
217
|
+
`Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
|
218
|
+
);
|
219
|
+
}
|
220
|
+
log.info(`Ping successful for peer ${peer.id.toString()}`);
|
221
|
+
} catch (error) {
|
222
|
+
log.error("Error pinging: ", error);
|
223
|
+
throw error; // Rethrow the actual error instead of wrapping it
|
193
224
|
}
|
225
|
+
});
|
194
226
|
|
195
|
-
|
196
|
-
FilterSubscribeResponse.decode(res[0].slice());
|
227
|
+
const results = await Promise.allSettled(promises);
|
197
228
|
|
198
|
-
|
199
|
-
throw new Error(
|
200
|
-
`Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
|
201
|
-
);
|
202
|
-
}
|
203
|
-
|
204
|
-
log.info("Ping successful");
|
205
|
-
} catch (error) {
|
206
|
-
log.error("Error pinging: ", error);
|
207
|
-
throw new Error("Error pinging: " + error);
|
208
|
-
}
|
229
|
+
this.handleErrors(results, "ping");
|
209
230
|
}
|
210
231
|
|
211
232
|
async unsubscribeAll(): Promise<void> {
|
212
|
-
const
|
213
|
-
|
214
|
-
const request = FilterSubscribeRpc.createUnsubscribeAllRequest(
|
215
|
-
this.pubsubTopic
|
216
|
-
);
|
233
|
+
const promises = this.peers.map(async (peer) => {
|
234
|
+
const stream = await this.newStream(peer);
|
217
235
|
|
218
|
-
|
219
|
-
|
220
|
-
[request.encode()],
|
221
|
-
lp.encode,
|
222
|
-
stream,
|
223
|
-
lp.decode,
|
224
|
-
async (source) => await all(source)
|
236
|
+
const request = FilterSubscribeRpc.createUnsubscribeAllRequest(
|
237
|
+
this.pubsubTopic
|
225
238
|
);
|
226
239
|
|
227
|
-
|
228
|
-
|
229
|
-
|
240
|
+
try {
|
241
|
+
const res = await pipe(
|
242
|
+
[request.encode()],
|
243
|
+
lp.encode,
|
244
|
+
stream,
|
245
|
+
lp.decode,
|
246
|
+
async (source) => await all(source)
|
230
247
|
);
|
231
|
-
}
|
232
248
|
|
233
|
-
|
234
|
-
|
249
|
+
if (!res || !res.length) {
|
250
|
+
throw Error(
|
251
|
+
`No response received for request ${request.requestId}: ${res}`
|
252
|
+
);
|
253
|
+
}
|
254
|
+
|
255
|
+
const { statusCode, requestId, statusDesc } =
|
256
|
+
FilterSubscribeResponse.decode(res[0].slice());
|
235
257
|
|
236
|
-
|
258
|
+
if (statusCode < 200 || statusCode >= 300) {
|
259
|
+
throw new Error(
|
260
|
+
`Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
|
261
|
+
);
|
262
|
+
}
|
263
|
+
|
264
|
+
this.subscriptionCallbacks.clear();
|
265
|
+
log.info(
|
266
|
+
`Unsubscribed from all content topics for pubsub topic ${this.pubsubTopic}`
|
267
|
+
);
|
268
|
+
} catch (error) {
|
237
269
|
throw new Error(
|
238
|
-
|
270
|
+
"Error unsubscribing from all content topics: " + error
|
239
271
|
);
|
240
272
|
}
|
273
|
+
});
|
241
274
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
throw new Error("Error unsubscribing from all content topics: " + error);
|
246
|
-
}
|
275
|
+
const results = await Promise.allSettled(promises);
|
276
|
+
|
277
|
+
this.handleErrors(results, "unsubscribeAll");
|
247
278
|
}
|
248
279
|
|
249
280
|
async processMessage(message: WakuMessage): Promise<void> {
|
250
|
-
const
|
281
|
+
const hashedMessageStr = messageHashStr(
|
282
|
+
this.pubsubTopic,
|
283
|
+
message as IProtoMessage
|
284
|
+
);
|
285
|
+
if (this.receivedMessagesHashStr.includes(hashedMessageStr)) {
|
286
|
+
log.info("Message already received, skipping");
|
287
|
+
return;
|
288
|
+
}
|
289
|
+
this.receivedMessagesHashStr.push(hashedMessageStr);
|
290
|
+
|
291
|
+
const { contentTopic } = message;
|
251
292
|
const subscriptionCallback = this.subscriptionCallbacks.get(contentTopic);
|
252
293
|
if (!subscriptionCallback) {
|
253
294
|
log.error("No subscription callback available for ", contentTopic);
|
254
295
|
return;
|
255
296
|
}
|
297
|
+
log.info(
|
298
|
+
"Processing message with content topic ",
|
299
|
+
contentTopic,
|
300
|
+
" on pubsub topic ",
|
301
|
+
this.pubsubTopic
|
302
|
+
);
|
256
303
|
await pushMessage(subscriptionCallback, this.pubsubTopic, message);
|
257
304
|
}
|
305
|
+
|
306
|
+
// Filter out only the rejected promises and extract & handle their reasons
|
307
|
+
private handleErrors(
|
308
|
+
results: PromiseSettledResult<void>[],
|
309
|
+
type: "ping" | "subscribe" | "unsubscribe" | "unsubscribeAll"
|
310
|
+
): void {
|
311
|
+
const errors = results
|
312
|
+
.filter(
|
313
|
+
(result): result is PromiseRejectedResult =>
|
314
|
+
result.status === "rejected"
|
315
|
+
)
|
316
|
+
.map((rejectedResult) => rejectedResult.reason);
|
317
|
+
|
318
|
+
if (errors.length === this.peers.length) {
|
319
|
+
const errorCounts = new Map<string, number>();
|
320
|
+
// TODO: streamline error logging with https://github.com/orgs/waku-org/projects/2/views/1?pane=issue&itemId=42849952
|
321
|
+
errors.forEach((error) => {
|
322
|
+
const message = error instanceof Error ? error.message : String(error);
|
323
|
+
errorCounts.set(message, (errorCounts.get(message) || 0) + 1);
|
324
|
+
});
|
325
|
+
|
326
|
+
const uniqueErrorMessages = Array.from(
|
327
|
+
errorCounts,
|
328
|
+
([message, count]) => `${message} (occurred ${count} times)`
|
329
|
+
).join(", ");
|
330
|
+
throw new Error(`Error ${type} all peers: ${uniqueErrorMessages}`);
|
331
|
+
} else if (errors.length > 0) {
|
332
|
+
// TODO: handle renewing faulty peers with new peers (https://github.com/waku-org/js-waku/issues/1463)
|
333
|
+
log.warn(
|
334
|
+
`Some ${type} failed. These will be refreshed with new peers`,
|
335
|
+
errors
|
336
|
+
);
|
337
|
+
} else {
|
338
|
+
log.info(`${type} successful for all peers`);
|
339
|
+
}
|
340
|
+
}
|
258
341
|
}
|
259
342
|
|
260
343
|
class Filter extends BaseProtocol implements IReceiver {
|
261
|
-
private readonly pubsubTopics: PubsubTopic[] = [];
|
262
344
|
private activeSubscriptions = new Map<string, Subscription>();
|
263
|
-
private readonly NUM_PEERS_PROTOCOL = 1;
|
264
345
|
|
265
346
|
private getActiveSubscription(
|
266
|
-
pubsubTopic: PubsubTopic
|
267
|
-
peerIdStr: PeerIdStr
|
347
|
+
pubsubTopic: PubsubTopic
|
268
348
|
): Subscription | undefined {
|
269
|
-
return this.activeSubscriptions.get(
|
349
|
+
return this.activeSubscriptions.get(pubsubTopic);
|
270
350
|
}
|
271
351
|
|
272
352
|
private setActiveSubscription(
|
273
353
|
pubsubTopic: PubsubTopic,
|
274
|
-
peerIdStr: PeerIdStr,
|
275
354
|
subscription: Subscription
|
276
355
|
): Subscription {
|
277
|
-
this.activeSubscriptions.set(
|
356
|
+
this.activeSubscriptions.set(pubsubTopic, subscription);
|
278
357
|
return subscription;
|
279
358
|
}
|
280
359
|
|
281
360
|
constructor(libp2p: Libp2p, options?: ProtocolCreateOptions) {
|
282
|
-
super(
|
283
|
-
|
284
|
-
|
361
|
+
super(
|
362
|
+
FilterCodecs.SUBSCRIBE,
|
363
|
+
libp2p.components,
|
364
|
+
log,
|
365
|
+
options!.pubsubTopics!,
|
366
|
+
options
|
367
|
+
);
|
285
368
|
|
286
369
|
libp2p.handle(FilterCodecs.PUSH, this.onRequest.bind(this)).catch((e) => {
|
287
370
|
log.error("Failed to register ", FilterCodecs.PUSH, e);
|
@@ -290,6 +373,12 @@ class Filter extends BaseProtocol implements IReceiver {
|
|
290
373
|
this.activeSubscriptions = new Map();
|
291
374
|
}
|
292
375
|
|
376
|
+
/**
|
377
|
+
* Creates a new subscription to the given pubsub topic.
|
378
|
+
* The subscription is made to multiple peers for decentralization.
|
379
|
+
* @param pubsubTopicShardInfo The pubsub topic to subscribe to.
|
380
|
+
* @returns The subscription object.
|
381
|
+
*/
|
293
382
|
async createSubscription(
|
294
383
|
pubsubTopicShardInfo: SingleShardInfo | PubsubTopic = DefaultPubsubTopic
|
295
384
|
): Promise<Subscription> {
|
@@ -300,21 +389,24 @@ class Filter extends BaseProtocol implements IReceiver {
|
|
300
389
|
|
301
390
|
ensurePubsubTopicIsConfigured(pubsubTopic, this.pubsubTopics);
|
302
391
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
392
|
+
const peers = await this.getPeers({
|
393
|
+
maxBootstrapPeers: 1,
|
394
|
+
numPeers: this.numPeersToUse
|
395
|
+
});
|
396
|
+
if (peers.length === 0) {
|
397
|
+
throw new Error("No peer found to initiate subscription.");
|
398
|
+
}
|
399
|
+
|
400
|
+
log.info(
|
401
|
+
`Creating filter subscription with ${peers.length} peers: `,
|
402
|
+
peers.map((peer) => peer.id.toString())
|
403
|
+
);
|
311
404
|
|
312
405
|
const subscription =
|
313
|
-
this.getActiveSubscription(pubsubTopic
|
406
|
+
this.getActiveSubscription(pubsubTopic) ??
|
314
407
|
this.setActiveSubscription(
|
315
408
|
pubsubTopic,
|
316
|
-
|
317
|
-
new Subscription(pubsubTopic, peer, this.getStream.bind(this, peer))
|
409
|
+
new Subscription(pubsubTopic, peers, this.getStream.bind(this))
|
318
410
|
);
|
319
411
|
|
320
412
|
return subscription;
|
@@ -361,8 +453,11 @@ class Filter extends BaseProtocol implements IReceiver {
|
|
361
453
|
}
|
362
454
|
|
363
455
|
private onRequest(streamData: IncomingStreamData): void {
|
456
|
+
const { connection, stream } = streamData;
|
457
|
+
const { remotePeer } = connection;
|
458
|
+
log.info(`Received message from ${remotePeer.toString()}`);
|
364
459
|
try {
|
365
|
-
pipe(
|
460
|
+
pipe(stream, lp.decode, async (source) => {
|
366
461
|
for await (const bytes of source) {
|
367
462
|
const response = FilterPushRpc.decode(bytes.slice());
|
368
463
|
|
@@ -378,11 +473,7 @@ class Filter extends BaseProtocol implements IReceiver {
|
|
378
473
|
return;
|
379
474
|
}
|
380
475
|
|
381
|
-
const
|
382
|
-
const subscription = this.getActiveSubscription(
|
383
|
-
pubsubTopic,
|
384
|
-
peerIdStr
|
385
|
-
);
|
476
|
+
const subscription = this.getActiveSubscription(pubsubTopic);
|
386
477
|
|
387
478
|
if (!subscription) {
|
388
479
|
log.error(
|
@@ -408,7 +499,7 @@ class Filter extends BaseProtocol implements IReceiver {
|
|
408
499
|
}
|
409
500
|
|
410
501
|
export function wakuFilter(
|
411
|
-
init:
|
502
|
+
init: ProtocolCreateOptions = { pubsubTopics: [] }
|
412
503
|
): (libp2p: Libp2p) => IFilter {
|
413
504
|
return (libp2p: Libp2p) => new Filter(libp2p, init);
|
414
505
|
}
|
package/src/lib/filterPeers.ts
CHANGED
@@ -1,24 +1,32 @@
|
|
1
|
-
import { Peer } from "@libp2p/interface
|
1
|
+
import { Peer } from "@libp2p/interface";
|
2
2
|
import { Tags } from "@waku/interfaces";
|
3
3
|
|
4
4
|
/**
|
5
|
-
* Retrieves a list of peers based on the specified criteria
|
5
|
+
* Retrieves a list of peers based on the specified criteria:
|
6
|
+
* 1. If numPeers is 0, return all peers
|
7
|
+
* 2. Bootstrap peers are prioritized
|
8
|
+
* 3. Non-bootstrap peers are randomly selected to fill up to numPeers
|
6
9
|
*
|
7
10
|
* @param peers - The list of peers to filter from.
|
8
|
-
* @param numPeers - The total number of peers to retrieve. If 0, all peers are returned
|
11
|
+
* @param numPeers - The total number of peers to retrieve. If 0, all peers are returned, irrespective of `maxBootstrapPeers`.
|
9
12
|
* @param maxBootstrapPeers - The maximum number of bootstrap peers to retrieve.
|
10
|
-
* @returns
|
13
|
+
* @returns An array of peers based on the specified criteria.
|
11
14
|
*/
|
12
|
-
export
|
15
|
+
export function filterPeersByDiscovery(
|
13
16
|
peers: Peer[],
|
14
17
|
numPeers: number,
|
15
18
|
maxBootstrapPeers: number
|
16
|
-
):
|
19
|
+
): Peer[] {
|
17
20
|
// Collect the bootstrap peers up to the specified maximum
|
18
|
-
|
21
|
+
let bootstrapPeers = peers
|
19
22
|
.filter((peer) => peer.tags.has(Tags.BOOTSTRAP))
|
20
23
|
.slice(0, maxBootstrapPeers);
|
21
24
|
|
25
|
+
// If numPeers is less than the number of bootstrap peers, adjust the bootstrapPeers array
|
26
|
+
if (numPeers > 0 && numPeers < bootstrapPeers.length) {
|
27
|
+
bootstrapPeers = bootstrapPeers.slice(0, numPeers);
|
28
|
+
}
|
29
|
+
|
22
30
|
// Collect non-bootstrap peers
|
23
31
|
const nonBootstrapPeers = peers.filter(
|
24
32
|
(peer) => !peer.tags.has(Tags.BOOTSTRAP)
|
@@ -1,10 +1,9 @@
|
|
1
|
-
import type { PeerId } from "@libp2p/interface
|
2
|
-
import type {
|
1
|
+
import type { PeerId, PeerStore } from "@libp2p/interface";
|
2
|
+
import type { PingService } from "@libp2p/ping";
|
3
3
|
import type { IRelay, PeerIdStr } from "@waku/interfaces";
|
4
4
|
import type { KeepAliveOptions } from "@waku/interfaces";
|
5
5
|
import { Logger, pubsubTopicToSingleShardInfo } from "@waku/utils";
|
6
6
|
import { utf8ToBytes } from "@waku/utils/bytes";
|
7
|
-
import type { PingService } from "libp2p/ping";
|
8
7
|
|
9
8
|
import { createEncoder } from "./message/version_0.js";
|
10
9
|
|
@@ -1,12 +1,10 @@
|
|
1
|
-
import type { Stream } from "@libp2p/interface
|
2
|
-
import type { PeerId } from "@libp2p/interface/peer-id";
|
1
|
+
import type { PeerId, Stream } from "@libp2p/interface";
|
3
2
|
import {
|
4
3
|
IEncoder,
|
5
4
|
ILightPush,
|
6
5
|
IMessage,
|
7
6
|
Libp2p,
|
8
7
|
ProtocolCreateOptions,
|
9
|
-
PubsubTopic,
|
10
8
|
SendError,
|
11
9
|
SendResult
|
12
10
|
} from "@waku/interfaces";
|
@@ -44,12 +42,14 @@ type PreparePushMessageResult =
|
|
44
42
|
* Implements the [Waku v2 Light Push protocol](https://rfc.vac.dev/spec/19/).
|
45
43
|
*/
|
46
44
|
class LightPush extends BaseProtocol implements ILightPush {
|
47
|
-
private readonly pubsubTopics: PubsubTopic[];
|
48
|
-
private readonly NUM_PEERS_PROTOCOL = 1;
|
49
|
-
|
50
45
|
constructor(libp2p: Libp2p, options?: ProtocolCreateOptions) {
|
51
|
-
super(
|
52
|
-
|
46
|
+
super(
|
47
|
+
LightPushCodec,
|
48
|
+
libp2p.components,
|
49
|
+
log,
|
50
|
+
options!.pubsubTopics!,
|
51
|
+
options
|
52
|
+
);
|
53
53
|
}
|
54
54
|
|
55
55
|
private async preparePushMessage(
|
@@ -108,10 +108,9 @@ class LightPush extends BaseProtocol implements ILightPush {
|
|
108
108
|
};
|
109
109
|
}
|
110
110
|
|
111
|
-
//TODO: get a relevant peer for the topic/shard
|
112
111
|
const peers = await this.getPeers({
|
113
112
|
maxBootstrapPeers: 1,
|
114
|
-
numPeers: this.
|
113
|
+
numPeers: this.numPeersToUse
|
115
114
|
});
|
116
115
|
|
117
116
|
if (!peers.length) {
|
@@ -177,6 +176,8 @@ class LightPush extends BaseProtocol implements ILightPush {
|
|
177
176
|
});
|
178
177
|
|
179
178
|
const results = await Promise.allSettled(promises);
|
179
|
+
|
180
|
+
// TODO: handle renewing faulty peers with new peers (https://github.com/waku-org/js-waku/issues/1463)
|
180
181
|
const errors = results
|
181
182
|
.filter(
|
182
183
|
(
|