@waku/core 0.0.23 → 0.0.24
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 +34 -0
- package/bundle/{base_protocol-84d9b670.js → base_protocol-2a0c882e.js} +182 -130
- package/bundle/{browser-bde977a3.js → browser-90197c87.js} +26 -1
- package/bundle/index.js +19159 -2228
- package/bundle/lib/base_protocol.js +2 -2
- package/bundle/lib/message/version_0.js +2 -2
- package/bundle/{version_0-74b4b9db.js → version_0-f4afd324.js} +33 -21
- package/dist/.tsbuildinfo +1 -1
- package/dist/lib/connection_manager.d.ts +15 -3
- package/dist/lib/connection_manager.js +83 -25
- package/dist/lib/connection_manager.js.map +1 -1
- package/dist/lib/filter/index.js +25 -20
- package/dist/lib/filter/index.js.map +1 -1
- package/dist/lib/keep_alive_manager.d.ts +1 -0
- package/dist/lib/keep_alive_manager.js +38 -14
- package/dist/lib/keep_alive_manager.js.map +1 -1
- package/dist/lib/light_push/index.js +49 -31
- package/dist/lib/light_push/index.js.map +1 -1
- package/dist/lib/light_push/push_rpc.d.ts +1 -1
- package/dist/lib/light_push/push_rpc.js +2 -2
- package/dist/lib/message/version_0.d.ts +13 -13
- package/dist/lib/message/version_0.js +19 -16
- package/dist/lib/message/version_0.js.map +1 -1
- package/dist/lib/store/history_rpc.d.ts +1 -1
- package/dist/lib/store/history_rpc.js +1 -1
- package/dist/lib/store/index.d.ts +1 -1
- package/dist/lib/store/index.js +37 -10
- package/dist/lib/store/index.js.map +1 -1
- package/dist/lib/stream_manager.d.ts +1 -1
- package/dist/lib/stream_manager.js +5 -2
- package/dist/lib/stream_manager.js.map +1 -1
- package/dist/lib/wait_for_remote_peer.d.ts +2 -2
- package/dist/lib/wait_for_remote_peer.js +10 -7
- package/dist/lib/wait_for_remote_peer.js.map +1 -1
- package/dist/lib/waku.d.ts +4 -3
- package/dist/lib/waku.js +5 -3
- package/dist/lib/waku.js.map +1 -1
- package/package.json +8 -18
- package/src/lib/connection_manager.ts +118 -31
- package/src/lib/filter/index.ts +36 -23
- package/src/lib/keep_alive_manager.ts +49 -16
- package/src/lib/light_push/index.ts +56 -31
- package/src/lib/light_push/push_rpc.ts +2 -2
- package/src/lib/message/version_0.ts +22 -13
- package/src/lib/store/history_rpc.ts +2 -2
- package/src/lib/store/index.ts +53 -14
- package/src/lib/stream_manager.ts +7 -4
- package/src/lib/wait_for_remote_peer.ts +10 -7
- package/src/lib/waku.ts +4 -1
- package/dist/lib/push_or_init_map.d.ts +0 -1
- package/dist/lib/push_or_init_map.js +0 -9
- package/dist/lib/push_or_init_map.js.map +0 -1
- package/src/lib/push_or_init_map.ts +0 -13
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@waku/core",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.24",
|
4
4
|
"description": "TypeScript implementation of the Waku v2 protocol",
|
5
5
|
"types": "./dist/index.d.ts",
|
6
6
|
"module": "./dist/index.js",
|
@@ -69,18 +69,19 @@
|
|
69
69
|
"reset-hard": "git clean -dfx -e .idea && git reset --hard && npm i && npm run build"
|
70
70
|
},
|
71
71
|
"engines": {
|
72
|
-
"node": ">=
|
72
|
+
"node": ">=18"
|
73
73
|
},
|
74
74
|
"dependencies": {
|
75
75
|
"@noble/hashes": "^1.3.2",
|
76
|
-
"@waku/
|
76
|
+
"@waku/enr": "^0.0.18",
|
77
|
+
"@waku/interfaces": "0.0.19",
|
77
78
|
"@waku/proto": "0.0.5",
|
78
|
-
"@waku/utils": "0.0.
|
79
|
+
"@waku/utils": "0.0.12",
|
79
80
|
"debug": "^4.3.4",
|
80
81
|
"it-all": "^3.0.3",
|
81
82
|
"it-length-prefixed": "^9.0.1",
|
82
83
|
"it-pipe": "^3.0.1",
|
83
|
-
"p-event": "^
|
84
|
+
"p-event": "^6.0.0",
|
84
85
|
"uint8arraylist": "^2.4.3",
|
85
86
|
"uuid": "^9.0.0"
|
86
87
|
},
|
@@ -96,21 +97,13 @@
|
|
96
97
|
"@waku/build-utils": "*",
|
97
98
|
"chai": "^4.3.7",
|
98
99
|
"cspell": "^7.3.2",
|
99
|
-
"fast-check": "^3.
|
100
|
+
"fast-check": "^3.13.1",
|
100
101
|
"ignore-loader": "^0.1.2",
|
101
102
|
"isomorphic-fetch": "^3.0.0",
|
102
|
-
"karma": "^6.4.1",
|
103
|
-
"karma-chrome-launcher": "^3.2.0",
|
104
|
-
"karma-mocha": "^2.0.1",
|
105
|
-
"karma-webpack": "^5.0.0",
|
106
103
|
"mocha": "^10.2.0",
|
107
104
|
"npm-run-all": "^4.1.5",
|
108
105
|
"process": "^0.11.10",
|
109
|
-
"
|
110
|
-
"rollup": "^3.29.0",
|
111
|
-
"ts-loader": "^9.4.2",
|
112
|
-
"ts-node": "^10.9.1",
|
113
|
-
"typescript": "^5.0.4"
|
106
|
+
"rollup": "^3.29.2"
|
114
107
|
},
|
115
108
|
"peerDependencies": {
|
116
109
|
"@multiformats/multiaddr": "^12.0.0",
|
@@ -121,9 +114,6 @@
|
|
121
114
|
"optional": true
|
122
115
|
}
|
123
116
|
},
|
124
|
-
"typedoc": {
|
125
|
-
"entryPoint": "./src/index.ts"
|
126
|
-
},
|
127
117
|
"files": [
|
128
118
|
"dist",
|
129
119
|
"bundle",
|
@@ -1,7 +1,9 @@
|
|
1
1
|
import type { PeerId } from "@libp2p/interface/peer-id";
|
2
2
|
import type { PeerInfo } from "@libp2p/interface/peer-info";
|
3
3
|
import type { Peer } from "@libp2p/interface/peer-store";
|
4
|
+
import type { PeerStore } from "@libp2p/interface/peer-store";
|
4
5
|
import { CustomEvent, EventEmitter } from "@libp2p/interfaces/events";
|
6
|
+
import { decodeRelayShard } from "@waku/enr";
|
5
7
|
import {
|
6
8
|
ConnectionManagerOptions,
|
7
9
|
EPeersByDiscoveryEvents,
|
@@ -9,9 +11,12 @@ import {
|
|
9
11
|
IPeersByDiscoveryEvents,
|
10
12
|
IRelay,
|
11
13
|
KeepAliveOptions,
|
12
|
-
PeersByDiscoveryResult
|
14
|
+
PeersByDiscoveryResult,
|
15
|
+
PubSubTopic,
|
16
|
+
ShardInfo
|
13
17
|
} from "@waku/interfaces";
|
14
18
|
import { Libp2p, Tags } from "@waku/interfaces";
|
19
|
+
import { shardInfoToPubSubTopics } from "@waku/utils";
|
15
20
|
import debug from "debug";
|
16
21
|
|
17
22
|
import { KeepAliveManager } from "./keep_alive_manager.js";
|
@@ -40,6 +45,7 @@ export class ConnectionManager
|
|
40
45
|
peerId: string,
|
41
46
|
libp2p: Libp2p,
|
42
47
|
keepAliveOptions: KeepAliveOptions,
|
48
|
+
pubsubTopics: PubSubTopic[],
|
43
49
|
relay?: IRelay,
|
44
50
|
options?: ConnectionManagerOptions
|
45
51
|
): ConnectionManager {
|
@@ -48,6 +54,7 @@ export class ConnectionManager
|
|
48
54
|
instance = new ConnectionManager(
|
49
55
|
libp2p,
|
50
56
|
keepAliveOptions,
|
57
|
+
pubsubTopics,
|
51
58
|
relay,
|
52
59
|
options
|
53
60
|
);
|
@@ -104,11 +111,13 @@ export class ConnectionManager
|
|
104
111
|
private constructor(
|
105
112
|
libp2p: Libp2p,
|
106
113
|
keepAliveOptions: KeepAliveOptions,
|
114
|
+
private configuredPubSubTopics: PubSubTopic[],
|
107
115
|
relay?: IRelay,
|
108
116
|
options?: Partial<ConnectionManagerOptions>
|
109
117
|
) {
|
110
118
|
super();
|
111
119
|
this.libp2p = libp2p;
|
120
|
+
this.configuredPubSubTopics = configuredPubSubTopics;
|
112
121
|
this.options = {
|
113
122
|
maxDialAttemptsForPeer: DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER,
|
114
123
|
maxBootstrapPeersAllowed: DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED,
|
@@ -217,16 +226,24 @@ export class ConnectionManager
|
|
217
226
|
try {
|
218
227
|
const error = this.dialErrorsForPeer.get(peerId.toString());
|
219
228
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
229
|
+
if (error) {
|
230
|
+
let errorMessage;
|
231
|
+
if (error instanceof AggregateError) {
|
232
|
+
if (!error.errors) {
|
233
|
+
log(`No errors array found for AggregateError`);
|
234
|
+
} else if (error.errors.length === 0) {
|
235
|
+
log(`Errors array is empty for AggregateError`);
|
236
|
+
} else {
|
237
|
+
errorMessage = JSON.stringify(error.errors[0]);
|
238
|
+
}
|
239
|
+
} else {
|
240
|
+
errorMessage = error.message;
|
241
|
+
}
|
226
242
|
|
227
|
-
|
228
|
-
|
229
|
-
|
243
|
+
log(
|
244
|
+
`Deleting undialable peer ${peerId.toString()} from peer store. Error: ${errorMessage}`
|
245
|
+
);
|
246
|
+
}
|
230
247
|
|
231
248
|
this.dialErrorsForPeer.delete(peerId.toString());
|
232
249
|
await this.libp2p.peerStore.delete(peerId);
|
@@ -297,15 +314,15 @@ export class ConnectionManager
|
|
297
314
|
}
|
298
315
|
|
299
316
|
private async attemptDial(peerId: PeerId): Promise<void> {
|
317
|
+
if (!(await this.shouldDialPeer(peerId))) return;
|
318
|
+
|
300
319
|
if (this.currentActiveDialCount >= this.options.maxParallelDials) {
|
301
320
|
this.pendingPeerDialQueue.push(peerId);
|
302
321
|
return;
|
303
322
|
}
|
304
323
|
|
305
|
-
if (!(await this.shouldDialPeer(peerId))) return;
|
306
|
-
|
307
324
|
this.dialPeer(peerId).catch((err) => {
|
308
|
-
|
325
|
+
log(`Error dialing peer ${peerId.toString()} : ${err}`);
|
309
326
|
});
|
310
327
|
}
|
311
328
|
|
@@ -314,20 +331,7 @@ export class ConnectionManager
|
|
314
331
|
void (async () => {
|
315
332
|
const { id: peerId } = evt.detail;
|
316
333
|
|
317
|
-
|
318
|
-
Tags.BOOTSTRAP
|
319
|
-
);
|
320
|
-
|
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
|
-
);
|
334
|
+
await this.dispatchDiscoveryEvent(peerId);
|
331
335
|
|
332
336
|
try {
|
333
337
|
await this.attemptDial(peerId);
|
@@ -390,15 +394,54 @@ export class ConnectionManager
|
|
390
394
|
};
|
391
395
|
|
392
396
|
/**
|
393
|
-
* Checks if the peer
|
394
|
-
* 1. If the peer is
|
395
|
-
* 2. If the peer is not
|
397
|
+
* Checks if the peer should be dialed based on the following conditions:
|
398
|
+
* 1. If the peer is already connected, don't dial
|
399
|
+
* 2. If the peer is not part of any of the configured pubsub topics, don't dial
|
400
|
+
* 3. If the peer is not dialable based on bootstrap status, don't dial
|
401
|
+
* @returns true if the peer should be dialed, false otherwise
|
396
402
|
*/
|
397
403
|
private async shouldDialPeer(peerId: PeerId): Promise<boolean> {
|
404
|
+
// if we're already connected to the peer, don't dial
|
398
405
|
const isConnected = this.libp2p.getConnections(peerId).length > 0;
|
406
|
+
if (isConnected) {
|
407
|
+
log(`Already connected to peer ${peerId.toString()}. Not dialing.`);
|
408
|
+
return false;
|
409
|
+
}
|
399
410
|
|
400
|
-
if
|
411
|
+
// if the peer is not part of any of the configured pubsub topics, don't dial
|
412
|
+
if (!(await this.isPeerTopicConfigured(peerId))) {
|
413
|
+
const shardInfo = await this.getPeerShardInfo(
|
414
|
+
peerId,
|
415
|
+
this.libp2p.peerStore
|
416
|
+
);
|
417
|
+
log(
|
418
|
+
`Discovered peer ${peerId.toString()} with ShardInfo ${shardInfo} is not part of any of the configured pubsub topics (${
|
419
|
+
this.configuredPubSubTopics
|
420
|
+
}).
|
421
|
+
Not dialing.`
|
422
|
+
);
|
423
|
+
return false;
|
424
|
+
}
|
401
425
|
|
426
|
+
// if the peer is not dialable based on bootstrap status, don't dial
|
427
|
+
if (!(await this.isPeerDialableBasedOnBootstrapStatus(peerId))) {
|
428
|
+
log(
|
429
|
+
`Peer ${peerId.toString()} is not dialable based on bootstrap status. Not dialing.`
|
430
|
+
);
|
431
|
+
return false;
|
432
|
+
}
|
433
|
+
|
434
|
+
return true;
|
435
|
+
}
|
436
|
+
|
437
|
+
/**
|
438
|
+
* Checks if the peer is dialable based on the following conditions:
|
439
|
+
* 1. If the peer is a bootstrap peer, it is only dialable if the number of current bootstrap connections is less than the max allowed.
|
440
|
+
* 2. If the peer is not a bootstrap peer
|
441
|
+
*/
|
442
|
+
private async isPeerDialableBasedOnBootstrapStatus(
|
443
|
+
peerId: PeerId
|
444
|
+
): Promise<boolean> {
|
402
445
|
const tagNames = await this.getTagNamesForPeer(peerId);
|
403
446
|
|
404
447
|
const isBootstrap = tagNames.some((tagName) => tagName === Tags.BOOTSTRAP);
|
@@ -418,6 +461,23 @@ export class ConnectionManager
|
|
418
461
|
return false;
|
419
462
|
}
|
420
463
|
|
464
|
+
private async dispatchDiscoveryEvent(peerId: PeerId): Promise<void> {
|
465
|
+
const isBootstrap = (await this.getTagNamesForPeer(peerId)).includes(
|
466
|
+
Tags.BOOTSTRAP
|
467
|
+
);
|
468
|
+
|
469
|
+
this.dispatchEvent(
|
470
|
+
new CustomEvent<PeerId>(
|
471
|
+
isBootstrap
|
472
|
+
? EPeersByDiscoveryEvents.PEER_DISCOVERY_BOOTSTRAP
|
473
|
+
: EPeersByDiscoveryEvents.PEER_DISCOVERY_PEER_EXCHANGE,
|
474
|
+
{
|
475
|
+
detail: peerId
|
476
|
+
}
|
477
|
+
)
|
478
|
+
);
|
479
|
+
}
|
480
|
+
|
421
481
|
/**
|
422
482
|
* Fetches the tag names for a given peer
|
423
483
|
*/
|
@@ -430,4 +490,31 @@ export class ConnectionManager
|
|
430
490
|
return [];
|
431
491
|
}
|
432
492
|
}
|
493
|
+
|
494
|
+
private async isPeerTopicConfigured(peerId: PeerId): Promise<boolean> {
|
495
|
+
const shardInfo = await this.getPeerShardInfo(
|
496
|
+
peerId,
|
497
|
+
this.libp2p.peerStore
|
498
|
+
);
|
499
|
+
|
500
|
+
// If there's no shard information, simply return true
|
501
|
+
if (!shardInfo) return true;
|
502
|
+
|
503
|
+
const pubsubTopics = shardInfoToPubSubTopics(shardInfo);
|
504
|
+
|
505
|
+
const isTopicConfigured = pubsubTopics.some((topic) =>
|
506
|
+
this.configuredPubSubTopics.includes(topic)
|
507
|
+
);
|
508
|
+
return isTopicConfigured;
|
509
|
+
}
|
510
|
+
|
511
|
+
private async getPeerShardInfo(
|
512
|
+
peerId: PeerId,
|
513
|
+
peerStore: PeerStore
|
514
|
+
): Promise<ShardInfo | undefined> {
|
515
|
+
const peer = await peerStore.get(peerId);
|
516
|
+
const shardInfoBytes = peer.metadata.get("shardInfo");
|
517
|
+
if (!shardInfoBytes) return undefined;
|
518
|
+
return decodeRelayShard(shardInfoBytes);
|
519
|
+
}
|
433
520
|
}
|
package/src/lib/filter/index.ts
CHANGED
@@ -17,7 +17,11 @@ import type {
|
|
17
17
|
Unsubscribe
|
18
18
|
} from "@waku/interfaces";
|
19
19
|
import { WakuMessage } from "@waku/proto";
|
20
|
-
import {
|
20
|
+
import {
|
21
|
+
ensurePubsubTopicIsConfigured,
|
22
|
+
groupByContentTopic,
|
23
|
+
toAsyncIterator
|
24
|
+
} from "@waku/utils";
|
21
25
|
import debug from "debug";
|
22
26
|
import all from "it-all";
|
23
27
|
import * as lp from "it-length-prefixed";
|
@@ -46,7 +50,7 @@ export const FilterCodecs = {
|
|
46
50
|
|
47
51
|
class Subscription {
|
48
52
|
private readonly peer: Peer;
|
49
|
-
private readonly
|
53
|
+
private readonly pubsubTopic: PubSubTopic;
|
50
54
|
private newStream: (peer: Peer) => Promise<Stream>;
|
51
55
|
|
52
56
|
private subscriptionCallbacks: Map<
|
@@ -55,12 +59,12 @@ class Subscription {
|
|
55
59
|
>;
|
56
60
|
|
57
61
|
constructor(
|
58
|
-
|
62
|
+
pubsubTopic: PubSubTopic,
|
59
63
|
remotePeer: Peer,
|
60
64
|
newStream: (peer: Peer) => Promise<Stream>
|
61
65
|
) {
|
62
66
|
this.peer = remotePeer;
|
63
|
-
this.
|
67
|
+
this.pubsubTopic = pubsubTopic;
|
64
68
|
this.newStream = newStream;
|
65
69
|
this.subscriptionCallbacks = new Map();
|
66
70
|
}
|
@@ -76,7 +80,7 @@ class Subscription {
|
|
76
80
|
const stream = await this.newStream(this.peer);
|
77
81
|
|
78
82
|
const request = FilterSubscribeRpc.createSubscribeRequest(
|
79
|
-
this.
|
83
|
+
this.pubsubTopic,
|
80
84
|
contentTopics
|
81
85
|
);
|
82
86
|
|
@@ -89,6 +93,12 @@ class Subscription {
|
|
89
93
|
async (source) => await all(source)
|
90
94
|
);
|
91
95
|
|
96
|
+
if (!res || !res.length) {
|
97
|
+
throw Error(
|
98
|
+
`No response received for request ${request.requestId}: ${res}`
|
99
|
+
);
|
100
|
+
}
|
101
|
+
|
92
102
|
const { statusCode, requestId, statusDesc } =
|
93
103
|
FilterSubscribeResponse.decode(res[0].slice());
|
94
104
|
|
@@ -135,7 +145,7 @@ class Subscription {
|
|
135
145
|
async unsubscribe(contentTopics: ContentTopic[]): Promise<void> {
|
136
146
|
const stream = await this.newStream(this.peer);
|
137
147
|
const unsubscribeRequest = FilterSubscribeRpc.createUnsubscribeRequest(
|
138
|
-
this.
|
148
|
+
this.pubsubTopic,
|
139
149
|
contentTopics
|
140
150
|
);
|
141
151
|
|
@@ -184,7 +194,7 @@ class Subscription {
|
|
184
194
|
const stream = await this.newStream(this.peer);
|
185
195
|
|
186
196
|
const request = FilterSubscribeRpc.createUnsubscribeAllRequest(
|
187
|
-
this.
|
197
|
+
this.pubsubTopic
|
188
198
|
);
|
189
199
|
|
190
200
|
try {
|
@@ -219,47 +229,50 @@ class Subscription {
|
|
219
229
|
log("No subscription callback available for ", contentTopic);
|
220
230
|
return;
|
221
231
|
}
|
222
|
-
await pushMessage(subscriptionCallback, this.
|
232
|
+
await pushMessage(subscriptionCallback, this.pubsubTopic, message);
|
223
233
|
}
|
224
234
|
}
|
225
235
|
|
226
236
|
class Filter extends BaseProtocol implements IReceiver {
|
227
|
-
private readonly
|
237
|
+
private readonly pubsubTopics: PubSubTopic[] = [];
|
228
238
|
private activeSubscriptions = new Map<string, Subscription>();
|
229
239
|
private readonly NUM_PEERS_PROTOCOL = 1;
|
230
240
|
|
231
241
|
private getActiveSubscription(
|
232
|
-
|
242
|
+
pubsubTopic: PubSubTopic,
|
233
243
|
peerIdStr: PeerIdStr
|
234
244
|
): Subscription | undefined {
|
235
|
-
return this.activeSubscriptions.get(`${
|
245
|
+
return this.activeSubscriptions.get(`${pubsubTopic}_${peerIdStr}`);
|
236
246
|
}
|
237
247
|
|
238
248
|
private setActiveSubscription(
|
239
|
-
|
249
|
+
pubsubTopic: PubSubTopic,
|
240
250
|
peerIdStr: PeerIdStr,
|
241
251
|
subscription: Subscription
|
242
252
|
): Subscription {
|
243
|
-
this.activeSubscriptions.set(`${
|
253
|
+
this.activeSubscriptions.set(`${pubsubTopic}_${peerIdStr}`, subscription);
|
244
254
|
return subscription;
|
245
255
|
}
|
246
256
|
|
247
257
|
constructor(libp2p: Libp2p, options?: ProtocolCreateOptions) {
|
248
258
|
super(FilterCodecs.SUBSCRIBE, libp2p.components);
|
249
259
|
|
260
|
+
this.pubsubTopics = options?.pubsubTopics || [DefaultPubSubTopic];
|
261
|
+
|
250
262
|
libp2p.handle(FilterCodecs.PUSH, this.onRequest.bind(this)).catch((e) => {
|
251
263
|
log("Failed to register ", FilterCodecs.PUSH, e);
|
252
264
|
});
|
253
265
|
|
254
266
|
this.activeSubscriptions = new Map();
|
255
|
-
|
256
|
-
this.options = options ?? {};
|
257
267
|
}
|
258
268
|
|
259
|
-
async createSubscription(
|
260
|
-
|
261
|
-
|
269
|
+
async createSubscription(
|
270
|
+
pubsubTopic: string = DefaultPubSubTopic
|
271
|
+
): Promise<Subscription> {
|
272
|
+
ensurePubsubTopicIsConfigured(pubsubTopic, this.pubsubTopics);
|
262
273
|
|
274
|
+
//TODO: get a relevant peer for the topic/shard
|
275
|
+
// https://github.com/waku-org/js-waku/pull/1586#discussion_r1336428230
|
263
276
|
const peer = (
|
264
277
|
await this.getPeers({
|
265
278
|
maxBootstrapPeers: 1,
|
@@ -268,11 +281,11 @@ class Filter extends BaseProtocol implements IReceiver {
|
|
268
281
|
)[0];
|
269
282
|
|
270
283
|
const subscription =
|
271
|
-
this.getActiveSubscription(
|
284
|
+
this.getActiveSubscription(pubsubTopic, peer.id.toString()) ??
|
272
285
|
this.setActiveSubscription(
|
273
|
-
|
286
|
+
pubsubTopic,
|
274
287
|
peer.id.toString(),
|
275
|
-
new Subscription(
|
288
|
+
new Subscription(pubsubTopic, peer, this.getStream.bind(this, peer))
|
276
289
|
);
|
277
290
|
|
278
291
|
return subscription;
|
@@ -372,7 +385,7 @@ export function wakuFilter(
|
|
372
385
|
|
373
386
|
async function pushMessage<T extends IDecodedMessage>(
|
374
387
|
subscriptionCallback: SubscriptionCallback<T>,
|
375
|
-
|
388
|
+
pubsubTopic: PubSubTopic,
|
376
389
|
message: WakuMessage
|
377
390
|
): Promise<void> {
|
378
391
|
const { decoders, callback } = subscriptionCallback;
|
@@ -386,7 +399,7 @@ async function pushMessage<T extends IDecodedMessage>(
|
|
386
399
|
try {
|
387
400
|
const decodePromises = decoders.map((dec) =>
|
388
401
|
dec
|
389
|
-
.fromProtoObj(
|
402
|
+
.fromProtoObj(pubsubTopic, message as IProtoMessage)
|
390
403
|
.then((decoded) => decoded || Promise.reject("Decoding failed"))
|
391
404
|
);
|
392
405
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import type { PeerId } from "@libp2p/interface/peer-id";
|
2
2
|
import type { PeerStore } from "@libp2p/interface/peer-store";
|
3
|
-
import type { IRelay } from "@waku/interfaces";
|
3
|
+
import type { IRelay, PeerIdStr } from "@waku/interfaces";
|
4
4
|
import type { KeepAliveOptions } from "@waku/interfaces";
|
5
5
|
import { utf8ToBytes } from "@waku/utils/bytes";
|
6
6
|
import debug from "debug";
|
@@ -13,7 +13,7 @@ const log = debug("waku:keep-alive");
|
|
13
13
|
|
14
14
|
export class KeepAliveManager {
|
15
15
|
private pingKeepAliveTimers: Map<string, ReturnType<typeof setInterval>>;
|
16
|
-
private relayKeepAliveTimers: Map<PeerId, ReturnType<typeof setInterval
|
16
|
+
private relayKeepAliveTimers: Map<PeerId, ReturnType<typeof setInterval>[]>;
|
17
17
|
private options: KeepAliveOptions;
|
18
18
|
private relay?: IRelay;
|
19
19
|
|
@@ -37,14 +37,24 @@ export class KeepAliveManager {
|
|
37
37
|
|
38
38
|
const peerIdStr = peerId.toString();
|
39
39
|
|
40
|
+
// Ping the peer every pingPeriodSecs seconds
|
41
|
+
// if pingPeriodSecs is 0, don't ping the peer
|
40
42
|
if (pingPeriodSecs !== 0) {
|
41
43
|
const interval = setInterval(() => {
|
42
44
|
void (async () => {
|
45
|
+
let ping: number;
|
43
46
|
try {
|
44
47
|
// ping the peer for keep alive
|
45
48
|
// also update the peer store with the latency
|
46
|
-
|
47
|
-
|
49
|
+
try {
|
50
|
+
ping = await libp2pPing.ping(peerId);
|
51
|
+
log(`Ping succeeded (${peerIdStr})`, ping);
|
52
|
+
} catch (error) {
|
53
|
+
log(`Ping failed for peer (${peerIdStr}).
|
54
|
+
Next ping will be attempted in ${pingPeriodSecs} seconds.
|
55
|
+
`);
|
56
|
+
return;
|
57
|
+
}
|
48
58
|
|
49
59
|
try {
|
50
60
|
await peerStore.patch(peerId, {
|
@@ -66,17 +76,12 @@ export class KeepAliveManager {
|
|
66
76
|
|
67
77
|
const relay = this.relay;
|
68
78
|
if (relay && relayPeriodSecs !== 0) {
|
69
|
-
const
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
relay
|
76
|
-
.send(encoder, { payload: new Uint8Array([1]) })
|
77
|
-
.catch((e) => log("Failed to send relay ping", e));
|
78
|
-
}, relayPeriodSecs * 1000);
|
79
|
-
this.relayKeepAliveTimers.set(peerId, interval);
|
79
|
+
const intervals = this.scheduleRelayPings(
|
80
|
+
relay,
|
81
|
+
relayPeriodSecs,
|
82
|
+
peerId.toString()
|
83
|
+
);
|
84
|
+
this.relayKeepAliveTimers.set(peerId, intervals);
|
80
85
|
}
|
81
86
|
}
|
82
87
|
|
@@ -89,7 +94,7 @@ export class KeepAliveManager {
|
|
89
94
|
}
|
90
95
|
|
91
96
|
if (this.relayKeepAliveTimers.has(peerId)) {
|
92
|
-
|
97
|
+
this.relayKeepAliveTimers.get(peerId)?.map(clearInterval);
|
93
98
|
this.relayKeepAliveTimers.delete(peerId);
|
94
99
|
}
|
95
100
|
}
|
@@ -105,4 +110,32 @@ export class KeepAliveManager {
|
|
105
110
|
this.pingKeepAliveTimers.clear();
|
106
111
|
this.relayKeepAliveTimers.clear();
|
107
112
|
}
|
113
|
+
|
114
|
+
private scheduleRelayPings(
|
115
|
+
relay: IRelay,
|
116
|
+
relayPeriodSecs: number,
|
117
|
+
peerIdStr: PeerIdStr
|
118
|
+
): NodeJS.Timeout[] {
|
119
|
+
// send a ping message to each PubSubTopic the peer is part of
|
120
|
+
const intervals: NodeJS.Timeout[] = [];
|
121
|
+
for (const topic of relay.pubsubTopics) {
|
122
|
+
const meshPeers = relay.getMeshPeers(topic);
|
123
|
+
if (!meshPeers.includes(peerIdStr)) continue;
|
124
|
+
|
125
|
+
const encoder = createEncoder({
|
126
|
+
pubsubTopic: topic,
|
127
|
+
contentTopic: RelayPingContentTopic,
|
128
|
+
ephemeral: true
|
129
|
+
});
|
130
|
+
const interval = setInterval(() => {
|
131
|
+
log("Sending Waku Relay ping message");
|
132
|
+
relay
|
133
|
+
.send(encoder, { payload: new Uint8Array([1]) })
|
134
|
+
.catch((e) => log("Failed to send relay ping", e));
|
135
|
+
}, relayPeriodSecs * 1000);
|
136
|
+
intervals.push(interval);
|
137
|
+
}
|
138
|
+
|
139
|
+
return intervals;
|
140
|
+
}
|
108
141
|
}
|