socket-function 1.1.28 → 1.1.30

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.
@@ -22,7 +22,6 @@ export declare class SocketFunction {
22
22
  static HTTP_ETAG_CACHE: boolean;
23
23
  static silent: boolean;
24
24
  static HTTP_COMPRESS: boolean;
25
- static LEGACY_INITIALIZE: boolean;
26
25
  static COEP: string;
27
26
  static COOP: string;
28
27
  static TOTAL_CALLS: number;
package/SocketFunction.ts CHANGED
@@ -61,8 +61,6 @@ export class SocketFunction {
61
61
 
62
62
  public static HTTP_COMPRESS = false;
63
63
 
64
- public static LEGACY_INITIALIZE = false;
65
-
66
64
  // If you have HTTP resources that require cookies you might to set `SocketFunction.COEP = "require-corp"`
67
65
  // - Cross-origin-resource-policy.
68
66
  public static COEP = "credentialless";
package/index.d.ts CHANGED
@@ -31,7 +31,6 @@ declare module "socket-function/SocketFunction" {
31
31
  static HTTP_ETAG_CACHE: boolean;
32
32
  static silent: boolean;
33
33
  static HTTP_COMPRESS: boolean;
34
- static LEGACY_INITIALIZE: boolean;
35
34
  static COEP: string;
36
35
  static COOP: string;
37
36
  static TOTAL_CALLS: number;
@@ -472,6 +471,7 @@ declare module "socket-function/src/CallFactory" {
472
471
  closedForever?: boolean;
473
472
  isConnected?: boolean;
474
473
  receivedInitializeState?: InitializeState;
474
+ protocolNegotiated?: boolean;
475
475
  performCall(call: CallType): Promise<unknown>;
476
476
  onNextDisconnect(callback: () => void): void;
477
477
  disconnect(): void;
@@ -482,6 +482,7 @@ declare module "socket-function/src/CallFactory" {
482
482
  export interface SenderInterface {
483
483
  nodeId?: string;
484
484
  _socket?: tls.TLSSocket;
485
+ protocol?: string;
485
486
  send(data: string | Buffer): void;
486
487
  close(): void;
487
488
  addEventListener(event: "open", listener: () => void): void;
@@ -1079,11 +1080,6 @@ declare module "socket-function/src/nodeCache" {
1079
1080
  export declare function getNodeIdDomain(nodeId: string): string;
1080
1081
  export declare function getNodeIdDomainMaybeUndefined(nodeId: string): string | undefined;
1081
1082
  export declare function registerNodeClient(callFactory: CallFactory): void;
1082
- export declare function changeNodeId(config: {
1083
- originalNodeId: string;
1084
- newNodeId: string;
1085
- callFactory: CallFactory;
1086
- }): boolean;
1087
1083
  export declare function getCreateCallFactory(nodeId: string): MaybePromise<CallFactory>;
1088
1084
  export declare function getCallFactory(nodeId: string): MaybePromise<CallFactory | undefined>;
1089
1085
  export declare function debugGetAllCallFactories(): CallFactory[];
@@ -1283,6 +1279,25 @@ declare module "socket-function/src/promiseRace" {
1283
1279
 
1284
1280
  }
1285
1281
 
1282
+ declare module "socket-function/src/protocolNegotiation" {
1283
+ export type ConnectionFlags = {
1284
+ clientLZ4: boolean;
1285
+ serverLZ4: boolean;
1286
+ };
1287
+ export type DecodedProtocol = {
1288
+ target: string;
1289
+ flags: ConnectionFlags;
1290
+ };
1291
+ export declare function decodeProtocol(hex: string): DecodedProtocol | undefined;
1292
+ export declare function proposeProtocols(target: string | undefined, clientCapabilities: {
1293
+ lz4: boolean;
1294
+ }): string[];
1295
+ export declare function chooseProtocol(proposed: string[], serverNodeId: string, serverCapabilities: {
1296
+ lz4: boolean;
1297
+ }): string | undefined;
1298
+
1299
+ }
1300
+
1286
1301
  declare module "socket-function/src/runPromise" {
1287
1302
  export declare const runAsync: typeof runPromise;
1288
1303
  export declare function runPromise(command: string, config?: {
@@ -1419,10 +1434,11 @@ declare module "socket-function/src/websocketFactory" {
1419
1434
  import { SenderInterface } from "socket-function/src/CallFactory";
1420
1435
  import type * as ws from "ws";
1421
1436
  export declare function getTLSSocket(webSocket: ws.WebSocket): tls.TLSSocket;
1437
+ export type WebsocketFactory = (nodeId: string, proposedProtocols?: string[]) => SenderInterface;
1422
1438
  /** NOTE: We create a factory, which embeds the key/cert information. Otherwise retries might use
1423
1439
  * a different key/cert context.
1424
1440
  */
1425
- export declare function createWebsocketFactory(): (nodeId: string) => SenderInterface;
1441
+ export declare function createWebsocketFactory(): WebsocketFactory;
1426
1442
 
1427
1443
  }
1428
1444
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "1.1.28",
3
+ "version": "1.1.30",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
@@ -11,6 +11,7 @@ export interface CallFactory {
11
11
  closedForever?: boolean;
12
12
  isConnected?: boolean;
13
13
  receivedInitializeState?: InitializeState;
14
+ protocolNegotiated?: boolean;
14
15
  performCall(call: CallType): Promise<unknown>;
15
16
  onNextDisconnect(callback: () => void): void;
16
17
  disconnect(): void;
@@ -21,6 +22,7 @@ export interface CallFactory {
21
22
  export interface SenderInterface {
22
23
  nodeId?: string;
23
24
  _socket?: tls.TLSSocket;
25
+ protocol?: string;
24
26
  send(data: string | Buffer): void;
25
27
  close(): void;
26
28
  addEventListener(event: "open", listener: () => void): void;
@@ -5,7 +5,7 @@ import { convertErrorStackToError, formatNumberSuffixed, isBufferType, isNode, l
5
5
  import { createWebsocketFactory, getTLSSocket } from "./websocketFactory";
6
6
  import { SocketFunction } from "../SocketFunction";
7
7
  import * as tls from "tls";
8
- import { changeNodeId, getClientNodeId, getNodeIdLocation, registerNodeClient } from "./nodeCache";
8
+ import { getClientNodeId, getNodeIdLocation, registerNodeClient } from "./nodeCache";
9
9
  import debugbreak from "debugbreak";
10
10
  import { lazy } from "./caching";
11
11
  import { blue, green, red, yellow } from "./formatting/logColors";
@@ -18,7 +18,8 @@ import { setFlag } from "../require/compileFlags";
18
18
  import { measureFnc, measureWrap, registerMeasureInfo } from "./profiling/measure";
19
19
  import { MaybePromise } from "./types";
20
20
  import { Zip } from "./Zip";
21
- import { LZ4 } from "./lz4/LZ4";
21
+ import { decodeProtocol, proposeProtocols } from "./protocolNegotiation";
22
+ setImmediate(() => import("./lz4/LZ4"));
22
23
 
23
24
  setFlag(require, "pako", "allowclient", true);
24
25
 
@@ -49,6 +50,9 @@ export interface CallFactory {
49
50
  closedForever?: boolean;
50
51
  isConnected?: boolean;
51
52
  receivedInitializeState?: InitializeState;
53
+ // True if the connection was established with a negotiated
54
+ // Sec-WebSocket-Protocol (so the legacy initialize packet should be skipped).
55
+ protocolNegotiated?: boolean;
52
56
  // NOTE: May or may not have reconnection or retry logic inside of performCall.
53
57
  // Trigger performLocalCall on the other side of the connection
54
58
  performCall(call: CallType): Promise<unknown>;
@@ -62,6 +66,9 @@ export interface SenderInterface {
62
66
  nodeId?: string;
63
67
  // Only set AFTER "open" (if set at all, as in the browser we don't have access to the socket).
64
68
  _socket?: tls.TLSSocket;
69
+ // The chosen Sec-WebSocket-Protocol value (set after "open" by both Node `ws`
70
+ // and the browser WebSocket). Empty string means none was negotiated.
71
+ protocol?: string;
65
72
 
66
73
  send(data: string | Buffer): void;
67
74
  close(): void;
@@ -368,6 +375,23 @@ export async function createCallFactory(
368
375
  } else {
369
376
  onClose(new Error(`Websocket received in closed state`).stack!);
370
377
  }
378
+
379
+ if (callFactory.lastClosed && callFactory.isConnected) {
380
+ console.log(`Successfully reconnected to ${nodeId}, which has been closed for ${formatTime(Date.now() - callFactory.lastClosed)}`, { nodeId });
381
+ }
382
+
383
+ if (callFactory.isConnected && newWebSocket.protocol) {
384
+ let decoded = decodeProtocol(newWebSocket.protocol);
385
+ if (decoded) {
386
+ callFactory.receivedInitializeState = {
387
+ supportsLZ4: decoded.flags.serverLZ4,
388
+ };
389
+ callFactory.protocolNegotiated = true;
390
+ if (SocketFunction.logMessages) {
391
+ console.log(green(`Negotiated protocol with ${niceConnectionName}: target=${decoded.target}, clientLZ4=${decoded.flags.clientLZ4}, serverLZ4=${decoded.flags.serverLZ4}`));
392
+ }
393
+ }
394
+ }
371
395
  }
372
396
 
373
397
  const BASE_LENGTH_OFFSET = 324_432_461_592_612;
@@ -458,12 +482,12 @@ export async function createCallFactory(
458
482
  }
459
483
  lastConnectionAttempt = Date.now();
460
484
 
461
- // Try alternates, and if any work, use them
485
+ // Try alternates, and if any work, use them.
462
486
  try {
463
487
  let alternates = await SocketFunction.GET_ALTERNATE_NODE_IDS(nodeId);
464
488
  if (alternates) {
465
489
  for (let alternateNodeId of alternates) {
466
- let newWebSocket = createWebsocket(alternateNodeId);
490
+ let newWebSocket = createWebsocket(alternateNodeId, proposeProtocols(isNode() ? nodeId : undefined, { lz4: true }));
467
491
  await initializeWebsocket(newWebSocket, true);
468
492
 
469
493
  if (callFactory.isConnected) {
@@ -475,7 +499,7 @@ export async function createCallFactory(
475
499
  console.error("Error getting alternate node IDs", e);
476
500
  }
477
501
 
478
- let newWebSocket = createWebsocket(nodeId);
502
+ let newWebSocket = createWebsocket(nodeId, proposeProtocols(isNode() ? nodeId : undefined, { lz4: true }));
479
503
  await initializeWebsocket(newWebSocket);
480
504
 
481
505
  return newWebSocket;
@@ -556,11 +580,10 @@ export async function createCallFactory(
556
580
  };
557
581
 
558
582
  if (call.isReturn) {
559
- if (!SocketFunction.LEGACY_INITIALIZE && call.seqNum === INITIALIZE_STATE_SEQ_NUM) {
560
- callFactory.receivedInitializeState = call.result as InitializeState;
561
- if (SocketFunction.logMessages) {
562
- console.log(green(`Received initialize state from ${callFactory.realNodeId} (for ${nodeId}) at ${Date.now()}`));
563
- }
583
+ // Tolerate the legacy initialize packet from old peers — silently
584
+ // ignore so it doesn't get logged as an unknown call. Our actual
585
+ // initialize state comes from Sec-WebSocket-Protocol negotiation.
586
+ if (call.seqNum === INITIALIZE_STATE_SEQ_NUM) {
564
587
  return;
565
588
  }
566
589
  let callbackObj = pendingCalls.get(call.seqNum);
@@ -770,25 +793,6 @@ export async function createCallFactory(
770
793
  }
771
794
 
772
795
 
773
- if (!SocketFunction.LEGACY_INITIALIZE) {
774
- let initState: InitializeState = {
775
- supportsLZ4: true,
776
- };
777
- let initReturn: InternalReturnType = {
778
- isReturn: true,
779
- result: initState,
780
- seqNum: INITIALIZE_STATE_SEQ_NUM,
781
- };
782
- if (SocketFunction.logMessages) {
783
- console.log(`Sending initialize state to ${nodeId}`);
784
- }
785
- let data = await SocketFunction.WIRE_SERIALIZER.serialize(initReturn);
786
- await send(data);
787
- if (SocketFunction.logMessages) {
788
- console.log(`Sent initialize state to ${nodeId}`);
789
- }
790
- }
791
-
792
796
  return callFactory;
793
797
  }
794
798
 
@@ -850,6 +854,7 @@ const decompressObj = measureWrap(async function wireCallDecompress(obj: Buffer,
850
854
  });
851
855
 
852
856
  const compressObjLZ4 = measureWrap(async function wireCallCompressLZ4(obj: unknown, stats: CompressionStats): Promise<Buffer[]> {
857
+ const { LZ4 } = await import("./lz4/LZ4");
853
858
  let headerParts: number[];
854
859
  let dataBuffers: Buffer[];
855
860
 
@@ -952,6 +957,8 @@ const compressObjLZ4 = measureWrap(async function wireCallCompressLZ4(obj: unkno
952
957
  });
953
958
 
954
959
  const decompressObjLZ4 = measureWrap(async function wireCallDecompressLZ4(obj: Buffer[], stats: CompressionStats): Promise<unknown> {
960
+
961
+ const { LZ4 } = await import("./lz4/LZ4");
955
962
  stats.compressedSize += obj.reduce((sum, buf) => sum + buf.length, 0);
956
963
 
957
964
  let decompressed: Buffer[] = [];
package/src/batching.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { formatTime } from "./formatting/format";
2
+ import { red } from "./formatting/logColors";
2
3
  import { PromiseObj, isNode, timeoutToError } from "./misc";
3
4
  import { measureWrap } from "./profiling/measure";
4
5
  import { AnyFunction, Args, MaybePromise } from "./types";
@@ -395,7 +396,7 @@ export async function safeLoop<T, R>(config: {
395
396
  while (!done) {
396
397
  await delay(5000);
397
398
  if (done) break;
398
- let message = `SLOW LOOP | ${index} / ${data.length} | ${formatTime(Date.now() - startTime)} | ${label}`;
399
+ let message = `${red("SLOW LOOP")} | ${index} / ${data.length} | ${formatTime(Date.now() - startTime)} | ${label}`;
399
400
  let timeOnCurrent = Date.now() - indexStartTime;
400
401
  if (timeOnCurrent > 5000) {
401
402
  message += `| SLOW INDEX (${index}) ${formatTime(timeOnCurrent)}+`;
@@ -18,11 +18,6 @@ export declare function getNodeIdLocation(nodeId: string): {
18
18
  export declare function getNodeIdDomain(nodeId: string): string;
19
19
  export declare function getNodeIdDomainMaybeUndefined(nodeId: string): string | undefined;
20
20
  export declare function registerNodeClient(callFactory: CallFactory): void;
21
- export declare function changeNodeId(config: {
22
- originalNodeId: string;
23
- newNodeId: string;
24
- callFactory: CallFactory;
25
- }): boolean;
26
21
  export declare function getCreateCallFactory(nodeId: string): MaybePromise<CallFactory>;
27
22
  export declare function getCallFactory(nodeId: string): MaybePromise<CallFactory | undefined>;
28
23
  export declare function debugGetAllCallFactories(): CallFactory[];
package/src/nodeCache.ts CHANGED
@@ -77,20 +77,6 @@ export function registerNodeClient(callFactory: CallFactory) {
77
77
  startCleanupLoop();
78
78
  }
79
79
 
80
- export function changeNodeId(config: {
81
- originalNodeId: string;
82
- newNodeId: string;
83
- callFactory: CallFactory;
84
- }) {
85
- if (nodeCache.has(config.newNodeId)) {
86
- console.warn(`Received connection we already have. Likely we and them tried to connect at the same time. Other nodeId: ${config.newNodeId}`);
87
- return false;
88
- }
89
- nodeCache.delete(config.originalNodeId);
90
- nodeCache.set(config.newNodeId, config.callFactory);
91
- return true;
92
- }
93
-
94
80
  export function getCreateCallFactory(nodeId: string): MaybePromise<CallFactory> {
95
81
  let callFactory = nodeCache.get(nodeId);
96
82
  if (callFactory === undefined) {
@@ -0,0 +1,15 @@
1
+ export type ConnectionFlags = {
2
+ clientLZ4: boolean;
3
+ serverLZ4: boolean;
4
+ };
5
+ export type DecodedProtocol = {
6
+ target: string;
7
+ flags: ConnectionFlags;
8
+ };
9
+ export declare function decodeProtocol(hex: string): DecodedProtocol | undefined;
10
+ export declare function proposeProtocols(target: string | undefined, clientCapabilities: {
11
+ lz4: boolean;
12
+ }): string[];
13
+ export declare function chooseProtocol(proposed: string[], serverNodeId: string, serverCapabilities: {
14
+ lz4: boolean;
15
+ }): string | undefined;
@@ -0,0 +1,108 @@
1
+ // Negotiates connection-level flags via Sec-WebSocket-Protocol on the WebSocket
2
+ // upgrade handshake. The client proposes every flag combination it accepts (hex-
3
+ // encoded so the value is a valid HTTP token). The server picks the first value
4
+ // whose target nodeId matches its own, then returns it verbatim. If none match,
5
+ // the server returns no protocol and the handshake fails — which is exactly the
6
+ // rejection semantics we want (indistinguishable from "node not reachable").
7
+
8
+ const PROTOCOL_VERSION = "v1";
9
+
10
+ export type ConnectionFlags = {
11
+ // Client supports receiving LZ4-compressed frames
12
+ clientLZ4: boolean;
13
+ // Server supports receiving LZ4-compressed frames (i.e. server can accept LZ4)
14
+ serverLZ4: boolean;
15
+ };
16
+
17
+ export type DecodedProtocol = {
18
+ target: string;
19
+ flags: ConnectionFlags;
20
+ };
21
+
22
+ function hexEncode(s: string): string {
23
+ return Buffer.from(s, "utf8").toString("hex");
24
+ }
25
+ function hexDecode(s: string): string {
26
+ return Buffer.from(s, "hex").toString("utf8");
27
+ }
28
+
29
+ function encodeFlagBit(b: boolean): string { return b ? "1" : "0"; }
30
+
31
+ // An empty-string target encodes "match any server nodeId" — used for
32
+ // browser clients which don't know our internal nodeId because they're
33
+ // connecting through a Let's Encrypt cert on a public domain.
34
+ const WILDCARD_TARGET = "";
35
+
36
+ function encodeOne(target: string, flags: ConnectionFlags): string {
37
+ let plain = `${PROTOCOL_VERSION}|${target}|clz4=${encodeFlagBit(flags.clientLZ4)}|slz4=${encodeFlagBit(flags.serverLZ4)}`;
38
+ return hexEncode(plain);
39
+ }
40
+
41
+ export function decodeProtocol(hex: string): DecodedProtocol | undefined {
42
+ if (!/^[0-9a-fA-F]+$/.test(hex)) return undefined;
43
+ let plain: string;
44
+ try {
45
+ plain = hexDecode(hex);
46
+ } catch {
47
+ return undefined;
48
+ }
49
+ let parts = plain.split("|");
50
+ if (parts.length < 2) return undefined;
51
+ if (parts[0] !== PROTOCOL_VERSION) return undefined;
52
+ let target = parts[1];
53
+ let flags: ConnectionFlags = { clientLZ4: false, serverLZ4: false };
54
+ for (let i = 2; i < parts.length; i++) {
55
+ let [k, v] = parts[i].split("=");
56
+ if (k === "clz4") flags.clientLZ4 = v === "1";
57
+ else if (k === "slz4") flags.serverLZ4 = v === "1";
58
+ }
59
+ return { target, flags };
60
+ }
61
+
62
+ // Build the list of subprotocol values the client wants to propose. We enumerate
63
+ // every flag combination the client accepts — the server will pick whichever
64
+ // one it can serve (matching its own flag support). Caller is responsible for
65
+ // not proposing flags it can't handle.
66
+ //
67
+ // `target` is the nodeId the client wants to reach. Pass undefined for browser
68
+ // clients (or any context where the client doesn't know the server's nodeId,
69
+ // because it's reaching the server through a public DNS name + Let's Encrypt
70
+ // cert). The server then accepts the connection regardless of its identity,
71
+ // while still negotiating flags.
72
+ export function proposeProtocols(target: string | undefined, clientCapabilities: { lz4: boolean }): string[] {
73
+ let out: string[] = [];
74
+ let clientLZ4Options = clientCapabilities.lz4 ? [true, false] : [false];
75
+ let serverLZ4Options = [true, false];
76
+ let encodedTarget = target ?? WILDCARD_TARGET;
77
+ for (let clientLZ4 of clientLZ4Options) {
78
+ for (let serverLZ4 of serverLZ4Options) {
79
+ out.push(encodeOne(encodedTarget, { clientLZ4, serverLZ4 }));
80
+ }
81
+ }
82
+ return out;
83
+ }
84
+
85
+ // Server-side: given the proposed (hex-encoded) subprotocol values from the
86
+ // client, the server's own nodeId, and the server's capabilities — pick the
87
+ // first value matching this server with a flag combo we can support. Returns
88
+ // the chosen hex string verbatim (so the server echoes it back), or undefined
89
+ // to signal no match → reject the handshake.
90
+ //
91
+ // A proposal with target === WILDCARD_TARGET ("") matches any server (used
92
+ // by browsers that don't know our internal nodeId).
93
+ export function chooseProtocol(
94
+ proposed: string[],
95
+ serverNodeId: string,
96
+ serverCapabilities: { lz4: boolean }
97
+ ): string | undefined {
98
+ for (let hex of proposed) {
99
+ let decoded = decodeProtocol(hex);
100
+ if (!decoded) continue;
101
+ if (decoded.target !== WILDCARD_TARGET && decoded.target !== serverNodeId) continue;
102
+ // Server capability check: if the proposal asks the server to receive
103
+ // LZ4 (slz4=1) but the server doesn't support it, skip.
104
+ if (decoded.flags.serverLZ4 && !serverCapabilities.lz4) continue;
105
+ return hex;
106
+ }
107
+ return undefined;
108
+ }
@@ -3,6 +3,7 @@ import http from "http";
3
3
  import net from "net";
4
4
  import tls from "tls";
5
5
  import { getNodeIdsFromRequest, httpCallHandler } from "./callHTTPHandler";
6
+ import { chooseProtocol, decodeProtocol } from "./protocolNegotiation";
6
7
  import { SocketFunction } from "../SocketFunction";
7
8
  import { getTrustedCertificates, watchTrustedCertificates } from "./certStore";
8
9
  import { createCallFactory } from "./CallFactory";
@@ -63,6 +64,26 @@ export async function startSocketServer(
63
64
 
64
65
  const webSocketServer = new ws.Server({
65
66
  noServer: true,
67
+ // Negotiate connection-level flags via Sec-WebSocket-Protocol. The
68
+ // client proposes hex-encoded values that include the target nodeId;
69
+ // we accept only those whose target matches OUR identity
70
+ // (SocketFunction.mountedNodeId — not the address the client used to
71
+ // reach us). If none match we return false, which rejects the
72
+ // handshake — exactly the semantics we want (indistinguishable from
73
+ // "node not reachable"). If the client sent no Sec-WebSocket-Protocol
74
+ // at all, this callback isn't invoked and the handshake proceeds as
75
+ // a legacy client.
76
+ handleProtocols: (protocols, request) => {
77
+ const ourNodeId = SocketFunction.mountedNodeId;
78
+ const proposed = Array.from(protocols);
79
+ const chosen = chooseProtocol(proposed, ourNodeId, { lz4: true });
80
+ if (!chosen) {
81
+ const proposedDecoded = proposed.map(p => decodeProtocol(p) ?? `<undecodable: ${p}>`);
82
+ console.log(`Rejecting handshake on ${ourNodeId}: none of the ${proposed.length} proposed protocols target us`, { ourNodeId, proposedDecoded });
83
+ return false;
84
+ }
85
+ return chosen;
86
+ },
66
87
  });
67
88
 
68
89
  async function setupHTTPSServer(watchOptions: Watchable<https.ServerOptions>) {
@@ -3,7 +3,8 @@ import tls from "tls";
3
3
  import { SenderInterface } from "./CallFactory";
4
4
  import type * as ws from "ws";
5
5
  export declare function getTLSSocket(webSocket: ws.WebSocket): tls.TLSSocket;
6
+ export type WebsocketFactory = (nodeId: string, proposedProtocols?: string[]) => SenderInterface;
6
7
  /** NOTE: We create a factory, which embeds the key/cert information. Otherwise retries might use
7
8
  * a different key/cert context.
8
9
  */
9
- export declare function createWebsocketFactory(): (nodeId: string) => SenderInterface;
10
+ export declare function createWebsocketFactory(): WebsocketFactory;
@@ -1,52 +1,56 @@
1
- import tls from "tls";
2
- import { isNode } from "./misc";
3
- import { SenderInterface } from "./CallFactory";
4
- import { getTrustedCertificates } from "./certStore";
5
- import { getNodeIdLocation } from "./nodeCache";
6
- import debugbreak from "debugbreak";
7
- import { SocketFunction } from "../SocketFunction";
8
- import type * as ws from "ws";
9
-
10
- export function getTLSSocket(webSocket: ws.WebSocket) {
11
- return (webSocket as any)._socket as tls.TLSSocket;
12
- }
13
-
14
- /** NOTE: We create a factory, which embeds the key/cert information. Otherwise retries might use
15
- * a different key/cert context.
16
- */
17
- export function createWebsocketFactory(): (nodeId: string) => SenderInterface {
18
-
19
- if (!isNode()) {
20
- return (nodeId: string) => {
21
- let location = getNodeIdLocation(nodeId);
22
- if (!location) throw new Error(`Cannot connect to ${nodeId}, no address known`);
23
- let { address, port } = location;
24
-
25
- if (!SocketFunction.silent) {
26
- console.log(`Connecting to ${address}:${port}`);
27
- }
28
- return new WebSocket(`wss://${address}:${port}`);
29
- };
30
- } else {
31
- return (nodeId: string) => {
32
- let location = getNodeIdLocation(nodeId);
33
- if (!location) throw new Error(`Cannot connect to ${nodeId}, no address known`);
34
- let { address, port } = location;
35
-
36
- if (!SocketFunction.silent) {
37
- console.log(`Connecting to ${address}:${port}`);
38
- }
39
- const ws = require("ws") as typeof import("ws");
40
- let webSocket = new ws.WebSocket(`wss://${address}:${port}`, undefined, {
41
- ca: getTrustedCertificates(),
42
- });
43
-
44
- // NOTE: Little setup is done here, because Sometimes websockets are created here,
45
- // and sometimes via incoming connections, We should do most setup in
46
- // CallFactory.ts:initializeWebsocket
47
-
48
- return webSocket;
49
- };
50
- }
51
- }
52
-
1
+ import tls from "tls";
2
+ import { isNode } from "./misc";
3
+ import { SenderInterface } from "./CallFactory";
4
+ import { getTrustedCertificates } from "./certStore";
5
+ import { getNodeIdLocation } from "./nodeCache";
6
+ import debugbreak from "debugbreak";
7
+ import { SocketFunction } from "../SocketFunction";
8
+ import type * as ws from "ws";
9
+
10
+ export function getTLSSocket(webSocket: ws.WebSocket) {
11
+ return (webSocket as any)._socket as tls.TLSSocket;
12
+ }
13
+
14
+ export type WebsocketFactory = (nodeId: string, proposedProtocols?: string[]) => SenderInterface;
15
+
16
+ /** NOTE: We create a factory, which embeds the key/cert information. Otherwise retries might use
17
+ * a different key/cert context.
18
+ */
19
+ export function createWebsocketFactory(): WebsocketFactory {
20
+
21
+ if (!isNode()) {
22
+ return (nodeId: string, proposedProtocols?: string[]) => {
23
+ let location = getNodeIdLocation(nodeId);
24
+ if (!location) throw new Error(`Cannot connect to ${nodeId}, no address known`);
25
+ let { address, port } = location;
26
+
27
+ if (!SocketFunction.silent) {
28
+ console.log(`Connecting to ${address}:${port}`);
29
+ }
30
+ if (proposedProtocols && proposedProtocols.length > 0) {
31
+ return new WebSocket(`wss://${address}:${port}`, proposedProtocols);
32
+ }
33
+ return new WebSocket(`wss://${address}:${port}`);
34
+ };
35
+ } else {
36
+ return (nodeId: string, proposedProtocols?: string[]) => {
37
+ let location = getNodeIdLocation(nodeId);
38
+ if (!location) throw new Error(`Cannot connect to ${nodeId}, no address known`);
39
+ let { address, port } = location;
40
+
41
+ if (!SocketFunction.silent) {
42
+ console.log(`Connecting to ${address}:${port}`);
43
+ }
44
+ const ws = require("ws") as typeof import("ws");
45
+ let webSocket = new ws.WebSocket(`wss://${address}:${port}`, proposedProtocols, {
46
+ ca: getTrustedCertificates(),
47
+ });
48
+
49
+ // NOTE: Little setup is done here, because Sometimes websockets are created here,
50
+ // and sometimes via incoming connections, We should do most setup in
51
+ // CallFactory.ts:initializeWebsocket
52
+
53
+ return webSocket;
54
+ };
55
+ }
56
+ }