socket-function 0.9.0 → 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.
- package/.eslintrc.js +50 -50
- package/SocketFunction.ts +280 -280
- package/SocketFunctionTypes.ts +90 -90
- package/hot/HotReloadController.ts +105 -105
- package/mobx/UrlParam.ts +39 -39
- package/mobx/observer.tsx +49 -49
- package/mobx/promiseToObservable.tsx +41 -41
- package/package.json +30 -28
- package/require/CSSShim.ts +19 -19
- package/require/RequireController.ts +252 -252
- package/require/buffer.js +2368 -2368
- package/require/compileFlags.ts +44 -44
- package/require/require.html +13 -13
- package/require/require.js +462 -456
- package/spec.txt +115 -115
- package/src/CallFactory.ts +389 -389
- package/src/JSONLACKS/JSONLACKS.generated.js +17 -17
- package/src/JSONLACKS/JSONLACKS.pegjs +247 -247
- package/src/JSONLACKS/JSONLACKS.ts +429 -375
- package/src/args.ts +21 -21
- package/src/batching.ts +170 -129
- package/src/caching.ts +318 -314
- package/src/callHTTPHandler.ts +203 -203
- package/src/callManager.ts +134 -134
- package/src/certStore.ts +29 -29
- package/src/fixLargeNetworkCalls.ts +8 -8
- package/src/formatting/colors.ts +78 -78
- package/src/formatting/format.ts +160 -156
- package/src/formatting/logColors.ts +17 -17
- package/src/misc.ts +302 -171
- package/src/nodeCache.ts +92 -92
- package/src/nodeProxy.ts +54 -54
- package/src/profiling/getOwnTime.ts +142 -142
- package/src/profiling/measure.ts +273 -244
- package/src/profiling/stats.ts +212 -212
- package/src/profiling/tcpLagProxy.ts +63 -63
- package/src/storagePath.ts +10 -10
- package/src/tlsParsing.ts +96 -96
- package/src/types.ts +8 -8
- package/src/webSocketServer.ts +250 -250
- package/test/client.css +2 -2
- package/test/client.ts +46 -46
- package/test/server.ts +43 -43
- package/test/shared.ts +52 -52
- package/tsconfig.json +26 -26
package/src/profiling/measure.ts
CHANGED
|
@@ -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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
let
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
let
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
function
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
let
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
entry
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
}
|