@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
package/bundle/index.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { e as equals$2, c as coerce, b as base32, a as base58btc, d as base36, v as version_0, f as allocUnsafe, g as alloc, h as encodingLength$1, i as encode$3, j as decode$4, L as Logger, F as FilterSubscribeRequest, k as FilterSubscribeResponse$1, M as MessagePush, P as ProtocolError, l as PushRpc$1, m as PushResponse, S as StoreQueryRequest$1, n as StoreQueryResponse$1, T as Tags, o as createEncoder, p as pubsubTopicToSingleShardInfo, u as utf8ToBytes, q as contentTopicToShardIndex, t as toString, r as fromString, s as hexToBytes, w as isBytes, x as abytes, y as bytesToHex, z as concatBytes, A as anumber, B as randomBytes, C as sha512, D as enumeration, E as message, G as encodeMessage, H as decodeMessage, I as Hash, J as ahash, K as toBytes, N as clean, O as aexists, Q as sha256$1, R as bases, U as base64url, V as encodeUint8Array, W as bytesToUtf8, X as WakuMetadataRequest, Y as pubsubTopicsToShardInfo, Z as WakuMetadataResponse, _ as concat$1, $ as sha256$2, a0 as bytesToHex$1, a1 as numberToBytes } from './version_0-
|
2
|
-
export { a2 as createDecoder } from './version_0-
|
1
|
+
import { e as equals$2, c as coerce, b as base32, a as base58btc, d as base36, v as version_0, f as allocUnsafe, g as alloc, h as encodingLength$1, i as encode$3, j as decode$4, L as Logger, F as FilterSubscribeRequest, k as FilterSubscribeResponse$1, M as MessagePush, P as ProtocolError, l as PushRpc$1, m as PushResponse, S as StoreQueryRequest$1, n as StoreQueryResponse$1, T as Tags, o as createEncoder, p as pubsubTopicToSingleShardInfo, u as utf8ToBytes, q as contentTopicToShardIndex, t as toString, r as fromString, s as hexToBytes, w as isBytes, x as abytes, y as bytesToHex, z as concatBytes, A as anumber, B as randomBytes, C as sha512, D as enumeration, E as message, G as encodeMessage, H as decodeMessage, I as Hash, J as ahash, K as toBytes, N as clean, O as aexists, Q as sha256$1, R as bases, U as base64url, V as encodeUint8Array, W as bytesToUtf8, X as WakuMetadataRequest, Y as pubsubTopicsToShardInfo, Z as WakuMetadataResponse, _ as concat$1, $ as sha256$2, a0 as bytesToHex$1, a1 as numberToBytes } from './version_0-BpF0pNhc.js';
|
2
|
+
export { a2 as createDecoder } from './version_0-BpF0pNhc.js';
|
3
3
|
|
4
4
|
/* eslint-disable */
|
5
5
|
var encode_1 = encode$2;
|
@@ -2478,7 +2478,7 @@ class FilterSubscribeResponse {
|
|
2478
2478
|
}
|
2479
2479
|
}
|
2480
2480
|
|
2481
|
-
const log$
|
2481
|
+
const log$9 = new Logger("filter-core");
|
2482
2482
|
const FilterCodecs = {
|
2483
2483
|
SUBSCRIBE: "/vac/waku/filter-subscribe/2.0.0-beta1",
|
2484
2484
|
PUSH: "/vac/waku/filter-push/2.0.0-beta1"
|
@@ -2495,7 +2495,7 @@ class FilterCore {
|
|
2495
2495
|
maxInboundStreams: 100
|
2496
2496
|
})
|
2497
2497
|
.catch((e) => {
|
2498
|
-
log$
|
2498
|
+
log$9.error("Failed to register ", FilterCodecs.PUSH, e);
|
2499
2499
|
});
|
2500
2500
|
}
|
2501
2501
|
async subscribe(pubsubTopic, peerId, contentTopics) {
|
@@ -2509,7 +2509,7 @@ class FilterCore {
|
|
2509
2509
|
}
|
2510
2510
|
}
|
2511
2511
|
catch (error) {
|
2512
|
-
log$
|
2512
|
+
log$9.error("Failed to send subscribe request", error);
|
2513
2513
|
return {
|
2514
2514
|
success: null,
|
2515
2515
|
failure: {
|
@@ -2520,7 +2520,7 @@ class FilterCore {
|
|
2520
2520
|
}
|
2521
2521
|
const { statusCode, requestId, statusDesc } = FilterSubscribeResponse.decode(res[0].slice());
|
2522
2522
|
if (statusCode < 200 || statusCode >= 300) {
|
2523
|
-
log$
|
2523
|
+
log$9.error(`Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
|
2524
2524
|
return {
|
2525
2525
|
failure: {
|
2526
2526
|
error: ProtocolError.REMOTE_PEER_REJECTED,
|
@@ -2540,7 +2540,7 @@ class FilterCore {
|
|
2540
2540
|
stream = await this.streamManager.getStream(peerId);
|
2541
2541
|
}
|
2542
2542
|
catch (error) {
|
2543
|
-
log$
|
2543
|
+
log$9.error(`Failed to get a stream for remote peer${peerId.toString()}`, error);
|
2544
2544
|
return {
|
2545
2545
|
success: null,
|
2546
2546
|
failure: {
|
@@ -2554,7 +2554,7 @@ class FilterCore {
|
|
2554
2554
|
await pipe([unsubscribeRequest.encode()], encode, stream.sink);
|
2555
2555
|
}
|
2556
2556
|
catch (error) {
|
2557
|
-
log$
|
2557
|
+
log$9.error("Failed to send unsubscribe request", error);
|
2558
2558
|
return {
|
2559
2559
|
success: null,
|
2560
2560
|
failure: {
|
@@ -2583,7 +2583,7 @@ class FilterCore {
|
|
2583
2583
|
}
|
2584
2584
|
const { statusCode, requestId, statusDesc } = FilterSubscribeResponse.decode(res[0].slice());
|
2585
2585
|
if (statusCode < 200 || statusCode >= 300) {
|
2586
|
-
log$
|
2586
|
+
log$9.error(`Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
|
2587
2587
|
return {
|
2588
2588
|
failure: {
|
2589
2589
|
error: ProtocolError.REMOTE_PEER_REJECTED,
|
@@ -2603,7 +2603,7 @@ class FilterCore {
|
|
2603
2603
|
stream = await this.streamManager.getStream(peerId);
|
2604
2604
|
}
|
2605
2605
|
catch (error) {
|
2606
|
-
log$
|
2606
|
+
log$9.error(`Failed to get a stream for remote peer${peerId.toString()}`, error);
|
2607
2607
|
return {
|
2608
2608
|
success: null,
|
2609
2609
|
failure: {
|
@@ -2618,7 +2618,7 @@ class FilterCore {
|
|
2618
2618
|
res = await pipe([request.encode()], encode, stream, decode, async (source) => await all(source));
|
2619
2619
|
}
|
2620
2620
|
catch (error) {
|
2621
|
-
log$
|
2621
|
+
log$9.error("Failed to send ping request", error);
|
2622
2622
|
return {
|
2623
2623
|
success: null,
|
2624
2624
|
failure: {
|
@@ -2638,7 +2638,7 @@ class FilterCore {
|
|
2638
2638
|
}
|
2639
2639
|
const { statusCode, requestId, statusDesc } = FilterSubscribeResponse.decode(res[0].slice());
|
2640
2640
|
if (statusCode < 200 || statusCode >= 300) {
|
2641
|
-
log$
|
2641
|
+
log$9.error(`Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
|
2642
2642
|
return {
|
2643
2643
|
success: null,
|
2644
2644
|
failure: {
|
@@ -2655,30 +2655,30 @@ class FilterCore {
|
|
2655
2655
|
onRequest(streamData) {
|
2656
2656
|
const { connection, stream } = streamData;
|
2657
2657
|
const { remotePeer } = connection;
|
2658
|
-
log$
|
2658
|
+
log$9.info(`Received message from ${remotePeer.toString()}`);
|
2659
2659
|
try {
|
2660
2660
|
pipe(stream, decode, async (source) => {
|
2661
2661
|
for await (const bytes of source) {
|
2662
2662
|
const response = FilterPushRpc.decode(bytes.slice());
|
2663
2663
|
const { pubsubTopic, wakuMessage } = response;
|
2664
2664
|
if (!wakuMessage) {
|
2665
|
-
log$
|
2665
|
+
log$9.error("Received empty message");
|
2666
2666
|
return;
|
2667
2667
|
}
|
2668
2668
|
if (!pubsubTopic) {
|
2669
|
-
log$
|
2669
|
+
log$9.error("Pubsub topic missing from push message");
|
2670
2670
|
return;
|
2671
2671
|
}
|
2672
2672
|
await this.handleIncomingMessage(pubsubTopic, wakuMessage, connection.remotePeer.toString());
|
2673
2673
|
}
|
2674
2674
|
}).then(() => {
|
2675
|
-
log$
|
2675
|
+
log$9.info("Receiving pipe closed.");
|
2676
2676
|
}, async (e) => {
|
2677
|
-
log$
|
2677
|
+
log$9.error(`Error with receiving pipe on peer:${connection.remotePeer.toString()} -- stream:${stream.id} -- protocol:${stream.protocol}: `, e);
|
2678
2678
|
});
|
2679
2679
|
}
|
2680
2680
|
catch (e) {
|
2681
|
-
log$
|
2681
|
+
log$9.error("Error decoding message", e);
|
2682
2682
|
}
|
2683
2683
|
}
|
2684
2684
|
}
|
@@ -2737,7 +2737,7 @@ const isRLNResponseError = (info) => {
|
|
2737
2737
|
info.includes(RLN_REMOTE_VALIDATION));
|
2738
2738
|
};
|
2739
2739
|
|
2740
|
-
const log$
|
2740
|
+
const log$8 = new Logger("light-push");
|
2741
2741
|
const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1";
|
2742
2742
|
/**
|
2743
2743
|
* Implements the [Waku v2 Light Push protocol](https://rfc.vac.dev/spec/19/).
|
@@ -2751,16 +2751,16 @@ class LightPushCore {
|
|
2751
2751
|
async preparePushMessage(encoder, message) {
|
2752
2752
|
try {
|
2753
2753
|
if (!message.payload || message.payload.length === 0) {
|
2754
|
-
log$
|
2754
|
+
log$8.error("Failed to send waku light push: payload is empty");
|
2755
2755
|
return { query: null, error: ProtocolError.EMPTY_PAYLOAD };
|
2756
2756
|
}
|
2757
2757
|
if (!(await isMessageSizeUnderCap(encoder, message))) {
|
2758
|
-
log$
|
2758
|
+
log$8.error("Failed to send waku light push: message is bigger than 1MB");
|
2759
2759
|
return { query: null, error: ProtocolError.SIZE_TOO_BIG };
|
2760
2760
|
}
|
2761
2761
|
const protoMessage = await encoder.toProtoObj(message);
|
2762
2762
|
if (!protoMessage) {
|
2763
|
-
log$
|
2763
|
+
log$8.error("Failed to encode to protoMessage, aborting push");
|
2764
2764
|
return {
|
2765
2765
|
query: null,
|
2766
2766
|
error: ProtocolError.ENCODE_FAILED
|
@@ -2770,7 +2770,7 @@ class LightPushCore {
|
|
2770
2770
|
return { query, error: null };
|
2771
2771
|
}
|
2772
2772
|
catch (error) {
|
2773
|
-
log$
|
2773
|
+
log$8.error("Failed to prepare push message", error);
|
2774
2774
|
return {
|
2775
2775
|
query: null,
|
2776
2776
|
error: ProtocolError.GENERIC_FAIL
|
@@ -2793,7 +2793,7 @@ class LightPushCore {
|
|
2793
2793
|
stream = await this.streamManager.getStream(peerId);
|
2794
2794
|
}
|
2795
2795
|
catch (error) {
|
2796
|
-
log$
|
2796
|
+
log$8.error("Failed to get stream", error);
|
2797
2797
|
return {
|
2798
2798
|
success: null,
|
2799
2799
|
failure: {
|
@@ -2808,7 +2808,7 @@ class LightPushCore {
|
|
2808
2808
|
}
|
2809
2809
|
catch (err) {
|
2810
2810
|
// can fail only because of `stream` abortion
|
2811
|
-
log$
|
2811
|
+
log$8.error("Failed to send waku light push request", err);
|
2812
2812
|
return {
|
2813
2813
|
success: null,
|
2814
2814
|
failure: {
|
@@ -2826,7 +2826,7 @@ class LightPushCore {
|
|
2826
2826
|
response = PushRpc.decode(bytes).response;
|
2827
2827
|
}
|
2828
2828
|
catch (err) {
|
2829
|
-
log$
|
2829
|
+
log$8.error("Failed to decode push reply", err);
|
2830
2830
|
return {
|
2831
2831
|
success: null,
|
2832
2832
|
failure: {
|
@@ -2836,7 +2836,7 @@ class LightPushCore {
|
|
2836
2836
|
};
|
2837
2837
|
}
|
2838
2838
|
if (!response) {
|
2839
|
-
log$
|
2839
|
+
log$8.error("Remote peer fault: No response in PushRPC");
|
2840
2840
|
return {
|
2841
2841
|
success: null,
|
2842
2842
|
failure: {
|
@@ -2846,7 +2846,7 @@ class LightPushCore {
|
|
2846
2846
|
};
|
2847
2847
|
}
|
2848
2848
|
if (isRLNResponseError(response.info)) {
|
2849
|
-
log$
|
2849
|
+
log$8.error("Remote peer fault: RLN generation");
|
2850
2850
|
return {
|
2851
2851
|
success: null,
|
2852
2852
|
failure: {
|
@@ -2856,7 +2856,7 @@ class LightPushCore {
|
|
2856
2856
|
};
|
2857
2857
|
}
|
2858
2858
|
if (!response.isSuccess) {
|
2859
|
-
log$
|
2859
|
+
log$8.error("Remote peer rejected the message: ", response.info);
|
2860
2860
|
return {
|
2861
2861
|
success: null,
|
2862
2862
|
failure: {
|
@@ -2967,7 +2967,7 @@ class StoreQueryResponse {
|
|
2967
2967
|
}
|
2968
2968
|
}
|
2969
2969
|
|
2970
|
-
const log$
|
2970
|
+
const log$7 = new Logger("store");
|
2971
2971
|
const StoreCodec = "/vac/waku/store-query/3.0.0";
|
2972
2972
|
class StoreCore {
|
2973
2973
|
streamManager;
|
@@ -2990,7 +2990,7 @@ class StoreCore {
|
|
2990
2990
|
...queryOpts,
|
2991
2991
|
paginationCursor: currentCursor
|
2992
2992
|
});
|
2993
|
-
log$
|
2993
|
+
log$7.info("Sending store query request:", {
|
2994
2994
|
hasMessageHashes: !!queryOpts.messageHashes?.length,
|
2995
2995
|
messageHashCount: queryOpts.messageHashes?.length,
|
2996
2996
|
pubsubTopic: queryOpts.pubsubTopic,
|
@@ -3001,7 +3001,7 @@ class StoreCore {
|
|
3001
3001
|
stream = await this.streamManager.getStream(peerId);
|
3002
3002
|
}
|
3003
3003
|
catch (e) {
|
3004
|
-
log$
|
3004
|
+
log$7.error("Failed to get stream", e);
|
3005
3005
|
break;
|
3006
3006
|
}
|
3007
3007
|
const res = await pipe([storeQueryRequest.encode()], encode, stream, decode, async (source) => await all(source));
|
@@ -3013,14 +3013,14 @@ class StoreCore {
|
|
3013
3013
|
if (!storeQueryResponse.statusCode ||
|
3014
3014
|
storeQueryResponse.statusCode >= 300) {
|
3015
3015
|
const errorMessage = `Store query failed with status code: ${storeQueryResponse.statusCode}, description: ${storeQueryResponse.statusDesc}`;
|
3016
|
-
log$
|
3016
|
+
log$7.error(errorMessage);
|
3017
3017
|
throw new Error(errorMessage);
|
3018
3018
|
}
|
3019
3019
|
if (!storeQueryResponse.messages || !storeQueryResponse.messages.length) {
|
3020
|
-
log$
|
3020
|
+
log$7.warn("Stopping pagination due to empty messages in response");
|
3021
3021
|
break;
|
3022
3022
|
}
|
3023
|
-
log$
|
3023
|
+
log$7.info(`${storeQueryResponse.messages.length} messages retrieved from store`);
|
3024
3024
|
const decodedMessages = storeQueryResponse.messages.map((protoMsg) => {
|
3025
3025
|
if (!protoMsg.message) {
|
3026
3026
|
return Promise.resolve(undefined);
|
@@ -3058,7 +3058,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
3058
3058
|
StoreCore: StoreCore
|
3059
3059
|
});
|
3060
3060
|
|
3061
|
-
const log$
|
3061
|
+
const log$6 = new Logger("connection-limiter");
|
3062
3062
|
/**
|
3063
3063
|
* This class is responsible for limiting the number of connections to peers.
|
3064
3064
|
* It also dials all known peers because libp2p might have emitted `peer:discovery` before initialization
|
@@ -3066,16 +3066,24 @@ const log$5 = new Logger("connection-limiter");
|
|
3066
3066
|
*/
|
3067
3067
|
class ConnectionLimiter {
|
3068
3068
|
libp2p;
|
3069
|
+
events;
|
3070
|
+
networkMonitor;
|
3071
|
+
dialer;
|
3069
3072
|
options;
|
3070
3073
|
constructor(options) {
|
3071
3074
|
this.libp2p = options.libp2p;
|
3075
|
+
this.events = options.events;
|
3076
|
+
this.networkMonitor = options.networkMonitor;
|
3077
|
+
this.dialer = options.dialer;
|
3072
3078
|
this.options = options.options;
|
3079
|
+
this.onWakuConnectionEvent = this.onWakuConnectionEvent.bind(this);
|
3073
3080
|
this.onConnectedEvent = this.onConnectedEvent.bind(this);
|
3074
3081
|
this.onDisconnectedEvent = this.onDisconnectedEvent.bind(this);
|
3075
3082
|
}
|
3076
3083
|
start() {
|
3077
3084
|
// dial all known peers because libp2p might have emitted `peer:discovery` before initialization
|
3078
3085
|
void this.dialPeersFromStore();
|
3086
|
+
this.events.addEventListener("waku:connection", this.onWakuConnectionEvent);
|
3079
3087
|
this.libp2p.addEventListener("peer:connect", this.onConnectedEvent);
|
3080
3088
|
/**
|
3081
3089
|
* NOTE: Event is not being emitted on closing nor losing a connection.
|
@@ -3091,37 +3099,50 @@ class ConnectionLimiter {
|
|
3091
3099
|
this.libp2p.addEventListener("peer:disconnect", this.onDisconnectedEvent);
|
3092
3100
|
}
|
3093
3101
|
stop() {
|
3102
|
+
this.events.removeEventListener("waku:connection", this.onWakuConnectionEvent);
|
3094
3103
|
this.libp2p.removeEventListener("peer:connect", this.onConnectedEvent);
|
3095
3104
|
this.libp2p.removeEventListener("peer:disconnect", this.onDisconnectedEvent);
|
3096
3105
|
}
|
3106
|
+
onWakuConnectionEvent() {
|
3107
|
+
if (this.networkMonitor.isBrowserConnected()) {
|
3108
|
+
void this.dialPeersFromStore();
|
3109
|
+
}
|
3110
|
+
}
|
3097
3111
|
async onConnectedEvent(evt) {
|
3098
|
-
log$
|
3112
|
+
log$6.info(`Connected to peer ${evt.detail.toString()}`);
|
3099
3113
|
const peerId = evt.detail;
|
3100
3114
|
const tags = await this.getTagsForPeer(peerId);
|
3101
3115
|
const isBootstrap = tags.includes(Tags.BOOTSTRAP);
|
3102
3116
|
if (!isBootstrap) {
|
3117
|
+
log$6.info(`Connected to peer ${peerId.toString()} is not a bootstrap peer`);
|
3103
3118
|
return;
|
3104
3119
|
}
|
3105
3120
|
if (await this.hasMoreThanMaxBootstrapConnections()) {
|
3121
|
+
log$6.info(`Connected to peer ${peerId.toString()} and node has more than max bootstrap connections ${this.options.maxBootstrapPeers}. Dropping connection.`);
|
3106
3122
|
await this.libp2p.hangUp(peerId);
|
3107
3123
|
}
|
3108
3124
|
}
|
3109
3125
|
async onDisconnectedEvent() {
|
3110
3126
|
if (this.libp2p.getConnections().length === 0) {
|
3127
|
+
log$6.info(`No connections, dialing peers from store`);
|
3111
3128
|
await this.dialPeersFromStore();
|
3112
3129
|
}
|
3113
3130
|
}
|
3114
3131
|
async dialPeersFromStore() {
|
3132
|
+
log$6.info(`Dialing peers from store`);
|
3115
3133
|
const allPeers = await this.libp2p.peerStore.all();
|
3116
3134
|
const allConnections = this.libp2p.getConnections();
|
3135
|
+
log$6.info(`Found ${allPeers.length} peers in store, and found ${allConnections.length} connections`);
|
3117
3136
|
const promises = allPeers
|
3118
3137
|
.filter((p) => !allConnections.some((c) => c.remotePeer.equals(p.id)))
|
3119
|
-
.map((p) => this.
|
3138
|
+
.map((p) => this.dialer.dial(p.id));
|
3120
3139
|
try {
|
3140
|
+
log$6.info(`Dialing ${promises.length} peers from store`);
|
3121
3141
|
await Promise.all(promises);
|
3142
|
+
log$6.info(`Dialed ${promises.length} peers from store`);
|
3122
3143
|
}
|
3123
3144
|
catch (error) {
|
3124
|
-
log$
|
3145
|
+
log$6.error(`Unexpected error while dialing peer store peers`, error);
|
3125
3146
|
}
|
3126
3147
|
}
|
3127
3148
|
async hasMoreThanMaxBootstrapConnections() {
|
@@ -3134,7 +3155,7 @@ class ConnectionLimiter {
|
|
3134
3155
|
return bootstrapPeers.length > this.options.maxBootstrapPeers;
|
3135
3156
|
}
|
3136
3157
|
catch (error) {
|
3137
|
-
log$
|
3158
|
+
log$6.error(`Unexpected error while checking for bootstrap connections`, error);
|
3138
3159
|
return false;
|
3139
3160
|
}
|
3140
3161
|
}
|
@@ -3143,7 +3164,7 @@ class ConnectionLimiter {
|
|
3143
3164
|
return await this.libp2p.peerStore.get(peerId);
|
3144
3165
|
}
|
3145
3166
|
catch (error) {
|
3146
|
-
log$
|
3167
|
+
log$6.error(`Failed to get peer ${peerId}, error: ${error}`);
|
3147
3168
|
return null;
|
3148
3169
|
}
|
3149
3170
|
}
|
@@ -3153,103 +3174,148 @@ class ConnectionLimiter {
|
|
3153
3174
|
return Array.from(peer.tags.keys());
|
3154
3175
|
}
|
3155
3176
|
catch (error) {
|
3156
|
-
log$
|
3177
|
+
log$6.error(`Failed to get peer ${peerId}, error: ${error}`);
|
3157
3178
|
return [];
|
3158
3179
|
}
|
3159
3180
|
}
|
3160
3181
|
}
|
3161
3182
|
|
3162
|
-
const log$
|
3163
|
-
|
3164
|
-
* This class is responsible for dialing peers that are discovered by the libp2p node.
|
3165
|
-
* Managing limits for the peers is out of scope for this class.
|
3166
|
-
* Dialing after discovery is needed to identify the peer and get all other information: metadata, protocols, etc.
|
3167
|
-
*/
|
3168
|
-
class DiscoveryDialer {
|
3183
|
+
const log$5 = new Logger("dialer");
|
3184
|
+
class Dialer {
|
3169
3185
|
libp2p;
|
3170
3186
|
shardReader;
|
3171
|
-
dialingInterval = null;
|
3172
3187
|
dialingQueue = [];
|
3173
|
-
dialHistory = new
|
3188
|
+
dialHistory = new Map();
|
3189
|
+
dialingInterval = null;
|
3190
|
+
isProcessing = false;
|
3174
3191
|
constructor(options) {
|
3175
3192
|
this.libp2p = options.libp2p;
|
3176
3193
|
this.shardReader = options.shardReader;
|
3177
|
-
this.onPeerDiscovery = this.onPeerDiscovery.bind(this);
|
3178
3194
|
}
|
3179
3195
|
start() {
|
3180
|
-
log$4.info("Starting discovery dialer");
|
3181
|
-
this.libp2p.addEventListener("peer:discovery", this.onPeerDiscovery);
|
3182
3196
|
if (!this.dialingInterval) {
|
3183
3197
|
this.dialingInterval = setInterval(() => {
|
3184
3198
|
void this.processQueue();
|
3185
3199
|
}, 500);
|
3186
|
-
log$4.info("Started dialing interval processor");
|
3187
3200
|
}
|
3188
3201
|
this.dialHistory.clear();
|
3189
3202
|
}
|
3190
3203
|
stop() {
|
3191
|
-
log$4.info("Stopping discovery dialer");
|
3192
|
-
this.libp2p.removeEventListener("peer:discovery", this.onPeerDiscovery);
|
3193
3204
|
if (this.dialingInterval) {
|
3194
3205
|
clearInterval(this.dialingInterval);
|
3195
3206
|
this.dialingInterval = null;
|
3196
|
-
log$4.info("Stopped dialing interval processor");
|
3197
3207
|
}
|
3198
3208
|
this.dialHistory.clear();
|
3199
3209
|
}
|
3200
|
-
async
|
3201
|
-
const
|
3202
|
-
|
3203
|
-
|
3204
|
-
|
3205
|
-
if (shouldSkip) {
|
3206
|
-
log$4.info(`Skipping peer: ${peerId}`);
|
3207
|
-
return;
|
3208
|
-
}
|
3209
|
-
await this.updatePeerStore(peerId, event.detail.multiaddrs);
|
3210
|
-
if (this.dialingQueue.length === 0) {
|
3211
|
-
await this.dialPeer(peerId);
|
3212
|
-
}
|
3213
|
-
else {
|
3214
|
-
this.dialingQueue.push(peerId);
|
3215
|
-
log$4.info(`Added peer to dialing queue, queue size: ${this.dialingQueue.length}`);
|
3216
|
-
}
|
3210
|
+
async dial(peerId) {
|
3211
|
+
const shouldSkip = await this.shouldSkipPeer(peerId);
|
3212
|
+
if (shouldSkip) {
|
3213
|
+
log$5.info(`Skipping peer: ${peerId}`);
|
3214
|
+
return;
|
3217
3215
|
}
|
3218
|
-
|
3219
|
-
|
3216
|
+
// If queue is empty and we're not currently processing, dial immediately
|
3217
|
+
if (this.dialingQueue.length === 0 && !this.isProcessing) {
|
3218
|
+
await this.dialPeer(peerId);
|
3219
|
+
}
|
3220
|
+
else {
|
3221
|
+
// Add to queue
|
3222
|
+
this.dialingQueue.push(peerId);
|
3223
|
+
log$5.info(`Added peer to dialing queue, queue size: ${this.dialingQueue.length}`);
|
3220
3224
|
}
|
3221
3225
|
}
|
3222
3226
|
async processQueue() {
|
3223
|
-
if (this.dialingQueue.length === 0)
|
3227
|
+
if (this.dialingQueue.length === 0 || this.isProcessing)
|
3224
3228
|
return;
|
3225
|
-
|
3226
|
-
|
3227
|
-
|
3228
|
-
|
3229
|
+
this.isProcessing = true;
|
3230
|
+
try {
|
3231
|
+
const peersToDial = this.dialingQueue.slice(0, 3);
|
3232
|
+
this.dialingQueue = this.dialingQueue.slice(peersToDial.length);
|
3233
|
+
log$5.info(`Processing dial queue: dialing ${peersToDial.length} peers, ${this.dialingQueue.length} remaining in queue`);
|
3234
|
+
await Promise.all(peersToDial.map((peerId) => this.dialPeer(peerId)));
|
3235
|
+
}
|
3236
|
+
finally {
|
3237
|
+
this.isProcessing = false;
|
3238
|
+
}
|
3239
|
+
}
|
3240
|
+
async dialPeer(peerId) {
|
3241
|
+
try {
|
3242
|
+
log$5.info(`Dialing peer from queue: ${peerId}`);
|
3243
|
+
await this.libp2p.dial(peerId);
|
3244
|
+
this.dialHistory.set(peerId.toString(), Date.now());
|
3245
|
+
log$5.info(`Successfully dialed peer from queue: ${peerId}`);
|
3246
|
+
}
|
3247
|
+
catch (error) {
|
3248
|
+
log$5.error(`Error dialing peer ${peerId}`, error);
|
3249
|
+
}
|
3229
3250
|
}
|
3230
3251
|
async shouldSkipPeer(peerId) {
|
3231
|
-
|
3252
|
+
const hasConnection = this.libp2p.getPeers().some((p) => p.equals(peerId));
|
3253
|
+
if (hasConnection) {
|
3254
|
+
log$5.info(`Skipping peer ${peerId} - already connected`);
|
3255
|
+
return true;
|
3256
|
+
}
|
3257
|
+
const lastDialed = this.dialHistory.get(peerId.toString());
|
3258
|
+
if (lastDialed && Date.now() - lastDialed < 10_000) {
|
3259
|
+
log$5.info(`Skipping peer ${peerId} - already dialed in the last 10 seconds`);
|
3232
3260
|
return true;
|
3233
3261
|
}
|
3234
|
-
|
3235
|
-
|
3262
|
+
try {
|
3263
|
+
const hasShardInfo = await this.shardReader.hasShardInfo(peerId);
|
3264
|
+
if (!hasShardInfo) {
|
3265
|
+
log$5.info(`Skipping peer ${peerId} - no shard info`);
|
3266
|
+
return false;
|
3267
|
+
}
|
3268
|
+
const isOnSameShard = await this.shardReader.isPeerOnNetwork(peerId);
|
3269
|
+
if (!isOnSameShard) {
|
3270
|
+
log$5.info(`Skipping peer ${peerId} - not on same shard`);
|
3271
|
+
return true;
|
3272
|
+
}
|
3236
3273
|
return false;
|
3237
3274
|
}
|
3238
|
-
|
3239
|
-
|
3240
|
-
|
3241
|
-
return true;
|
3275
|
+
catch (error) {
|
3276
|
+
log$5.error(`Error checking shard info for peer ${peerId}`, error);
|
3277
|
+
return true; // Skip peer when there's an error
|
3242
3278
|
}
|
3243
|
-
|
3244
|
-
|
3245
|
-
|
3279
|
+
}
|
3280
|
+
}
|
3281
|
+
|
3282
|
+
const log$4 = new Logger("discovery-dialer");
|
3283
|
+
/**
|
3284
|
+
* This class is responsible for dialing peers that are discovered by the libp2p node.
|
3285
|
+
* Managing limits for the peers is out of scope for this class.
|
3286
|
+
* Dialing after discovery is needed to identify the peer and get all other information: metadata, protocols, etc.
|
3287
|
+
*/
|
3288
|
+
class DiscoveryDialer {
|
3289
|
+
libp2p;
|
3290
|
+
dialer;
|
3291
|
+
constructor(options) {
|
3292
|
+
this.libp2p = options.libp2p;
|
3293
|
+
this.dialer = options.dialer;
|
3294
|
+
this.onPeerDiscovery = this.onPeerDiscovery.bind(this);
|
3295
|
+
}
|
3296
|
+
start() {
|
3297
|
+
this.libp2p.addEventListener("peer:discovery", this.onPeerDiscovery);
|
3298
|
+
}
|
3299
|
+
stop() {
|
3300
|
+
this.libp2p.removeEventListener("peer:discovery", this.onPeerDiscovery);
|
3301
|
+
}
|
3302
|
+
async onPeerDiscovery(event) {
|
3303
|
+
const peerId = event.detail.id;
|
3304
|
+
log$4.info(`Discovered new peer: ${peerId}`);
|
3305
|
+
try {
|
3306
|
+
await this.updatePeerStore(peerId, event.detail.multiaddrs);
|
3307
|
+
await this.dialer.dial(peerId);
|
3308
|
+
}
|
3309
|
+
catch (error) {
|
3310
|
+
log$4.error(`Error dialing peer ${peerId}`, error);
|
3246
3311
|
}
|
3247
|
-
return false;
|
3248
3312
|
}
|
3249
3313
|
async updatePeerStore(peerId, multiaddrs) {
|
3250
3314
|
try {
|
3315
|
+
log$4.info(`Updating peer store for ${peerId}`);
|
3251
3316
|
const peer = await this.getPeer(peerId);
|
3252
3317
|
if (!peer) {
|
3318
|
+
log$4.info(`Peer ${peerId} not found in store, saving`);
|
3253
3319
|
await this.libp2p.peerStore.save(peerId, {
|
3254
3320
|
multiaddrs: multiaddrs
|
3255
3321
|
});
|
@@ -3257,8 +3323,10 @@ class DiscoveryDialer {
|
|
3257
3323
|
}
|
3258
3324
|
const hasSameAddr = multiaddrs.every((addr) => peer.addresses.some((a) => a.multiaddr.equals(addr)));
|
3259
3325
|
if (hasSameAddr) {
|
3326
|
+
log$4.info(`Peer ${peerId} has same addresses in peer store, skipping`);
|
3260
3327
|
return;
|
3261
3328
|
}
|
3329
|
+
log$4.info(`Merging peer ${peerId} addresses in peer store`);
|
3262
3330
|
await this.libp2p.peerStore.merge(peerId, {
|
3263
3331
|
multiaddrs: multiaddrs
|
3264
3332
|
});
|
@@ -3267,17 +3335,6 @@ class DiscoveryDialer {
|
|
3267
3335
|
log$4.error(`Error updating peer store for ${peerId}`, error);
|
3268
3336
|
}
|
3269
3337
|
}
|
3270
|
-
async dialPeer(peerId) {
|
3271
|
-
try {
|
3272
|
-
log$4.info(`Dialing peer from queue: ${peerId}`);
|
3273
|
-
await this.libp2p.dial(peerId);
|
3274
|
-
this.dialHistory.add(peerId.toString());
|
3275
|
-
log$4.info(`Successfully dialed peer from queue: ${peerId}`);
|
3276
|
-
}
|
3277
|
-
catch (error) {
|
3278
|
-
log$4.error(`Error dialing peer ${peerId}`, error);
|
3279
|
-
}
|
3280
|
-
}
|
3281
3338
|
async getPeer(peerId) {
|
3282
3339
|
try {
|
3283
3340
|
return await this.libp2p.peerStore.get(peerId);
|
@@ -3467,7 +3524,25 @@ class NetworkMonitor {
|
|
3467
3524
|
// ignore
|
3468
3525
|
}
|
3469
3526
|
}
|
3527
|
+
/**
|
3528
|
+
* Returns true if the node is connected to the network via libp2p and browser.
|
3529
|
+
*/
|
3470
3530
|
isConnected() {
|
3531
|
+
if (!this.isBrowserConnected()) {
|
3532
|
+
return false;
|
3533
|
+
}
|
3534
|
+
return this.isP2PConnected();
|
3535
|
+
}
|
3536
|
+
/**
|
3537
|
+
* Returns true if the node is connected to the network via libp2p.
|
3538
|
+
*/
|
3539
|
+
isP2PConnected() {
|
3540
|
+
return this.isNetworkConnected;
|
3541
|
+
}
|
3542
|
+
/**
|
3543
|
+
* Returns true if the node is connected to the network via browser.
|
3544
|
+
*/
|
3545
|
+
isBrowserConnected() {
|
3471
3546
|
try {
|
3472
3547
|
if (globalThis?.navigator && !globalThis?.navigator?.onLine) {
|
3473
3548
|
return false;
|
@@ -3476,7 +3551,7 @@ class NetworkMonitor {
|
|
3476
3551
|
catch (err) {
|
3477
3552
|
// ignore
|
3478
3553
|
}
|
3479
|
-
return
|
3554
|
+
return true;
|
3480
3555
|
}
|
3481
3556
|
onConnectedEvent() {
|
3482
3557
|
if (!this.isNetworkConnected) {
|
@@ -8849,6 +8924,7 @@ class ConnectionManager {
|
|
8849
8924
|
pubsubTopics;
|
8850
8925
|
keepAliveManager;
|
8851
8926
|
discoveryDialer;
|
8927
|
+
dialer;
|
8852
8928
|
shardReader;
|
8853
8929
|
networkMonitor;
|
8854
8930
|
connectionLimiter;
|
@@ -8875,16 +8951,23 @@ class ConnectionManager {
|
|
8875
8951
|
libp2p: options.libp2p,
|
8876
8952
|
networkConfig: options.networkConfig
|
8877
8953
|
});
|
8878
|
-
this.
|
8954
|
+
this.dialer = new Dialer({
|
8879
8955
|
libp2p: options.libp2p,
|
8880
8956
|
shardReader: this.shardReader
|
8881
8957
|
});
|
8958
|
+
this.discoveryDialer = new DiscoveryDialer({
|
8959
|
+
libp2p: options.libp2p,
|
8960
|
+
dialer: this.dialer
|
8961
|
+
});
|
8882
8962
|
this.networkMonitor = new NetworkMonitor({
|
8883
8963
|
libp2p: options.libp2p,
|
8884
8964
|
events: options.events
|
8885
8965
|
});
|
8886
8966
|
this.connectionLimiter = new ConnectionLimiter({
|
8887
8967
|
libp2p: options.libp2p,
|
8968
|
+
events: options.events,
|
8969
|
+
networkMonitor: this.networkMonitor,
|
8970
|
+
dialer: this.dialer,
|
8888
8971
|
options: this.options
|
8889
8972
|
});
|
8890
8973
|
}
|
@@ -8905,11 +8988,16 @@ class ConnectionManager {
|
|
8905
8988
|
}
|
8906
8989
|
async dial(peer, protocolCodecs) {
|
8907
8990
|
const ma = mapToPeerIdOrMultiaddr(peer);
|
8908
|
-
|
8991
|
+
log$1.info(`Dialing peer ${ma.toString()} with protocols ${protocolCodecs}`);
|
8992
|
+
// must use libp2p directly instead of dialer because we need to dial the peer right away
|
8993
|
+
const stream = await this.libp2p.dialProtocol(ma, protocolCodecs);
|
8994
|
+
log$1.info(`Dialed peer ${ma.toString()} with protocols ${protocolCodecs}`);
|
8995
|
+
return stream;
|
8909
8996
|
}
|
8910
8997
|
async hangUp(peer) {
|
8911
8998
|
const peerId = mapToPeerId(peer);
|
8912
8999
|
try {
|
9000
|
+
log$1.info(`Dropping connection with peer ${peerId.toString()}`);
|
8913
9001
|
await this.libp2p.hangUp(peerId);
|
8914
9002
|
log$1.info(`Dropped connection with peer ${peerId.toString()}`);
|
8915
9003
|
return true;
|
@@ -8921,7 +9009,9 @@ class ConnectionManager {
|
|
8921
9009
|
}
|
8922
9010
|
async getConnectedPeers(codec) {
|
8923
9011
|
const peerIDs = this.libp2p.getPeers();
|
9012
|
+
log$1.info(`Getting connected peers for codec ${codec}`);
|
8924
9013
|
if (peerIDs.length === 0) {
|
9014
|
+
log$1.info(`No connected peers`);
|
8925
9015
|
return [];
|
8926
9016
|
}
|
8927
9017
|
const peers = await Promise.all(peerIDs.map(async (id) => {
|
@@ -8932,10 +9022,12 @@ class ConnectionManager {
|
|
8932
9022
|
return null;
|
8933
9023
|
}
|
8934
9024
|
}));
|
8935
|
-
|
9025
|
+
const result = peers
|
8936
9026
|
.filter((p) => !!p)
|
8937
9027
|
.filter((p) => (codec ? p.protocols.includes(codec) : true))
|
8938
9028
|
.sort((left, right) => getPeerPing(left) - getPeerPing(right));
|
9029
|
+
log$1.info(`Found ${result.length} connected peers for codec ${codec}`);
|
9030
|
+
return result;
|
8939
9031
|
}
|
8940
9032
|
isTopicConfigured(pubsubTopic) {
|
8941
9033
|
return this.pubsubTopics.includes(pubsubTopic);
|