@waku/core 0.0.36-f911bf8.0 → 0.0.37-2ed5ddc.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/CHANGELOG.md +39 -0
- package/bundle/index.js +5647 -1359
- package/bundle/lib/message/version_0.js +1 -2
- package/bundle/{version_0-CiYGrPc2.js → version_0-Bc0h7ah2.js} +1886 -31
- package/dist/.tsbuildinfo +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/connection_manager/connection_limiter.d.ts +35 -0
- package/dist/lib/connection_manager/connection_limiter.js +103 -0
- package/dist/lib/connection_manager/connection_limiter.js.map +1 -0
- package/dist/lib/connection_manager/connection_manager.d.ts +19 -104
- package/dist/lib/connection_manager/connection_manager.js +64 -499
- package/dist/lib/connection_manager/connection_manager.js.map +1 -1
- package/dist/lib/connection_manager/discovery_dialer.d.ts +32 -0
- package/dist/lib/connection_manager/discovery_dialer.js +131 -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 +22 -0
- package/dist/lib/connection_manager/network_monitor.js +63 -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 +7 -5
- package/dist/lib/filter/filter.js +14 -11
- package/dist/lib/filter/filter.js.map +1 -1
- package/dist/lib/light_push/light_push.d.ts +5 -5
- package/dist/lib/light_push/light_push.js +7 -7
- package/dist/lib/light_push/light_push.js.map +1 -1
- package/dist/lib/message/version_0.d.ts +3 -4
- package/dist/lib/message/version_0.js +1 -4
- package/dist/lib/message/version_0.js.map +1 -1
- package/dist/lib/message_hash/index.d.ts +1 -0
- package/dist/lib/message_hash/index.js +2 -0
- package/dist/lib/message_hash/index.js.map +1 -0
- package/dist/lib/message_hash/message_hash.d.ts +52 -0
- package/dist/lib/message_hash/message_hash.js +84 -0
- package/dist/lib/message_hash/message_hash.js.map +1 -0
- package/dist/lib/metadata/metadata.js +6 -4
- package/dist/lib/metadata/metadata.js.map +1 -1
- package/dist/lib/store/rpc.js +16 -10
- package/dist/lib/store/rpc.js.map +1 -1
- package/dist/lib/store/store.d.ts +5 -5
- package/dist/lib/store/store.js +19 -9
- package/dist/lib/store/store.js.map +1 -1
- package/dist/lib/stream_manager/stream_manager.d.ts +3 -4
- package/dist/lib/stream_manager/stream_manager.js +6 -8
- package/dist/lib/stream_manager/stream_manager.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/lib/connection_manager/connection_limiter.ts +161 -0
- package/src/lib/connection_manager/connection_manager.ts +87 -668
- package/src/lib/connection_manager/discovery_dialer.ts +195 -0
- package/src/lib/connection_manager/keep_alive_manager.ts +154 -87
- package/src/lib/connection_manager/network_monitor.ts +88 -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 +26 -15
- package/src/lib/light_push/light_push.ts +9 -10
- package/src/lib/message/version_0.ts +3 -7
- package/src/lib/message_hash/index.ts +1 -0
- package/src/lib/message_hash/message_hash.ts +106 -0
- package/src/lib/metadata/metadata.ts +8 -5
- package/src/lib/store/rpc.ts +23 -19
- package/src/lib/store/store.ts +22 -11
- package/src/lib/stream_manager/stream_manager.ts +8 -6
- package/bundle/base_protocol-DvQrudwy.js +0 -152
- package/bundle/index-CTo1my9M.js +0 -1543
- package/bundle/lib/base_protocol.js +0 -2
- package/dist/lib/base_protocol.d.ts +0 -18
- package/dist/lib/base_protocol.js +0 -25
- package/dist/lib/base_protocol.js.map +0 -1
- package/src/lib/base_protocol.ts +0 -44
@@ -0,0 +1,195 @@
|
|
1
|
+
import { Peer, PeerId, PeerInfo } from "@libp2p/interface";
|
2
|
+
import { Multiaddr } from "@multiformats/multiaddr";
|
3
|
+
import { Logger } from "@waku/utils";
|
4
|
+
import { Libp2p } from "libp2p";
|
5
|
+
|
6
|
+
import type { ShardReader } from "./shard_reader.js";
|
7
|
+
|
8
|
+
type Libp2pEventHandler<T> = (e: CustomEvent<T>) => void;
|
9
|
+
|
10
|
+
type DiscoveryDialerConstructorOptions = {
|
11
|
+
libp2p: Libp2p;
|
12
|
+
shardReader: ShardReader;
|
13
|
+
};
|
14
|
+
|
15
|
+
interface IDiscoveryDialer {
|
16
|
+
start(): void;
|
17
|
+
stop(): void;
|
18
|
+
}
|
19
|
+
|
20
|
+
const log = new Logger("discovery-dialer");
|
21
|
+
|
22
|
+
/**
|
23
|
+
* This class is responsible for dialing peers that are discovered by the libp2p node.
|
24
|
+
* Managing limits for the peers is out of scope for this class.
|
25
|
+
* Dialing after discovery is needed to identify the peer and get all other information: metadata, protocols, etc.
|
26
|
+
*/
|
27
|
+
export class DiscoveryDialer implements IDiscoveryDialer {
|
28
|
+
private readonly libp2p: Libp2p;
|
29
|
+
private readonly shardReader: ShardReader;
|
30
|
+
|
31
|
+
private dialingInterval: NodeJS.Timeout | null = null;
|
32
|
+
private dialingQueue: PeerId[] = [];
|
33
|
+
private dialHistory: Set<string> = new Set();
|
34
|
+
|
35
|
+
public constructor(options: DiscoveryDialerConstructorOptions) {
|
36
|
+
this.libp2p = options.libp2p;
|
37
|
+
this.shardReader = options.shardReader;
|
38
|
+
|
39
|
+
this.onPeerDiscovery = this.onPeerDiscovery.bind(this);
|
40
|
+
}
|
41
|
+
|
42
|
+
public start(): void {
|
43
|
+
log.info("Starting discovery dialer");
|
44
|
+
|
45
|
+
this.libp2p.addEventListener(
|
46
|
+
"peer:discovery",
|
47
|
+
this.onPeerDiscovery as Libp2pEventHandler<PeerInfo>
|
48
|
+
);
|
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
|
+
}
|
60
|
+
|
61
|
+
public stop(): void {
|
62
|
+
log.info("Stopping discovery dialer");
|
63
|
+
|
64
|
+
this.libp2p.removeEventListener(
|
65
|
+
"peer:discovery",
|
66
|
+
this.onPeerDiscovery as Libp2pEventHandler<PeerInfo>
|
67
|
+
);
|
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
|
+
}
|
78
|
+
|
79
|
+
private async onPeerDiscovery(event: CustomEvent<PeerInfo>): Promise<void> {
|
80
|
+
const peerId = event.detail.id;
|
81
|
+
log.info(`Discovered new peer: ${peerId}`);
|
82
|
+
|
83
|
+
try {
|
84
|
+
const shouldSkip = await this.shouldSkipPeer(peerId);
|
85
|
+
|
86
|
+
if (shouldSkip) {
|
87
|
+
log.info(`Skipping peer: ${peerId}`);
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
|
91
|
+
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
|
+
}
|
102
|
+
} catch (error) {
|
103
|
+
log.error(`Error dialing peer ${peerId}`, error);
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
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
|
+
private async updatePeerStore(
|
145
|
+
peerId: PeerId,
|
146
|
+
multiaddrs: Multiaddr[]
|
147
|
+
): Promise<void> {
|
148
|
+
try {
|
149
|
+
const peer = await this.getPeer(peerId);
|
150
|
+
|
151
|
+
if (!peer) {
|
152
|
+
await this.libp2p.peerStore.save(peerId, {
|
153
|
+
multiaddrs: multiaddrs
|
154
|
+
});
|
155
|
+
return;
|
156
|
+
}
|
157
|
+
|
158
|
+
const hasSameAddr = multiaddrs.every((addr) =>
|
159
|
+
peer.addresses.some((a) => a.multiaddr.equals(addr))
|
160
|
+
);
|
161
|
+
|
162
|
+
if (hasSameAddr) {
|
163
|
+
return;
|
164
|
+
}
|
165
|
+
|
166
|
+
await this.libp2p.peerStore.merge(peerId, {
|
167
|
+
multiaddrs: multiaddrs
|
168
|
+
});
|
169
|
+
} catch (error) {
|
170
|
+
log.error(`Error updating peer store for ${peerId}`, error);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
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
|
+
private async getPeer(peerId: PeerId): Promise<Peer | undefined> {
|
188
|
+
try {
|
189
|
+
return await this.libp2p.peerStore.get(peerId);
|
190
|
+
} catch (error) {
|
191
|
+
log.error(`Error getting peer info for ${peerId}`, error);
|
192
|
+
return undefined;
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import type { PeerId } from "@libp2p/interface";
|
2
|
-
import type { IRelay, Libp2p
|
2
|
+
import type { IEncoder, IRelay, Libp2p } from "@waku/interfaces";
|
3
3
|
import { Logger, pubsubTopicToSingleShardInfo } from "@waku/utils";
|
4
4
|
import { utf8ToBytes } from "@waku/utils/bytes";
|
5
5
|
|
@@ -19,7 +19,12 @@ type CreateKeepAliveManagerOptions = {
|
|
19
19
|
relay?: IRelay;
|
20
20
|
};
|
21
21
|
|
22
|
-
|
22
|
+
interface IKeepAliveManager {
|
23
|
+
start(): void;
|
24
|
+
stop(): void;
|
25
|
+
}
|
26
|
+
|
27
|
+
export class KeepAliveManager implements IKeepAliveManager {
|
23
28
|
private readonly relay?: IRelay;
|
24
29
|
private readonly libp2p: Libp2p;
|
25
30
|
|
@@ -27,7 +32,7 @@ export class KeepAliveManager {
|
|
27
32
|
|
28
33
|
private pingKeepAliveTimers: Map<string, ReturnType<typeof setInterval>> =
|
29
34
|
new Map();
|
30
|
-
private relayKeepAliveTimers: Map<
|
35
|
+
private relayKeepAliveTimers: Map<string, ReturnType<typeof setInterval>[]> =
|
31
36
|
new Map();
|
32
37
|
|
33
38
|
public constructor({
|
@@ -38,122 +43,184 @@ export class KeepAliveManager {
|
|
38
43
|
this.options = options;
|
39
44
|
this.relay = relay;
|
40
45
|
this.libp2p = libp2p;
|
46
|
+
|
47
|
+
this.onPeerConnect = this.onPeerConnect.bind(this);
|
48
|
+
this.onPeerDisconnect = this.onPeerDisconnect.bind(this);
|
41
49
|
}
|
42
50
|
|
43
|
-
public start(
|
44
|
-
|
45
|
-
this.
|
51
|
+
public start(): void {
|
52
|
+
this.libp2p.addEventListener("peer:connect", this.onPeerConnect);
|
53
|
+
this.libp2p.addEventListener("peer:disconnect", this.onPeerDisconnect);
|
54
|
+
}
|
46
55
|
|
47
|
-
|
48
|
-
|
56
|
+
public stop(): void {
|
57
|
+
this.libp2p.removeEventListener("peer:connect", this.onPeerConnect);
|
58
|
+
this.libp2p.removeEventListener("peer:disconnect", this.onPeerDisconnect);
|
49
59
|
|
50
|
-
const
|
60
|
+
for (const timer of this.pingKeepAliveTimers.values()) {
|
61
|
+
clearInterval(timer);
|
62
|
+
}
|
51
63
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
void (async () => {
|
57
|
-
let ping: number;
|
58
|
-
try {
|
59
|
-
// ping the peer for keep alive
|
60
|
-
// also update the peer store with the latency
|
61
|
-
try {
|
62
|
-
ping = await this.libp2p.services.ping.ping(peerId);
|
63
|
-
log.info(`Ping succeeded (${peerIdStr})`, ping);
|
64
|
-
} catch (error) {
|
65
|
-
log.error(`Ping failed for peer (${peerIdStr}).
|
66
|
-
Next ping will be attempted in ${pingPeriodSecs} seconds.
|
67
|
-
`);
|
68
|
-
return;
|
69
|
-
}
|
70
|
-
|
71
|
-
try {
|
72
|
-
await this.libp2p.peerStore.merge(peerId, {
|
73
|
-
metadata: {
|
74
|
-
ping: utf8ToBytes(ping.toString())
|
75
|
-
}
|
76
|
-
});
|
77
|
-
} catch (e) {
|
78
|
-
log.error("Failed to update ping", e);
|
79
|
-
}
|
80
|
-
} catch (e) {
|
81
|
-
log.error(`Ping failed (${peerIdStr})`, e);
|
82
|
-
}
|
83
|
-
})();
|
84
|
-
}, pingPeriodSecs * 1000);
|
85
|
-
|
86
|
-
this.pingKeepAliveTimers.set(peerIdStr, interval);
|
64
|
+
for (const timerArray of this.relayKeepAliveTimers.values()) {
|
65
|
+
for (const timer of timerArray) {
|
66
|
+
clearInterval(timer);
|
67
|
+
}
|
87
68
|
}
|
88
69
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
70
|
+
this.pingKeepAliveTimers.clear();
|
71
|
+
this.relayKeepAliveTimers.clear();
|
72
|
+
}
|
73
|
+
|
74
|
+
private onPeerConnect(evt: CustomEvent<PeerId>): void {
|
75
|
+
const peerId = evt.detail;
|
76
|
+
this.startPingForPeer(peerId);
|
77
|
+
}
|
78
|
+
|
79
|
+
private onPeerDisconnect(evt: CustomEvent<PeerId>): void {
|
80
|
+
const peerId = evt.detail;
|
81
|
+
this.stopPingForPeer(peerId);
|
82
|
+
}
|
83
|
+
|
84
|
+
private startPingForPeer(peerId: PeerId): void {
|
85
|
+
// Just in case a timer already exists for this peer
|
86
|
+
this.stopPingForPeer(peerId);
|
87
|
+
|
88
|
+
this.startLibp2pPing(peerId);
|
89
|
+
this.startRelayPing(peerId);
|
90
|
+
}
|
91
|
+
|
92
|
+
private stopPingForPeer(peerId: PeerId): void {
|
93
|
+
this.stopLibp2pPing(peerId);
|
94
|
+
this.stopRelayPing(peerId);
|
95
|
+
}
|
96
|
+
|
97
|
+
private startLibp2pPing(peerId: PeerId): void {
|
98
|
+
if (this.options.pingKeepAlive === 0) {
|
99
|
+
log.warn(
|
100
|
+
`Ping keep alive is disabled pingKeepAlive:${this.options.pingKeepAlive}, skipping start for libp2p ping`
|
95
101
|
);
|
96
|
-
|
102
|
+
return;
|
97
103
|
}
|
98
|
-
}
|
99
104
|
|
100
|
-
public stop(peerId: PeerId): void {
|
101
105
|
const peerIdStr = peerId.toString();
|
102
106
|
|
103
107
|
if (this.pingKeepAliveTimers.has(peerIdStr)) {
|
104
|
-
|
105
|
-
|
108
|
+
log.warn(
|
109
|
+
`Ping already started for peer: ${peerIdStr}, skipping start for libp2p ping`
|
110
|
+
);
|
111
|
+
return;
|
106
112
|
}
|
107
113
|
|
108
|
-
|
109
|
-
this.
|
110
|
-
|
111
|
-
|
114
|
+
const interval = setInterval(() => {
|
115
|
+
void this.pingLibp2p(peerId);
|
116
|
+
}, this.options.pingKeepAlive * 1000);
|
117
|
+
|
118
|
+
this.pingKeepAliveTimers.set(peerIdStr, interval);
|
112
119
|
}
|
113
120
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
121
|
+
private stopLibp2pPing(peerId: PeerId): void {
|
122
|
+
const peerIdStr = peerId.toString();
|
123
|
+
|
124
|
+
if (!this.pingKeepAliveTimers.has(peerIdStr)) {
|
125
|
+
log.warn(
|
126
|
+
`Ping not started for peer: ${peerIdStr}, skipping stop for ping`
|
127
|
+
);
|
128
|
+
return;
|
120
129
|
}
|
121
130
|
|
122
|
-
this.pingKeepAliveTimers.
|
123
|
-
this.
|
131
|
+
clearInterval(this.pingKeepAliveTimers.get(peerIdStr));
|
132
|
+
this.pingKeepAliveTimers.delete(peerIdStr);
|
124
133
|
}
|
125
134
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
135
|
+
private startRelayPing(peerId: PeerId): void {
|
136
|
+
if (!this.relay) {
|
137
|
+
return;
|
138
|
+
}
|
139
|
+
|
140
|
+
if (this.options.relayKeepAlive === 0) {
|
141
|
+
log.warn(
|
142
|
+
`Relay keep alive is disabled relayKeepAlive:${this.options.relayKeepAlive}, skipping start for relay ping`
|
143
|
+
);
|
144
|
+
return;
|
145
|
+
}
|
146
|
+
|
147
|
+
if (this.relayKeepAliveTimers.has(peerId.toString())) {
|
148
|
+
log.warn(
|
149
|
+
`Relay ping already started for peer: ${peerId.toString()}, skipping start for relay ping`
|
150
|
+
);
|
151
|
+
return;
|
152
|
+
}
|
131
153
|
|
132
|
-
private scheduleRelayPings(
|
133
|
-
relay: IRelay,
|
134
|
-
relayPeriodSecs: number,
|
135
|
-
peerIdStr: PeerIdStr
|
136
|
-
): NodeJS.Timeout[] {
|
137
|
-
// send a ping message to each PubsubTopic the peer is part of
|
138
154
|
const intervals: NodeJS.Timeout[] = [];
|
139
|
-
|
140
|
-
|
141
|
-
|
155
|
+
|
156
|
+
for (const topic of this.relay.pubsubTopics) {
|
157
|
+
const meshPeers = this.relay.getMeshPeers(topic);
|
158
|
+
|
159
|
+
if (!meshPeers.includes(peerId.toString())) {
|
160
|
+
log.warn(
|
161
|
+
`Peer: ${peerId.toString()} is not in the mesh for topic: ${topic}, skipping start for relay ping`
|
162
|
+
);
|
163
|
+
continue;
|
164
|
+
}
|
142
165
|
|
143
166
|
const encoder = createEncoder({
|
144
167
|
pubsubTopicShardInfo: pubsubTopicToSingleShardInfo(topic),
|
145
168
|
contentTopic: RelayPingContentTopic,
|
146
169
|
ephemeral: true
|
147
170
|
});
|
171
|
+
|
148
172
|
const interval = setInterval(() => {
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
.catch((e) => log.error("Failed to send relay ping", e));
|
153
|
-
}, relayPeriodSecs * 1000);
|
173
|
+
void this.pingRelay(encoder);
|
174
|
+
}, this.options.relayKeepAlive * 1000);
|
175
|
+
|
154
176
|
intervals.push(interval);
|
155
177
|
}
|
156
178
|
|
157
|
-
|
179
|
+
this.relayKeepAliveTimers.set(peerId.toString(), intervals);
|
180
|
+
}
|
181
|
+
|
182
|
+
private stopRelayPing(peerId: PeerId): void {
|
183
|
+
if (!this.relay) {
|
184
|
+
return;
|
185
|
+
}
|
186
|
+
|
187
|
+
const peerIdStr = peerId.toString();
|
188
|
+
|
189
|
+
if (!this.relayKeepAliveTimers.has(peerIdStr)) {
|
190
|
+
log.warn(
|
191
|
+
`Relay ping not started for peer: ${peerIdStr}, skipping stop for relay ping`
|
192
|
+
);
|
193
|
+
return;
|
194
|
+
}
|
195
|
+
|
196
|
+
this.relayKeepAliveTimers.get(peerIdStr)?.map(clearInterval);
|
197
|
+
this.relayKeepAliveTimers.delete(peerIdStr);
|
198
|
+
}
|
199
|
+
|
200
|
+
private async pingRelay(encoder: IEncoder): Promise<void> {
|
201
|
+
try {
|
202
|
+
log.info("Sending Waku Relay ping message");
|
203
|
+
await this.relay!.send(encoder, { payload: new Uint8Array([1]) });
|
204
|
+
} catch (e) {
|
205
|
+
log.error("Failed to send relay ping", e);
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
private async pingLibp2p(peerId: PeerId): Promise<void> {
|
210
|
+
try {
|
211
|
+
log.info(`Pinging libp2p peer (${peerId.toString()})`);
|
212
|
+
const ping = await this.libp2p.services.ping.ping(peerId);
|
213
|
+
|
214
|
+
log.info(`Ping succeeded (${peerId.toString()})`, ping);
|
215
|
+
|
216
|
+
await this.libp2p.peerStore.merge(peerId, {
|
217
|
+
metadata: {
|
218
|
+
ping: utf8ToBytes(ping.toString())
|
219
|
+
}
|
220
|
+
});
|
221
|
+
log.info(`Ping updated for peer (${peerId.toString()})`);
|
222
|
+
} catch (e) {
|
223
|
+
log.error(`Ping failed for peer (${peerId.toString()})`, e);
|
224
|
+
}
|
158
225
|
}
|
159
226
|
}
|
@@ -0,0 +1,88 @@
|
|
1
|
+
import { IWakuEventEmitter, Libp2p } from "@waku/interfaces";
|
2
|
+
|
3
|
+
type NetworkMonitorConstructorOptions = {
|
4
|
+
libp2p: Libp2p;
|
5
|
+
events: IWakuEventEmitter;
|
6
|
+
};
|
7
|
+
|
8
|
+
interface INetworkMonitor {
|
9
|
+
start(): void;
|
10
|
+
stop(): void;
|
11
|
+
}
|
12
|
+
|
13
|
+
export class NetworkMonitor implements INetworkMonitor {
|
14
|
+
private readonly libp2p: Libp2p;
|
15
|
+
private readonly events: IWakuEventEmitter;
|
16
|
+
|
17
|
+
private isNetworkConnected: boolean = false;
|
18
|
+
|
19
|
+
public constructor(options: NetworkMonitorConstructorOptions) {
|
20
|
+
this.libp2p = options.libp2p;
|
21
|
+
this.events = options.events;
|
22
|
+
|
23
|
+
this.onConnectedEvent = this.onConnectedEvent.bind(this);
|
24
|
+
this.onDisconnectedEvent = this.onDisconnectedEvent.bind(this);
|
25
|
+
this.dispatchNetworkEvent = this.dispatchNetworkEvent.bind(this);
|
26
|
+
}
|
27
|
+
|
28
|
+
public start(): void {
|
29
|
+
this.libp2p.addEventListener("peer:connect", this.onConnectedEvent);
|
30
|
+
this.libp2p.addEventListener("peer:disconnect", this.onDisconnectedEvent);
|
31
|
+
|
32
|
+
try {
|
33
|
+
globalThis.addEventListener("online", this.dispatchNetworkEvent);
|
34
|
+
globalThis.addEventListener("offline", this.dispatchNetworkEvent);
|
35
|
+
} catch (err) {
|
36
|
+
// ignore
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
public stop(): void {
|
41
|
+
this.libp2p.removeEventListener("peer:connect", this.onConnectedEvent);
|
42
|
+
this.libp2p.removeEventListener(
|
43
|
+
"peer:disconnect",
|
44
|
+
this.onDisconnectedEvent
|
45
|
+
);
|
46
|
+
|
47
|
+
try {
|
48
|
+
globalThis.removeEventListener("online", this.dispatchNetworkEvent);
|
49
|
+
globalThis.removeEventListener("offline", this.dispatchNetworkEvent);
|
50
|
+
} catch (err) {
|
51
|
+
// ignore
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
public isConnected(): boolean {
|
56
|
+
try {
|
57
|
+
if (globalThis?.navigator && !globalThis?.navigator?.onLine) {
|
58
|
+
return false;
|
59
|
+
}
|
60
|
+
} catch (err) {
|
61
|
+
// ignore
|
62
|
+
}
|
63
|
+
|
64
|
+
return this.isNetworkConnected;
|
65
|
+
}
|
66
|
+
|
67
|
+
private onConnectedEvent(): void {
|
68
|
+
if (!this.isNetworkConnected) {
|
69
|
+
this.isNetworkConnected = true;
|
70
|
+
this.dispatchNetworkEvent();
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
private onDisconnectedEvent(): void {
|
75
|
+
if (this.isNetworkConnected && this.libp2p.getConnections().length === 0) {
|
76
|
+
this.isNetworkConnected = false;
|
77
|
+
this.dispatchNetworkEvent();
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
private dispatchNetworkEvent(): void {
|
82
|
+
this.events.dispatchEvent(
|
83
|
+
new CustomEvent<boolean>("waku:connection", {
|
84
|
+
detail: this.isConnected()
|
85
|
+
})
|
86
|
+
);
|
87
|
+
}
|
88
|
+
}
|