@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 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-Bc0h7ah2.js';
2
- export { a2 as createDecoder } from './version_0-Bc0h7ah2.js';
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$8 = new Logger("filter-core");
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$8.error("Failed to register ", FilterCodecs.PUSH, e);
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$8.error("Failed to send subscribe request", error);
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$8.error(`Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
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$8.error(`Failed to get a stream for remote peer${peerId.toString()}`, error);
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$8.error("Failed to send unsubscribe request", error);
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$8.error(`Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
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$8.error(`Failed to get a stream for remote peer${peerId.toString()}`, error);
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$8.error("Failed to send ping request", error);
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$8.error(`Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
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$8.info(`Received message from ${remotePeer.toString()}`);
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$8.error("Received empty message");
2665
+ log$9.error("Received empty message");
2666
2666
  return;
2667
2667
  }
2668
2668
  if (!pubsubTopic) {
2669
- log$8.error("Pubsub topic missing from push message");
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$8.info("Receiving pipe closed.");
2675
+ log$9.info("Receiving pipe closed.");
2676
2676
  }, async (e) => {
2677
- log$8.error(`Error with receiving pipe on peer:${connection.remotePeer.toString()} -- stream:${stream.id} -- protocol:${stream.protocol}: `, e);
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$8.error("Error decoding message", e);
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$7 = new Logger("light-push");
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$7.error("Failed to send waku light push: payload is empty");
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$7.error("Failed to send waku light push: message is bigger than 1MB");
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$7.error("Failed to encode to protoMessage, aborting push");
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$7.error("Failed to prepare push message", error);
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$7.error("Failed to get stream", error);
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$7.error("Failed to send waku light push request", err);
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$7.error("Failed to decode push reply", err);
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$7.error("Remote peer fault: No response in PushRPC");
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$7.error("Remote peer fault: RLN generation");
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$7.error("Remote peer rejected the message: ", response.info);
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$6 = new Logger("store");
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$6.info("Sending store query request:", {
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$6.error("Failed to get stream", e);
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$6.error(errorMessage);
3016
+ log$7.error(errorMessage);
3017
3017
  throw new Error(errorMessage);
3018
3018
  }
3019
3019
  if (!storeQueryResponse.messages || !storeQueryResponse.messages.length) {
3020
- log$6.warn("Stopping pagination due to empty messages in response");
3020
+ log$7.warn("Stopping pagination due to empty messages in response");
3021
3021
  break;
3022
3022
  }
3023
- log$6.info(`${storeQueryResponse.messages.length} messages retrieved from store`);
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$5 = new Logger("connection-limiter");
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$5.info(`Connected to peer ${evt.detail.toString()}`);
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.libp2p.dial(p.id));
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$5.error(`Unexpected error while dialing peer store peers`, error);
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$5.error(`Unexpected error while checking for bootstrap connections`, error);
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$5.error(`Failed to get peer ${peerId}, error: ${error}`);
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$5.error(`Failed to get peer ${peerId}, error: ${error}`);
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$4 = new Logger("discovery-dialer");
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 Set();
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 onPeerDiscovery(event) {
3201
- const peerId = event.detail.id;
3202
- log$4.info(`Discovered new peer: ${peerId}`);
3203
- try {
3204
- const shouldSkip = await this.shouldSkipPeer(peerId);
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
- catch (error) {
3219
- log$4.error(`Error dialing peer ${peerId}`, error);
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
- const peersToDial = this.dialingQueue.slice(0, 3);
3226
- this.dialingQueue = this.dialingQueue.slice(peersToDial.length);
3227
- log$4.info(`Processing dial queue: dialing ${peersToDial.length} peers, ${this.dialingQueue.length} remaining in queue`);
3228
- await Promise.all(peersToDial.map(this.dialPeer));
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
- if (this.dialHistory.has(peerId.toString())) {
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
- const hasShardInfo = await this.shardReader.hasShardInfo(peerId);
3235
- if (!hasShardInfo) {
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
- const isOnSameShard = await this.shardReader.isPeerOnNetwork(peerId);
3239
- if (!isOnSameShard) {
3240
- log$4.info(`Skipping peer ${peerId} - not on same shard`);
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
- const hasConnection = this.libp2p.getPeers().some((p) => p.equals(peerId));
3244
- if (hasConnection) {
3245
- return true;
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 this.isNetworkConnected;
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.discoveryDialer = new DiscoveryDialer({
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
- return this.libp2p.dialProtocol(ma, protocolCodecs);
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
- return peers
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);