@waku/core 0.0.37-2ed5ddc.0 → 0.0.37-987c6cd.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 +200 -108
- package/bundle/lib/message/version_0.js +1 -1
- package/bundle/{version_0-Bc0h7ah2.js → version_0-BpF0pNhc.js} +2 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/lib/connection_manager/connection_limiter.d.ts +10 -8
- package/dist/lib/connection_manager/connection_limiter.js +22 -1
- package/dist/lib/connection_manager/connection_limiter.js.map +1 -1
- package/dist/lib/connection_manager/connection_manager.d.ts +1 -0
- package/dist/lib/connection_manager/connection_manager.js +21 -3
- package/dist/lib/connection_manager/connection_manager.js.map +1 -1
- package/dist/lib/connection_manager/dialer.d.ts +28 -0
- package/dist/lib/connection_manager/dialer.js +100 -0
- package/dist/lib/connection_manager/dialer.js.map +1 -0
- package/dist/lib/connection_manager/discovery_dialer.d.ts +3 -9
- package/dist/lib/connection_manager/discovery_dialer.js +7 -70
- package/dist/lib/connection_manager/discovery_dialer.js.map +1 -1
- package/dist/lib/connection_manager/network_monitor.d.ts +14 -0
- package/dist/lib/connection_manager/network_monitor.js +19 -1
- package/dist/lib/connection_manager/network_monitor.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/connection_manager/connection_limiter.ts +50 -10
- package/src/lib/connection_manager/connection_manager.ts +28 -4
- package/src/lib/connection_manager/dialer.ts +139 -0
- package/src/lib/connection_manager/discovery_dialer.ts +9 -98
- package/src/lib/connection_manager/network_monitor.ts +25 -1
@@ -12,6 +12,7 @@ import { Libp2p } from "@waku/interfaces";
|
|
12
12
|
import { Logger } from "@waku/utils";
|
13
13
|
|
14
14
|
import { ConnectionLimiter } from "./connection_limiter.js";
|
15
|
+
import { Dialer } from "./dialer.js";
|
15
16
|
import { DiscoveryDialer } from "./discovery_dialer.js";
|
16
17
|
import { KeepAliveManager } from "./keep_alive_manager.js";
|
17
18
|
import { NetworkMonitor } from "./network_monitor.js";
|
@@ -38,6 +39,7 @@ export class ConnectionManager implements IConnectionManager {
|
|
38
39
|
|
39
40
|
private readonly keepAliveManager: KeepAliveManager;
|
40
41
|
private readonly discoveryDialer: DiscoveryDialer;
|
42
|
+
private readonly dialer: Dialer;
|
41
43
|
private readonly shardReader: ShardReader;
|
42
44
|
private readonly networkMonitor: NetworkMonitor;
|
43
45
|
private readonly connectionLimiter: ConnectionLimiter;
|
@@ -70,11 +72,16 @@ export class ConnectionManager implements IConnectionManager {
|
|
70
72
|
networkConfig: options.networkConfig
|
71
73
|
});
|
72
74
|
|
73
|
-
this.
|
75
|
+
this.dialer = new Dialer({
|
74
76
|
libp2p: options.libp2p,
|
75
77
|
shardReader: this.shardReader
|
76
78
|
});
|
77
79
|
|
80
|
+
this.discoveryDialer = new DiscoveryDialer({
|
81
|
+
libp2p: options.libp2p,
|
82
|
+
dialer: this.dialer
|
83
|
+
});
|
84
|
+
|
78
85
|
this.networkMonitor = new NetworkMonitor({
|
79
86
|
libp2p: options.libp2p,
|
80
87
|
events: options.events
|
@@ -82,6 +89,9 @@ export class ConnectionManager implements IConnectionManager {
|
|
82
89
|
|
83
90
|
this.connectionLimiter = new ConnectionLimiter({
|
84
91
|
libp2p: options.libp2p,
|
92
|
+
events: options.events,
|
93
|
+
networkMonitor: this.networkMonitor,
|
94
|
+
dialer: this.dialer,
|
85
95
|
options: this.options
|
86
96
|
});
|
87
97
|
}
|
@@ -109,16 +119,23 @@ export class ConnectionManager implements IConnectionManager {
|
|
109
119
|
protocolCodecs: string[]
|
110
120
|
): Promise<Stream> {
|
111
121
|
const ma = mapToPeerIdOrMultiaddr(peer);
|
112
|
-
|
122
|
+
log.info(`Dialing peer ${ma.toString()} with protocols ${protocolCodecs}`);
|
123
|
+
|
124
|
+
// must use libp2p directly instead of dialer because we need to dial the peer right away
|
125
|
+
const stream = await this.libp2p.dialProtocol(ma, protocolCodecs);
|
126
|
+
log.info(`Dialed peer ${ma.toString()} with protocols ${protocolCodecs}`);
|
127
|
+
|
128
|
+
return stream;
|
113
129
|
}
|
114
130
|
|
115
131
|
public async hangUp(peer: PeerId | MultiaddrInput): Promise<boolean> {
|
116
132
|
const peerId = mapToPeerId(peer);
|
117
133
|
|
118
134
|
try {
|
135
|
+
log.info(`Dropping connection with peer ${peerId.toString()}`);
|
119
136
|
await this.libp2p.hangUp(peerId);
|
120
|
-
|
121
137
|
log.info(`Dropped connection with peer ${peerId.toString()}`);
|
138
|
+
|
122
139
|
return true;
|
123
140
|
} catch (error) {
|
124
141
|
log.error(
|
@@ -132,7 +149,10 @@ export class ConnectionManager implements IConnectionManager {
|
|
132
149
|
public async getConnectedPeers(codec?: string): Promise<Peer[]> {
|
133
150
|
const peerIDs = this.libp2p.getPeers();
|
134
151
|
|
152
|
+
log.info(`Getting connected peers for codec ${codec}`);
|
153
|
+
|
135
154
|
if (peerIDs.length === 0) {
|
155
|
+
log.info(`No connected peers`);
|
136
156
|
return [];
|
137
157
|
}
|
138
158
|
|
@@ -146,10 +166,14 @@ export class ConnectionManager implements IConnectionManager {
|
|
146
166
|
})
|
147
167
|
);
|
148
168
|
|
149
|
-
|
169
|
+
const result = peers
|
150
170
|
.filter((p) => !!p)
|
151
171
|
.filter((p) => (codec ? (p as Peer).protocols.includes(codec) : true))
|
152
172
|
.sort((left, right) => getPeerPing(left) - getPeerPing(right)) as Peer[];
|
173
|
+
|
174
|
+
log.info(`Found ${result.length} connected peers for codec ${codec}`);
|
175
|
+
|
176
|
+
return result;
|
153
177
|
}
|
154
178
|
|
155
179
|
public isTopicConfigured(pubsubTopic: PubsubTopic): boolean {
|
@@ -0,0 +1,139 @@
|
|
1
|
+
import type { PeerId } from "@libp2p/interface";
|
2
|
+
import { Libp2p } from "@waku/interfaces";
|
3
|
+
import { Logger } from "@waku/utils";
|
4
|
+
|
5
|
+
import { ShardReader } from "./shard_reader.js";
|
6
|
+
|
7
|
+
const log = new Logger("dialer");
|
8
|
+
|
9
|
+
type DialerConstructorOptions = {
|
10
|
+
libp2p: Libp2p;
|
11
|
+
shardReader: ShardReader;
|
12
|
+
};
|
13
|
+
|
14
|
+
interface IDialer {
|
15
|
+
start(): void;
|
16
|
+
stop(): void;
|
17
|
+
dial(peerId: PeerId): Promise<void>;
|
18
|
+
}
|
19
|
+
|
20
|
+
export class Dialer implements IDialer {
|
21
|
+
private readonly libp2p: Libp2p;
|
22
|
+
private readonly shardReader: ShardReader;
|
23
|
+
|
24
|
+
private dialingQueue: PeerId[] = [];
|
25
|
+
private dialHistory: Map<string, number> = new Map();
|
26
|
+
private dialingInterval: NodeJS.Timeout | null = null;
|
27
|
+
private isProcessing = false;
|
28
|
+
|
29
|
+
public constructor(options: DialerConstructorOptions) {
|
30
|
+
this.libp2p = options.libp2p;
|
31
|
+
this.shardReader = options.shardReader;
|
32
|
+
}
|
33
|
+
|
34
|
+
public start(): void {
|
35
|
+
if (!this.dialingInterval) {
|
36
|
+
this.dialingInterval = setInterval(() => {
|
37
|
+
void this.processQueue();
|
38
|
+
}, 500);
|
39
|
+
}
|
40
|
+
|
41
|
+
this.dialHistory.clear();
|
42
|
+
}
|
43
|
+
|
44
|
+
public stop(): void {
|
45
|
+
if (this.dialingInterval) {
|
46
|
+
clearInterval(this.dialingInterval);
|
47
|
+
this.dialingInterval = null;
|
48
|
+
}
|
49
|
+
|
50
|
+
this.dialHistory.clear();
|
51
|
+
}
|
52
|
+
|
53
|
+
public async dial(peerId: PeerId): Promise<void> {
|
54
|
+
const shouldSkip = await this.shouldSkipPeer(peerId);
|
55
|
+
|
56
|
+
if (shouldSkip) {
|
57
|
+
log.info(`Skipping peer: ${peerId}`);
|
58
|
+
return;
|
59
|
+
}
|
60
|
+
|
61
|
+
// If queue is empty and we're not currently processing, dial immediately
|
62
|
+
if (this.dialingQueue.length === 0 && !this.isProcessing) {
|
63
|
+
await this.dialPeer(peerId);
|
64
|
+
} else {
|
65
|
+
// Add to queue
|
66
|
+
this.dialingQueue.push(peerId);
|
67
|
+
log.info(
|
68
|
+
`Added peer to dialing queue, queue size: ${this.dialingQueue.length}`
|
69
|
+
);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
private async processQueue(): Promise<void> {
|
74
|
+
if (this.dialingQueue.length === 0 || this.isProcessing) return;
|
75
|
+
|
76
|
+
this.isProcessing = true;
|
77
|
+
|
78
|
+
try {
|
79
|
+
const peersToDial = this.dialingQueue.slice(0, 3);
|
80
|
+
this.dialingQueue = this.dialingQueue.slice(peersToDial.length);
|
81
|
+
|
82
|
+
log.info(
|
83
|
+
`Processing dial queue: dialing ${peersToDial.length} peers, ${this.dialingQueue.length} remaining in queue`
|
84
|
+
);
|
85
|
+
|
86
|
+
await Promise.all(peersToDial.map((peerId) => this.dialPeer(peerId)));
|
87
|
+
} finally {
|
88
|
+
this.isProcessing = false;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
private async dialPeer(peerId: PeerId): Promise<void> {
|
93
|
+
try {
|
94
|
+
log.info(`Dialing peer from queue: ${peerId}`);
|
95
|
+
|
96
|
+
await this.libp2p.dial(peerId);
|
97
|
+
this.dialHistory.set(peerId.toString(), Date.now());
|
98
|
+
|
99
|
+
log.info(`Successfully dialed peer from queue: ${peerId}`);
|
100
|
+
} catch (error) {
|
101
|
+
log.error(`Error dialing peer ${peerId}`, error);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
private async shouldSkipPeer(peerId: PeerId): Promise<boolean> {
|
106
|
+
const hasConnection = this.libp2p.getPeers().some((p) => p.equals(peerId));
|
107
|
+
if (hasConnection) {
|
108
|
+
log.info(`Skipping peer ${peerId} - already connected`);
|
109
|
+
return true;
|
110
|
+
}
|
111
|
+
|
112
|
+
const lastDialed = this.dialHistory.get(peerId.toString());
|
113
|
+
if (lastDialed && Date.now() - lastDialed < 10_000) {
|
114
|
+
log.info(
|
115
|
+
`Skipping peer ${peerId} - already dialed in the last 10 seconds`
|
116
|
+
);
|
117
|
+
return true;
|
118
|
+
}
|
119
|
+
|
120
|
+
try {
|
121
|
+
const hasShardInfo = await this.shardReader.hasShardInfo(peerId);
|
122
|
+
if (!hasShardInfo) {
|
123
|
+
log.info(`Skipping peer ${peerId} - no shard info`);
|
124
|
+
return false;
|
125
|
+
}
|
126
|
+
|
127
|
+
const isOnSameShard = await this.shardReader.isPeerOnNetwork(peerId);
|
128
|
+
if (!isOnSameShard) {
|
129
|
+
log.info(`Skipping peer ${peerId} - not on same shard`);
|
130
|
+
return true;
|
131
|
+
}
|
132
|
+
|
133
|
+
return false;
|
134
|
+
} catch (error) {
|
135
|
+
log.error(`Error checking shard info for peer ${peerId}`, error);
|
136
|
+
return true; // Skip peer when there's an error
|
137
|
+
}
|
138
|
+
}
|
139
|
+
}
|
@@ -3,13 +3,13 @@ import { Multiaddr } from "@multiformats/multiaddr";
|
|
3
3
|
import { Logger } from "@waku/utils";
|
4
4
|
import { Libp2p } from "libp2p";
|
5
5
|
|
6
|
-
import
|
6
|
+
import { Dialer } from "./dialer.js";
|
7
7
|
|
8
8
|
type Libp2pEventHandler<T> = (e: CustomEvent<T>) => void;
|
9
9
|
|
10
10
|
type DiscoveryDialerConstructorOptions = {
|
11
11
|
libp2p: Libp2p;
|
12
|
-
|
12
|
+
dialer: Dialer;
|
13
13
|
};
|
14
14
|
|
15
15
|
interface IDiscoveryDialer {
|
@@ -26,54 +26,27 @@ const log = new Logger("discovery-dialer");
|
|
26
26
|
*/
|
27
27
|
export class DiscoveryDialer implements IDiscoveryDialer {
|
28
28
|
private readonly libp2p: Libp2p;
|
29
|
-
private readonly
|
30
|
-
|
31
|
-
private dialingInterval: NodeJS.Timeout | null = null;
|
32
|
-
private dialingQueue: PeerId[] = [];
|
33
|
-
private dialHistory: Set<string> = new Set();
|
29
|
+
private readonly dialer: Dialer;
|
34
30
|
|
35
31
|
public constructor(options: DiscoveryDialerConstructorOptions) {
|
36
32
|
this.libp2p = options.libp2p;
|
37
|
-
this.
|
33
|
+
this.dialer = options.dialer;
|
38
34
|
|
39
35
|
this.onPeerDiscovery = this.onPeerDiscovery.bind(this);
|
40
36
|
}
|
41
37
|
|
42
38
|
public start(): void {
|
43
|
-
log.info("Starting discovery dialer");
|
44
|
-
|
45
39
|
this.libp2p.addEventListener(
|
46
40
|
"peer:discovery",
|
47
41
|
this.onPeerDiscovery as Libp2pEventHandler<PeerInfo>
|
48
42
|
);
|
49
|
-
|
50
|
-
if (!this.dialingInterval) {
|
51
|
-
this.dialingInterval = setInterval(() => {
|
52
|
-
void this.processQueue();
|
53
|
-
}, 500);
|
54
|
-
|
55
|
-
log.info("Started dialing interval processor");
|
56
|
-
}
|
57
|
-
|
58
|
-
this.dialHistory.clear();
|
59
43
|
}
|
60
44
|
|
61
45
|
public stop(): void {
|
62
|
-
log.info("Stopping discovery dialer");
|
63
|
-
|
64
46
|
this.libp2p.removeEventListener(
|
65
47
|
"peer:discovery",
|
66
48
|
this.onPeerDiscovery as Libp2pEventHandler<PeerInfo>
|
67
49
|
);
|
68
|
-
|
69
|
-
if (this.dialingInterval) {
|
70
|
-
clearInterval(this.dialingInterval);
|
71
|
-
this.dialingInterval = null;
|
72
|
-
|
73
|
-
log.info("Stopped dialing interval processor");
|
74
|
-
}
|
75
|
-
|
76
|
-
this.dialHistory.clear();
|
77
50
|
}
|
78
51
|
|
79
52
|
private async onPeerDiscovery(event: CustomEvent<PeerInfo>): Promise<void> {
|
@@ -81,74 +54,23 @@ export class DiscoveryDialer implements IDiscoveryDialer {
|
|
81
54
|
log.info(`Discovered new peer: ${peerId}`);
|
82
55
|
|
83
56
|
try {
|
84
|
-
const shouldSkip = await this.shouldSkipPeer(peerId);
|
85
|
-
|
86
|
-
if (shouldSkip) {
|
87
|
-
log.info(`Skipping peer: ${peerId}`);
|
88
|
-
return;
|
89
|
-
}
|
90
|
-
|
91
57
|
await this.updatePeerStore(peerId, event.detail.multiaddrs);
|
92
|
-
|
93
|
-
if (this.dialingQueue.length === 0) {
|
94
|
-
await this.dialPeer(peerId);
|
95
|
-
} else {
|
96
|
-
this.dialingQueue.push(peerId);
|
97
|
-
|
98
|
-
log.info(
|
99
|
-
`Added peer to dialing queue, queue size: ${this.dialingQueue.length}`
|
100
|
-
);
|
101
|
-
}
|
58
|
+
await this.dialer.dial(peerId);
|
102
59
|
} catch (error) {
|
103
60
|
log.error(`Error dialing peer ${peerId}`, error);
|
104
61
|
}
|
105
62
|
}
|
106
63
|
|
107
|
-
private async processQueue(): Promise<void> {
|
108
|
-
if (this.dialingQueue.length === 0) return;
|
109
|
-
|
110
|
-
const peersToDial = this.dialingQueue.slice(0, 3);
|
111
|
-
this.dialingQueue = this.dialingQueue.slice(peersToDial.length);
|
112
|
-
|
113
|
-
log.info(
|
114
|
-
`Processing dial queue: dialing ${peersToDial.length} peers, ${this.dialingQueue.length} remaining in queue`
|
115
|
-
);
|
116
|
-
|
117
|
-
await Promise.all(peersToDial.map(this.dialPeer));
|
118
|
-
}
|
119
|
-
|
120
|
-
private async shouldSkipPeer(peerId: PeerId): Promise<boolean> {
|
121
|
-
if (this.dialHistory.has(peerId.toString())) {
|
122
|
-
return true;
|
123
|
-
}
|
124
|
-
|
125
|
-
const hasShardInfo = await this.shardReader.hasShardInfo(peerId);
|
126
|
-
if (!hasShardInfo) {
|
127
|
-
return false;
|
128
|
-
}
|
129
|
-
|
130
|
-
const isOnSameShard = await this.shardReader.isPeerOnNetwork(peerId);
|
131
|
-
if (!isOnSameShard) {
|
132
|
-
log.info(`Skipping peer ${peerId} - not on same shard`);
|
133
|
-
return true;
|
134
|
-
}
|
135
|
-
|
136
|
-
const hasConnection = this.libp2p.getPeers().some((p) => p.equals(peerId));
|
137
|
-
if (hasConnection) {
|
138
|
-
return true;
|
139
|
-
}
|
140
|
-
|
141
|
-
return false;
|
142
|
-
}
|
143
|
-
|
144
64
|
private async updatePeerStore(
|
145
65
|
peerId: PeerId,
|
146
66
|
multiaddrs: Multiaddr[]
|
147
67
|
): Promise<void> {
|
148
68
|
try {
|
69
|
+
log.info(`Updating peer store for ${peerId}`);
|
149
70
|
const peer = await this.getPeer(peerId);
|
150
71
|
|
151
72
|
if (!peer) {
|
73
|
+
log.info(`Peer ${peerId} not found in store, saving`);
|
152
74
|
await this.libp2p.peerStore.save(peerId, {
|
153
75
|
multiaddrs: multiaddrs
|
154
76
|
});
|
@@ -160,9 +82,11 @@ export class DiscoveryDialer implements IDiscoveryDialer {
|
|
160
82
|
);
|
161
83
|
|
162
84
|
if (hasSameAddr) {
|
85
|
+
log.info(`Peer ${peerId} has same addresses in peer store, skipping`);
|
163
86
|
return;
|
164
87
|
}
|
165
88
|
|
89
|
+
log.info(`Merging peer ${peerId} addresses in peer store`);
|
166
90
|
await this.libp2p.peerStore.merge(peerId, {
|
167
91
|
multiaddrs: multiaddrs
|
168
92
|
});
|
@@ -171,19 +95,6 @@ export class DiscoveryDialer implements IDiscoveryDialer {
|
|
171
95
|
}
|
172
96
|
}
|
173
97
|
|
174
|
-
private async dialPeer(peerId: PeerId): Promise<void> {
|
175
|
-
try {
|
176
|
-
log.info(`Dialing peer from queue: ${peerId}`);
|
177
|
-
|
178
|
-
await this.libp2p.dial(peerId);
|
179
|
-
this.dialHistory.add(peerId.toString());
|
180
|
-
|
181
|
-
log.info(`Successfully dialed peer from queue: ${peerId}`);
|
182
|
-
} catch (error) {
|
183
|
-
log.error(`Error dialing peer ${peerId}`, error);
|
184
|
-
}
|
185
|
-
}
|
186
|
-
|
187
98
|
private async getPeer(peerId: PeerId): Promise<Peer | undefined> {
|
188
99
|
try {
|
189
100
|
return await this.libp2p.peerStore.get(peerId);
|
@@ -8,6 +8,9 @@ type NetworkMonitorConstructorOptions = {
|
|
8
8
|
interface INetworkMonitor {
|
9
9
|
start(): void;
|
10
10
|
stop(): void;
|
11
|
+
isConnected(): boolean;
|
12
|
+
isP2PConnected(): boolean;
|
13
|
+
isBrowserConnected(): boolean;
|
11
14
|
}
|
12
15
|
|
13
16
|
export class NetworkMonitor implements INetworkMonitor {
|
@@ -52,7 +55,28 @@ export class NetworkMonitor implements INetworkMonitor {
|
|
52
55
|
}
|
53
56
|
}
|
54
57
|
|
58
|
+
/**
|
59
|
+
* Returns true if the node is connected to the network via libp2p and browser.
|
60
|
+
*/
|
55
61
|
public isConnected(): boolean {
|
62
|
+
if (!this.isBrowserConnected()) {
|
63
|
+
return false;
|
64
|
+
}
|
65
|
+
|
66
|
+
return this.isP2PConnected();
|
67
|
+
}
|
68
|
+
|
69
|
+
/**
|
70
|
+
* Returns true if the node is connected to the network via libp2p.
|
71
|
+
*/
|
72
|
+
public isP2PConnected(): boolean {
|
73
|
+
return this.isNetworkConnected;
|
74
|
+
}
|
75
|
+
|
76
|
+
/**
|
77
|
+
* Returns true if the node is connected to the network via browser.
|
78
|
+
*/
|
79
|
+
public isBrowserConnected(): boolean {
|
56
80
|
try {
|
57
81
|
if (globalThis?.navigator && !globalThis?.navigator?.onLine) {
|
58
82
|
return false;
|
@@ -61,7 +85,7 @@ export class NetworkMonitor implements INetworkMonitor {
|
|
61
85
|
// ignore
|
62
86
|
}
|
63
87
|
|
64
|
-
return
|
88
|
+
return true;
|
65
89
|
}
|
66
90
|
|
67
91
|
private onConnectedEvent(): void {
|