@livedesk/hub 0.1.14 → 0.1.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livedesk/hub",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "LiveDesk local Hub API and browser frame bridge",
5
5
  "type": "module",
6
6
  "main": "src/server.js",
@@ -21,6 +21,7 @@ const DEFAULT_MAX_PEER_QUEUE_BYTES = 1024 * 1024;
21
21
  const DEFAULT_MAX_PEER_QUEUE_MESSAGES = 64;
22
22
  const DEFAULT_RECONNECT_MIN_MS = 1_000;
23
23
  const DEFAULT_RECONNECT_MAX_MS = 30_000;
24
+ const DEFAULT_CONNECT_TIMEOUT_MS = 5_000;
24
25
 
25
26
  function isEnabled(value, fallback = false) {
26
27
  if (value === undefined || value === null || value === '') return fallback;
@@ -429,6 +430,11 @@ export function createHubRelayControl({
429
430
  reconnectMinMs,
430
431
  5 * 60_000,
431
432
  DEFAULT_RECONNECT_MAX_MS);
433
+ const connectTimeoutMs = boundedInteger(
434
+ env.LIVEDESK_RELAY_CONNECT_TIMEOUT_MS,
435
+ 250,
436
+ 30_000,
437
+ DEFAULT_CONNECT_TIMEOUT_MS);
432
438
  const peers = new Map();
433
439
  const retiredPeerIds = new Map();
434
440
  const sendQueue = [];
@@ -449,6 +455,7 @@ export function createHubRelayControl({
449
455
  let connection = null;
450
456
  let connectionGeneration = 0;
451
457
  let reconnectTimer = null;
458
+ let connectAttemptTimer = null;
452
459
  let reconnectAttempt = 0;
453
460
  let receiveBuffer = Buffer.alloc(0);
454
461
  let queuedBytes = 0;
@@ -477,7 +484,8 @@ export function createHubRelayControl({
477
484
  function releaseQueuedItem(item) {
478
485
  queuedBytes = Math.max(0, queuedBytes - item.buffer.length);
479
486
  if (!item.peerId) return;
480
- const stats = queueStats(item.peerId);
487
+ const stats = peerQueueStats.get(item.peerId);
488
+ if (!stats) return;
481
489
  stats.messages = Math.max(0, stats.messages - 1);
482
490
  stats.bytes = Math.max(0, stats.bytes - item.buffer.length);
483
491
  }
@@ -566,7 +574,7 @@ export function createHubRelayControl({
566
574
  roomId,
567
575
  peerId,
568
576
  reason: safeText(reason, 80) || 'relay-peer-closed'
569
- }, peerId);
577
+ });
570
578
  }
571
579
 
572
580
  function closePeer(peerId, reason = 'relay-peer-closed', {
@@ -786,6 +794,24 @@ export function createHubRelayControl({
786
794
 
787
795
  function handleRelayEnvelope(message) {
788
796
  if (!message || typeof message !== 'object' || Array.isArray(message)) return;
797
+ if (message.type === 'relay.registered') {
798
+ if (message.protocol !== RELAY_CONTROL_PROTOCOL
799
+ || message.roomId !== roomId
800
+ || message.role !== 'hub'
801
+ || safeText(message.peerId, 64) !== ''
802
+ || state !== 'registering') {
803
+ lastError = 'relay-registration-invalid';
804
+ connection?.destroy();
805
+ return;
806
+ }
807
+ clearConnectAttemptTimer();
808
+ reconnectAttempt = 0;
809
+ lastConnectedAt = new Date().toISOString();
810
+ lastError = '';
811
+ transition('registered');
812
+ logEvent('relay', `Encrypted relay control registered at ${host}:${port}`);
813
+ return;
814
+ }
789
815
  const peerId = safeText(message.peerId, 64);
790
816
  if (message.protocol !== RELAY_CONTROL_PROTOCOL || message.roomId !== roomId) {
791
817
  if (peerId) rejectPeer(peerId, 'relay-routing-mismatch');
@@ -859,8 +885,14 @@ export function createHubRelayControl({
859
885
  reconnectTimer.unref?.();
860
886
  }
861
887
 
888
+ function clearConnectAttemptTimer() {
889
+ if (connectAttemptTimer) clearTimeout(connectAttemptTimer);
890
+ connectAttemptTimer = null;
891
+ }
892
+
862
893
  function handleConnectionClosed(socket, generation) {
863
894
  if (connection !== socket || generation !== connectionGeneration) return;
895
+ clearConnectAttemptTimer();
864
896
  connection = null;
865
897
  receiveBuffer = Buffer.alloc(0);
866
898
  clearQueue();
@@ -887,20 +919,17 @@ export function createHubRelayControl({
887
919
  socket.once('connect', () => {
888
920
  if (connection !== socket || generation !== connectionGeneration || !desired) return;
889
921
  counters.connections += 1;
890
- reconnectAttempt = 0;
891
- lastConnectedAt = new Date().toISOString();
892
- lastError = '';
893
- transition('registered');
922
+ transition('registering');
894
923
  const registered = enqueueEnvelope({
895
924
  type: 'relay.register',
896
925
  protocol: RELAY_CONTROL_PROTOCOL,
897
926
  roomId,
898
927
  role: 'hub',
899
928
  peerId: '',
929
+ ack: true,
900
930
  token: registrationToken
901
931
  });
902
932
  if (!registered) socket.destroy();
903
- else logEvent('relay', `Encrypted relay control registered at ${host}:${port}`);
904
933
  });
905
934
  socket.on('data', onConnectionData);
906
935
  socket.on('drain', () => {
@@ -914,6 +943,16 @@ export function createHubRelayControl({
914
943
  logWarn('relay', `Encrypted relay control connection failed code=${lastError}`);
915
944
  });
916
945
  socket.once('close', () => handleConnectionClosed(socket, generation));
946
+ connectAttemptTimer = setTimeout(() => {
947
+ if (connection !== socket
948
+ || generation !== connectionGeneration
949
+ || socket.destroyed
950
+ || (state !== 'connecting' && state !== 'registering')) return;
951
+ lastError = 'relay-connect-timeout';
952
+ logWarn('relay', `Encrypted relay control connection failed code=${lastError}`);
953
+ socket.destroy();
954
+ }, connectTimeoutMs);
955
+ connectAttemptTimer.unref?.();
917
956
  }
918
957
 
919
958
  async function start() {
@@ -931,6 +970,7 @@ export function createHubRelayControl({
931
970
  closing = true;
932
971
  if (reconnectTimer) clearTimeout(reconnectTimer);
933
972
  reconnectTimer = null;
973
+ clearConnectAttemptTimer();
934
974
  closeAllPeers('hub-shutdown');
935
975
  clearQueue();
936
976
  const socket = connection;
@@ -975,6 +1015,7 @@ export function createHubRelayControl({
975
1015
  host,
976
1016
  port,
977
1017
  peerCount: peers.size,
1018
+ peerQueueCount: peerQueueStats.size,
978
1019
  queuedMessages: sendQueue.length,
979
1020
  queuedBytes,
980
1021
  maxPeers,