Skip to content

Commit a8d198f

Browse files
committed
feat: track node connection state
1 parent 535a748 commit a8d198f

File tree

4 files changed

+122
-2
lines changed

4 files changed

+122
-2
lines changed

packages/core/src/lib/connection_manager.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,25 @@ export class ConnectionManager
4040

4141
private currentActiveParallelDialCount = 0;
4242
private pendingPeerDialQueue: Array<PeerId> = [];
43+
private online: boolean = false;
44+
45+
public isConnected(): boolean {
46+
return this.online;
47+
}
48+
49+
private toggleOnline(): void {
50+
if (!this.online) {
51+
this.online = true;
52+
this.dispatchEvent(new CustomEvent(EPeersByDiscoveryEvents.NODE_ONLINE));
53+
}
54+
}
55+
56+
private toggleOffline(): void {
57+
if (this.libp2p.getPeers().length == 0) {
58+
this.online = false;
59+
this.dispatchEvent(new CustomEvent(EPeersByDiscoveryEvents.NODE_OFFLINE));
60+
}
61+
}
4362

4463
public static create(
4564
peerId: string,
@@ -393,11 +412,13 @@ export class ConnectionManager
393412
)
394413
);
395414
}
415+
this.toggleOnline();
396416
})();
397417
},
398418
"peer:disconnect": () => {
399419
return (evt: CustomEvent<PeerId>): void => {
400420
this.keepAliveManager.stop(evt.detail);
421+
this.toggleOffline();
401422
};
402423
}
403424
};
@@ -427,7 +448,7 @@ export class ConnectionManager
427448
log.warn(
428449
`Discovered peer ${peerId.toString()} with ShardInfo ${shardInfo} is not part of any of the configured pubsub topics (${
429450
this.configuredPubSubTopics
430-
}).
451+
}).
431452
Not dialing.`
432453
);
433454
return false;

packages/core/src/lib/waku.ts

+4
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ export class WakuNode implements Waku {
178178
return this.libp2p.isStarted();
179179
}
180180

181+
isConnected(): boolean {
182+
return this.connectionManager.isConnected();
183+
}
184+
181185
/**
182186
* Return the local multiaddr with peer id on which libp2p is listening.
183187
*

packages/interfaces/src/connection_manager.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,18 @@ export enum EPeersByDiscoveryEvents {
2828
PEER_DISCOVERY_BOOTSTRAP = "peer:discovery:bootstrap",
2929
PEER_DISCOVERY_PEER_EXCHANGE = "peer:discovery:peer-exchange",
3030
PEER_CONNECT_BOOTSTRAP = "peer:connected:bootstrap",
31-
PEER_CONNECT_PEER_EXCHANGE = "peer:connected:peer-exchange"
31+
PEER_CONNECT_PEER_EXCHANGE = "peer:connected:peer-exchange",
32+
NODE_ONLINE = "waku:online",
33+
NODE_OFFLINE = "waku:offline"
3234
}
3335

3436
export interface IPeersByDiscoveryEvents {
3537
[EPeersByDiscoveryEvents.PEER_DISCOVERY_BOOTSTRAP]: CustomEvent<PeerId>;
3638
[EPeersByDiscoveryEvents.PEER_DISCOVERY_PEER_EXCHANGE]: CustomEvent<PeerId>;
3739
[EPeersByDiscoveryEvents.PEER_CONNECT_BOOTSTRAP]: CustomEvent<PeerId>;
3840
[EPeersByDiscoveryEvents.PEER_CONNECT_PEER_EXCHANGE]: CustomEvent<PeerId>;
41+
[EPeersByDiscoveryEvents.NODE_ONLINE]: CustomEvent<void>;
42+
[EPeersByDiscoveryEvents.NODE_OFFLINE]: CustomEvent<void>;
3943
}
4044

4145
export interface PeersByDiscoveryResult {

packages/tests/tests/connection_manager.spec.ts

+91
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,97 @@ describe("ConnectionManager", function () {
156156
expect(await peerConnectedPeerExchange).to.eq(true);
157157
});
158158
});
159+
it("should emit `waku:online` event only when first peer is connected", async function () {
160+
const peerIdPx = await createSecp256k1PeerId();
161+
162+
await waku.libp2p.peerStore.save(peerIdPx, {
163+
tags: {
164+
[Tags.PEER_EXCHANGE]: {
165+
value: 50,
166+
ttl: 1200000
167+
}
168+
}
169+
});
170+
171+
let eventCount = 0;
172+
const wakuOnline = new Promise<boolean>((resolve) => {
173+
waku.connectionManager.addEventListener(
174+
EPeersByDiscoveryEvents.NODE_ONLINE,
175+
() => {
176+
eventCount++;
177+
resolve(true);
178+
}
179+
);
180+
});
181+
182+
waku.libp2p.dispatchEvent(
183+
new CustomEvent<PeerId>("peer:connect", { detail: peerIdPx })
184+
);
185+
waku.libp2p.dispatchEvent(
186+
new CustomEvent<PeerId>("peer:connect", {
187+
detail: await createSecp256k1PeerId()
188+
})
189+
);
190+
waku.libp2p.dispatchEvent(
191+
new CustomEvent<PeerId>("peer:connect", {
192+
detail: await createSecp256k1PeerId()
193+
})
194+
);
195+
196+
expect(await wakuOnline).to.eq(true);
197+
expect(eventCount).to.be.eq(1);
198+
});
199+
// This test currently fails
200+
it("should emit `waku:offline` event when all peers disconnect", async function () {
201+
const peerIdPx = await createSecp256k1PeerId();
202+
const peerIdPx2 = await createSecp256k1PeerId();
203+
204+
await waku.libp2p.peerStore.save(peerIdPx, {
205+
tags: {
206+
[Tags.PEER_EXCHANGE]: {
207+
value: 50,
208+
ttl: 1200000
209+
}
210+
}
211+
});
212+
213+
await waku.libp2p.peerStore.save(peerIdPx2, {
214+
tags: {
215+
[Tags.PEER_EXCHANGE]: {
216+
value: 50,
217+
ttl: 1200000
218+
}
219+
}
220+
});
221+
222+
let eventCount = 0;
223+
const wakuOffline = new Promise<boolean>((resolve) => {
224+
waku.connectionManager.addEventListener(
225+
EPeersByDiscoveryEvents.NODE_OFFLINE,
226+
() => {
227+
eventCount++;
228+
resolve(true);
229+
}
230+
);
231+
});
232+
233+
waku.libp2p.dispatchEvent(
234+
new CustomEvent<PeerId>("peer:connect", { detail: peerIdPx })
235+
);
236+
waku.libp2p.dispatchEvent(
237+
new CustomEvent<PeerId>("peer:connect", { detail: peerIdPx2 })
238+
);
239+
240+
waku.libp2p.dispatchEvent(
241+
new CustomEvent<PeerId>("peer:disconnect", { detail: peerIdPx })
242+
);
243+
waku.libp2p.dispatchEvent(
244+
new CustomEvent<PeerId>("peer:disconnect", { detail: peerIdPx2 })
245+
);
246+
247+
expect(await wakuOffline).to.eq(true);
248+
expect(eventCount).to.be.eq(1);
249+
});
159250
});
160251

161252
describe("Dials", () => {

0 commit comments

Comments
 (0)