@waku/core 0.0.19 → 0.0.20
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 +20 -0
- package/bundle/index.js +173 -73
- package/dist/lib/connection_manager.d.ts +8 -0
- package/dist/lib/connection_manager.js +74 -6
- package/dist/lib/connection_manager.js.map +1 -1
- package/dist/lib/wait_for_remote_peer.d.ts +1 -1
- package/dist/lib/wait_for_remote_peer.js +1 -1
- package/package.json +7 -7
- package/src/lib/connection_manager.ts +96 -8
- package/src/lib/wait_for_remote_peer.ts +1 -1
package/CHANGELOG.md
CHANGED
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The file is maintained by [Release Please](https://github.com/googleapis/release-please) based on [Conventional Commits](https://www.conventionalcommits.org) specification,
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [0.0.20](https://github.com/waku-org/js-waku/compare/core-v0.0.19...core-v0.0.20) (2023-06-08)
|
9
|
+
|
10
|
+
|
11
|
+
### ⚠ BREAKING CHANGES
|
12
|
+
|
13
|
+
* rename package from @waku/create to @waku/sdk ([#1386](https://github.com/waku-org/js-waku/issues/1386))
|
14
|
+
|
15
|
+
### Features
|
16
|
+
|
17
|
+
* Allow passing of multiple ENR URLs to DNS Discovery & dial multiple peers in parallel ([#1379](https://github.com/waku-org/js-waku/issues/1379)) ([f32d7d9](https://github.com/waku-org/js-waku/commit/f32d7d9fe0b930b4fa9c46b8644e6d21be45d5c1))
|
18
|
+
* Rename package from @waku/create to @waku/sdk ([#1386](https://github.com/waku-org/js-waku/issues/1386)) ([951ebda](https://github.com/waku-org/js-waku/commit/951ebdac9d5b594583acf5e4a21f6471fa81ff74))
|
19
|
+
|
20
|
+
|
21
|
+
### Dependencies
|
22
|
+
|
23
|
+
* The following workspace dependencies were updated
|
24
|
+
* dependencies
|
25
|
+
* @waku/interfaces bumped from 0.0.14 to 0.0.15
|
26
|
+
* @waku/utils bumped from 0.0.7 to 0.0.8
|
27
|
+
|
8
28
|
## [0.0.19](https://github.com/waku-org/js-waku/compare/core-v0.0.18...core-v0.0.19) (2023-05-26)
|
9
29
|
|
10
30
|
|
package/bundle/index.js
CHANGED
@@ -3041,6 +3041,7 @@ class KeepAliveManager {
|
|
3041
3041
|
const log$6 = debug("waku:connection-manager");
|
3042
3042
|
const DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED = 1;
|
3043
3043
|
const DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER = 3;
|
3044
|
+
const DEFAULT_MAX_PARALLEL_DIALS = 3;
|
3044
3045
|
class ConnectionManager {
|
3045
3046
|
static instances = new Map();
|
3046
3047
|
keepAliveManager;
|
@@ -3048,6 +3049,8 @@ class ConnectionManager {
|
|
3048
3049
|
libp2pComponents;
|
3049
3050
|
dialAttemptsForPeer = new Map();
|
3050
3051
|
dialErrorsForPeer = new Map();
|
3052
|
+
currentActiveDialCount = 0;
|
3053
|
+
pendingPeerDialQueue = [];
|
3051
3054
|
static create(peerId, libp2p, keepAliveOptions, relay, options) {
|
3052
3055
|
let instance = ConnectionManager.instances.get(peerId);
|
3053
3056
|
if (!instance) {
|
@@ -3061,12 +3064,34 @@ class ConnectionManager {
|
|
3061
3064
|
this.options = {
|
3062
3065
|
maxDialAttemptsForPeer: DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER,
|
3063
3066
|
maxBootstrapPeersAllowed: DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED,
|
3067
|
+
maxParallelDials: DEFAULT_MAX_PARALLEL_DIALS,
|
3064
3068
|
...options,
|
3065
3069
|
};
|
3066
3070
|
this.keepAliveManager = new KeepAliveManager(keepAliveOptions, relay);
|
3067
3071
|
this.run()
|
3068
3072
|
.then(() => log$6(`Connection Manager is now running`))
|
3069
3073
|
.catch((error) => log$6(`Unexpected error while running service`, error));
|
3074
|
+
// libp2p emits `peer:discovery` events during its initialization
|
3075
|
+
// which means that before the ConnectionManager is initialized, some peers may have been discovered
|
3076
|
+
// we will dial the peers in peerStore ONCE before we start to listen to the `peer:discovery` events within the ConnectionManager
|
3077
|
+
this.dialPeerStorePeers();
|
3078
|
+
}
|
3079
|
+
async dialPeerStorePeers() {
|
3080
|
+
const peerInfos = await this.libp2pComponents.peerStore.all();
|
3081
|
+
const dialPromises = [];
|
3082
|
+
for (const peerInfo of peerInfos) {
|
3083
|
+
if (this.libp2pComponents
|
3084
|
+
.getConnections()
|
3085
|
+
.find((c) => c.remotePeer === peerInfo.id))
|
3086
|
+
continue;
|
3087
|
+
dialPromises.push(this.attemptDial(peerInfo.id));
|
3088
|
+
}
|
3089
|
+
try {
|
3090
|
+
await Promise.all(dialPromises);
|
3091
|
+
}
|
3092
|
+
catch (error) {
|
3093
|
+
log$6(`Unexpected error while dialing peer store peers`, error);
|
3094
|
+
}
|
3070
3095
|
}
|
3071
3096
|
async run() {
|
3072
3097
|
// start event listeners
|
@@ -3081,6 +3106,7 @@ class ConnectionManager {
|
|
3081
3106
|
this.libp2pComponents.removeEventListener("peer:discovery", this.onEventHandlers["peer:discovery"]);
|
3082
3107
|
}
|
3083
3108
|
async dialPeer(peerId) {
|
3109
|
+
this.currentActiveDialCount += 1;
|
3084
3110
|
let dialAttempt = 0;
|
3085
3111
|
while (dialAttempt <= this.options.maxDialAttemptsForPeer) {
|
3086
3112
|
try {
|
@@ -3115,6 +3141,30 @@ class ConnectionManager {
|
|
3115
3141
|
catch (error) {
|
3116
3142
|
throw `Error deleting undialable peer ${peerId.toString()} from peer store - ${error}`;
|
3117
3143
|
}
|
3144
|
+
finally {
|
3145
|
+
this.currentActiveDialCount -= 1;
|
3146
|
+
this.processDialQueue();
|
3147
|
+
}
|
3148
|
+
}
|
3149
|
+
async dropConnection(peerId) {
|
3150
|
+
try {
|
3151
|
+
await this.libp2pComponents.hangUp(peerId);
|
3152
|
+
log$6(`Dropped connection with peer ${peerId.toString()}`);
|
3153
|
+
}
|
3154
|
+
catch (error) {
|
3155
|
+
log$6(`Error dropping connection with peer ${peerId.toString()} - ${error}`);
|
3156
|
+
}
|
3157
|
+
}
|
3158
|
+
async processDialQueue() {
|
3159
|
+
if (this.pendingPeerDialQueue.length > 0 &&
|
3160
|
+
this.currentActiveDialCount < this.options.maxParallelDials) {
|
3161
|
+
const peerId = this.pendingPeerDialQueue.shift();
|
3162
|
+
if (!peerId)
|
3163
|
+
return;
|
3164
|
+
this.attemptDial(peerId).catch((error) => {
|
3165
|
+
log$6(error);
|
3166
|
+
});
|
3167
|
+
}
|
3118
3168
|
}
|
3119
3169
|
startPeerDiscoveryListener() {
|
3120
3170
|
this.libp2pComponents.peerStore.addEventListener("peer", this.onEventHandlers["peer:discovery"]);
|
@@ -3137,16 +3187,34 @@ class ConnectionManager {
|
|
3137
3187
|
*/
|
3138
3188
|
this.libp2pComponents.addEventListener("peer:disconnect", this.onEventHandlers["peer:disconnect"]);
|
3139
3189
|
}
|
3190
|
+
async attemptDial(peerId) {
|
3191
|
+
if (this.currentActiveDialCount >= this.options.maxParallelDials) {
|
3192
|
+
this.pendingPeerDialQueue.push(peerId);
|
3193
|
+
return;
|
3194
|
+
}
|
3195
|
+
if (!(await this.shouldDialPeer(peerId)))
|
3196
|
+
return;
|
3197
|
+
this.dialPeer(peerId).catch((err) => {
|
3198
|
+
throw `Error dialing peer ${peerId.toString()} : ${err}`;
|
3199
|
+
});
|
3200
|
+
}
|
3140
3201
|
onEventHandlers = {
|
3141
3202
|
"peer:discovery": async (evt) => {
|
3142
3203
|
const { id: peerId } = evt.detail;
|
3143
|
-
|
3144
|
-
return;
|
3145
|
-
this.dialPeer(peerId).catch((err) => log$6(`Error dialing peer ${peerId.toString()} : ${err}`));
|
3204
|
+
this.attemptDial(peerId).catch((err) => log$6(`Error dialing peer ${peerId.toString()} : ${err}`));
|
3146
3205
|
},
|
3147
|
-
"peer:connect": (evt) => {
|
3148
|
-
{
|
3149
|
-
|
3206
|
+
"peer:connect": async (evt) => {
|
3207
|
+
const { remotePeer: peerId } = evt.detail;
|
3208
|
+
this.keepAliveManager.start(peerId, this.libp2pComponents.ping.bind(this));
|
3209
|
+
const isBootstrap = (await this.getTagNamesForPeer(peerId)).includes(Tags.BOOTSTRAP);
|
3210
|
+
if (isBootstrap) {
|
3211
|
+
const bootstrapConnections = this.libp2pComponents
|
3212
|
+
.getConnections()
|
3213
|
+
.filter((conn) => conn.tags.includes(Tags.BOOTSTRAP));
|
3214
|
+
// If we have too many bootstrap connections, drop one
|
3215
|
+
if (bootstrapConnections.length > this.options.maxBootstrapPeersAllowed) {
|
3216
|
+
await this.dropConnection(peerId);
|
3217
|
+
}
|
3150
3218
|
}
|
3151
3219
|
},
|
3152
3220
|
"peer:disconnect": () => {
|
@@ -3397,11 +3465,11 @@ const isSizeValid = (payload) => {
|
|
3397
3465
|
return true;
|
3398
3466
|
};
|
3399
3467
|
|
3400
|
-
function isAsyncIterable$
|
3468
|
+
function isAsyncIterable$3(thing) {
|
3401
3469
|
return thing[Symbol.asyncIterator] != null;
|
3402
3470
|
}
|
3403
3471
|
function all(source) {
|
3404
|
-
if (isAsyncIterable$
|
3472
|
+
if (isAsyncIterable$3(source)) {
|
3405
3473
|
return (async () => {
|
3406
3474
|
const arr = [];
|
3407
3475
|
for await (const entry of source) {
|
@@ -4158,7 +4226,7 @@ const unsigned = {
|
|
4158
4226
|
}
|
4159
4227
|
};
|
4160
4228
|
|
4161
|
-
function isAsyncIterable(thing) {
|
4229
|
+
function isAsyncIterable$2(thing) {
|
4162
4230
|
return thing[Symbol.asyncIterator] != null;
|
4163
4231
|
}
|
4164
4232
|
|
@@ -4191,7 +4259,7 @@ function encode(source, options) {
|
|
4191
4259
|
yield* chunk;
|
4192
4260
|
}
|
4193
4261
|
}
|
4194
|
-
if (isAsyncIterable(source)) {
|
4262
|
+
if (isAsyncIterable$2(source)) {
|
4195
4263
|
return (async function* () {
|
4196
4264
|
for await (const chunk of source) {
|
4197
4265
|
yield* maybeYield(chunk);
|
@@ -4347,7 +4415,7 @@ function decode(source, options) {
|
|
4347
4415
|
}
|
4348
4416
|
}
|
4349
4417
|
}
|
4350
|
-
if (isAsyncIterable(source)) {
|
4418
|
+
if (isAsyncIterable$2(source)) {
|
4351
4419
|
return (async function* () {
|
4352
4420
|
for await (const buf of source) {
|
4353
4421
|
buffer.append(buf);
|
@@ -4662,77 +4730,56 @@ function _pushable(getNext, options) {
|
|
4662
4730
|
return pushable;
|
4663
4731
|
}
|
4664
4732
|
|
4665
|
-
|
4666
|
-
|
4667
|
-
|
4668
|
-
|
4669
|
-
|
4670
|
-
|
4671
|
-
|
4672
|
-
|
4673
|
-
objectMode: true
|
4674
|
-
});
|
4675
|
-
void Promise.resolve().then(async () => {
|
4676
|
-
try {
|
4677
|
-
await Promise.all(sources.map(async (source) => {
|
4678
|
-
for await (const item of source) {
|
4679
|
-
output.push(item);
|
4680
|
-
}
|
4681
|
-
}));
|
4682
|
-
output.end();
|
4683
|
-
}
|
4684
|
-
catch (err) {
|
4685
|
-
output.end(err);
|
4733
|
+
function isAsyncIterable$1(thing) {
|
4734
|
+
return thing[Symbol.asyncIterator] != null;
|
4735
|
+
}
|
4736
|
+
function merge(...sources) {
|
4737
|
+
const syncSources = [];
|
4738
|
+
for (const source of sources) {
|
4739
|
+
if (!isAsyncIterable$1(source)) {
|
4740
|
+
syncSources.push(source);
|
4686
4741
|
}
|
4687
|
-
}
|
4688
|
-
|
4742
|
+
}
|
4743
|
+
if (syncSources.length === sources.length) {
|
4744
|
+
// all sources are synchronous
|
4745
|
+
return (function* () {
|
4746
|
+
for (const source of syncSources) {
|
4747
|
+
yield* source;
|
4748
|
+
}
|
4749
|
+
})();
|
4750
|
+
}
|
4751
|
+
return (async function* () {
|
4752
|
+
const output = pushable({
|
4753
|
+
objectMode: true
|
4754
|
+
});
|
4755
|
+
void Promise.resolve().then(async () => {
|
4756
|
+
try {
|
4757
|
+
await Promise.all(sources.map(async (source) => {
|
4758
|
+
for await (const item of source) {
|
4759
|
+
output.push(item);
|
4760
|
+
}
|
4761
|
+
}));
|
4762
|
+
output.end();
|
4763
|
+
}
|
4764
|
+
catch (err) {
|
4765
|
+
output.end(err);
|
4766
|
+
}
|
4767
|
+
});
|
4768
|
+
yield* output;
|
4769
|
+
})();
|
4689
4770
|
}
|
4690
4771
|
|
4691
|
-
const rawPipe = (...fns) => {
|
4692
|
-
let res;
|
4693
|
-
while (fns.length > 0) {
|
4694
|
-
res = fns.shift()(res);
|
4695
|
-
}
|
4696
|
-
return res;
|
4697
|
-
};
|
4698
|
-
const isIterable = (obj) => {
|
4699
|
-
return obj != null && (typeof obj[Symbol.asyncIterator] === 'function' ||
|
4700
|
-
typeof obj[Symbol.iterator] === 'function' ||
|
4701
|
-
typeof obj.next === 'function' // Probably, right?
|
4702
|
-
);
|
4703
|
-
};
|
4704
|
-
const isDuplex = (obj) => {
|
4705
|
-
return obj != null && typeof obj.sink === 'function' && isIterable(obj.source);
|
4706
|
-
};
|
4707
|
-
const duplexPipelineFn = (duplex) => {
|
4708
|
-
return (source) => {
|
4709
|
-
const p = duplex.sink(source);
|
4710
|
-
if (p.then != null) {
|
4711
|
-
const stream = pushable({
|
4712
|
-
objectMode: true
|
4713
|
-
});
|
4714
|
-
p.then(() => {
|
4715
|
-
stream.end();
|
4716
|
-
}, (err) => {
|
4717
|
-
stream.end(err);
|
4718
|
-
});
|
4719
|
-
const sourceWrap = async function* () {
|
4720
|
-
yield* duplex.source;
|
4721
|
-
stream.end();
|
4722
|
-
};
|
4723
|
-
return merge(stream, sourceWrap());
|
4724
|
-
}
|
4725
|
-
return duplex.source;
|
4726
|
-
};
|
4727
|
-
};
|
4728
4772
|
function pipe(first, ...rest) {
|
4773
|
+
if (first == null) {
|
4774
|
+
throw new Error('Empty pipeline');
|
4775
|
+
}
|
4729
4776
|
// Duplex at start: wrap in function and return duplex source
|
4730
4777
|
if (isDuplex(first)) {
|
4731
4778
|
const duplex = first;
|
4732
4779
|
first = () => duplex.source;
|
4733
4780
|
// Iterable at start: wrap in function
|
4734
4781
|
}
|
4735
|
-
else if (isIterable(first)) {
|
4782
|
+
else if (isIterable(first) || isAsyncIterable(first)) {
|
4736
4783
|
const source = first;
|
4737
4784
|
first = () => source;
|
4738
4785
|
}
|
@@ -4753,6 +4800,59 @@ function pipe(first, ...rest) {
|
|
4753
4800
|
}
|
4754
4801
|
return rawPipe(...fns);
|
4755
4802
|
}
|
4803
|
+
const rawPipe = (...fns) => {
|
4804
|
+
let res;
|
4805
|
+
while (fns.length > 0) {
|
4806
|
+
res = fns.shift()(res);
|
4807
|
+
}
|
4808
|
+
return res;
|
4809
|
+
};
|
4810
|
+
const isAsyncIterable = (obj) => {
|
4811
|
+
return obj?.[Symbol.asyncIterator] != null;
|
4812
|
+
};
|
4813
|
+
const isIterable = (obj) => {
|
4814
|
+
return obj?.[Symbol.iterator] != null;
|
4815
|
+
};
|
4816
|
+
const isDuplex = (obj) => {
|
4817
|
+
if (obj == null) {
|
4818
|
+
return false;
|
4819
|
+
}
|
4820
|
+
return obj.sink != null && obj.source != null;
|
4821
|
+
};
|
4822
|
+
const duplexPipelineFn = (duplex) => {
|
4823
|
+
return (source) => {
|
4824
|
+
const p = duplex.sink(source);
|
4825
|
+
if (p?.then != null) {
|
4826
|
+
const stream = pushable({
|
4827
|
+
objectMode: true
|
4828
|
+
});
|
4829
|
+
p.then(() => {
|
4830
|
+
stream.end();
|
4831
|
+
}, (err) => {
|
4832
|
+
stream.end(err);
|
4833
|
+
});
|
4834
|
+
let sourceWrap;
|
4835
|
+
const source = duplex.source;
|
4836
|
+
if (isAsyncIterable(source)) {
|
4837
|
+
sourceWrap = async function* () {
|
4838
|
+
yield* source;
|
4839
|
+
stream.end();
|
4840
|
+
};
|
4841
|
+
}
|
4842
|
+
else if (isIterable(source)) {
|
4843
|
+
sourceWrap = function* () {
|
4844
|
+
yield* source;
|
4845
|
+
stream.end();
|
4846
|
+
};
|
4847
|
+
}
|
4848
|
+
else {
|
4849
|
+
throw new Error('Unknown duplex source type - must be Iterable or AsyncIterable');
|
4850
|
+
}
|
4851
|
+
return merge(stream, sourceWrap());
|
4852
|
+
}
|
4853
|
+
return duplex.source;
|
4854
|
+
};
|
4855
|
+
};
|
4756
4856
|
|
4757
4857
|
const EmptyMessage = {
|
4758
4858
|
payload: new Uint8Array(),
|
@@ -6313,7 +6413,7 @@ const log = debug("waku:wait-for-remote-peer");
|
|
6313
6413
|
* Wait for a remote peer to be ready given the passed protocols.
|
6314
6414
|
* Must be used after attempting to connect to nodes, using
|
6315
6415
|
* {@link @waku/core.WakuNode.dial} or a bootstrap method with
|
6316
|
-
* {@link @waku/
|
6416
|
+
* {@link @waku/sdk.createLightNode}.
|
6317
6417
|
*
|
6318
6418
|
* If the passed protocols is a GossipSub protocol, then it resolves only once
|
6319
6419
|
* a peer is in a mesh, to help ensure that other peers will send and receive
|
@@ -1,8 +1,10 @@
|
|
1
1
|
import type { Libp2p } from "@libp2p/interface-libp2p";
|
2
|
+
import type { PeerId } from "@libp2p/interface-peer-id";
|
2
3
|
import type { ConnectionManagerOptions, IRelay } from "@waku/interfaces";
|
3
4
|
import { KeepAliveOptions } from "./keep_alive_manager.js";
|
4
5
|
export declare const DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED = 1;
|
5
6
|
export declare const DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER = 3;
|
7
|
+
export declare const DEFAULT_MAX_PARALLEL_DIALS = 3;
|
6
8
|
export declare class ConnectionManager {
|
7
9
|
private static instances;
|
8
10
|
private keepAliveManager;
|
@@ -10,14 +12,20 @@ export declare class ConnectionManager {
|
|
10
12
|
private libp2pComponents;
|
11
13
|
private dialAttemptsForPeer;
|
12
14
|
private dialErrorsForPeer;
|
15
|
+
private currentActiveDialCount;
|
16
|
+
private pendingPeerDialQueue;
|
13
17
|
static create(peerId: string, libp2p: Libp2p, keepAliveOptions: KeepAliveOptions, relay?: IRelay, options?: ConnectionManagerOptions): ConnectionManager;
|
14
18
|
private constructor();
|
19
|
+
private dialPeerStorePeers;
|
15
20
|
private run;
|
16
21
|
stop(): void;
|
17
22
|
private dialPeer;
|
23
|
+
dropConnection(peerId: PeerId): Promise<void>;
|
24
|
+
private processDialQueue;
|
18
25
|
private startPeerDiscoveryListener;
|
19
26
|
private startPeerConnectionListener;
|
20
27
|
private startPeerDisconnectionListener;
|
28
|
+
private attemptDial;
|
21
29
|
private onEventHandlers;
|
22
30
|
/**
|
23
31
|
* Checks if the peer is dialable based on the following conditions:
|
@@ -4,6 +4,7 @@ import { KeepAliveManager } from "./keep_alive_manager.js";
|
|
4
4
|
const log = debug("waku:connection-manager");
|
5
5
|
export const DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED = 1;
|
6
6
|
export const DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER = 3;
|
7
|
+
export const DEFAULT_MAX_PARALLEL_DIALS = 3;
|
7
8
|
class ConnectionManager {
|
8
9
|
static instances = new Map();
|
9
10
|
keepAliveManager;
|
@@ -11,6 +12,8 @@ class ConnectionManager {
|
|
11
12
|
libp2pComponents;
|
12
13
|
dialAttemptsForPeer = new Map();
|
13
14
|
dialErrorsForPeer = new Map();
|
15
|
+
currentActiveDialCount = 0;
|
16
|
+
pendingPeerDialQueue = [];
|
14
17
|
static create(peerId, libp2p, keepAliveOptions, relay, options) {
|
15
18
|
let instance = ConnectionManager.instances.get(peerId);
|
16
19
|
if (!instance) {
|
@@ -24,12 +27,34 @@ class ConnectionManager {
|
|
24
27
|
this.options = {
|
25
28
|
maxDialAttemptsForPeer: DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER,
|
26
29
|
maxBootstrapPeersAllowed: DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED,
|
30
|
+
maxParallelDials: DEFAULT_MAX_PARALLEL_DIALS,
|
27
31
|
...options,
|
28
32
|
};
|
29
33
|
this.keepAliveManager = new KeepAliveManager(keepAliveOptions, relay);
|
30
34
|
this.run()
|
31
35
|
.then(() => log(`Connection Manager is now running`))
|
32
36
|
.catch((error) => log(`Unexpected error while running service`, error));
|
37
|
+
// libp2p emits `peer:discovery` events during its initialization
|
38
|
+
// which means that before the ConnectionManager is initialized, some peers may have been discovered
|
39
|
+
// we will dial the peers in peerStore ONCE before we start to listen to the `peer:discovery` events within the ConnectionManager
|
40
|
+
this.dialPeerStorePeers();
|
41
|
+
}
|
42
|
+
async dialPeerStorePeers() {
|
43
|
+
const peerInfos = await this.libp2pComponents.peerStore.all();
|
44
|
+
const dialPromises = [];
|
45
|
+
for (const peerInfo of peerInfos) {
|
46
|
+
if (this.libp2pComponents
|
47
|
+
.getConnections()
|
48
|
+
.find((c) => c.remotePeer === peerInfo.id))
|
49
|
+
continue;
|
50
|
+
dialPromises.push(this.attemptDial(peerInfo.id));
|
51
|
+
}
|
52
|
+
try {
|
53
|
+
await Promise.all(dialPromises);
|
54
|
+
}
|
55
|
+
catch (error) {
|
56
|
+
log(`Unexpected error while dialing peer store peers`, error);
|
57
|
+
}
|
33
58
|
}
|
34
59
|
async run() {
|
35
60
|
// start event listeners
|
@@ -44,6 +69,7 @@ class ConnectionManager {
|
|
44
69
|
this.libp2pComponents.removeEventListener("peer:discovery", this.onEventHandlers["peer:discovery"]);
|
45
70
|
}
|
46
71
|
async dialPeer(peerId) {
|
72
|
+
this.currentActiveDialCount += 1;
|
47
73
|
let dialAttempt = 0;
|
48
74
|
while (dialAttempt <= this.options.maxDialAttemptsForPeer) {
|
49
75
|
try {
|
@@ -78,6 +104,30 @@ class ConnectionManager {
|
|
78
104
|
catch (error) {
|
79
105
|
throw `Error deleting undialable peer ${peerId.toString()} from peer store - ${error}`;
|
80
106
|
}
|
107
|
+
finally {
|
108
|
+
this.currentActiveDialCount -= 1;
|
109
|
+
this.processDialQueue();
|
110
|
+
}
|
111
|
+
}
|
112
|
+
async dropConnection(peerId) {
|
113
|
+
try {
|
114
|
+
await this.libp2pComponents.hangUp(peerId);
|
115
|
+
log(`Dropped connection with peer ${peerId.toString()}`);
|
116
|
+
}
|
117
|
+
catch (error) {
|
118
|
+
log(`Error dropping connection with peer ${peerId.toString()} - ${error}`);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
async processDialQueue() {
|
122
|
+
if (this.pendingPeerDialQueue.length > 0 &&
|
123
|
+
this.currentActiveDialCount < this.options.maxParallelDials) {
|
124
|
+
const peerId = this.pendingPeerDialQueue.shift();
|
125
|
+
if (!peerId)
|
126
|
+
return;
|
127
|
+
this.attemptDial(peerId).catch((error) => {
|
128
|
+
log(error);
|
129
|
+
});
|
130
|
+
}
|
81
131
|
}
|
82
132
|
startPeerDiscoveryListener() {
|
83
133
|
this.libp2pComponents.peerStore.addEventListener("peer", this.onEventHandlers["peer:discovery"]);
|
@@ -100,16 +150,34 @@ class ConnectionManager {
|
|
100
150
|
*/
|
101
151
|
this.libp2pComponents.addEventListener("peer:disconnect", this.onEventHandlers["peer:disconnect"]);
|
102
152
|
}
|
153
|
+
async attemptDial(peerId) {
|
154
|
+
if (this.currentActiveDialCount >= this.options.maxParallelDials) {
|
155
|
+
this.pendingPeerDialQueue.push(peerId);
|
156
|
+
return;
|
157
|
+
}
|
158
|
+
if (!(await this.shouldDialPeer(peerId)))
|
159
|
+
return;
|
160
|
+
this.dialPeer(peerId).catch((err) => {
|
161
|
+
throw `Error dialing peer ${peerId.toString()} : ${err}`;
|
162
|
+
});
|
163
|
+
}
|
103
164
|
onEventHandlers = {
|
104
165
|
"peer:discovery": async (evt) => {
|
105
166
|
const { id: peerId } = evt.detail;
|
106
|
-
|
107
|
-
return;
|
108
|
-
this.dialPeer(peerId).catch((err) => log(`Error dialing peer ${peerId.toString()} : ${err}`));
|
167
|
+
this.attemptDial(peerId).catch((err) => log(`Error dialing peer ${peerId.toString()} : ${err}`));
|
109
168
|
},
|
110
|
-
"peer:connect": (evt) => {
|
111
|
-
{
|
112
|
-
|
169
|
+
"peer:connect": async (evt) => {
|
170
|
+
const { remotePeer: peerId } = evt.detail;
|
171
|
+
this.keepAliveManager.start(peerId, this.libp2pComponents.ping.bind(this));
|
172
|
+
const isBootstrap = (await this.getTagNamesForPeer(peerId)).includes(Tags.BOOTSTRAP);
|
173
|
+
if (isBootstrap) {
|
174
|
+
const bootstrapConnections = this.libp2pComponents
|
175
|
+
.getConnections()
|
176
|
+
.filter((conn) => conn.tags.includes(Tags.BOOTSTRAP));
|
177
|
+
// If we have too many bootstrap connections, drop one
|
178
|
+
if (bootstrapConnections.length > this.options.maxBootstrapPeersAllowed) {
|
179
|
+
await this.dropConnection(peerId);
|
180
|
+
}
|
113
181
|
}
|
114
182
|
},
|
115
183
|
"peer:disconnect": () => {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"connection_manager.js","sourceRoot":"","sources":["../../src/lib/connection_manager.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAoB,MAAM,yBAAyB,CAAC;AAE7E,MAAM,GAAG,GAAG,KAAK,CAAC,yBAAyB,CAAC,CAAC;AAE7C,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,CAAC;AACrD,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAC,CAAC;
|
1
|
+
{"version":3,"file":"connection_manager.js","sourceRoot":"","sources":["../../src/lib/connection_manager.ts"],"names":[],"mappings":"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"}
|
@@ -4,7 +4,7 @@ import { Protocols } from "@waku/interfaces";
|
|
4
4
|
* Wait for a remote peer to be ready given the passed protocols.
|
5
5
|
* Must be used after attempting to connect to nodes, using
|
6
6
|
* {@link @waku/core.WakuNode.dial} or a bootstrap method with
|
7
|
-
* {@link @waku/
|
7
|
+
* {@link @waku/sdk.createLightNode}.
|
8
8
|
*
|
9
9
|
* If the passed protocols is a GossipSub protocol, then it resolves only once
|
10
10
|
* a peer is in a mesh, to help ensure that other peers will send and receive
|
@@ -6,7 +6,7 @@ const log = debug("waku:wait-for-remote-peer");
|
|
6
6
|
* Wait for a remote peer to be ready given the passed protocols.
|
7
7
|
* Must be used after attempting to connect to nodes, using
|
8
8
|
* {@link @waku/core.WakuNode.dial} or a bootstrap method with
|
9
|
-
* {@link @waku/
|
9
|
+
* {@link @waku/sdk.createLightNode}.
|
10
10
|
*
|
11
11
|
* If the passed protocols is a GossipSub protocol, then it resolves only once
|
12
12
|
* a peer is in a mesh, to help ensure that other peers will send and receive
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@waku/core",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.20",
|
4
4
|
"description": "TypeScript implementation of the Waku v2 protocol",
|
5
5
|
"types": "./dist/index.d.ts",
|
6
6
|
"module": "./dist/index.js",
|
@@ -73,13 +73,13 @@
|
|
73
73
|
},
|
74
74
|
"dependencies": {
|
75
75
|
"@noble/hashes": "^1.3.0",
|
76
|
-
"@waku/interfaces": "0.0.
|
76
|
+
"@waku/interfaces": "0.0.15",
|
77
77
|
"@waku/proto": "0.0.5",
|
78
|
-
"@waku/utils": "0.0.
|
78
|
+
"@waku/utils": "0.0.8",
|
79
79
|
"debug": "^4.3.4",
|
80
|
-
"it-all": "^3.0.
|
80
|
+
"it-all": "^3.0.2",
|
81
81
|
"it-length-prefixed": "^9.0.1",
|
82
|
-
"it-pipe": "^
|
82
|
+
"it-pipe": "^3.0.1",
|
83
83
|
"p-event": "^5.0.1",
|
84
84
|
"uint8arraylist": "^2.4.3",
|
85
85
|
"uuid": "^9.0.0"
|
@@ -99,11 +99,11 @@
|
|
99
99
|
"@types/mocha": "^10.0.1",
|
100
100
|
"@types/uuid": "^9.0.1",
|
101
101
|
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
102
|
-
"@typescript-eslint/parser": "^5.
|
102
|
+
"@typescript-eslint/parser": "^5.59.8",
|
103
103
|
"@waku/build-utils": "*",
|
104
104
|
"chai": "^4.3.7",
|
105
105
|
"cspell": "^6.31.1",
|
106
|
-
"eslint": "^8.
|
106
|
+
"eslint": "^8.41.0",
|
107
107
|
"eslint-config-prettier": "^8.6.0",
|
108
108
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
109
109
|
"eslint-plugin-functional": "^5.0.4",
|
@@ -12,6 +12,7 @@ const log = debug("waku:connection-manager");
|
|
12
12
|
|
13
13
|
export const DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED = 1;
|
14
14
|
export const DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER = 3;
|
15
|
+
export const DEFAULT_MAX_PARALLEL_DIALS = 3;
|
15
16
|
|
16
17
|
export class ConnectionManager {
|
17
18
|
private static instances = new Map<string, ConnectionManager>();
|
@@ -21,6 +22,9 @@ export class ConnectionManager {
|
|
21
22
|
private dialAttemptsForPeer: Map<string, number> = new Map();
|
22
23
|
private dialErrorsForPeer: Map<string, any> = new Map();
|
23
24
|
|
25
|
+
private currentActiveDialCount = 0;
|
26
|
+
private pendingPeerDialQueue: Array<PeerId> = [];
|
27
|
+
|
24
28
|
public static create(
|
25
29
|
peerId: string,
|
26
30
|
libp2p: Libp2p,
|
@@ -52,6 +56,7 @@ export class ConnectionManager {
|
|
52
56
|
this.options = {
|
53
57
|
maxDialAttemptsForPeer: DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER,
|
54
58
|
maxBootstrapPeersAllowed: DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED,
|
59
|
+
maxParallelDials: DEFAULT_MAX_PARALLEL_DIALS,
|
55
60
|
...options,
|
56
61
|
};
|
57
62
|
|
@@ -60,6 +65,31 @@ export class ConnectionManager {
|
|
60
65
|
this.run()
|
61
66
|
.then(() => log(`Connection Manager is now running`))
|
62
67
|
.catch((error) => log(`Unexpected error while running service`, error));
|
68
|
+
|
69
|
+
// libp2p emits `peer:discovery` events during its initialization
|
70
|
+
// which means that before the ConnectionManager is initialized, some peers may have been discovered
|
71
|
+
// we will dial the peers in peerStore ONCE before we start to listen to the `peer:discovery` events within the ConnectionManager
|
72
|
+
this.dialPeerStorePeers();
|
73
|
+
}
|
74
|
+
|
75
|
+
private async dialPeerStorePeers(): Promise<void> {
|
76
|
+
const peerInfos = await this.libp2pComponents.peerStore.all();
|
77
|
+
const dialPromises = [];
|
78
|
+
for (const peerInfo of peerInfos) {
|
79
|
+
if (
|
80
|
+
this.libp2pComponents
|
81
|
+
.getConnections()
|
82
|
+
.find((c) => c.remotePeer === peerInfo.id)
|
83
|
+
)
|
84
|
+
continue;
|
85
|
+
|
86
|
+
dialPromises.push(this.attemptDial(peerInfo.id));
|
87
|
+
}
|
88
|
+
try {
|
89
|
+
await Promise.all(dialPromises);
|
90
|
+
} catch (error) {
|
91
|
+
log(`Unexpected error while dialing peer store peers`, error);
|
92
|
+
}
|
63
93
|
}
|
64
94
|
|
65
95
|
private async run(): Promise<void> {
|
@@ -86,6 +116,7 @@ export class ConnectionManager {
|
|
86
116
|
}
|
87
117
|
|
88
118
|
private async dialPeer(peerId: PeerId): Promise<void> {
|
119
|
+
this.currentActiveDialCount += 1;
|
89
120
|
let dialAttempt = 0;
|
90
121
|
while (dialAttempt <= this.options.maxDialAttemptsForPeer) {
|
91
122
|
try {
|
@@ -105,6 +136,7 @@ export class ConnectionManager {
|
|
105
136
|
return;
|
106
137
|
} catch (e) {
|
107
138
|
const error = e as AggregateError;
|
139
|
+
|
108
140
|
this.dialErrorsForPeer.set(peerId.toString(), error);
|
109
141
|
log(`Error dialing peer ${peerId.toString()} - ${error.errors}`);
|
110
142
|
|
@@ -128,6 +160,33 @@ export class ConnectionManager {
|
|
128
160
|
return await this.libp2pComponents.peerStore.delete(peerId);
|
129
161
|
} catch (error) {
|
130
162
|
throw `Error deleting undialable peer ${peerId.toString()} from peer store - ${error}`;
|
163
|
+
} finally {
|
164
|
+
this.currentActiveDialCount -= 1;
|
165
|
+
this.processDialQueue();
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
async dropConnection(peerId: PeerId): Promise<void> {
|
170
|
+
try {
|
171
|
+
await this.libp2pComponents.hangUp(peerId);
|
172
|
+
log(`Dropped connection with peer ${peerId.toString()}`);
|
173
|
+
} catch (error) {
|
174
|
+
log(
|
175
|
+
`Error dropping connection with peer ${peerId.toString()} - ${error}`
|
176
|
+
);
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
private async processDialQueue(): Promise<void> {
|
181
|
+
if (
|
182
|
+
this.pendingPeerDialQueue.length > 0 &&
|
183
|
+
this.currentActiveDialCount < this.options.maxParallelDials
|
184
|
+
) {
|
185
|
+
const peerId = this.pendingPeerDialQueue.shift();
|
186
|
+
if (!peerId) return;
|
187
|
+
this.attemptDial(peerId).catch((error) => {
|
188
|
+
log(error);
|
189
|
+
});
|
131
190
|
}
|
132
191
|
}
|
133
192
|
|
@@ -164,21 +223,50 @@ export class ConnectionManager {
|
|
164
223
|
);
|
165
224
|
}
|
166
225
|
|
226
|
+
private async attemptDial(peerId: PeerId): Promise<void> {
|
227
|
+
if (this.currentActiveDialCount >= this.options.maxParallelDials) {
|
228
|
+
this.pendingPeerDialQueue.push(peerId);
|
229
|
+
return;
|
230
|
+
}
|
231
|
+
|
232
|
+
if (!(await this.shouldDialPeer(peerId))) return;
|
233
|
+
|
234
|
+
this.dialPeer(peerId).catch((err) => {
|
235
|
+
throw `Error dialing peer ${peerId.toString()} : ${err}`;
|
236
|
+
});
|
237
|
+
}
|
238
|
+
|
167
239
|
private onEventHandlers = {
|
168
240
|
"peer:discovery": async (evt: CustomEvent<PeerInfo>): Promise<void> => {
|
169
241
|
const { id: peerId } = evt.detail;
|
170
|
-
if (!(await this.shouldDialPeer(peerId))) return;
|
171
242
|
|
172
|
-
this.
|
243
|
+
this.attemptDial(peerId).catch((err) =>
|
173
244
|
log(`Error dialing peer ${peerId.toString()} : ${err}`)
|
174
245
|
);
|
175
246
|
},
|
176
|
-
"peer:connect": (evt: CustomEvent<Connection>): void => {
|
177
|
-
{
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
)
|
247
|
+
"peer:connect": async (evt: CustomEvent<Connection>): Promise<void> => {
|
248
|
+
const { remotePeer: peerId } = evt.detail;
|
249
|
+
|
250
|
+
this.keepAliveManager.start(
|
251
|
+
peerId,
|
252
|
+
this.libp2pComponents.ping.bind(this)
|
253
|
+
);
|
254
|
+
|
255
|
+
const isBootstrap = (await this.getTagNamesForPeer(peerId)).includes(
|
256
|
+
Tags.BOOTSTRAP
|
257
|
+
);
|
258
|
+
|
259
|
+
if (isBootstrap) {
|
260
|
+
const bootstrapConnections = this.libp2pComponents
|
261
|
+
.getConnections()
|
262
|
+
.filter((conn) => conn.tags.includes(Tags.BOOTSTRAP));
|
263
|
+
|
264
|
+
// If we have too many bootstrap connections, drop one
|
265
|
+
if (
|
266
|
+
bootstrapConnections.length > this.options.maxBootstrapPeersAllowed
|
267
|
+
) {
|
268
|
+
await this.dropConnection(peerId);
|
269
|
+
}
|
182
270
|
}
|
183
271
|
},
|
184
272
|
"peer:disconnect": () => {
|
@@ -10,7 +10,7 @@ const log = debug("waku:wait-for-remote-peer");
|
|
10
10
|
* Wait for a remote peer to be ready given the passed protocols.
|
11
11
|
* Must be used after attempting to connect to nodes, using
|
12
12
|
* {@link @waku/core.WakuNode.dial} or a bootstrap method with
|
13
|
-
* {@link @waku/
|
13
|
+
* {@link @waku/sdk.createLightNode}.
|
14
14
|
*
|
15
15
|
* If the passed protocols is a GossipSub protocol, then it resolves only once
|
16
16
|
* a peer is in a mesh, to help ensure that other peers will send and receive
|