@waku/core 0.0.33-c50088a.0 → 0.0.33-c9fdfb3.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.
@@ -1,4 +1,4 @@
1
- import { g as bytesToUtf8, T as Tags, L as Logger } from './index-CpCu13gb.js';
1
+ import { g as bytesToUtf8, T as Tags, L as Logger } from './index-CeEH6b9b.js';
2
2
 
3
3
  /**
4
4
  * Function to sort peers by latency from lowest to highest
@@ -80,110 +80,129 @@ function filterPeersByDiscovery(peers, numPeers, maxBootstrapPeers) {
80
80
  return selectedPeers;
81
81
  }
82
82
 
83
- function selectConnection(connections) {
84
- if (!connections.length)
85
- return;
86
- if (connections.length === 1)
87
- return connections[0];
88
- let latestConnection;
89
- connections.forEach((connection) => {
90
- if (connection.status === "open") {
91
- if (!latestConnection) {
92
- latestConnection = connection;
93
- }
94
- else if (connection.timeline.open > latestConnection.timeline.open) {
95
- latestConnection = connection;
96
- }
97
- }
98
- });
99
- return latestConnection;
83
+ function selectOpenConnection(connections) {
84
+ return connections
85
+ .filter((c) => c.status === "open")
86
+ .sort((left, right) => right.timeline.open - left.timeline.open)
87
+ .at(0);
100
88
  }
101
89
 
102
- const CONNECTION_TIMEOUT = 5_000;
103
- const RETRY_BACKOFF_BASE = 1_000;
104
- const MAX_RETRIES = 3;
90
+ const STREAM_LOCK_KEY = "consumed";
105
91
  class StreamManager {
106
92
  multicodec;
107
93
  getConnections;
108
94
  addEventListener;
109
- streamPool;
110
95
  log;
96
+ ongoingCreation = new Set();
97
+ streamPool = new Map();
111
98
  constructor(multicodec, getConnections, addEventListener) {
112
99
  this.multicodec = multicodec;
113
100
  this.getConnections = getConnections;
114
101
  this.addEventListener = addEventListener;
115
102
  this.log = new Logger(`stream-manager:${multicodec}`);
116
- this.streamPool = new Map();
117
103
  this.addEventListener("peer:update", this.handlePeerUpdateStreamPool);
118
104
  }
119
105
  async getStream(peer) {
120
- const peerIdStr = peer.id.toString();
121
- const streamPromise = this.streamPool.get(peerIdStr);
122
- if (!streamPromise) {
123
- return this.createStream(peer);
106
+ const peerId = peer.id.toString();
107
+ const scheduledStream = this.streamPool.get(peerId);
108
+ if (scheduledStream) {
109
+ this.streamPool.delete(peerId);
110
+ await scheduledStream;
124
111
  }
125
- this.streamPool.delete(peerIdStr);
126
- this.prepareStream(peer);
127
- try {
128
- const stream = await streamPromise;
129
- if (stream && stream.status !== "closed") {
130
- return stream;
131
- }
132
- }
133
- catch (error) {
134
- this.log.warn(`Failed to get stream for ${peerIdStr} -- `, error);
135
- this.log.warn("Attempting to create a new stream for the peer");
112
+ let stream = this.getOpenStreamForCodec(peer.id);
113
+ if (stream) {
114
+ this.log.info(`Found existing stream peerId=${peer.id.toString()} multicodec=${this.multicodec}`);
115
+ this.lockStream(peer.id.toString(), stream);
116
+ return stream;
136
117
  }
137
- return this.createStream(peer);
118
+ stream = await this.createStream(peer);
119
+ this.lockStream(peer.id.toString(), stream);
120
+ return stream;
138
121
  }
139
122
  async createStream(peer, retries = 0) {
140
123
  const connections = this.getConnections(peer.id);
141
- const connection = selectConnection(connections);
124
+ const connection = selectOpenConnection(connections);
142
125
  if (!connection) {
143
- throw new Error("Failed to get a connection to the peer");
126
+ throw new Error(`Failed to get a connection to the peer peerId=${peer.id.toString()} multicodec=${this.multicodec}`);
127
+ }
128
+ let lastError;
129
+ let stream;
130
+ for (let i = 0; i < retries + 1; i++) {
131
+ try {
132
+ this.log.info(`Attempting to create a stream for peerId=${peer.id.toString()} multicodec=${this.multicodec}`);
133
+ stream = await connection.newStream(this.multicodec);
134
+ this.log.info(`Created stream for peerId=${peer.id.toString()} multicodec=${this.multicodec}`);
135
+ break;
136
+ }
137
+ catch (error) {
138
+ lastError = error;
139
+ }
140
+ }
141
+ if (!stream) {
142
+ throw new Error(`Failed to create a new stream for ${peer.id.toString()} -- ` +
143
+ lastError);
144
+ }
145
+ return stream;
146
+ }
147
+ async createStreamWithLock(peer) {
148
+ const peerId = peer.id.toString();
149
+ if (this.ongoingCreation.has(peerId)) {
150
+ this.log.info(`Skipping creation of a stream due to lock for peerId=${peerId} multicodec=${this.multicodec}`);
151
+ return;
144
152
  }
145
153
  try {
146
- return await connection.newStream(this.multicodec);
154
+ this.ongoingCreation.add(peerId);
155
+ await this.createStream(peer);
147
156
  }
148
157
  catch (error) {
149
- if (retries < MAX_RETRIES) {
150
- const backoff = RETRY_BACKOFF_BASE * Math.pow(2, retries);
151
- await new Promise((resolve) => setTimeout(resolve, backoff));
152
- return this.createStream(peer, retries + 1);
153
- }
154
- throw new Error(`Failed to create a new stream for ${peer.id.toString()} -- ` + error);
158
+ this.log.error(`Failed to createStreamWithLock:`, error);
155
159
  }
156
- }
157
- prepareStream(peer) {
158
- const timeoutPromise = new Promise((resolve) => setTimeout(resolve, CONNECTION_TIMEOUT));
159
- const streamPromise = Promise.race([
160
- this.createStream(peer),
161
- timeoutPromise.then(() => {
162
- throw new Error("Connection timeout");
163
- })
164
- ]).catch((error) => {
165
- this.log.error(`Failed to prepare a new stream for ${peer.id.toString()} -- `, error);
166
- });
167
- this.streamPool.set(peer.id.toString(), streamPromise);
160
+ finally {
161
+ this.ongoingCreation.delete(peerId);
162
+ }
163
+ return;
168
164
  }
169
165
  handlePeerUpdateStreamPool = (evt) => {
170
166
  const { peer } = evt.detail;
171
- if (peer.protocols.includes(this.multicodec)) {
172
- const isConnected = this.isConnectedTo(peer.id);
173
- if (isConnected) {
174
- this.log.info(`Preemptively opening a stream to ${peer.id.toString()}`);
175
- this.prepareStream(peer);
176
- }
177
- else {
178
- const peerIdStr = peer.id.toString();
179
- this.streamPool.delete(peerIdStr);
180
- this.log.info(`Removed pending stream for disconnected peer ${peerIdStr}`);
181
- }
167
+ if (!peer.protocols.includes(this.multicodec)) {
168
+ return;
182
169
  }
170
+ const stream = this.getOpenStreamForCodec(peer.id);
171
+ if (stream) {
172
+ return;
173
+ }
174
+ this.scheduleNewStream(peer);
183
175
  };
184
- isConnectedTo(peerId) {
176
+ scheduleNewStream(peer) {
177
+ this.log.info(`Scheduling creation of a stream for peerId=${peer.id.toString()} multicodec=${this.multicodec}`);
178
+ // abandon previous attempt
179
+ if (this.streamPool.has(peer.id.toString())) {
180
+ this.streamPool.delete(peer.id.toString());
181
+ }
182
+ this.streamPool.set(peer.id.toString(), this.createStreamWithLock(peer));
183
+ }
184
+ getOpenStreamForCodec(peerId) {
185
185
  const connections = this.getConnections(peerId);
186
- return connections.some((connection) => connection.status === "open");
186
+ const connection = selectOpenConnection(connections);
187
+ if (!connection) {
188
+ return;
189
+ }
190
+ const stream = connection.streams.find((s) => s.protocol === this.multicodec);
191
+ if (!stream) {
192
+ return;
193
+ }
194
+ const isStreamUnusable = ["done", "closed", "closing"].includes(stream.writeStatus || "");
195
+ if (isStreamUnusable || this.isStreamLocked(stream)) {
196
+ return;
197
+ }
198
+ return stream;
199
+ }
200
+ lockStream(peerId, stream) {
201
+ this.log.info(`Locking stream for peerId:${peerId}\tstreamId:${stream.id}`);
202
+ stream.metadata[STREAM_LOCK_KEY] = true;
203
+ }
204
+ isStreamLocked(stream) {
205
+ return !!stream.metadata[STREAM_LOCK_KEY];
187
206
  }
188
207
  }
189
208
 
@@ -211,7 +230,6 @@ class BaseProtocol {
211
230
  async getStream(peer) {
212
231
  return this.streamManager.getStream(peer);
213
232
  }
214
- //TODO: move to SDK
215
233
  /**
216
234
  * Returns known peers from the address book (`libp2p.peerStore`) that support
217
235
  * the class protocol. Waku may or may not be currently connected to these
@@ -220,13 +238,10 @@ class BaseProtocol {
220
238
  async allPeers() {
221
239
  return getPeersForProtocol(this.components.peerStore, [this.multicodec]);
222
240
  }
223
- async connectedPeers(withOpenStreams = false) {
241
+ async connectedPeers() {
224
242
  const peers = await this.allPeers();
225
243
  return peers.filter((peer) => {
226
244
  const connections = this.components.connectionManager.getConnections(peer.id);
227
- if (withOpenStreams) {
228
- return connections.some((c) => c.streams.some((s) => s.protocol === this.multicodec));
229
- }
230
245
  return connections.length > 0;
231
246
  });
232
247
  }
@@ -236,11 +236,12 @@ class Decoder {
236
236
  constructor(name, prefix, baseDecode) {
237
237
  this.name = name;
238
238
  this.prefix = prefix;
239
+ const prefixCodePoint = prefix.codePointAt(0);
239
240
  /* c8 ignore next 3 */
240
- if (prefix.codePointAt(0) === undefined) {
241
+ if (prefixCodePoint === undefined) {
241
242
  throw new Error('Invalid prefix character');
242
243
  }
243
- this.prefixCodePoint = prefix.codePointAt(0);
244
+ this.prefixCodePoint = prefixCodePoint;
244
245
  this.baseDecode = baseDecode;
245
246
  }
246
247
  decode(text) {
@@ -444,7 +445,14 @@ var base2$1 = /*#__PURE__*/Object.freeze({
444
445
 
445
446
  const alphabet = Array.from('🚀🪐☄🛰🌌🌑🌒🌓🌔🌕🌖🌗🌘🌍🌏🌎🐉☀💻🖥💾💿😂❤😍🤣😊🙏💕😭😘👍😅👏😁🔥🥰💔💖💙😢🤔😆🙄💪😉☺👌🤗💜😔😎😇🌹🤦🎉💞✌✨🤷😱😌🌸🙌😋💗💚😏💛🙂💓🤩😄😀🖤😃💯🙈👇🎶😒🤭❣😜💋👀😪😑💥🙋😞😩😡🤪👊🥳😥🤤👉💃😳✋😚😝😴🌟😬🙃🍀🌷😻😓⭐✅🥺🌈😈🤘💦✔😣🏃💐☹🎊💘😠☝😕🌺🎂🌻😐🖕💝🙊😹🗣💫💀👑🎵🤞😛🔴😤🌼😫⚽🤙☕🏆🤫👈😮🙆🍻🍃🐶💁😲🌿🧡🎁⚡🌞🎈❌✊👋😰🤨😶🤝🚶💰🍓💢🤟🙁🚨💨🤬✈🎀🍺🤓😙💟🌱😖👶🥴▶➡❓💎💸⬇😨🌚🦋😷🕺⚠🙅😟😵👎🤲🤠🤧📌🔵💅🧐🐾🍒😗🤑🌊🤯🐷☎💧😯💆👆🎤🙇🍑❄🌴💣🐸💌📍🥀🤢👅💡💩👐📸👻🤐🤮🎼🥵🚩🍎🍊👼💍📣🥂');
446
447
  const alphabetBytesToChars = (alphabet.reduce((p, c, i) => { p[i] = c; return p; }, ([])));
447
- const alphabetCharsToBytes = (alphabet.reduce((p, c, i) => { p[c.codePointAt(0)] = i; return p; }, ([])));
448
+ const alphabetCharsToBytes = (alphabet.reduce((p, c, i) => {
449
+ const codePoint = c.codePointAt(0);
450
+ if (codePoint == null) {
451
+ throw new Error(`Invalid character: ${c}`);
452
+ }
453
+ p[codePoint] = i;
454
+ return p;
455
+ }, ([])));
448
456
  function encode(data) {
449
457
  return data.reduce((p, c) => {
450
458
  p += alphabetBytesToChars[c];
@@ -454,8 +462,12 @@ function encode(data) {
454
462
  function decode(str) {
455
463
  const byts = [];
456
464
  for (const char of str) {
457
- const byt = alphabetCharsToBytes[char.codePointAt(0)];
458
- if (byt === undefined) {
465
+ const codePoint = char.codePointAt(0);
466
+ if (codePoint == null) {
467
+ throw new Error(`Invalid character: ${char}`);
468
+ }
469
+ const byt = alphabetCharsToBytes[codePoint];
470
+ if (byt == null) {
459
471
  throw new Error(`Non-base256emoji character: ${char}`);
460
472
  }
461
473
  byts.push(byt);
@@ -895,7 +907,7 @@ function requireMs () {
895
907
  * @api public
896
908
  */
897
909
 
898
- ms = function(val, options) {
910
+ ms = function (val, options) {
899
911
  options = options || {};
900
912
  var type = typeof val;
901
913
  if (type === 'string' && val.length > 0) {
@@ -1588,6 +1600,7 @@ var debug = /*@__PURE__*/getDefaultExportFromCjs(browserExports);
1588
1600
 
1589
1601
  const APP_NAME = "waku";
1590
1602
  class Logger {
1603
+ _debug;
1591
1604
  _info;
1592
1605
  _warn;
1593
1606
  _error;
@@ -1595,10 +1608,14 @@ class Logger {
1595
1608
  return prefix ? `${APP_NAME}:${level}:${prefix}` : `${APP_NAME}:${level}`;
1596
1609
  }
1597
1610
  constructor(prefix) {
1611
+ this._debug = debug(Logger.createDebugNamespace("debug", prefix));
1598
1612
  this._info = debug(Logger.createDebugNamespace("info", prefix));
1599
1613
  this._warn = debug(Logger.createDebugNamespace("warn", prefix));
1600
1614
  this._error = debug(Logger.createDebugNamespace("error", prefix));
1601
1615
  }
1616
+ get debug() {
1617
+ return this._debug;
1618
+ }
1602
1619
  get info() {
1603
1620
  return this._info;
1604
1621
  }
@@ -1614,4 +1631,4 @@ class Logger {
1614
1631
  }
1615
1632
  }
1616
1633
 
1617
- export { EPeersByDiscoveryEvents as E, HealthStatus as H, Logger as L, ProtocolError as P, Tags as T, allocUnsafe as a, alloc as b, Protocols as c, EConnectionStateEvents as d, concat as e, fromString as f, bytesToUtf8 as g, utf8ToBytes as u };
1634
+ export { EPeersByDiscoveryEvents as E, HealthStatus as H, Logger as L, ProtocolError as P, Tags as T, allocUnsafe as a, alloc as b, EConnectionStateEvents as c, Protocols as d, concat as e, fromString as f, bytesToUtf8 as g, utf8ToBytes as u };