@waku/core 0.0.21 → 0.0.23

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 (62) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/bundle/base_protocol-84d9b670.js +1198 -0
  3. package/bundle/index.js +1163 -1281
  4. package/bundle/lib/base_protocol.js +2 -116
  5. package/bundle/lib/message/version_0.js +1 -1
  6. package/bundle/lib/predefined_bootstrap_nodes.js +6 -6
  7. package/bundle/{version_0-86411fdf.js → version_0-74b4b9db.js} +875 -794
  8. package/dist/.tsbuildinfo +1 -0
  9. package/dist/index.d.ts +6 -5
  10. package/dist/index.js +5 -4
  11. package/dist/index.js.map +1 -1
  12. package/dist/lib/base_protocol.d.ts +18 -5
  13. package/dist/lib/base_protocol.js +25 -8
  14. package/dist/lib/base_protocol.js.map +1 -1
  15. package/dist/lib/connection_manager.d.ts +3 -5
  16. package/dist/lib/connection_manager.js +53 -45
  17. package/dist/lib/connection_manager.js.map +1 -1
  18. package/dist/lib/filter/filter_rpc.js +4 -4
  19. package/dist/lib/filter/index.d.ts +4 -0
  20. package/dist/lib/filter/index.js +24 -27
  21. package/dist/lib/filter/index.js.map +1 -1
  22. package/dist/lib/filterPeers.d.ts +10 -0
  23. package/dist/lib/filterPeers.js +31 -0
  24. package/dist/lib/filterPeers.js.map +1 -0
  25. package/dist/lib/keep_alive_manager.d.ts +4 -6
  26. package/dist/lib/keep_alive_manager.js +27 -8
  27. package/dist/lib/keep_alive_manager.js.map +1 -1
  28. package/dist/lib/light_push/index.js +62 -33
  29. package/dist/lib/light_push/index.js.map +1 -1
  30. package/dist/lib/light_push/push_rpc.js +2 -2
  31. package/dist/lib/message/version_0.d.ts +1 -1
  32. package/dist/lib/message/version_0.js +3 -3
  33. package/dist/lib/message/version_0.js.map +1 -1
  34. package/dist/lib/predefined_bootstrap_nodes.js +6 -6
  35. package/dist/lib/store/history_rpc.js +3 -3
  36. package/dist/lib/store/index.d.ts +0 -5
  37. package/dist/lib/store/index.js +54 -37
  38. package/dist/lib/store/index.js.map +1 -1
  39. package/dist/lib/stream_manager.d.ts +15 -0
  40. package/dist/lib/stream_manager.js +53 -0
  41. package/dist/lib/stream_manager.js.map +1 -0
  42. package/dist/lib/to_proto_message.js +1 -1
  43. package/dist/lib/waku.d.ts +2 -2
  44. package/dist/lib/waku.js +1 -1
  45. package/package.json +16 -22
  46. package/src/index.ts +7 -13
  47. package/src/lib/base_protocol.ts +49 -18
  48. package/src/lib/connection_manager.ts +82 -66
  49. package/src/lib/filter/filter_rpc.ts +4 -4
  50. package/src/lib/filter/index.ts +32 -39
  51. package/src/lib/filterPeers.ts +43 -0
  52. package/src/lib/keep_alive_manager.ts +34 -14
  53. package/src/lib/light_push/index.ts +103 -47
  54. package/src/lib/light_push/push_rpc.ts +2 -2
  55. package/src/lib/message/version_0.ts +8 -5
  56. package/src/lib/predefined_bootstrap_nodes.ts +7 -7
  57. package/src/lib/store/history_rpc.ts +4 -4
  58. package/src/lib/store/index.ts +70 -51
  59. package/src/lib/stream_manager.ts +69 -0
  60. package/src/lib/to_proto_message.ts +1 -1
  61. package/src/lib/wait_for_remote_peer.ts +1 -1
  62. package/src/lib/waku.ts +3 -3
@@ -1,18 +1,20 @@
1
- import type { PeerId } from "@libp2p/interface-peer-id";
2
- import type { PeerInfo } from "@libp2p/interface-peer-info";
3
- import type { Peer } from "@libp2p/interface-peer-store";
1
+ import type { PeerId } from "@libp2p/interface/peer-id";
2
+ import type { PeerInfo } from "@libp2p/interface/peer-info";
3
+ import type { Peer } from "@libp2p/interface/peer-store";
4
4
  import { CustomEvent, EventEmitter } from "@libp2p/interfaces/events";
5
5
  import {
6
6
  ConnectionManagerOptions,
7
7
  EPeersByDiscoveryEvents,
8
+ IConnectionManager,
8
9
  IPeersByDiscoveryEvents,
9
10
  IRelay,
10
- PeersByDiscoveryResult,
11
+ KeepAliveOptions,
12
+ PeersByDiscoveryResult
11
13
  } from "@waku/interfaces";
12
14
  import { Libp2p, Tags } from "@waku/interfaces";
13
15
  import debug from "debug";
14
16
 
15
- import { KeepAliveManager, KeepAliveOptions } from "./keep_alive_manager.js";
17
+ import { KeepAliveManager } from "./keep_alive_manager.js";
16
18
 
17
19
  const log = debug("waku:connection-manager");
18
20
 
@@ -20,7 +22,10 @@ export const DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED = 1;
20
22
  export const DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER = 3;
21
23
  export const DEFAULT_MAX_PARALLEL_DIALS = 3;
22
24
 
23
- export class ConnectionManager extends EventEmitter<IPeersByDiscoveryEvents> {
25
+ export class ConnectionManager
26
+ extends EventEmitter<IPeersByDiscoveryEvents>
27
+ implements IConnectionManager
28
+ {
24
29
  private static instances = new Map<string, ConnectionManager>();
25
30
  private keepAliveManager: KeepAliveManager;
26
31
  private options: ConnectionManagerOptions;
@@ -87,12 +92,12 @@ export class ConnectionManager extends EventEmitter<IPeersByDiscoveryEvents> {
87
92
  return {
88
93
  DISCOVERED: {
89
94
  [Tags.BOOTSTRAP]: peersDiscoveredByBootstrap,
90
- [Tags.PEER_EXCHANGE]: peersDiscoveredByPeerExchange,
95
+ [Tags.PEER_EXCHANGE]: peersDiscoveredByPeerExchange
91
96
  },
92
97
  CONNECTED: {
93
98
  [Tags.BOOTSTRAP]: peersConnectedByBootstrap,
94
- [Tags.PEER_EXCHANGE]: peersConnectedByPeerExchange,
95
- },
99
+ [Tags.PEER_EXCHANGE]: peersConnectedByPeerExchange
100
+ }
96
101
  };
97
102
  }
98
103
 
@@ -108,7 +113,7 @@ export class ConnectionManager extends EventEmitter<IPeersByDiscoveryEvents> {
108
113
  maxDialAttemptsForPeer: DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER,
109
114
  maxBootstrapPeersAllowed: DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED,
110
115
  maxParallelDials: DEFAULT_MAX_PARALLEL_DIALS,
111
- ...options,
116
+ ...options
112
117
  };
113
118
 
114
119
  this.keepAliveManager = new KeepAliveManager(keepAliveOptions, relay);
@@ -169,55 +174,71 @@ export class ConnectionManager extends EventEmitter<IPeersByDiscoveryEvents> {
169
174
  private async dialPeer(peerId: PeerId): Promise<void> {
170
175
  this.currentActiveDialCount += 1;
171
176
  let dialAttempt = 0;
172
- while (dialAttempt <= this.options.maxDialAttemptsForPeer) {
177
+ while (dialAttempt < this.options.maxDialAttemptsForPeer) {
173
178
  try {
174
- log(`Dialing peer ${peerId.toString()}`);
179
+ log(`Dialing peer ${peerId.toString()} on attempt ${dialAttempt + 1}`);
175
180
  await this.libp2p.dial(peerId);
176
181
 
177
182
  const tags = await this.getTagNamesForPeer(peerId);
178
183
  // add tag to connection describing discovery mechanism
179
184
  // don't add duplicate tags
180
- this.libp2p
181
- .getConnections(peerId)
182
- .forEach(
183
- (conn) => (conn.tags = Array.from(new Set([...conn.tags, ...tags])))
184
- );
185
+ this.libp2p.getConnections(peerId).forEach((conn) => {
186
+ conn.tags = Array.from(new Set([...conn.tags, ...tags]));
187
+ });
185
188
 
186
189
  this.dialAttemptsForPeer.delete(peerId.toString());
187
- return;
188
- } catch (e) {
189
- const error = e as AggregateError;
190
-
190
+ // Dialing succeeded, break the loop
191
+ break;
192
+ } catch (error) {
193
+ if (error instanceof AggregateError) {
194
+ // Handle AggregateError
195
+ log(`Error dialing peer ${peerId.toString()} - ${error.errors}`);
196
+ } else {
197
+ // Handle generic error
198
+ log(
199
+ `Error dialing peer ${peerId.toString()} - ${
200
+ (error as any).message
201
+ }`
202
+ );
203
+ }
191
204
  this.dialErrorsForPeer.set(peerId.toString(), error);
192
- log(`Error dialing peer ${peerId.toString()} - ${error.errors}`);
193
-
194
- dialAttempt = this.dialAttemptsForPeer.get(peerId.toString()) ?? 1;
195
- this.dialAttemptsForPeer.set(peerId.toString(), dialAttempt + 1);
196
205
 
197
- if (dialAttempt <= this.options.maxDialAttemptsForPeer) {
198
- log(`Reattempting dial (${dialAttempt})`);
199
- }
206
+ dialAttempt++;
207
+ this.dialAttemptsForPeer.set(peerId.toString(), dialAttempt);
200
208
  }
201
209
  }
202
210
 
203
- try {
204
- log(
205
- `Deleting undialable peer ${peerId.toString()} from peer store. Error: ${JSON.stringify(
206
- this.dialErrorsForPeer.get(peerId.toString()).errors[0]
207
- )}
208
- }`
209
- );
210
- this.dialErrorsForPeer.delete(peerId.toString());
211
- return await this.libp2p.peerStore.delete(peerId);
212
- } catch (error) {
213
- throw `Error deleting undialable peer ${peerId.toString()} from peer store - ${error}`;
214
- } finally {
215
- this.currentActiveDialCount -= 1;
216
- this.processDialQueue();
211
+ // Always decrease the active dial count and process the dial queue
212
+ this.currentActiveDialCount--;
213
+ this.processDialQueue();
214
+
215
+ // If max dial attempts reached and dialing failed, delete the peer
216
+ if (dialAttempt === this.options.maxDialAttemptsForPeer) {
217
+ try {
218
+ const error = this.dialErrorsForPeer.get(peerId.toString());
219
+
220
+ let errorMessage;
221
+ if (error instanceof AggregateError) {
222
+ errorMessage = JSON.stringify(error.errors[0]);
223
+ } else {
224
+ errorMessage = error.message;
225
+ }
226
+
227
+ log(
228
+ `Deleting undialable peer ${peerId.toString()} from peer store. Error: ${errorMessage}`
229
+ );
230
+
231
+ this.dialErrorsForPeer.delete(peerId.toString());
232
+ await this.libp2p.peerStore.delete(peerId);
233
+ } catch (error) {
234
+ throw new Error(
235
+ `Error deleting undialable peer ${peerId.toString()} from peer store - ${error}`
236
+ );
237
+ }
217
238
  }
218
239
  }
219
240
 
220
- async dropConnection(peerId: PeerId): Promise<void> {
241
+ private async dropConnection(peerId: PeerId): Promise<void> {
221
242
  try {
222
243
  this.keepAliveManager.stop(peerId);
223
244
  await this.libp2p.hangUp(peerId);
@@ -297,25 +318,16 @@ export class ConnectionManager extends EventEmitter<IPeersByDiscoveryEvents> {
297
318
  Tags.BOOTSTRAP
298
319
  );
299
320
 
300
- if (isBootstrap) {
301
- this.dispatchEvent(
302
- new CustomEvent<PeerId>(
303
- EPeersByDiscoveryEvents.PEER_DISCOVERY_BOOTSTRAP,
304
- {
305
- detail: peerId,
306
- }
307
- )
308
- );
309
- } else {
310
- this.dispatchEvent(
311
- new CustomEvent<PeerId>(
312
- EPeersByDiscoveryEvents.PEER_DISCOVERY_PEER_EXCHANGE,
313
- {
314
- detail: peerId,
315
- }
316
- )
317
- );
318
- }
321
+ this.dispatchEvent(
322
+ new CustomEvent<PeerId>(
323
+ isBootstrap
324
+ ? EPeersByDiscoveryEvents.PEER_DISCOVERY_BOOTSTRAP
325
+ : EPeersByDiscoveryEvents.PEER_DISCOVERY_PEER_EXCHANGE,
326
+ {
327
+ detail: peerId
328
+ }
329
+ )
330
+ );
319
331
 
320
332
  try {
321
333
  await this.attemptDial(peerId);
@@ -328,7 +340,11 @@ export class ConnectionManager extends EventEmitter<IPeersByDiscoveryEvents> {
328
340
  void (async () => {
329
341
  const peerId = evt.detail;
330
342
 
331
- this.keepAliveManager.start(peerId, this.libp2p.services.ping);
343
+ this.keepAliveManager.start(
344
+ peerId,
345
+ this.libp2p.services.ping,
346
+ this.libp2p.peerStore
347
+ );
332
348
 
333
349
  const isBootstrap = (await this.getTagNamesForPeer(peerId)).includes(
334
350
  Tags.BOOTSTRAP
@@ -349,7 +365,7 @@ export class ConnectionManager extends EventEmitter<IPeersByDiscoveryEvents> {
349
365
  new CustomEvent<PeerId>(
350
366
  EPeersByDiscoveryEvents.PEER_CONNECT_BOOTSTRAP,
351
367
  {
352
- detail: peerId,
368
+ detail: peerId
353
369
  }
354
370
  )
355
371
  );
@@ -359,7 +375,7 @@ export class ConnectionManager extends EventEmitter<IPeersByDiscoveryEvents> {
359
375
  new CustomEvent<PeerId>(
360
376
  EPeersByDiscoveryEvents.PEER_CONNECT_PEER_EXCHANGE,
361
377
  {
362
- detail: peerId,
378
+ detail: peerId
363
379
  }
364
380
  )
365
381
  );
@@ -370,7 +386,7 @@ export class ConnectionManager extends EventEmitter<IPeersByDiscoveryEvents> {
370
386
  return (evt: CustomEvent<PeerId>): void => {
371
387
  this.keepAliveManager.stop(evt.detail);
372
388
  };
373
- },
389
+ }
374
390
  };
375
391
 
376
392
  /**
@@ -42,7 +42,7 @@ export class FilterSubscribeRpc {
42
42
  filterSubscribeType:
43
43
  proto.FilterSubscribeRequest.FilterSubscribeType.SUBSCRIBE,
44
44
  pubsubTopic,
45
- contentTopics,
45
+ contentTopics
46
46
  });
47
47
  }
48
48
 
@@ -55,7 +55,7 @@ export class FilterSubscribeRpc {
55
55
  filterSubscribeType:
56
56
  proto.FilterSubscribeRequest.FilterSubscribeType.UNSUBSCRIBE,
57
57
  pubsubTopic,
58
- contentTopics,
58
+ contentTopics
59
59
  });
60
60
  }
61
61
 
@@ -65,7 +65,7 @@ export class FilterSubscribeRpc {
65
65
  filterSubscribeType:
66
66
  proto.FilterSubscribeRequest.FilterSubscribeType.UNSUBSCRIBE_ALL,
67
67
  pubsubTopic,
68
- contentTopics: [],
68
+ contentTopics: []
69
69
  });
70
70
  }
71
71
 
@@ -75,7 +75,7 @@ export class FilterSubscribeRpc {
75
75
  filterSubscribeType:
76
76
  proto.FilterSubscribeRequest.FilterSubscribeType.SUBSCRIBER_PING,
77
77
  pubsubTopic: "",
78
- contentTopics: [],
78
+ contentTopics: []
79
79
  });
80
80
  }
81
81
 
@@ -1,7 +1,6 @@
1
- import { Stream } from "@libp2p/interface-connection";
2
- import type { PeerId } from "@libp2p/interface-peer-id";
3
- import type { Peer } from "@libp2p/interface-peer-store";
4
- import type { IncomingStreamData } from "@libp2p/interface-registrar";
1
+ import { Stream } from "@libp2p/interface/connection";
2
+ import type { Peer } from "@libp2p/interface/peer-store";
3
+ import type { IncomingStreamData } from "@libp2p/interface-internal/registrar";
5
4
  import type {
6
5
  Callback,
7
6
  ContentTopic,
@@ -14,9 +13,8 @@ import type {
14
13
  Libp2p,
15
14
  PeerIdStr,
16
15
  ProtocolCreateOptions,
17
- ProtocolOptions,
18
16
  PubSubTopic,
19
- Unsubscribe,
17
+ Unsubscribe
20
18
  } from "@waku/interfaces";
21
19
  import { WakuMessage } from "@waku/proto";
22
20
  import { groupByContentTopic, toAsyncIterator } from "@waku/utils";
@@ -31,7 +29,7 @@ import { DefaultPubSubTopic } from "../constants.js";
31
29
  import {
32
30
  FilterPushRpc,
33
31
  FilterSubscribeResponse,
34
- FilterSubscribeRpc,
32
+ FilterSubscribeRpc
35
33
  } from "./filter_rpc.js";
36
34
 
37
35
  const log = debug("waku:filter:v2");
@@ -41,9 +39,9 @@ type SubscriptionCallback<T extends IDecodedMessage> = {
41
39
  callback: Callback<T>;
42
40
  };
43
41
 
44
- const FilterCodecs = {
42
+ export const FilterCodecs = {
45
43
  SUBSCRIBE: "/vac/waku/filter-subscribe/2.0.0-beta1",
46
- PUSH: "/vac/waku/filter-push/2.0.0-beta1",
44
+ PUSH: "/vac/waku/filter-push/2.0.0-beta1"
47
45
  };
48
46
 
49
47
  class Subscription {
@@ -125,7 +123,7 @@ class Subscription {
125
123
  // Decoder that decode to different implementations of `IDecodedMessage`
126
124
  const subscriptionCallback = {
127
125
  decoders,
128
- callback,
126
+ callback
129
127
  } as unknown as SubscriptionCallback<IDecodedMessage>;
130
128
 
131
129
  // The callback and decoder may override previous values, this is on
@@ -228,6 +226,7 @@ class Subscription {
228
226
  class Filter extends BaseProtocol implements IReceiver {
229
227
  private readonly options: ProtocolCreateOptions;
230
228
  private activeSubscriptions = new Map<string, Subscription>();
229
+ private readonly NUM_PEERS_PROTOCOL = 1;
231
230
 
232
231
  private getActiveSubscription(
233
232
  pubSubTopic: PubSubTopic,
@@ -257,31 +256,32 @@ class Filter extends BaseProtocol implements IReceiver {
257
256
  this.options = options ?? {};
258
257
  }
259
258
 
260
- async createSubscription(
261
- pubSubTopic?: string,
262
- peerId?: PeerId
263
- ): Promise<Subscription> {
259
+ async createSubscription(pubSubTopic?: string): Promise<Subscription> {
264
260
  const _pubSubTopic =
265
261
  pubSubTopic ?? this.options.pubSubTopic ?? DefaultPubSubTopic;
266
262
 
267
- const peer = await this.getPeer(peerId);
263
+ const peer = (
264
+ await this.getPeers({
265
+ maxBootstrapPeers: 1,
266
+ numPeers: this.NUM_PEERS_PROTOCOL
267
+ })
268
+ )[0];
268
269
 
269
270
  const subscription =
270
271
  this.getActiveSubscription(_pubSubTopic, peer.id.toString()) ??
271
272
  this.setActiveSubscription(
272
273
  _pubSubTopic,
273
274
  peer.id.toString(),
274
- new Subscription(_pubSubTopic, peer, this.newStream.bind(this, peer))
275
+ new Subscription(_pubSubTopic, peer, this.getStream.bind(this, peer))
275
276
  );
276
277
 
277
278
  return subscription;
278
279
  }
279
280
 
280
281
  public toSubscriptionIterator<T extends IDecodedMessage>(
281
- decoders: IDecoder<T> | IDecoder<T>[],
282
- opts?: ProtocolOptions | undefined
282
+ decoders: IDecoder<T> | IDecoder<T>[]
283
283
  ): Promise<IAsyncIterator<T>> {
284
- return toAsyncIterator(this, decoders, opts);
284
+ return toAsyncIterator(this, decoders);
285
285
  }
286
286
 
287
287
  /**
@@ -301,10 +301,9 @@ class Filter extends BaseProtocol implements IReceiver {
301
301
  */
302
302
  async subscribe<T extends IDecodedMessage>(
303
303
  decoders: IDecoder<T> | IDecoder<T>[],
304
- callback: Callback<T>,
305
- opts?: ProtocolOptions
304
+ callback: Callback<T>
306
305
  ): Promise<Unsubscribe> {
307
- const subscription = await this.createSubscription(undefined, opts?.peerId);
306
+ const subscription = await this.createSubscription();
308
307
 
309
308
  await subscription.subscribe(decoders, callback);
310
309
 
@@ -384,23 +383,17 @@ async function pushMessage<T extends IDecodedMessage>(
384
383
  return;
385
384
  }
386
385
 
387
- let didDecodeMsg = false;
388
- // We don't want to wait for decoding failure, just attempt to decode
389
- // all messages and do the call back on the one that works
390
- // noinspection ES6MissingAwait
391
- for (const dec of decoders) {
392
- if (didDecodeMsg) break;
393
- const decoded = await dec.fromProtoObj(
394
- pubSubTopic,
395
- message as IProtoMessage
386
+ try {
387
+ const decodePromises = decoders.map((dec) =>
388
+ dec
389
+ .fromProtoObj(pubSubTopic, message as IProtoMessage)
390
+ .then((decoded) => decoded || Promise.reject("Decoding failed"))
396
391
  );
397
- if (!decoded) {
398
- log("Not able to decode message");
399
- continue;
400
- }
401
- // This is just to prevent more decoding attempt
402
- // TODO: Could be better if we were to abort promises
403
- didDecodeMsg = Boolean(decoded);
404
- await callback(decoded);
392
+
393
+ const decodedMessage = await Promise.any(decodePromises);
394
+
395
+ await callback(decodedMessage);
396
+ } catch (e) {
397
+ log("Error decoding message", e);
405
398
  }
406
399
  }
@@ -0,0 +1,43 @@
1
+ import { Peer } from "@libp2p/interface/peer-store";
2
+ import { Tags } from "@waku/interfaces";
3
+
4
+ /**
5
+ * Retrieves a list of peers based on the specified criteria.
6
+ *
7
+ * @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.
9
+ * @param maxBootstrapPeers - The maximum number of bootstrap peers to retrieve.
10
+ * @returns A Promise that resolves to an array of peers based on the specified criteria.
11
+ */
12
+ export async function filterPeers(
13
+ peers: Peer[],
14
+ numPeers: number,
15
+ maxBootstrapPeers: number
16
+ ): Promise<Peer[]> {
17
+ // Collect the bootstrap peers up to the specified maximum
18
+ const bootstrapPeers = peers
19
+ .filter((peer) => peer.tags.has(Tags.BOOTSTRAP))
20
+ .slice(0, maxBootstrapPeers);
21
+
22
+ // Collect non-bootstrap peers
23
+ const nonBootstrapPeers = peers.filter(
24
+ (peer) => !peer.tags.has(Tags.BOOTSTRAP)
25
+ );
26
+
27
+ // If numPeers is 0, return all peers
28
+ if (numPeers === 0) {
29
+ return [...bootstrapPeers, ...nonBootstrapPeers];
30
+ }
31
+
32
+ // Initialize the list of selected peers with the bootstrap peers
33
+ const selectedPeers: Peer[] = [...bootstrapPeers];
34
+
35
+ // Fill up to numPeers with remaining random peers if needed
36
+ while (selectedPeers.length < numPeers && nonBootstrapPeers.length > 0) {
37
+ const randomIndex = Math.floor(Math.random() * nonBootstrapPeers.length);
38
+ const randomPeer = nonBootstrapPeers.splice(randomIndex, 1)[0];
39
+ selectedPeers.push(randomPeer);
40
+ }
41
+
42
+ return selectedPeers;
43
+ }
@@ -1,18 +1,16 @@
1
- import type { PeerId } from "@libp2p/interface-peer-id";
1
+ import type { PeerId } from "@libp2p/interface/peer-id";
2
+ import type { PeerStore } from "@libp2p/interface/peer-store";
2
3
  import type { IRelay } from "@waku/interfaces";
4
+ import type { KeepAliveOptions } from "@waku/interfaces";
5
+ import { utf8ToBytes } from "@waku/utils/bytes";
3
6
  import debug from "debug";
4
7
  import type { PingService } from "libp2p/ping";
5
8
 
6
- import { createEncoder } from "../index.js";
9
+ import { createEncoder } from "./message/version_0.js";
7
10
 
8
11
  export const RelayPingContentTopic = "/relay-ping/1/ping/null";
9
12
  const log = debug("waku:keep-alive");
10
13
 
11
- export interface KeepAliveOptions {
12
- pingKeepAlive: number;
13
- relayKeepAlive: number;
14
- }
15
-
16
14
  export class KeepAliveManager {
17
15
  private pingKeepAliveTimers: Map<string, ReturnType<typeof setInterval>>;
18
16
  private relayKeepAliveTimers: Map<PeerId, ReturnType<typeof setInterval>>;
@@ -26,8 +24,12 @@ export class KeepAliveManager {
26
24
  this.relay = relay;
27
25
  }
28
26
 
29
- public start(peerId: PeerId, libp2pPing: PingService): void {
30
- // Just in case a timer already exist for this peer
27
+ public start(
28
+ peerId: PeerId,
29
+ libp2pPing: PingService,
30
+ peerStore: PeerStore
31
+ ): void {
32
+ // Just in case a timer already exists for this peer
31
33
  this.stop(peerId);
32
34
 
33
35
  const { pingKeepAlive: pingPeriodSecs, relayKeepAlive: relayPeriodSecs } =
@@ -37,10 +39,28 @@ export class KeepAliveManager {
37
39
 
38
40
  if (pingPeriodSecs !== 0) {
39
41
  const interval = setInterval(() => {
40
- libp2pPing.ping(peerId).catch((e) => {
41
- log(`Ping failed (${peerIdStr})`, e);
42
- });
42
+ void (async () => {
43
+ try {
44
+ // ping the peer for keep alive
45
+ // also update the peer store with the latency
46
+ const ping = await libp2pPing.ping(peerId);
47
+ log(`Ping succeeded (${peerIdStr})`, ping);
48
+
49
+ try {
50
+ await peerStore.patch(peerId, {
51
+ metadata: {
52
+ ping: utf8ToBytes(ping.toString())
53
+ }
54
+ });
55
+ } catch (e) {
56
+ log("Failed to update ping", e);
57
+ }
58
+ } catch (e) {
59
+ log(`Ping failed (${peerIdStr})`, e);
60
+ }
61
+ })();
43
62
  }, pingPeriodSecs * 1000);
63
+
44
64
  this.pingKeepAliveTimers.set(peerIdStr, interval);
45
65
  }
46
66
 
@@ -48,7 +68,7 @@ export class KeepAliveManager {
48
68
  if (relay && relayPeriodSecs !== 0) {
49
69
  const encoder = createEncoder({
50
70
  contentTopic: RelayPingContentTopic,
51
- ephemeral: true,
71
+ ephemeral: true
52
72
  });
53
73
  const interval = setInterval(() => {
54
74
  log("Sending Waku Relay ping message");
@@ -77,7 +97,7 @@ export class KeepAliveManager {
77
97
  public stopAll(): void {
78
98
  for (const timer of [
79
99
  ...Object.values(this.pingKeepAliveTimers),
80
- ...Object.values(this.relayKeepAliveTimers),
100
+ ...Object.values(this.relayKeepAliveTimers)
81
101
  ]) {
82
102
  clearInterval(timer);
83
103
  }