@waku/core 0.0.37-7a9850d.0 → 0.0.37-c24842a.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/index.js +4852 -904
- package/bundle/lib/message/version_0.js +1 -1
- package/bundle/{version_0-9DPFjcJG.js → version_0-BHaZD8Qu.js} +485 -60
- package/dist/.tsbuildinfo +1 -1
- package/dist/lib/connection_manager/connection_limiter.d.ts +46 -0
- package/dist/lib/connection_manager/connection_limiter.js +177 -0
- package/dist/lib/connection_manager/connection_limiter.js.map +1 -0
- package/dist/lib/connection_manager/connection_manager.d.ts +18 -106
- package/dist/lib/connection_manager/connection_manager.js +95 -512
- package/dist/lib/connection_manager/connection_manager.js.map +1 -1
- package/dist/lib/connection_manager/dialer.d.ts +34 -0
- package/dist/lib/connection_manager/dialer.js +135 -0
- package/dist/lib/connection_manager/dialer.js.map +1 -0
- package/dist/lib/connection_manager/discovery_dialer.d.ts +26 -0
- package/dist/lib/connection_manager/discovery_dialer.js +68 -0
- package/dist/lib/connection_manager/discovery_dialer.js.map +1 -0
- package/dist/lib/connection_manager/keep_alive_manager.d.ts +17 -7
- package/dist/lib/connection_manager/keep_alive_manager.js +110 -74
- package/dist/lib/connection_manager/keep_alive_manager.js.map +1 -1
- package/dist/lib/connection_manager/network_monitor.d.ts +36 -0
- package/dist/lib/connection_manager/network_monitor.js +81 -0
- package/dist/lib/connection_manager/network_monitor.js.map +1 -0
- package/dist/lib/connection_manager/shard_reader.d.ts +28 -0
- package/dist/lib/connection_manager/shard_reader.js +70 -0
- package/dist/lib/connection_manager/shard_reader.js.map +1 -0
- package/dist/lib/connection_manager/utils.d.ts +16 -1
- package/dist/lib/connection_manager/utils.js +23 -0
- package/dist/lib/connection_manager/utils.js.map +1 -1
- package/dist/lib/filter/filter.d.ts +2 -3
- package/dist/lib/filter/filter.js +5 -25
- package/dist/lib/filter/filter.js.map +1 -1
- package/dist/lib/light_push/light_push.d.ts +2 -3
- package/dist/lib/light_push/light_push.js +1 -3
- package/dist/lib/light_push/light_push.js.map +1 -1
- package/dist/lib/metadata/metadata.d.ts +2 -2
- package/dist/lib/metadata/metadata.js +14 -8
- package/dist/lib/metadata/metadata.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/connection_manager/connection_limiter.ts +292 -0
- package/src/lib/connection_manager/connection_manager.ts +112 -673
- package/src/lib/connection_manager/dialer.ts +192 -0
- package/src/lib/connection_manager/discovery_dialer.ts +104 -0
- package/src/lib/connection_manager/keep_alive_manager.ts +154 -87
- package/src/lib/connection_manager/network_monitor.ts +112 -0
- package/src/lib/connection_manager/shard_reader.ts +134 -0
- package/src/lib/connection_manager/utils.ts +27 -1
- package/src/lib/filter/filter.ts +3 -28
- package/src/lib/light_push/light_push.ts +1 -5
- package/src/lib/metadata/metadata.ts +13 -12
@@ -0,0 +1,292 @@
|
|
1
|
+
import { Peer, PeerId } from "@libp2p/interface";
|
2
|
+
import {
|
3
|
+
CONNECTION_LOCKED_TAG,
|
4
|
+
ConnectionManagerOptions,
|
5
|
+
IWakuEventEmitter,
|
6
|
+
Libp2p,
|
7
|
+
Libp2pEventHandler,
|
8
|
+
Tags
|
9
|
+
} from "@waku/interfaces";
|
10
|
+
import { Logger } from "@waku/utils";
|
11
|
+
|
12
|
+
import { Dialer } from "./dialer.js";
|
13
|
+
import { NetworkMonitor } from "./network_monitor.js";
|
14
|
+
|
15
|
+
const log = new Logger("connection-limiter");
|
16
|
+
|
17
|
+
const DEFAULT_CONNECTION_MONITOR_INTERVAL = 5 * 1_000;
|
18
|
+
|
19
|
+
type ConnectionLimiterConstructorOptions = {
|
20
|
+
libp2p: Libp2p;
|
21
|
+
events: IWakuEventEmitter;
|
22
|
+
dialer: Dialer;
|
23
|
+
networkMonitor: NetworkMonitor;
|
24
|
+
options: ConnectionManagerOptions;
|
25
|
+
};
|
26
|
+
|
27
|
+
interface IConnectionLimiter {
|
28
|
+
start(): void;
|
29
|
+
stop(): void;
|
30
|
+
}
|
31
|
+
|
32
|
+
/**
|
33
|
+
* This class is responsible for limiting the number of connections to peers.
|
34
|
+
* It also dials all known peers because libp2p might have emitted `peer:discovery` before initialization
|
35
|
+
* and listen to `peer:connect` and `peer:disconnect` events to manage connections.
|
36
|
+
*/
|
37
|
+
export class ConnectionLimiter implements IConnectionLimiter {
|
38
|
+
private readonly libp2p: Libp2p;
|
39
|
+
private readonly events: IWakuEventEmitter;
|
40
|
+
private readonly networkMonitor: NetworkMonitor;
|
41
|
+
private readonly dialer: Dialer;
|
42
|
+
|
43
|
+
private connectionMonitorInterval: NodeJS.Timeout | null = null;
|
44
|
+
private readonly options: ConnectionManagerOptions;
|
45
|
+
|
46
|
+
public constructor(options: ConnectionLimiterConstructorOptions) {
|
47
|
+
this.libp2p = options.libp2p;
|
48
|
+
this.events = options.events;
|
49
|
+
this.networkMonitor = options.networkMonitor;
|
50
|
+
this.dialer = options.dialer;
|
51
|
+
|
52
|
+
this.options = options.options;
|
53
|
+
|
54
|
+
this.onWakuConnectionEvent = this.onWakuConnectionEvent.bind(this);
|
55
|
+
this.onDisconnectedEvent = this.onDisconnectedEvent.bind(this);
|
56
|
+
}
|
57
|
+
|
58
|
+
public start(): void {
|
59
|
+
// dial all known peers because libp2p might have emitted `peer:discovery` before initialization
|
60
|
+
void this.dialPeersFromStore();
|
61
|
+
|
62
|
+
if (
|
63
|
+
this.options.enableAutoRecovery &&
|
64
|
+
this.connectionMonitorInterval === null
|
65
|
+
) {
|
66
|
+
this.connectionMonitorInterval = setInterval(
|
67
|
+
() => void this.maintainConnections(),
|
68
|
+
DEFAULT_CONNECTION_MONITOR_INTERVAL
|
69
|
+
);
|
70
|
+
}
|
71
|
+
|
72
|
+
this.events.addEventListener("waku:connection", this.onWakuConnectionEvent);
|
73
|
+
|
74
|
+
/**
|
75
|
+
* NOTE: Event is not being emitted on closing nor losing a connection.
|
76
|
+
* @see https://github.com/libp2p/js-libp2p/issues/939
|
77
|
+
* @see https://github.com/status-im/js-waku/issues/252
|
78
|
+
*
|
79
|
+
* >This event will be triggered anytime we are disconnected from another peer,
|
80
|
+
* >regardless of the circumstances of that disconnection.
|
81
|
+
* >If we happen to have multiple connections to a peer,
|
82
|
+
* >this event will **only** be triggered when the last connection is closed.
|
83
|
+
* @see https://github.com/libp2p/js-libp2p/blob/bad9e8c0ff58d60a78314077720c82ae331cc55b/doc/API.md?plain=1#L2100
|
84
|
+
*/
|
85
|
+
this.libp2p.addEventListener(
|
86
|
+
"peer:disconnect",
|
87
|
+
this.onDisconnectedEvent as Libp2pEventHandler<PeerId>
|
88
|
+
);
|
89
|
+
}
|
90
|
+
|
91
|
+
public stop(): void {
|
92
|
+
this.events.removeEventListener(
|
93
|
+
"waku:connection",
|
94
|
+
this.onWakuConnectionEvent
|
95
|
+
);
|
96
|
+
|
97
|
+
this.libp2p.removeEventListener(
|
98
|
+
"peer:disconnect",
|
99
|
+
this.onDisconnectedEvent as Libp2pEventHandler<PeerId>
|
100
|
+
);
|
101
|
+
|
102
|
+
if (this.connectionMonitorInterval) {
|
103
|
+
clearInterval(this.connectionMonitorInterval);
|
104
|
+
this.connectionMonitorInterval = null;
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
private onWakuConnectionEvent(): void {
|
109
|
+
if (!this.options.enableAutoRecovery) {
|
110
|
+
log.info(`Auto recovery is disabled, skipping`);
|
111
|
+
return;
|
112
|
+
}
|
113
|
+
|
114
|
+
if (this.networkMonitor.isBrowserConnected()) {
|
115
|
+
void this.dialPeersFromStore();
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
private async maintainConnections(): Promise<void> {
|
120
|
+
await this.maintainConnectionsCount();
|
121
|
+
await this.maintainBootstrapConnections();
|
122
|
+
}
|
123
|
+
|
124
|
+
private async onDisconnectedEvent(): Promise<void> {
|
125
|
+
if (this.libp2p.getConnections().length === 0) {
|
126
|
+
log.info(`No connections, dialing peers from store`);
|
127
|
+
await this.dialPeersFromStore();
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
private async maintainConnectionsCount(): Promise<void> {
|
132
|
+
log.info(`Maintaining connections count`);
|
133
|
+
|
134
|
+
const connections = this.libp2p.getConnections();
|
135
|
+
|
136
|
+
if (connections.length <= this.options.maxConnections) {
|
137
|
+
log.info(
|
138
|
+
`Node has less than max connections ${this.options.maxConnections}, trying to dial more peers`
|
139
|
+
);
|
140
|
+
|
141
|
+
const peers = await this.getPrioritizedPeers();
|
142
|
+
|
143
|
+
if (peers.length === 0) {
|
144
|
+
log.info(`No peers to dial, node is utilizing all known peers`);
|
145
|
+
return;
|
146
|
+
}
|
147
|
+
|
148
|
+
const promises = peers
|
149
|
+
.slice(0, this.options.maxConnections - connections.length)
|
150
|
+
.map((p) => this.dialer.dial(p.id));
|
151
|
+
await Promise.all(promises);
|
152
|
+
|
153
|
+
return;
|
154
|
+
}
|
155
|
+
|
156
|
+
log.info(
|
157
|
+
`Node has more than max connections ${this.options.maxConnections}, dropping connections`
|
158
|
+
);
|
159
|
+
|
160
|
+
try {
|
161
|
+
const connectionsToDrop = connections
|
162
|
+
.filter((c) => !c.tags.includes(CONNECTION_LOCKED_TAG))
|
163
|
+
.slice(this.options.maxConnections);
|
164
|
+
|
165
|
+
if (connectionsToDrop.length === 0) {
|
166
|
+
log.info(`No connections to drop, skipping`);
|
167
|
+
return;
|
168
|
+
}
|
169
|
+
|
170
|
+
const promises = connectionsToDrop.map((c) =>
|
171
|
+
this.libp2p.hangUp(c.remotePeer)
|
172
|
+
);
|
173
|
+
await Promise.all(promises);
|
174
|
+
|
175
|
+
log.info(`Dropped ${connectionsToDrop.length} connections`);
|
176
|
+
} catch (error) {
|
177
|
+
log.error(`Unexpected error while maintaining connections`, error);
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
private async maintainBootstrapConnections(): Promise<void> {
|
182
|
+
log.info(`Maintaining bootstrap connections`);
|
183
|
+
|
184
|
+
const bootstrapPeers = await this.getBootstrapPeers();
|
185
|
+
|
186
|
+
if (bootstrapPeers.length <= this.options.maxBootstrapPeers) {
|
187
|
+
return;
|
188
|
+
}
|
189
|
+
|
190
|
+
try {
|
191
|
+
const peersToDrop = bootstrapPeers.slice(this.options.maxBootstrapPeers);
|
192
|
+
|
193
|
+
log.info(
|
194
|
+
`Dropping ${peersToDrop.length} bootstrap connections because node has more than max bootstrap connections ${this.options.maxBootstrapPeers}`
|
195
|
+
);
|
196
|
+
|
197
|
+
const promises = peersToDrop.map((p) => this.libp2p.hangUp(p.id));
|
198
|
+
await Promise.all(promises);
|
199
|
+
|
200
|
+
log.info(`Dropped ${peersToDrop.length} bootstrap connections`);
|
201
|
+
} catch (error) {
|
202
|
+
log.error(
|
203
|
+
`Unexpected error while maintaining bootstrap connections`,
|
204
|
+
error
|
205
|
+
);
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
private async dialPeersFromStore(): Promise<void> {
|
210
|
+
log.info(`Dialing peers from store`);
|
211
|
+
|
212
|
+
try {
|
213
|
+
const peers = await this.getPrioritizedPeers();
|
214
|
+
|
215
|
+
if (peers.length === 0) {
|
216
|
+
log.info(`No peers to dial, skipping`);
|
217
|
+
return;
|
218
|
+
}
|
219
|
+
|
220
|
+
const promises = peers.map((p) => this.dialer.dial(p.id));
|
221
|
+
|
222
|
+
log.info(`Dialing ${peers.length} peers from store`);
|
223
|
+
await Promise.all(promises);
|
224
|
+
log.info(`Dialed ${promises.length} peers from store`);
|
225
|
+
} catch (error) {
|
226
|
+
log.error(`Unexpected error while dialing peer store peers`, error);
|
227
|
+
}
|
228
|
+
}
|
229
|
+
|
230
|
+
/**
|
231
|
+
* Returns a list of peers ordered by priority:
|
232
|
+
* - bootstrap peers
|
233
|
+
* - peers from peer exchange
|
234
|
+
* - peers from local store (last because we are not sure that locally stored information is up to date)
|
235
|
+
*/
|
236
|
+
private async getPrioritizedPeers(): Promise<Peer[]> {
|
237
|
+
const allPeers = await this.libp2p.peerStore.all();
|
238
|
+
const allConnections = this.libp2p.getConnections();
|
239
|
+
|
240
|
+
log.info(
|
241
|
+
`Found ${allPeers.length} peers in store, and found ${allConnections.length} connections`
|
242
|
+
);
|
243
|
+
|
244
|
+
const notConnectedPeers = allPeers.filter(
|
245
|
+
(p) =>
|
246
|
+
!allConnections.some((c) => c.remotePeer.equals(p.id)) &&
|
247
|
+
p.addresses.some(
|
248
|
+
(a) =>
|
249
|
+
a.multiaddr.toString().includes("wss") ||
|
250
|
+
a.multiaddr.toString().includes("ws")
|
251
|
+
)
|
252
|
+
);
|
253
|
+
|
254
|
+
const bootstrapPeers = notConnectedPeers.filter((p) =>
|
255
|
+
p.tags.has(Tags.BOOTSTRAP)
|
256
|
+
);
|
257
|
+
|
258
|
+
const peerExchangePeers = notConnectedPeers.filter((p) =>
|
259
|
+
p.tags.has(Tags.PEER_EXCHANGE)
|
260
|
+
);
|
261
|
+
|
262
|
+
const localStorePeers = notConnectedPeers.filter((p) =>
|
263
|
+
p.tags.has(Tags.LOCAL)
|
264
|
+
);
|
265
|
+
|
266
|
+
return [...bootstrapPeers, ...peerExchangePeers, ...localStorePeers];
|
267
|
+
}
|
268
|
+
|
269
|
+
private async getBootstrapPeers(): Promise<Peer[]> {
|
270
|
+
const peers = await Promise.all(
|
271
|
+
this.libp2p
|
272
|
+
.getConnections()
|
273
|
+
.map((conn) => conn.remotePeer)
|
274
|
+
.map((id) => this.getPeer(id))
|
275
|
+
);
|
276
|
+
|
277
|
+
const bootstrapPeers = peers.filter(
|
278
|
+
(peer) => peer && peer.tags.has(Tags.BOOTSTRAP)
|
279
|
+
) as Peer[];
|
280
|
+
|
281
|
+
return bootstrapPeers;
|
282
|
+
}
|
283
|
+
|
284
|
+
private async getPeer(peerId: PeerId): Promise<Peer | null> {
|
285
|
+
try {
|
286
|
+
return await this.libp2p.peerStore.get(peerId);
|
287
|
+
} catch (error) {
|
288
|
+
log.error(`Failed to get peer ${peerId}, error: ${error}`);
|
289
|
+
return null;
|
290
|
+
}
|
291
|
+
}
|
292
|
+
}
|