@waku/core 0.0.34-c41b319.0 → 0.0.34-c43cec2.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/{base_protocol-CCK9RCtH.js → base_protocol-DxFKDXX2.js} +20 -19
- package/bundle/{index-Db7LxDrL.js → index-yLOEQnIE.js} +39 -75
- package/bundle/index.js +133 -1815
- package/bundle/lib/base_protocol.js +2 -2
- package/bundle/lib/message/version_0.js +2 -2
- package/bundle/{version_0-ANFNAdFD.js → version_0-Che4t3mN.js} +42 -163
- 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/base_protocol.d.ts +2 -2
- package/dist/lib/base_protocol.js +2 -2
- package/dist/lib/base_protocol.js.map +1 -1
- package/dist/lib/connection_manager/connection_manager.d.ts +3 -56
- package/dist/lib/connection_manager/connection_manager.js +13 -96
- package/dist/lib/connection_manager/connection_manager.js.map +1 -1
- package/dist/lib/filter/index.d.ts +18 -1
- package/dist/lib/filter/index.js +208 -1
- package/dist/lib/filter/index.js.map +1 -1
- package/dist/lib/health_manager.d.ts +14 -0
- package/dist/lib/health_manager.js +70 -0
- package/dist/lib/health_manager.js.map +1 -0
- package/dist/lib/light_push/index.d.ts +15 -1
- package/dist/lib/light_push/index.js +144 -1
- package/dist/lib/light_push/index.js.map +1 -1
- package/dist/lib/metadata/index.d.ts +3 -1
- package/dist/lib/metadata/index.js +118 -1
- package/dist/lib/metadata/index.js.map +1 -1
- package/dist/lib/store/index.d.ts +9 -1
- package/dist/lib/store/index.js +82 -1
- package/dist/lib/store/index.js.map +1 -1
- package/dist/lib/stream_manager/stream_manager.d.ts +2 -2
- package/dist/lib/stream_manager/stream_manager.js +17 -16
- 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/base_protocol.ts +3 -3
- package/src/lib/connection_manager/connection_manager.ts +20 -114
- package/src/lib/filter/index.ts +315 -1
- package/src/lib/health_manager.ts +90 -0
- package/src/lib/light_push/index.ts +189 -1
- package/src/lib/metadata/index.ts +182 -1
- package/src/lib/store/index.ts +136 -1
- package/src/lib/stream_manager/stream_manager.ts +18 -16
- package/dist/lib/filter/filter.d.ts +0 -18
- package/dist/lib/filter/filter.js +0 -209
- package/dist/lib/filter/filter.js.map +0 -1
- package/dist/lib/light_push/light_push.d.ts +0 -15
- package/dist/lib/light_push/light_push.js +0 -144
- package/dist/lib/light_push/light_push.js.map +0 -1
- package/dist/lib/metadata/metadata.d.ts +0 -3
- package/dist/lib/metadata/metadata.js +0 -119
- package/dist/lib/metadata/metadata.js.map +0 -1
- package/dist/lib/store/store.d.ts +0 -9
- package/dist/lib/store/store.js +0 -83
- package/dist/lib/store/store.js.map +0 -1
- package/src/lib/filter/filter.ts +0 -315
- package/src/lib/light_push/light_push.ts +0 -188
- package/src/lib/metadata/metadata.ts +0 -182
- package/src/lib/store/store.ts +0 -136
@@ -1,14 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
|
3
|
-
isPeerId,
|
4
|
-
type Peer,
|
5
|
-
type PeerId,
|
6
|
-
type PeerInfo,
|
7
|
-
type PeerStore,
|
8
|
-
type Stream,
|
9
|
-
TypedEventEmitter
|
10
|
-
} from "@libp2p/interface";
|
11
|
-
import { Multiaddr, multiaddr, MultiaddrInput } from "@multiformats/multiaddr";
|
1
|
+
import type { Peer, PeerId, PeerInfo, PeerStore } from "@libp2p/interface";
|
2
|
+
import { TypedEventEmitter } from "@libp2p/interface";
|
12
3
|
import {
|
13
4
|
ConnectionManagerOptions,
|
14
5
|
DiscoveryTrigger,
|
@@ -239,60 +230,15 @@ export class ConnectionManager
|
|
239
230
|
this.startNetworkStatusListener();
|
240
231
|
}
|
241
232
|
|
242
|
-
|
243
|
-
* Attempts to establish a connection with a peer and set up specified protocols.
|
244
|
-
* The method handles both PeerId and Multiaddr inputs, manages connection attempts,
|
245
|
-
* and maintains the connection state.
|
246
|
-
*
|
247
|
-
* The dialing process includes:
|
248
|
-
* 1. Converting input to dialable peer info
|
249
|
-
* 2. Managing parallel dial attempts
|
250
|
-
* 3. Attempting to establish protocol-specific connections
|
251
|
-
* 4. Handling connection failures and retries
|
252
|
-
* 5. Updating the peer store and connection state
|
253
|
-
*
|
254
|
-
* @param {PeerId | MultiaddrInput} peer - The peer to connect to, either as a PeerId or multiaddr
|
255
|
-
* @param {string[]} [protocolCodecs] - Optional array of protocol-specific codec strings to establish
|
256
|
-
* (e.g., for LightPush, Filter, Store protocols)
|
257
|
-
*
|
258
|
-
* @throws {Error} If the multiaddr is missing a peer ID
|
259
|
-
* @throws {Error} If the maximum dial attempts are reached and the peer cannot be dialed
|
260
|
-
* @throws {Error} If there's an error deleting an undialable peer from the peer store
|
261
|
-
*
|
262
|
-
* @example
|
263
|
-
* ```typescript
|
264
|
-
* // Dial using PeerId
|
265
|
-
* await connectionManager.dialPeer(peerId);
|
266
|
-
*
|
267
|
-
* // Dial using multiaddr with specific protocols
|
268
|
-
* await connectionManager.dialPeer(multiaddr, [
|
269
|
-
* "/vac/waku/relay/2.0.0",
|
270
|
-
* "/vac/waku/lightpush/2.0.0-beta1"
|
271
|
-
* ]);
|
272
|
-
* ```
|
273
|
-
*
|
274
|
-
* @remarks
|
275
|
-
* - The method implements exponential backoff through multiple dial attempts
|
276
|
-
* - Maintains a queue for parallel dial attempts (limited by maxParallelDials)
|
277
|
-
* - Integrates with the KeepAliveManager for connection maintenance
|
278
|
-
* - Updates the peer store and connection state after successful/failed attempts
|
279
|
-
* - If all dial attempts fail, triggers DNS discovery as a fallback
|
280
|
-
*/
|
281
|
-
public async dialPeer(peer: PeerId | MultiaddrInput): Promise<Connection> {
|
282
|
-
let connection: Connection | undefined;
|
283
|
-
let peerId: PeerId | undefined;
|
284
|
-
const peerDialInfo = this.getDialablePeerInfo(peer);
|
285
|
-
const peerIdStr = isPeerId(peerDialInfo)
|
286
|
-
? peerDialInfo.toString()
|
287
|
-
: peerDialInfo.getPeerId()!;
|
288
|
-
|
233
|
+
private async dialPeer(peerId: PeerId): Promise<void> {
|
289
234
|
this.currentActiveParallelDialCount += 1;
|
290
235
|
let dialAttempt = 0;
|
291
236
|
while (dialAttempt < this.options.maxDialAttemptsForPeer) {
|
292
237
|
try {
|
293
|
-
log.info(
|
294
|
-
|
295
|
-
|
238
|
+
log.info(
|
239
|
+
`Dialing peer ${peerId.toString()} on attempt ${dialAttempt + 1}`
|
240
|
+
);
|
241
|
+
await this.libp2p.dial(peerId);
|
296
242
|
|
297
243
|
const tags = await this.getTagNamesForPeer(peerId);
|
298
244
|
// add tag to connection describing discovery mechanism
|
@@ -311,17 +257,21 @@ export class ConnectionManager
|
|
311
257
|
} catch (error) {
|
312
258
|
if (error instanceof AggregateError) {
|
313
259
|
// Handle AggregateError
|
314
|
-
log.error(
|
260
|
+
log.error(
|
261
|
+
`Error dialing peer ${peerId.toString()} - ${error.errors}`
|
262
|
+
);
|
315
263
|
} else {
|
316
264
|
// Handle generic error
|
317
265
|
log.error(
|
318
|
-
`Error dialing peer ${
|
266
|
+
`Error dialing peer ${peerId.toString()} - ${
|
267
|
+
(error as any).message
|
268
|
+
}`
|
319
269
|
);
|
320
270
|
}
|
321
|
-
this.dialErrorsForPeer.set(
|
271
|
+
this.dialErrorsForPeer.set(peerId.toString(), error);
|
322
272
|
|
323
273
|
dialAttempt++;
|
324
|
-
this.dialAttemptsForPeer.set(
|
274
|
+
this.dialAttemptsForPeer.set(peerId.toString(), dialAttempt);
|
325
275
|
}
|
326
276
|
}
|
327
277
|
|
@@ -332,7 +282,7 @@ export class ConnectionManager
|
|
332
282
|
// If max dial attempts reached and dialing failed, delete the peer
|
333
283
|
if (dialAttempt === this.options.maxDialAttemptsForPeer) {
|
334
284
|
try {
|
335
|
-
const error = this.dialErrorsForPeer.get(
|
285
|
+
const error = this.dialErrorsForPeer.get(peerId.toString());
|
336
286
|
|
337
287
|
if (error) {
|
338
288
|
let errorMessage;
|
@@ -349,65 +299,21 @@ export class ConnectionManager
|
|
349
299
|
}
|
350
300
|
|
351
301
|
log.info(
|
352
|
-
`Deleting undialable peer ${
|
302
|
+
`Deleting undialable peer ${peerId.toString()} from peer store. Reason: ${errorMessage}`
|
353
303
|
);
|
354
304
|
}
|
355
305
|
|
356
|
-
this.dialErrorsForPeer.delete(
|
357
|
-
|
358
|
-
await this.libp2p.peerStore.delete(peerId);
|
359
|
-
}
|
306
|
+
this.dialErrorsForPeer.delete(peerId.toString());
|
307
|
+
await this.libp2p.peerStore.delete(peerId);
|
360
308
|
|
361
309
|
// if it was last available peer - attempt DNS discovery
|
362
310
|
await this.attemptDnsDiscovery();
|
363
311
|
} catch (error) {
|
364
312
|
throw new Error(
|
365
|
-
`Error deleting undialable peer ${
|
313
|
+
`Error deleting undialable peer ${peerId.toString()} from peer store - ${error}`
|
366
314
|
);
|
367
315
|
}
|
368
316
|
}
|
369
|
-
|
370
|
-
if (!connection) {
|
371
|
-
throw new Error(`Failed to dial peer ${peerDialInfo}`);
|
372
|
-
}
|
373
|
-
|
374
|
-
return connection;
|
375
|
-
}
|
376
|
-
|
377
|
-
/**
|
378
|
-
* Dial a peer with specific protocols.
|
379
|
-
* This method is a raw proxy to the libp2p dialProtocol method.
|
380
|
-
* @param peer - The peer to connect to, either as a PeerId or multiaddr
|
381
|
-
* @param protocolCodecs - Optional array of protocol-specific codec strings to establish
|
382
|
-
* @returns A stream to the peer
|
383
|
-
*/
|
384
|
-
public async rawDialPeerWithProtocols(
|
385
|
-
peer: PeerId | MultiaddrInput,
|
386
|
-
protocolCodecs: string[]
|
387
|
-
): Promise<Stream> {
|
388
|
-
const peerDialInfo = this.getDialablePeerInfo(peer);
|
389
|
-
return await this.libp2p.dialProtocol(peerDialInfo, protocolCodecs);
|
390
|
-
}
|
391
|
-
|
392
|
-
/**
|
393
|
-
* Internal utility to extract a PeerId or Multiaddr from a peer input.
|
394
|
-
* This is used internally by the connection manager to handle different peer input formats.
|
395
|
-
* @internal
|
396
|
-
*/
|
397
|
-
private getDialablePeerInfo(
|
398
|
-
peer: PeerId | MultiaddrInput
|
399
|
-
): PeerId | Multiaddr {
|
400
|
-
if (isPeerId(peer)) {
|
401
|
-
return peer;
|
402
|
-
} else {
|
403
|
-
// peer is of MultiaddrInput type
|
404
|
-
const ma = multiaddr(peer);
|
405
|
-
const peerIdStr = ma.getPeerId();
|
406
|
-
if (!peerIdStr) {
|
407
|
-
throw new Error("Failed to dial multiaddr: missing peer ID");
|
408
|
-
}
|
409
|
-
return ma;
|
410
|
-
}
|
411
317
|
}
|
412
318
|
|
413
319
|
private async attemptDnsDiscovery(): Promise<void> {
|
package/src/lib/filter/index.ts
CHANGED
@@ -1 +1,315 @@
|
|
1
|
-
|
1
|
+
import type { Peer, Stream } from "@libp2p/interface";
|
2
|
+
import type { IncomingStreamData } from "@libp2p/interface-internal";
|
3
|
+
import {
|
4
|
+
type ContentTopic,
|
5
|
+
type CoreProtocolResult,
|
6
|
+
type IBaseProtocolCore,
|
7
|
+
type Libp2p,
|
8
|
+
ProtocolError,
|
9
|
+
type PubsubTopic
|
10
|
+
} from "@waku/interfaces";
|
11
|
+
import { WakuMessage } from "@waku/proto";
|
12
|
+
import { Logger } from "@waku/utils";
|
13
|
+
import all from "it-all";
|
14
|
+
import * as lp from "it-length-prefixed";
|
15
|
+
import { pipe } from "it-pipe";
|
16
|
+
import { Uint8ArrayList } from "uint8arraylist";
|
17
|
+
|
18
|
+
import { BaseProtocol } from "../base_protocol.js";
|
19
|
+
|
20
|
+
import {
|
21
|
+
FilterPushRpc,
|
22
|
+
FilterSubscribeResponse,
|
23
|
+
FilterSubscribeRpc
|
24
|
+
} from "./filter_rpc.js";
|
25
|
+
|
26
|
+
const log = new Logger("filter:v2");
|
27
|
+
|
28
|
+
export const FilterCodecs = {
|
29
|
+
SUBSCRIBE: "/vac/waku/filter-subscribe/2.0.0-beta1",
|
30
|
+
PUSH: "/vac/waku/filter-push/2.0.0-beta1"
|
31
|
+
};
|
32
|
+
|
33
|
+
export class FilterCore extends BaseProtocol implements IBaseProtocolCore {
|
34
|
+
public constructor(
|
35
|
+
private handleIncomingMessage: (
|
36
|
+
pubsubTopic: PubsubTopic,
|
37
|
+
wakuMessage: WakuMessage,
|
38
|
+
peerIdStr: string
|
39
|
+
) => Promise<void>,
|
40
|
+
public readonly pubsubTopics: PubsubTopic[],
|
41
|
+
libp2p: Libp2p
|
42
|
+
) {
|
43
|
+
super(FilterCodecs.SUBSCRIBE, libp2p.components, pubsubTopics);
|
44
|
+
|
45
|
+
libp2p
|
46
|
+
.handle(FilterCodecs.PUSH, this.onRequest.bind(this), {
|
47
|
+
maxInboundStreams: 100
|
48
|
+
})
|
49
|
+
.catch((e) => {
|
50
|
+
log.error("Failed to register ", FilterCodecs.PUSH, e);
|
51
|
+
});
|
52
|
+
}
|
53
|
+
|
54
|
+
public async subscribe(
|
55
|
+
pubsubTopic: PubsubTopic,
|
56
|
+
peer: Peer,
|
57
|
+
contentTopics: ContentTopic[]
|
58
|
+
): Promise<CoreProtocolResult> {
|
59
|
+
const stream = await this.getStream(peer);
|
60
|
+
|
61
|
+
const request = FilterSubscribeRpc.createSubscribeRequest(
|
62
|
+
pubsubTopic,
|
63
|
+
contentTopics
|
64
|
+
);
|
65
|
+
|
66
|
+
let res: Uint8ArrayList[] | undefined;
|
67
|
+
try {
|
68
|
+
res = await pipe(
|
69
|
+
[request.encode()],
|
70
|
+
lp.encode,
|
71
|
+
stream,
|
72
|
+
lp.decode,
|
73
|
+
async (source) => await all(source)
|
74
|
+
);
|
75
|
+
} catch (error) {
|
76
|
+
log.error("Failed to send subscribe request", error);
|
77
|
+
return {
|
78
|
+
success: null,
|
79
|
+
failure: {
|
80
|
+
error: ProtocolError.GENERIC_FAIL,
|
81
|
+
peerId: peer.id
|
82
|
+
}
|
83
|
+
};
|
84
|
+
}
|
85
|
+
|
86
|
+
const { statusCode, requestId, statusDesc } =
|
87
|
+
FilterSubscribeResponse.decode(res[0].slice());
|
88
|
+
|
89
|
+
if (statusCode < 200 || statusCode >= 300) {
|
90
|
+
log.error(
|
91
|
+
`Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
|
92
|
+
);
|
93
|
+
return {
|
94
|
+
failure: {
|
95
|
+
error: ProtocolError.REMOTE_PEER_REJECTED,
|
96
|
+
peerId: peer.id
|
97
|
+
},
|
98
|
+
success: null
|
99
|
+
};
|
100
|
+
}
|
101
|
+
|
102
|
+
return {
|
103
|
+
failure: null,
|
104
|
+
success: peer.id
|
105
|
+
};
|
106
|
+
}
|
107
|
+
|
108
|
+
public async unsubscribe(
|
109
|
+
pubsubTopic: PubsubTopic,
|
110
|
+
peer: Peer,
|
111
|
+
contentTopics: ContentTopic[]
|
112
|
+
): Promise<CoreProtocolResult> {
|
113
|
+
let stream: Stream | undefined;
|
114
|
+
try {
|
115
|
+
stream = await this.getStream(peer);
|
116
|
+
} catch (error) {
|
117
|
+
log.error(
|
118
|
+
`Failed to get a stream for remote peer${peer.id.toString()}`,
|
119
|
+
error
|
120
|
+
);
|
121
|
+
return {
|
122
|
+
success: null,
|
123
|
+
failure: {
|
124
|
+
error: ProtocolError.NO_STREAM_AVAILABLE,
|
125
|
+
peerId: peer.id
|
126
|
+
}
|
127
|
+
};
|
128
|
+
}
|
129
|
+
|
130
|
+
const unsubscribeRequest = FilterSubscribeRpc.createUnsubscribeRequest(
|
131
|
+
pubsubTopic,
|
132
|
+
contentTopics
|
133
|
+
);
|
134
|
+
|
135
|
+
try {
|
136
|
+
await pipe([unsubscribeRequest.encode()], lp.encode, stream.sink);
|
137
|
+
} catch (error) {
|
138
|
+
log.error("Failed to send unsubscribe request", error);
|
139
|
+
return {
|
140
|
+
success: null,
|
141
|
+
failure: {
|
142
|
+
error: ProtocolError.GENERIC_FAIL,
|
143
|
+
peerId: peer.id
|
144
|
+
}
|
145
|
+
};
|
146
|
+
}
|
147
|
+
|
148
|
+
return {
|
149
|
+
success: peer.id,
|
150
|
+
failure: null
|
151
|
+
};
|
152
|
+
}
|
153
|
+
|
154
|
+
public async unsubscribeAll(
|
155
|
+
pubsubTopic: PubsubTopic,
|
156
|
+
peer: Peer
|
157
|
+
): Promise<CoreProtocolResult> {
|
158
|
+
const stream = await this.getStream(peer);
|
159
|
+
|
160
|
+
const request = FilterSubscribeRpc.createUnsubscribeAllRequest(pubsubTopic);
|
161
|
+
|
162
|
+
const res = await pipe(
|
163
|
+
[request.encode()],
|
164
|
+
lp.encode,
|
165
|
+
stream,
|
166
|
+
lp.decode,
|
167
|
+
async (source) => await all(source)
|
168
|
+
);
|
169
|
+
|
170
|
+
if (!res || !res.length) {
|
171
|
+
return {
|
172
|
+
failure: {
|
173
|
+
error: ProtocolError.NO_RESPONSE,
|
174
|
+
peerId: peer.id
|
175
|
+
},
|
176
|
+
success: null
|
177
|
+
};
|
178
|
+
}
|
179
|
+
|
180
|
+
const { statusCode, requestId, statusDesc } =
|
181
|
+
FilterSubscribeResponse.decode(res[0].slice());
|
182
|
+
|
183
|
+
if (statusCode < 200 || statusCode >= 300) {
|
184
|
+
log.error(
|
185
|
+
`Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
|
186
|
+
);
|
187
|
+
return {
|
188
|
+
failure: {
|
189
|
+
error: ProtocolError.REMOTE_PEER_REJECTED,
|
190
|
+
peerId: peer.id
|
191
|
+
},
|
192
|
+
success: null
|
193
|
+
};
|
194
|
+
}
|
195
|
+
|
196
|
+
return {
|
197
|
+
failure: null,
|
198
|
+
success: peer.id
|
199
|
+
};
|
200
|
+
}
|
201
|
+
|
202
|
+
public async ping(peer: Peer): Promise<CoreProtocolResult> {
|
203
|
+
let stream: Stream | undefined;
|
204
|
+
try {
|
205
|
+
stream = await this.getStream(peer);
|
206
|
+
} catch (error) {
|
207
|
+
log.error(
|
208
|
+
`Failed to get a stream for remote peer${peer.id.toString()}`,
|
209
|
+
error
|
210
|
+
);
|
211
|
+
return {
|
212
|
+
success: null,
|
213
|
+
failure: {
|
214
|
+
error: ProtocolError.NO_STREAM_AVAILABLE,
|
215
|
+
peerId: peer.id
|
216
|
+
}
|
217
|
+
};
|
218
|
+
}
|
219
|
+
|
220
|
+
const request = FilterSubscribeRpc.createSubscriberPingRequest();
|
221
|
+
|
222
|
+
let res: Uint8ArrayList[] | undefined;
|
223
|
+
try {
|
224
|
+
res = await pipe(
|
225
|
+
[request.encode()],
|
226
|
+
lp.encode,
|
227
|
+
stream,
|
228
|
+
lp.decode,
|
229
|
+
async (source) => await all(source)
|
230
|
+
);
|
231
|
+
} catch (error) {
|
232
|
+
log.error("Failed to send ping request", error);
|
233
|
+
return {
|
234
|
+
success: null,
|
235
|
+
failure: {
|
236
|
+
error: ProtocolError.GENERIC_FAIL,
|
237
|
+
peerId: peer.id
|
238
|
+
}
|
239
|
+
};
|
240
|
+
}
|
241
|
+
|
242
|
+
if (!res || !res.length) {
|
243
|
+
return {
|
244
|
+
success: null,
|
245
|
+
failure: {
|
246
|
+
error: ProtocolError.NO_RESPONSE,
|
247
|
+
peerId: peer.id
|
248
|
+
}
|
249
|
+
};
|
250
|
+
}
|
251
|
+
|
252
|
+
const { statusCode, requestId, statusDesc } =
|
253
|
+
FilterSubscribeResponse.decode(res[0].slice());
|
254
|
+
|
255
|
+
if (statusCode < 200 || statusCode >= 300) {
|
256
|
+
log.error(
|
257
|
+
`Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
|
258
|
+
);
|
259
|
+
return {
|
260
|
+
success: null,
|
261
|
+
failure: {
|
262
|
+
error: ProtocolError.REMOTE_PEER_REJECTED,
|
263
|
+
peerId: peer.id
|
264
|
+
}
|
265
|
+
};
|
266
|
+
}
|
267
|
+
return {
|
268
|
+
success: peer.id,
|
269
|
+
failure: null
|
270
|
+
};
|
271
|
+
}
|
272
|
+
|
273
|
+
private onRequest(streamData: IncomingStreamData): void {
|
274
|
+
const { connection, stream } = streamData;
|
275
|
+
const { remotePeer } = connection;
|
276
|
+
log.info(`Received message from ${remotePeer.toString()}`);
|
277
|
+
try {
|
278
|
+
pipe(stream, lp.decode, async (source) => {
|
279
|
+
for await (const bytes of source) {
|
280
|
+
const response = FilterPushRpc.decode(bytes.slice());
|
281
|
+
|
282
|
+
const { pubsubTopic, wakuMessage } = response;
|
283
|
+
|
284
|
+
if (!wakuMessage) {
|
285
|
+
log.error("Received empty message");
|
286
|
+
return;
|
287
|
+
}
|
288
|
+
|
289
|
+
if (!pubsubTopic) {
|
290
|
+
log.error("Pubsub topic missing from push message");
|
291
|
+
return;
|
292
|
+
}
|
293
|
+
|
294
|
+
await this.handleIncomingMessage(
|
295
|
+
pubsubTopic,
|
296
|
+
wakuMessage,
|
297
|
+
connection.remotePeer.toString()
|
298
|
+
);
|
299
|
+
}
|
300
|
+
}).then(
|
301
|
+
() => {
|
302
|
+
log.info("Receiving pipe closed.");
|
303
|
+
},
|
304
|
+
async (e) => {
|
305
|
+
log.error(
|
306
|
+
`Error with receiving pipe on peer:${connection.remotePeer.toString()} -- stream:${stream.id} -- protocol:${stream.protocol}: `,
|
307
|
+
e
|
308
|
+
);
|
309
|
+
}
|
310
|
+
);
|
311
|
+
} catch (e) {
|
312
|
+
log.error("Error decoding message", e);
|
313
|
+
}
|
314
|
+
}
|
315
|
+
}
|
@@ -0,0 +1,90 @@
|
|
1
|
+
import {
|
2
|
+
HealthStatus,
|
3
|
+
type IHealthManager,
|
4
|
+
NodeHealth,
|
5
|
+
type ProtocolHealth,
|
6
|
+
Protocols
|
7
|
+
} from "@waku/interfaces";
|
8
|
+
|
9
|
+
class HealthManager implements IHealthManager {
|
10
|
+
public static instance: HealthManager;
|
11
|
+
private readonly health: NodeHealth;
|
12
|
+
|
13
|
+
private constructor() {
|
14
|
+
this.health = {
|
15
|
+
overallStatus: HealthStatus.Unhealthy,
|
16
|
+
protocolStatuses: new Map()
|
17
|
+
};
|
18
|
+
}
|
19
|
+
|
20
|
+
public static getInstance(): HealthManager {
|
21
|
+
if (!HealthManager.instance) {
|
22
|
+
HealthManager.instance = new HealthManager();
|
23
|
+
}
|
24
|
+
return HealthManager.instance;
|
25
|
+
}
|
26
|
+
|
27
|
+
public getHealthStatus(): HealthStatus {
|
28
|
+
return this.health.overallStatus;
|
29
|
+
}
|
30
|
+
|
31
|
+
public getProtocolStatus(protocol: Protocols): ProtocolHealth | undefined {
|
32
|
+
return this.health.protocolStatuses.get(protocol);
|
33
|
+
}
|
34
|
+
|
35
|
+
public updateProtocolHealth(
|
36
|
+
multicodec: string,
|
37
|
+
connectedPeers: number
|
38
|
+
): void {
|
39
|
+
const protocol = this.getNameFromMulticodec(multicodec);
|
40
|
+
|
41
|
+
let status: HealthStatus = HealthStatus.Unhealthy;
|
42
|
+
if (connectedPeers == 1) {
|
43
|
+
status = HealthStatus.MinimallyHealthy;
|
44
|
+
} else if (connectedPeers >= 2) {
|
45
|
+
status = HealthStatus.SufficientlyHealthy;
|
46
|
+
}
|
47
|
+
|
48
|
+
this.health.protocolStatuses.set(protocol, {
|
49
|
+
name: protocol,
|
50
|
+
status: status,
|
51
|
+
lastUpdate: new Date()
|
52
|
+
});
|
53
|
+
|
54
|
+
this.updateOverallHealth();
|
55
|
+
}
|
56
|
+
|
57
|
+
private getNameFromMulticodec(multicodec: string): Protocols {
|
58
|
+
let name: Protocols;
|
59
|
+
if (multicodec.includes("filter")) {
|
60
|
+
name = Protocols.Filter;
|
61
|
+
} else if (multicodec.includes("lightpush")) {
|
62
|
+
name = Protocols.LightPush;
|
63
|
+
} else if (multicodec.includes("store")) {
|
64
|
+
name = Protocols.Store;
|
65
|
+
} else {
|
66
|
+
throw new Error(`Unknown protocol: ${multicodec}`);
|
67
|
+
}
|
68
|
+
return name;
|
69
|
+
}
|
70
|
+
|
71
|
+
private updateOverallHealth(): void {
|
72
|
+
const relevantProtocols = [Protocols.LightPush, Protocols.Filter];
|
73
|
+
const statuses = relevantProtocols.map(
|
74
|
+
(p) => this.getProtocolStatus(p)?.status
|
75
|
+
);
|
76
|
+
|
77
|
+
if (statuses.some((status) => status === HealthStatus.Unhealthy)) {
|
78
|
+
this.health.overallStatus = HealthStatus.Unhealthy;
|
79
|
+
} else if (
|
80
|
+
statuses.some((status) => status === HealthStatus.MinimallyHealthy)
|
81
|
+
) {
|
82
|
+
this.health.overallStatus = HealthStatus.MinimallyHealthy;
|
83
|
+
} else {
|
84
|
+
this.health.overallStatus = HealthStatus.SufficientlyHealthy;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
export const getHealthManager = (): HealthManager =>
|
90
|
+
HealthManager.getInstance();
|