socket-function 0.8.39 → 0.8.40
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/SocketFunction.ts +3 -0
- package/package.json +2 -2
- package/src/CallFactory.ts +25 -6
- package/src/caching.ts +5 -1
- package/src/fixLargeNetworkCalls.ts +1 -1
- package/src/misc.ts +3 -0
- package/src/profiling/measure.ts +4 -4
- package/src/webSocketServer.ts +1 -0
- package/src/websocketFactory.ts +1 -1
package/SocketFunction.ts
CHANGED
|
@@ -201,6 +201,8 @@ export class SocketFunction {
|
|
|
201
201
|
public static mountedNodeId: string = "";
|
|
202
202
|
public static mountedIP: string = "";
|
|
203
203
|
private static hasMounted = false;
|
|
204
|
+
private static onMountCallback: () => void = () => { };
|
|
205
|
+
public static mountPromise: Promise<void> = new Promise(r => this.onMountCallback = r);
|
|
204
206
|
public static async mount(config: SocketServerConfig) {
|
|
205
207
|
if (this.mountedNodeId) {
|
|
206
208
|
throw new Error("SocketFunction already mounted, mounting twice in one thread is not allowed.");
|
|
@@ -223,6 +225,7 @@ export class SocketFunction {
|
|
|
223
225
|
await callback();
|
|
224
226
|
}
|
|
225
227
|
}
|
|
228
|
+
this.onMountCallback();
|
|
226
229
|
return this.mountedNodeId;
|
|
227
230
|
}
|
|
228
231
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "socket-function",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.40",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"node-forge": "https://github.com/sliftist/forge#name",
|
|
11
11
|
"preact": "^10.10.6",
|
|
12
12
|
"rdtsc-now": "^0.3.0",
|
|
13
|
-
"typenode": "^4.9.4-
|
|
13
|
+
"typenode": "^4.9.4-f",
|
|
14
14
|
"ws": "^8.8.0"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
package/src/CallFactory.ts
CHANGED
|
@@ -10,8 +10,9 @@ import { getClientNodeId, getNodeIdLocation, registerNodeClient } from "./nodeCa
|
|
|
10
10
|
import debugbreak from "debugbreak";
|
|
11
11
|
import { lazy } from "./caching";
|
|
12
12
|
import { JSONLACKS } from "./JSONLACKS/JSONLACKS";
|
|
13
|
-
import { red } from "./formatting/logColors";
|
|
14
|
-
import { isSplitableArray } from "./fixLargeNetworkCalls";
|
|
13
|
+
import { red, yellow } from "./formatting/logColors";
|
|
14
|
+
import { isSplitableArray, markArrayAsSplitable } from "./fixLargeNetworkCalls";
|
|
15
|
+
import { delay } from "./batching";
|
|
15
16
|
|
|
16
17
|
const MIN_RETRY_DELAY = 1000;
|
|
17
18
|
|
|
@@ -56,6 +57,8 @@ export interface SenderInterface {
|
|
|
56
57
|
addEventListener(event: "message", listener: (data: ws.RawData | ws.MessageEvent | string) => void): void;
|
|
57
58
|
|
|
58
59
|
readyState: number;
|
|
60
|
+
|
|
61
|
+
ping?(): void;
|
|
59
62
|
}
|
|
60
63
|
|
|
61
64
|
export async function createCallFactory(
|
|
@@ -82,6 +85,18 @@ export async function createCallFactory(
|
|
|
82
85
|
// in return calls.
|
|
83
86
|
let nextSeqNum = Date.now() + Math.random();
|
|
84
87
|
|
|
88
|
+
// NOTE: I'm not sure if this is needed, I thought it was, but... now I think
|
|
89
|
+
// it probably isn't...
|
|
90
|
+
// if (webSocketBase?.readyState === 1 /* OPEN */ && webSocketBase.ping) {
|
|
91
|
+
// // Heartbeat loop, otherwise onDisconnect is never called.
|
|
92
|
+
// ((async () => {
|
|
93
|
+
// while (webSocketBase?.readyState === 1 /* OPEN */ && webSocketBase.ping) {
|
|
94
|
+
// await delay(1000 * 60);
|
|
95
|
+
// webSocketBase.ping?.();
|
|
96
|
+
// }
|
|
97
|
+
// }))().catch(() => { });
|
|
98
|
+
// }
|
|
99
|
+
|
|
85
100
|
let lastConnectionAttempt = 0;
|
|
86
101
|
|
|
87
102
|
let callerContext: CallerContextBase = {
|
|
@@ -120,6 +135,7 @@ export async function createCallFactory(
|
|
|
120
135
|
if (data.byteLength > SocketFunction.MAX_MESSAGE_SIZE * 1.5) {
|
|
121
136
|
let splitArgIndex = call.args.findIndex(isSplitableArray);
|
|
122
137
|
if (splitArgIndex >= 0) {
|
|
138
|
+
console.log(yellow(`Splitting large call due to large args: ${call.classGuid}.${call.functionName}`));
|
|
123
139
|
let SPLIT_GROUPS = 10;
|
|
124
140
|
let splitArg = call.args[splitArgIndex] as unknown[];
|
|
125
141
|
let subCalls = list(SPLIT_GROUPS).map(index => {
|
|
@@ -127,12 +143,15 @@ export async function createCallFactory(
|
|
|
127
143
|
let end = Math.floor((index + 1) / SPLIT_GROUPS * splitArg.length);
|
|
128
144
|
return splitArg.slice(start, end);
|
|
129
145
|
}).filter(x => x.length > 0);
|
|
130
|
-
|
|
146
|
+
|
|
147
|
+
let calls = subCalls.map(async splitList => {
|
|
131
148
|
let subCall = { ...call };
|
|
132
149
|
subCall.args = subCall.args.slice();
|
|
133
|
-
subCall.args[splitArgIndex] = splitList;
|
|
150
|
+
subCall.args[splitArgIndex] = markArrayAsSplitable(splitList);
|
|
134
151
|
await callFactory.performCall(subCall);
|
|
135
|
-
}
|
|
152
|
+
});
|
|
153
|
+
await Promise.allSettled(calls);
|
|
154
|
+
await Promise.all(calls);
|
|
136
155
|
// Eh... we COULD return the array of results, but... then the result would sometimes be an array,
|
|
137
156
|
// some times not, so, it is better to return a string which will make it more clear why it sometimes varies.
|
|
138
157
|
return "CALLS_SPLIT_DUE_TO_LARGE_ARGS";
|
|
@@ -355,7 +374,7 @@ export async function createCallFactory(
|
|
|
355
374
|
}
|
|
356
375
|
throw new Error(`Unhandled data type ${typeof message}`);
|
|
357
376
|
} catch (e: any) {
|
|
358
|
-
debugbreak(
|
|
377
|
+
debugbreak(2);
|
|
359
378
|
debugger;
|
|
360
379
|
console.error(e.stack);
|
|
361
380
|
}
|
package/src/caching.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { AnyFunction, Args, canHaveChildren } from "./types";
|
|
|
3
3
|
|
|
4
4
|
export function lazy<T>(factory: () => T): () => T {
|
|
5
5
|
let value: { value: T } | undefined = undefined;
|
|
6
|
-
|
|
7
6
|
return () => {
|
|
8
7
|
if (!value) {
|
|
9
8
|
value = { value: factory() };
|
|
@@ -33,8 +32,10 @@ export function cacheEmptyArray<T>(array: T[]): T[] {
|
|
|
33
32
|
|
|
34
33
|
export function cache<Output, Key>(getValue: (key: Key) => Output): {
|
|
35
34
|
(key: Key): Output;
|
|
35
|
+
// NOTE: If you want to clear all, just make a new cache!
|
|
36
36
|
clear(key: Key): void;
|
|
37
37
|
forceSet(key: Key, value: Output): void;
|
|
38
|
+
getAllKeys(): Key[];
|
|
38
39
|
} {
|
|
39
40
|
let startingCalculating = new Set<Key>();
|
|
40
41
|
let values = new Map<Key, Output>();
|
|
@@ -61,6 +62,9 @@ export function cache<Output, Key>(getValue: (key: Key) => Output): {
|
|
|
61
62
|
values.set(key, value);
|
|
62
63
|
startingCalculating.add(key);
|
|
63
64
|
};
|
|
65
|
+
cache.getAllKeys = () => {
|
|
66
|
+
return [...values.keys()];
|
|
67
|
+
};
|
|
64
68
|
return cache;
|
|
65
69
|
}
|
|
66
70
|
|
|
@@ -5,5 +5,5 @@ export function markArrayAsSplitable<T>(data: T[]): T[] {
|
|
|
5
5
|
}
|
|
6
6
|
export function isSplitableArray<T>(data: T): data is T & (unknown[]) {
|
|
7
7
|
if (!Array.isArray(data)) return false;
|
|
8
|
-
return (data as any)[arrayIsSplitable]
|
|
8
|
+
return !!(data as any)[arrayIsSplitable];
|
|
9
9
|
}
|
package/src/misc.ts
CHANGED
|
@@ -139,6 +139,9 @@ export function getKeys(obj: unknown) {
|
|
|
139
139
|
}
|
|
140
140
|
return keyArray;
|
|
141
141
|
}
|
|
142
|
+
export function getStringKeys<T extends {}>(obj: T): ((keyof T) & string)[] {
|
|
143
|
+
return Object.keys(obj) as any;
|
|
144
|
+
}
|
|
142
145
|
|
|
143
146
|
if (isNode()) {
|
|
144
147
|
// TODO: Find a better place for this...
|
package/src/profiling/measure.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import debugbreak from "debugbreak";
|
|
2
2
|
import { formatTime, formatNumber } from "../formatting/format";
|
|
3
|
-
import { red, yellow, blue } from "../formatting/logColors";
|
|
3
|
+
import { red, yellow, blue, magenta } from "../formatting/logColors";
|
|
4
4
|
|
|
5
5
|
import { getOwnTime, getPendingOwnTimeInstances, getPendingOwnTimeObjs, OwnTimeObj } from "./getOwnTime";
|
|
6
6
|
import { addToStats, addToStatsValue, createStatsValue, getStatsTop, StatsValue } from "./stats";
|
|
@@ -108,9 +108,9 @@ export function logMeasureTable(
|
|
|
108
108
|
let totalTime = entries.map(x => getTime(x).sum).reduce((a, b) => a + b, 0);
|
|
109
109
|
|
|
110
110
|
console.log();
|
|
111
|
-
let title = yellow(`Profiled ${formatTime(totalTime)}`);
|
|
111
|
+
let title = yellow(`Profiled ${formatTime(totalTime)} (logged at ${new Date().toISOString()})`);
|
|
112
112
|
if (name) {
|
|
113
|
-
title
|
|
113
|
+
title = `(${blue(name)}) ${title}`;
|
|
114
114
|
}
|
|
115
115
|
console.log(title);
|
|
116
116
|
function percent(value: number) {
|
|
@@ -142,7 +142,7 @@ export function logMeasureTable(
|
|
|
142
142
|
|
|
143
143
|
let ownTimeTop = getStatsTop(getTime(entry));
|
|
144
144
|
if (ownTimeTop.topHeavy) {
|
|
145
|
-
output += red(` TOP ${percent(ownTimeTop.valueFraction)} of the time is owned by ${percent(ownTimeTop.countFraction)} of the calls`);
|
|
145
|
+
output += red(` TOP ${percent(ownTimeTop.valueFraction)} of the time is owned by ${percent(ownTimeTop.countFraction)} of the calls (${formatTime(ownTimeTop.value / ownTimeTop.count)} per * ${formatNumber(ownTimeTop.count)} = ${formatTime(ownTimeTop.value)})`);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
if (entry.stillOpenCount > 0) {
|
package/src/webSocketServer.ts
CHANGED
|
@@ -12,6 +12,7 @@ import debugbreak from "debugbreak";
|
|
|
12
12
|
import { getNodeId } from "./nodeCache";
|
|
13
13
|
import crypto from "crypto";
|
|
14
14
|
import { Watchable } from "./misc";
|
|
15
|
+
import { delay, runInfinitePoll } from "./batching";
|
|
15
16
|
|
|
16
17
|
export type SocketServerConfig = (
|
|
17
18
|
https.ServerOptions & {
|
package/src/websocketFactory.ts
CHANGED
|
@@ -38,7 +38,7 @@ export function createWebsocketFactory(): (nodeId: string) => SenderInterface {
|
|
|
38
38
|
console.log(`Connecting to ${address}:${port}`);
|
|
39
39
|
}
|
|
40
40
|
let webSocket = new ws.WebSocket(`wss://${address}:${port}`, {
|
|
41
|
-
ca:
|
|
41
|
+
ca: getTrustedCertificates()
|
|
42
42
|
});
|
|
43
43
|
let result = Object.assign(webSocket, { socket: undefined as tls.TLSSocket | undefined });
|
|
44
44
|
webSocket.once("upgrade", e => {
|