@hive-p2p/server 1.0.36 → 1.0.38

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.
@@ -47,21 +47,25 @@ class OfferQueue {
47
47
  }
48
48
 
49
49
  export class Topologist {
50
- id; cryptoCodex; gossip; messager; peerStore; bootstraps;
51
- halfTarget = Math.ceil(DISCOVERY.TARGET_NEIGHBORS_COUNT / 2);
52
- twiceTarget = DISCOVERY.TARGET_NEIGHBORS_COUNT * 2;
50
+ id; cryptoCodex; gossip; messager; peerStore; bootstraps; offersQueue = new OfferQueue();
53
51
  /** @type {Map<string, boolean>} */ bootstrapsConnectionState = new Map();
54
-
55
- get isPublicNode() { return this.services?.publicUrl ? true : false; }
56
52
  /** @type {import('./node-services.mjs').NodeServices | undefined} */ services;
57
-
58
- phase = 0;
59
- nextBootstrapIndex = 0;
60
- offersQueue = new OfferQueue();
53
+ /** @type {number} */ NEIGHBORS_TARGET;
54
+ /** @type {number} */ HALF_TARGET;
55
+ /** @type {number} */ TWICE_TARGET;
56
+ setNeighborsTarget(count = DISCOVERY.TARGET_NEIGHBORS_COUNT) { // Setter for hot swapping
57
+ this.NEIGHBORS_TARGET = count;
58
+ this.HALF_TARGET = Math.ceil(this.NEIGHBORS_TARGET / 2);
59
+ this.TWICE_TARGET = this.NEIGHBORS_TARGET * 2;
60
+ }
61
+
62
+ phase = 0; nextBootstrapIndex = 0;
61
63
  maxBonus = NODE.CONNECTION_UPGRADE_TIMEOUT * .2; // 20% of 15sec: 3sec max
64
+ get isPublicNode() { return this.services?.publicUrl ? true : false; }
62
65
 
63
66
  /** @param {string} selfId @param {import('./crypto-codex.mjs').CryptoCodex} cryptoCodex @param {import('./gossip.mjs').Gossip} gossip @param {import('./unicast.mjs').UnicastMessager} messager @param {import('./peer-store.mjs').PeerStore} peerStore @param {string[]} bootstraps */
64
67
  constructor(selfId, cryptoCodex, gossip, messager, peerStore, bootstraps) {
68
+ this.setNeighborsTarget(DISCOVERY.TARGET_NEIGHBORS_COUNT);
65
69
  this.id = selfId; this.cryptoCodex = cryptoCodex; this.gossip = gossip; this.messager = messager; this.peerStore = peerStore;
66
70
  for (const url of bootstraps) this.bootstrapsConnectionState.set(url, false);
67
71
  this.bootstraps = [...bootstraps].sort(() => Math.random() - 0.5); // shuffle
@@ -71,7 +75,7 @@ export class Topologist {
71
75
  // PUBLIC METHODS
72
76
  tick() {
73
77
  const { neighborsCount, nonPublicNeighborsCount, isEnough, isTooMany, isHalfReached } = this.#localTopologyInfo;
74
- const offersToCreate = nonPublicNeighborsCount >= DISCOVERY.TARGET_NEIGHBORS_COUNT / 3 ? 1 : TRANSPORTS.MAX_SDP_OFFERS;
78
+ const offersToCreate = nonPublicNeighborsCount >= this.NEIGHBORS_TARGET / 3 ? 1 : TRANSPORTS.MAX_SDP_OFFERS;
75
79
  this.peerStore.offerManager.offersToCreate = isEnough ? 0 : offersToCreate;
76
80
  if (this.isPublicNode) { this.services.freePublicNodeByKickingPeers(); return; } // public nodes don't need more connections
77
81
  if (isTooMany) return Math.random() > .05 ? this.#improveTopologyByKickingPeers() : null;
@@ -95,15 +99,15 @@ export class Topologist {
95
99
  if (signal.type === 'answer') { // ANSWER SHORT CIRCUIT => Rich should connect poor, and poor should connect rich.
96
100
  if (this.peerStore.addConnectingPeer(senderId, signal, offerHash) !== true) return;
97
101
  const delta = Math.abs(nonPublicNeighborsCount - this.#getOverlap(senderId).nonPublicCount);
98
- const bonusPerDeltaPoint = this.maxBonus / DISCOVERY.TARGET_NEIGHBORS_COUNT; // from 0 to maxBonus
102
+ const bonusPerDeltaPoint = this.maxBonus / this.NEIGHBORS_TARGET; // from 0 to maxBonus
99
103
  const bonus = Math.round(Math.min(this.maxBonus, delta * bonusPerDeltaPoint));
100
104
  return this.peerStore.assignSignal(senderId, signal, offerHash, CLOCK.time + bonus);
101
105
  }
102
106
 
103
107
  // OFFER
104
- if (nonPublicNeighborsCount > this.twiceTarget) return; // we are over connected, ignore the offer
108
+ if (nonPublicNeighborsCount > this.TWICE_TARGET) return; // we are over connected, ignore the offer
105
109
  const { overlap, nonPublicCount } = this.#getOverlap(senderId);
106
- if (nonPublicCount > this.twiceTarget) return; // the sender is over connected, ignore the offer
110
+ if (nonPublicCount > this.TWICE_TARGET) return; // the sender is over connected, ignore the offer
107
111
 
108
112
  const offerItem = { senderId, data, overlap, neighborsCount: nonPublicCount, timestamp: CLOCK.time };
109
113
  this.offersQueue.updateOrderingBy(isHalfReached);
@@ -116,9 +120,10 @@ export class Topologist {
116
120
  for (const id in this.peerStore.connecting) connectingCount++;
117
121
 
118
122
  // MINIMIZE BOOTSTRAP CONNECTIONS DEPENDING ON HOW MANY NEIGHBORS WE HAVE
119
- if (publicConnectedCount >= this.halfTarget) return; // already connected to enough bootstraps
120
- if (neighborsCount >= DISCOVERY.TARGET_NEIGHBORS_COUNT) return; // no more bootstrap needed
121
- if (connectingCount + nonPublicNeighborsCount > this.twiceTarget) return; // no more bootstrap needed
123
+ if (this.NEIGHBORS_TARGET || neighborsCount) // BYPASS IF NO TARGET => AUTHORIZE BOOTSTRAP CONNECTION
124
+ if (publicConnectedCount >= this.HALF_TARGET) return; // already connected to enough bootstraps
125
+ else if (neighborsCount >= this.NEIGHBORS_TARGET) return; // no more bootstrap needed
126
+ else if (connectingCount + nonPublicNeighborsCount > this.TWICE_TARGET) return; // no more bootstrap needed
122
127
 
123
128
  const publicUrl = this.bootstraps[this.nextBootstrapIndex++ % this.bootstraps.length];
124
129
  if (this.bootstrapsConnectionState.get(publicUrl)) return; // already connecting/connected
@@ -131,9 +136,9 @@ export class Topologist {
131
136
  connected: this.peerStore.connected,
132
137
  neighborsCount: this.peerStore.neighborsList.length,
133
138
  nonPublicNeighborsCount: this.peerStore.standardNeighborsList.length,
134
- isEnough: this.peerStore.standardNeighborsList.length >= DISCOVERY.TARGET_NEIGHBORS_COUNT,
135
- isTooMany: this.peerStore.standardNeighborsList.length > DISCOVERY.TARGET_NEIGHBORS_COUNT,
136
- isHalfReached: this.peerStore.standardNeighborsList.length >= this.halfTarget,
139
+ isEnough: this.peerStore.standardNeighborsList.length >= this.NEIGHBORS_TARGET,
140
+ isTooMany: this.peerStore.standardNeighborsList.length > this.NEIGHBORS_TARGET,
141
+ isHalfReached: this.peerStore.standardNeighborsList.length >= this.HALF_TARGET,
137
142
  }
138
143
  }
139
144
  #getOverlap(peerId1 = 'toto') {
@@ -212,7 +217,7 @@ export class Topologist {
212
217
  if (!offerHash || !readyOffer) return; // no ready offer to spread
213
218
 
214
219
  // IF WE ARE CONNECTED TO LESS 2 (WRTC) AND NOT TO MUCH CONNECTING, WE CAN BROADCAST IT TO ALL
215
- if (!isHalfReached && ingPlusEd <= this.twiceTarget) {
220
+ if (!isHalfReached && ingPlusEd <= this.TWICE_TARGET) {
216
221
  this.gossip.broadcastToAll({ signal: readyOffer.signal, offerHash }, 'signal_offer');
217
222
  readyOffer.sentCounter++; // avoid sending it again
218
223
  return; // limit to one per loop
@@ -236,7 +241,7 @@ export class Topologist {
236
241
  else if (this.peerStore.connected[id] || this.peerStore.connecting[id]) continue;
237
242
 
238
243
  const { overlap, nonPublicCount } = this.#getOverlap(id);
239
- if (nonPublicCount > DISCOVERY.TARGET_NEIGHBORS_COUNT) continue; // the peer is over connected, ignore it
244
+ if (nonPublicCount > this.NEIGHBORS_TARGET) continue; // the peer is over connected, ignore it
240
245
  if (bestValue === null) bestValue = isHalfReached ? overlap : nonPublicCount;
241
246
  if (isHalfReached && overlap > bestValue) continue; // only target lowest overlap
242
247
  if (!isHalfReached && nonPublicCount < bestValue) continue; // only target highest neighbors count
@@ -264,7 +269,7 @@ export class Topologist {
264
269
  this.offersQueue.updateOrderingBy(this.#localTopologyInfo.isHalfReached);
265
270
  this.offersQueue.removeOlderThan(TRANSPORTS.SDP_OFFER_EXPIRATION / 2); // remove close to expiration offers
266
271
  for (let i = 0; i < this.offersQueue.size; i++) {
267
- //if (connectingCount > this.twiceTarget * 2) break; // stop if we are over connecting
272
+ //if (connectingCount > this.TWICE_TARGET * 2) break; // stop if we are over connecting
268
273
  const { senderId, data, timestamp, value } = this.offersQueue.bestOfferInfo;
269
274
  if (!senderId || !data || !timestamp) break;
270
275
  if (this.peerStore.connected[senderId] || this.peerStore.isKicked(senderId)) continue;
@@ -277,7 +282,6 @@ export class Topologist {
277
282
  connectingCount++;
278
283
  }
279
284
  }
280
-
281
285
  /** Kick the peer with the biggest overlap (any round of 2.5sec is isTooMany)
282
286
  * - If all peers have the same overlap, kick the one with the most non-public neighbors */
283
287
  #improveTopologyByKickingPeers() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hive-p2p/server",
3
- "version": "1.0.36",
3
+ "version": "1.0.38",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1,6 +1,6 @@
1
1
  import { NetworkRendererElements, NetworkRendererOptions } from './renderer-options.mjs';
2
2
  import { Node, NodesStore, ConnectionsStore } from './renderer-stores.mjs';
3
- import { NODE, DISCOVERY } from '../core/config.mjs';
3
+ import { DISCOVERY } from '../core/config.mjs';
4
4
 
5
5
  export class NetworkRenderer {
6
6
  initCameraZ = 1400;