socket-function 0.8.40 → 0.9.1

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.
Files changed (45) hide show
  1. package/.eslintrc.js +50 -50
  2. package/SocketFunction.ts +280 -276
  3. package/SocketFunctionTypes.ts +90 -90
  4. package/hot/HotReloadController.ts +105 -70
  5. package/mobx/UrlParam.ts +39 -39
  6. package/mobx/observer.tsx +49 -49
  7. package/mobx/promiseToObservable.tsx +41 -41
  8. package/package.json +30 -28
  9. package/require/CSSShim.ts +19 -19
  10. package/require/RequireController.ts +252 -252
  11. package/require/buffer.js +2368 -2368
  12. package/require/compileFlags.ts +44 -44
  13. package/require/require.html +13 -13
  14. package/require/require.js +462 -454
  15. package/spec.txt +115 -115
  16. package/src/CallFactory.ts +389 -383
  17. package/src/JSONLACKS/JSONLACKS.generated.js +17 -17
  18. package/src/JSONLACKS/JSONLACKS.pegjs +247 -247
  19. package/src/JSONLACKS/JSONLACKS.ts +429 -375
  20. package/src/args.ts +21 -21
  21. package/src/batching.ts +170 -126
  22. package/src/caching.ts +318 -314
  23. package/src/callHTTPHandler.ts +203 -203
  24. package/src/callManager.ts +134 -134
  25. package/src/certStore.ts +29 -25
  26. package/src/fixLargeNetworkCalls.ts +8 -8
  27. package/src/formatting/colors.ts +78 -78
  28. package/src/formatting/format.ts +160 -156
  29. package/src/formatting/logColors.ts +17 -17
  30. package/src/misc.ts +302 -150
  31. package/src/nodeCache.ts +92 -92
  32. package/src/nodeProxy.ts +54 -54
  33. package/src/profiling/getOwnTime.ts +142 -142
  34. package/src/profiling/measure.ts +273 -244
  35. package/src/profiling/stats.ts +212 -212
  36. package/src/profiling/tcpLagProxy.ts +63 -63
  37. package/src/storagePath.ts +10 -10
  38. package/src/tlsParsing.ts +96 -96
  39. package/src/types.ts +8 -8
  40. package/src/webSocketServer.ts +250 -237
  41. package/test/client.css +2 -2
  42. package/test/client.ts +46 -46
  43. package/test/server.ts +43 -43
  44. package/test/shared.ts +52 -58
  45. package/tsconfig.json +26 -26
@@ -1,245 +1,274 @@
1
- import debugbreak from "debugbreak";
2
- import { formatTime, formatNumber } from "../formatting/format";
3
- import { red, yellow, blue, magenta } from "../formatting/logColors";
4
-
5
- import { getOwnTime, getPendingOwnTimeInstances, getPendingOwnTimeObjs, OwnTimeObj } from "./getOwnTime";
6
- import { addToStats, addToStatsValue, createStatsValue, getStatsTop, StatsValue } from "./stats";
7
-
8
- /** NOTE: Must be called BEFORE anything else is imported! */
9
- export function enableMeasurements() {
10
- if (functionsSkipped) {
11
- console.warn(red(`Skipped measure shimming ${functionsSkipped} functions. Fix this by calling enableMeasurements before any other imports.`));
12
- }
13
- measurementsEnabled = true;
14
- }
15
- /** NOTE: Must be called BEFORE anything else is imported! */
16
- export function disableMeasurements() {
17
- measurementsEnabled = false;
18
- }
19
-
20
- let functionsSkipped = 0;
21
-
22
- const measureOverhead = 5 / 1000;
23
-
24
- const AsyncFunction = (async () => { }).constructor;
25
-
26
- // TIMING: 1-5us. I have seen timing values greatly vary, but it does seem to be quite high, despite
27
- // microbenchmarks saying it is slow. Perhaps it is because getOwnTime breaks the cpu pipeline,
28
- // which causes slowness for code around us, but not if we are running in isolation?
29
- export function measureFnc(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
30
- let name = propertyKey;
31
- if (target.name) {
32
- name = `${target.name}.${name}`;
33
- } else {
34
- let constructorName = target.constructor.name;
35
- if (constructorName) {
36
- name = `${constructorName}().${name}`;
37
- }
38
- }
39
- if (descriptor.value instanceof AsyncFunction) {
40
- name += `(async)`;
41
- }
42
- descriptor.value = measureWrap(descriptor.value, name);
43
- }
44
- export function measureWrap<T extends (...args: any[]) => any>(fnc: T, name?: string): T {
45
- if (!measurementsEnabled) {
46
- functionsSkipped++;
47
- return fnc;
48
- }
49
- let usedName = name || fnc.name;
50
- return (function (this: any, ...args: unknown[]): unknown {
51
- if (outstandingProfiles.length === 0) {
52
- return fnc.apply(this, args);
53
- }
54
- return getOwnTime(usedName, () => fnc.apply(this, args), recordOwnTime);
55
- }) as T;
56
- }
57
- export function measureBlock<T extends (...args: any[]) => any>(fnc: T, name?: string): ReturnType<T> {
58
- return measureWrap(fnc, name)();
59
- }
60
-
61
- export function startMeasure(): {
62
- finish: () => MeasureProfile;
63
- } {
64
- if (!measurementsEnabled) {
65
- console.warn(red(`To capture measurements enableMeasurements() must be called before any other imports in your entry point`));
66
- }
67
- let profile: MeasureProfile = {
68
- entries: Object.create(null),
69
- };
70
- let openAtStart = new Set(getPendingOwnTimeInstances());
71
-
72
- outstandingProfiles.push(profile);
73
- return {
74
- finish() {
75
- let pending = getPendingOwnTimeObjs() || [];
76
- for (let timeObj of pending) {
77
- if (openAtStart.has(timeObj.source)) continue;
78
- addToProfile(profile, timeObj, true);
79
- }
80
- outstandingProfiles.splice(outstandingProfiles.indexOf(profile), 1);
81
- return profile;
82
- }
83
- };
84
- }
85
-
86
- export interface LogMeasureTableConfig {
87
- useTotalTime?: boolean;
88
- name?: string;
89
- // Defaults to 0.05
90
- thresholdInTable?: number;
91
- }
92
-
93
- export function logMeasureTable(
94
- profile: MeasureProfile,
95
- config?: LogMeasureTableConfig
96
- ) {
97
- let { useTotalTime, name, thresholdInTable } = config || {};
98
- if (thresholdInTable === undefined) {
99
- thresholdInTable = 0.05;
100
- }
101
-
102
- function getTime(entry: ProfileEntry) {
103
- return useTotalTime ? entry.totalTime : entry.ownTime;
104
- }
105
- let entries = Object.values(profile.entries);
106
- entries.sort((a, b) => getTime(b).sum - getTime(a).sum);
107
-
108
- let totalTime = entries.map(x => getTime(x).sum).reduce((a, b) => a + b, 0);
109
-
110
- console.log();
111
- let title = yellow(`Profiled ${formatTime(totalTime)} (logged at ${new Date().toISOString()})`);
112
- if (name) {
113
- title = `(${blue(name)}) ${title}`;
114
- }
115
- console.log(title);
116
- function percent(value: number) {
117
- return `${(value * 100).toFixed(2)}%`;
118
- }
119
-
120
- entries = entries.slice(0, 10);
121
- let maxNameLength = Math.max(...entries.map(x => x.name.length));
122
-
123
- for (let entry of entries.slice(0, 10)) {
124
- if (getTime(entry).sum / totalTime < thresholdInTable) break;
125
- let output = "";
126
- output += `${blue(entry.name)}`;
127
- output += Array(maxNameLength + 4 - entry.name.length).fill(" ").join("");
128
-
129
- let text = `${percent(getTime(entry).sum / totalTime).padStart(6, " ")} ( ${formatTime(getTime(entry).sum / getTime(entry).count).padStart(6, " ")} per * ${formatNumber(getTime(entry).count).padStart(6, " ")} = ${formatTime(getTime(entry).sum).padStart(6, " ")} )`;
130
- let overhead = measureOverhead * getTime(entry).count;
131
- let overheadFraction = overhead / getTime(entry).sum;
132
- let overheadIsAProblem = overheadFraction > 0.5;
133
- if (overheadIsAProblem) {
134
- text = yellow(text);
135
- }
136
-
137
- output += text;
138
-
139
- if (overheadIsAProblem) {
140
- output += red(` measurement overhead is ~${percent(overheadFraction)} of the time.`);
141
- }
142
-
143
- let ownTimeTop = getStatsTop(getTime(entry));
144
- if (ownTimeTop.topHeavy) {
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
- }
147
-
148
- if (entry.stillOpenCount > 0) {
149
- output += red(` (${entry.stillOpenCount} open)`);
150
- }
151
-
152
- console.log(output);
153
- }
154
- console.log();
155
- }
156
-
157
- export async function measureCode<T>(code: () => Promise<T>, config?: LogMeasureTableConfig) {
158
- let measure = startMeasure();
159
- try {
160
- return await measureBlock(code, code.name || "untracked");
161
- } finally {
162
- finishProfile(measure, config);
163
- }
164
- }
165
- export function measureCodeSync<T>(code: () => T, config?: LogMeasureTableConfig): T {
166
- let measure = startMeasure();
167
- try {
168
- return measureBlock(code, code.name || "untracked");
169
- } finally {
170
- finishProfile(measure, config);
171
- }
172
- }
173
- function finishProfile(measure: { finish(): MeasureProfile }, config?: LogMeasureTableConfig) {
174
- let profile = measure.finish();
175
- logMeasureTable(profile, config);
176
- }
177
-
178
-
179
- export interface MeasureProfile {
180
- entries: {
181
- [name: string]: ProfileEntry;
182
- };
183
- }
184
- export function createMeasureProfile(): MeasureProfile {
185
- return {
186
- entries: Object.create(null),
187
- };
188
- }
189
-
190
- export function addToMeasureProfile(base: MeasureProfile, other: MeasureProfile) {
191
- for (let name in other.entries) {
192
- let entry = other.entries[name];
193
- let baseEntry = base.entries[name];
194
- if (!baseEntry) {
195
- baseEntry = {
196
- name: name,
197
- ownTime: createStatsValue(),
198
- totalTime: createStatsValue(),
199
- stillOpenCount: 0,
200
- };
201
- base.entries[name] = baseEntry;
202
- }
203
- addToStats(baseEntry.ownTime, entry.ownTime);
204
- addToStats(baseEntry.totalTime, entry.totalTime);
205
- baseEntry.stillOpenCount += entry.stillOpenCount;
206
- }
207
- }
208
-
209
- interface ProfileEntry {
210
- name: string;
211
- ownTime: StatsValue;
212
- totalTime: StatsValue;
213
- stillOpenCount: number;
214
- }
215
-
216
- let measurementsEnabled = true;
217
-
218
- let outstandingProfiles: MeasureProfile[] = [];
219
- function recordOwnTime(ownTimeObj: OwnTimeObj) {
220
- if (outstandingProfiles.length === 0) return;
221
- for (let i = 0; i < outstandingProfiles.length; i++) {
222
- let profile = outstandingProfiles[i];
223
- addToProfile(profile, ownTimeObj);
224
- }
225
- }
226
-
227
-
228
- function addToProfile(profile: MeasureProfile, ownTimeObj: OwnTimeObj, stillOpen?: boolean) {
229
- let name = ownTimeObj.name;
230
- let entry = profile.entries[name];
231
- if (!entry) {
232
- entry = {
233
- name: name,
234
- ownTime: createStatsValue(),
235
- totalTime: createStatsValue(),
236
- stillOpenCount: 0,
237
- };
238
- profile.entries[name] = entry;
239
- }
240
- addToStatsValue(entry.ownTime, ownTimeObj.ownTime);
241
- addToStatsValue(entry.totalTime, ownTimeObj.time);
242
- if (stillOpen) {
243
- entry.stillOpenCount++;
244
- }
1
+ import debugbreak from "debugbreak";
2
+ import { formatTime, formatNumber } from "../formatting/format";
3
+ import { red, yellow, blue, magenta } from "../formatting/logColors";
4
+
5
+ import { getOwnTime, getPendingOwnTimeInstances, getPendingOwnTimeObjs, OwnTimeObj } from "./getOwnTime";
6
+ import { addToStats, addToStatsValue, createStatsValue, getStatsTop, StatsValue } from "./stats";
7
+ import { white } from "../formatting/logColors";
8
+ import { isNode } from "../misc";
9
+
10
+ /** NOTE: Must be called BEFORE anything else is imported! */
11
+ export function enableMeasurements() {
12
+ if (functionsSkipped) {
13
+ console.warn(red(`Skipped measure shimming ${functionsSkipped} functions. Fix this by calling enableMeasurements before any other imports.`));
14
+ }
15
+ measurementsEnabled = true;
16
+ }
17
+ /** NOTE: Must be called BEFORE anything else is imported! */
18
+ export function disableMeasurements() {
19
+ measurementsEnabled = false;
20
+ }
21
+
22
+ let functionsSkipped = 0;
23
+
24
+ const measureOverhead = 5 / 1000;
25
+
26
+ const AsyncFunction = (async () => { }).constructor;
27
+
28
+ // TIMING: 1-5us. I have seen timing values greatly vary, but it does seem to be quite high, despite
29
+ // microbenchmarks saying it is slow. Perhaps it is because getOwnTime breaks the cpu pipeline,
30
+ // which causes slowness for code around us, but not if we are running in isolation?
31
+ export function measureFnc(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
32
+ let name = propertyKey;
33
+ if (target.name) {
34
+ name = `${target.name}.${name}`;
35
+ } else {
36
+ let constructorName = target.constructor.name;
37
+ if (constructorName) {
38
+ name = `${constructorName}().${name}`;
39
+ }
40
+ }
41
+ if (descriptor.value instanceof AsyncFunction) {
42
+ name += `(async)`;
43
+ }
44
+ descriptor.value = measureWrap(descriptor.value, name);
45
+ }
46
+
47
+ // https://stackoverflow.com/questions/5905492/dynamic-function-name-in-javascript
48
+ export function nameFunction<T extends Function>(name: string, fnc: T) {
49
+ Object.defineProperty(fnc, "name", { value: name });
50
+ return fnc;
51
+ }
52
+ export function measureWrap<T extends (...args: any[]) => any>(fnc: T, name?: string): T {
53
+ if (!measurementsEnabled) {
54
+ functionsSkipped++;
55
+ return fnc;
56
+ }
57
+ let usedName = name || fnc.name;
58
+ return nameFunction(usedName, (function (this: any, ...args: unknown[]): unknown {
59
+ if (outstandingProfiles.length === 0) {
60
+ return fnc.apply(this, args);
61
+ }
62
+ return getOwnTime(usedName, () => fnc.apply(this, args), recordOwnTime);
63
+ })) as T;
64
+ }
65
+ export function measureBlock<T extends (...args: any[]) => any>(fnc: T, name?: string): ReturnType<T> {
66
+ return measureWrap(fnc, name)();
67
+ }
68
+
69
+ export function startMeasure(): {
70
+ finish: () => MeasureProfile;
71
+ } {
72
+ if (!measurementsEnabled) {
73
+ console.warn(red(`To capture measurements enableMeasurements() must be called before any other imports in your entry point`));
74
+ }
75
+ let profile: MeasureProfile = {
76
+ entries: Object.create(null),
77
+ };
78
+ let openAtStart = new Set(getPendingOwnTimeInstances());
79
+
80
+ outstandingProfiles.push(profile);
81
+ return {
82
+ finish() {
83
+ let pending = getPendingOwnTimeObjs() || [];
84
+ for (let timeObj of pending) {
85
+ if (openAtStart.has(timeObj.source)) continue;
86
+ addToProfile(profile, timeObj, true);
87
+ }
88
+ outstandingProfiles.splice(outstandingProfiles.indexOf(profile), 1);
89
+ return profile;
90
+ }
91
+ };
92
+ }
93
+
94
+ export interface LogMeasureTableConfig {
95
+ useTotalTime?: boolean;
96
+ name?: string;
97
+ // Defaults to 0.05
98
+ thresholdInTable?: number;
99
+ }
100
+
101
+ export function logMeasureTable(
102
+ profile: MeasureProfile,
103
+ config?: LogMeasureTableConfig
104
+ ) {
105
+ let { useTotalTime, name, thresholdInTable } = config || {};
106
+ if (thresholdInTable === undefined) {
107
+ thresholdInTable = 0.05;
108
+ }
109
+
110
+ function getTime(entry: ProfileEntry) {
111
+ return useTotalTime ? entry.totalTime : entry.ownTime;
112
+ }
113
+ let entries = Object.values(profile.entries);
114
+ entries.sort((a, b) => getTime(b).sum - getTime(a).sum);
115
+
116
+ let totalTime = entries.map(x => getTime(x).sum).reduce((a, b) => a + b, 0);
117
+
118
+ console.log();
119
+ let title = yellow(`Profiled ${formatTime(totalTime)} (logged at ${new Date().toISOString()})`);
120
+ if (name) {
121
+ title = `(${blue(name)}) ${title}`;
122
+ }
123
+ console.log(title);
124
+ function percent(value: number) {
125
+ return `${(value * 100).toFixed(2)}%`;
126
+ }
127
+
128
+ entries = entries.slice(0, 10);
129
+ let maxNameLength = Math.max(...entries.map(x => x.name.length));
130
+
131
+ for (let entry of entries.slice(0, 10)) {
132
+ if (getTime(entry).sum / totalTime < thresholdInTable) break;
133
+ let output = "";
134
+ output += `${blue(entry.name)}`;
135
+ output += Array(maxNameLength + 4 - entry.name.length).fill(" ").join("");
136
+
137
+ function p(count: number, text: string | number) {
138
+ return String(text).padStart(count, " ");
139
+ }
140
+ let fractionText = percent(getTime(entry).sum / totalTime);
141
+ let perText = formatTime(getTime(entry).sum / getTime(entry).count);
142
+ let countText = formatNumber(getTime(entry).count);
143
+ let sumText = formatTime(getTime(entry).sum);
144
+
145
+ let equation = `${p(6, sumText)} = ${p(6, countText)} * ${p(6, perText)}`;
146
+
147
+ let ownTimeTop = getStatsTop(getTime(entry));
148
+ if (ownTimeTop.topHeavy) {
149
+ let topText = formatTime(ownTimeTop.value / ownTimeTop.count);
150
+ let topCountText = formatNumber(ownTimeTop.count);
151
+ let bottomText = formatTime((getTime(entry).sum - ownTimeTop.value) / getTime(entry).count, ownTimeTop.value);
152
+ let bottomCountText = formatNumber(getTime(entry).count - ownTimeTop.count);
153
+ let topPart = `${p(6, topText)} per * ${topCountText}`;
154
+ let bottomPart = `${bottomText} * ${bottomCountText}`;
155
+ if (isNode()) {
156
+ topPart = red(topPart);
157
+ } else {
158
+ bottomPart = white(bottomPart);
159
+ }
160
+ equation = `${p(6, sumText)} = ${p(6, topPart)} + ${bottomPart}`;
161
+ }
162
+
163
+ let text = `${p(6, fractionText)} ( ${equation} )`;
164
+ let overhead = measureOverhead * getTime(entry).count;
165
+ let overheadFraction = overhead / getTime(entry).sum;
166
+ let overheadIsAProblem = overheadFraction > 0.5;
167
+ if (overheadIsAProblem) {
168
+ text = yellow(text);
169
+ }
170
+
171
+ output += text;
172
+
173
+ if (overheadIsAProblem) {
174
+ output += red(` measurement overhead is ~${percent(overheadFraction)} of the time.`);
175
+ }
176
+
177
+ if (entry.stillOpenCount > 0) {
178
+ output += red(` (${entry.stillOpenCount} open)`);
179
+ }
180
+
181
+ console.log(output);
182
+ }
183
+ console.log();
184
+ }
185
+
186
+ export async function measureCode<T>(code: () => Promise<T>, config?: LogMeasureTableConfig) {
187
+ let measure = startMeasure();
188
+ try {
189
+ return await measureBlock(code, code.name || "untracked");
190
+ } finally {
191
+ finishProfile(measure, config);
192
+ }
193
+ }
194
+ export function measureCodeSync<T>(code: () => T, config?: LogMeasureTableConfig): T {
195
+ let measure = startMeasure();
196
+ try {
197
+ return measureBlock(code, code.name || "untracked");
198
+ } finally {
199
+ finishProfile(measure, config);
200
+ }
201
+ }
202
+ function finishProfile(measure: { finish(): MeasureProfile }, config?: LogMeasureTableConfig) {
203
+ let profile = measure.finish();
204
+ logMeasureTable(profile, config);
205
+ }
206
+
207
+
208
+ export interface MeasureProfile {
209
+ entries: {
210
+ [name: string]: ProfileEntry;
211
+ };
212
+ }
213
+ export function createMeasureProfile(): MeasureProfile {
214
+ return {
215
+ entries: Object.create(null),
216
+ };
217
+ }
218
+
219
+ export function addToMeasureProfile(base: MeasureProfile, other: MeasureProfile) {
220
+ for (let name in other.entries) {
221
+ let entry = other.entries[name];
222
+ let baseEntry = base.entries[name];
223
+ if (!baseEntry) {
224
+ baseEntry = {
225
+ name: name,
226
+ ownTime: createStatsValue(),
227
+ totalTime: createStatsValue(),
228
+ stillOpenCount: 0,
229
+ };
230
+ base.entries[name] = baseEntry;
231
+ }
232
+ addToStats(baseEntry.ownTime, entry.ownTime);
233
+ addToStats(baseEntry.totalTime, entry.totalTime);
234
+ baseEntry.stillOpenCount += entry.stillOpenCount;
235
+ }
236
+ }
237
+
238
+ interface ProfileEntry {
239
+ name: string;
240
+ ownTime: StatsValue;
241
+ totalTime: StatsValue;
242
+ stillOpenCount: number;
243
+ }
244
+
245
+ let measurementsEnabled = true;
246
+
247
+ let outstandingProfiles: MeasureProfile[] = [];
248
+ function recordOwnTime(ownTimeObj: OwnTimeObj) {
249
+ if (outstandingProfiles.length === 0) return;
250
+ for (let i = 0; i < outstandingProfiles.length; i++) {
251
+ let profile = outstandingProfiles[i];
252
+ addToProfile(profile, ownTimeObj);
253
+ }
254
+ }
255
+
256
+
257
+ function addToProfile(profile: MeasureProfile, ownTimeObj: OwnTimeObj, stillOpen?: boolean) {
258
+ let name = ownTimeObj.name;
259
+ let entry = profile.entries[name];
260
+ if (!entry) {
261
+ entry = {
262
+ name: name,
263
+ ownTime: createStatsValue(),
264
+ totalTime: createStatsValue(),
265
+ stillOpenCount: 0,
266
+ };
267
+ profile.entries[name] = entry;
268
+ }
269
+ addToStatsValue(entry.ownTime, ownTimeObj.ownTime);
270
+ addToStatsValue(entry.totalTime, ownTimeObj.time);
271
+ if (stillOpen) {
272
+ entry.stillOpenCount++;
273
+ }
245
274
  }