socket-function 0.9.4 → 0.9.5

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": "socket-function",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
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",
@@ -27,7 +27,9 @@
27
27
  // https://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor
28
28
  inherits(constructor, superConstructor) {
29
29
  Object.setPrototypeOf(constructor.prototype, superConstructor.prototype);
30
- }
30
+ },
31
+ TextDecoder: TextDecoder,
32
+ TextEncoder: TextEncoder,
31
33
  },
32
34
  buffer: { Buffer },
33
35
  stream: {
@@ -68,6 +68,18 @@ export class JSONLACKS {
68
68
  return Buffer.concat(buffers);
69
69
  });
70
70
  }
71
+ public static stringifyFileSync(obj: unknown[], config?: JSONLACKS_StringifyConfig): Buffer {
72
+ let serialized = JSONLACKS.escapeSpecialObjects(obj, config) as unknown[];
73
+ return measureBlock(function JSONstringifyAndJoin() {
74
+ let buffers: Buffer[] = [];
75
+ for (let i = 0; i < serialized.length; i += SERIALIZE_OBJECT_BATCH_COUNT) {
76
+ let str = serialized.slice(i, i + SERIALIZE_OBJECT_BATCH_COUNT).map(x => JSON.stringify(x) + "\n").join("");
77
+ buffers.push(Buffer.from(str));
78
+ }
79
+ // Break up into chunks, as string => Buffer i
80
+ return Buffer.concat(buffers);
81
+ });
82
+ }
71
83
  // TIMING: Seems to be about 40X slower than JSON.parse unless extended is set to false,
72
84
  // then it is about 2X slower (although it depends on the size and complexity of the objects!)
73
85
  @measureFnc
package/src/batching.ts CHANGED
@@ -113,15 +113,22 @@ export function batchFunction<Arg, Result = void>(
113
113
  }
114
114
 
115
115
  export function runInSerial<T extends (...args: any[]) => Promise<any>>(fnc: T): T {
116
- let updateQueue: (() => void)[] = [];
116
+ let updateQueue: { promise: Promise<void>; resolve: () => void; }[] = [];
117
117
 
118
118
  return (async (...args: any[]) => {
119
+ let promise = {
120
+ promise: null as any as Promise<void>,
121
+ resolve: () => { },
122
+ };
123
+ promise.promise = new Promise<void>(resolve => {
124
+ promise.resolve = resolve;
125
+ });
119
126
  const queueWasEmpty = updateQueue.length === 0;
120
- if (!queueWasEmpty) {
121
- // Wait for the previous promise to resolve
122
- await new Promise<void>(resolve => updateQueue.push(resolve));
127
+ if (queueWasEmpty) {
128
+ promise.resolve();
123
129
  }
124
- updateQueue.push(() => { });
130
+ updateQueue.push(promise);
131
+ await promise.promise;
125
132
 
126
133
  try {
127
134
  return await fnc(...args);
@@ -129,7 +136,7 @@ export function runInSerial<T extends (...args: any[]) => Promise<any>>(fnc: T):
129
136
  // Pop ourself off
130
137
  updateQueue.shift();
131
138
  // Resolve the next promise
132
- updateQueue[0]?.();
139
+ updateQueue[0]?.resolve();
133
140
  }
134
141
  }) as T;
135
142
  }
package/src/caching.ts CHANGED
@@ -38,8 +38,10 @@ export function cache<Output, Key>(getValue: (key: Key) => Output): {
38
38
  (key: Key): Output;
39
39
  // NOTE: If you want to clear all, just make a new cache!
40
40
  clear(key: Key): void;
41
+ clearAll(): void;
41
42
  forceSet(key: Key, value: Output): void;
42
43
  getAllKeys(): Key[];
44
+ get(key: Key): Output | undefined;
43
45
  } {
44
46
  let startingCalculating = new Set<Key>();
45
47
  let values = new Map<Key, Output>();
@@ -69,6 +71,13 @@ export function cache<Output, Key>(getValue: (key: Key) => Output): {
69
71
  cache.getAllKeys = () => {
70
72
  return [...values.keys()];
71
73
  };
74
+ cache.get = (key: Key) => {
75
+ return values.get(key);
76
+ };
77
+ cache.clearAll = () => {
78
+ values.clear();
79
+ startingCalculating.clear();
80
+ };
72
81
  return cache;
73
82
  }
74
83
 
@@ -114,6 +123,14 @@ export function cacheLimited<Output, Key>(
114
123
  values.set(key, value);
115
124
  startingCalculating.add(key);
116
125
  };
126
+ get["clearKey"] = (key: Key) => {
127
+ values.delete(key);
128
+ startingCalculating.delete(key);
129
+ };
130
+ get["clear"] = () => {
131
+ values.clear();
132
+ startingCalculating.clear();
133
+ };
117
134
 
118
135
  return get;
119
136
  }
@@ -186,6 +203,7 @@ export function cacheArrayEqual<Input extends unknown[] | undefined, Output>(
186
203
  ): {
187
204
  (array: Input): Output;
188
205
  clear(array: Input): void;
206
+ clearAll(): void;
189
207
  } {
190
208
  let state: {
191
209
  cache: {
@@ -227,7 +245,10 @@ export function cacheArrayEqual<Input extends unknown[] | undefined, Output>(
227
245
  state.cache.splice(i, 1);
228
246
  }
229
247
  }
230
- }
248
+ },
249
+ clearAll() {
250
+ state.cache = [];
251
+ },
231
252
  }
232
253
  );
233
254
  }
@@ -247,7 +268,7 @@ export function cacheArgsEqual<Fnc extends AnyFunction>(
247
268
  {
248
269
  clear(...args: unknown[]) {
249
270
  cache.clear(args);
250
- }
271
+ },
251
272
  }
252
273
  );
253
274
  }
@@ -255,13 +276,23 @@ export function cacheArgsEqual<Fnc extends AnyFunction>(
255
276
  export function cacheJSONArgsEqual<Fnc extends AnyFunction>(
256
277
  fnc: Fnc,
257
278
  limit = 10
258
- ): Fnc {
279
+ ) {
259
280
  let cache = cacheLimited(limit, (argsJSON: string) => {
260
281
  return fnc(...JSON.parse(argsJSON));
261
282
  });
262
- return ((...args: unknown[]) => {
263
- return cache(JSON.stringify(args));
264
- }) as Fnc;
283
+ return Object.assign(
284
+ ((...args: unknown[]) => {
285
+ return cache(JSON.stringify(args));
286
+ }) as Fnc,
287
+ {
288
+ clear(...args: unknown[]) {
289
+ cache.clearKey(JSON.stringify(args));
290
+ },
291
+ clearAll() {
292
+ cache.clear();
293
+ }
294
+ }
295
+ );
265
296
  }
266
297
 
267
298
  export function cacheShallowConfigArgEqual<Fnc extends AnyFunction>(
@@ -269,6 +300,7 @@ export function cacheShallowConfigArgEqual<Fnc extends AnyFunction>(
269
300
  limit = 10
270
301
  ): Fnc & {
271
302
  clear(...args: Args<Fnc>): void;
303
+ clearAll(): void;
272
304
  } {
273
305
  let cache = cacheArrayEqual((kvpsFlat: unknown[]) => {
274
306
  output.missCount++;
@@ -301,6 +333,9 @@ export function cacheShallowConfigArgEqual<Fnc extends AnyFunction>(
301
333
  clear(configArg: object) {
302
334
  cache.clear(getKVPs(configArg));
303
335
  },
336
+ clearAll() {
337
+ cache.clearAll();
338
+ },
304
339
  callCount: 0,
305
340
  missCount: 0,
306
341
  }
package/src/misc.ts CHANGED
@@ -1,6 +1,13 @@
1
1
  import * as crypto from "crypto";
2
2
  import { canHaveChildren, MaybePromise } from "./types";
3
3
 
4
+ export const timeInSecond = 1000;
5
+ export const timeInMinute = timeInSecond * 60;
6
+ export const timeInHour = timeInMinute * 60;
7
+ export const timeInDay = timeInHour * 24;
8
+ export const timeInWeek = timeInDay * 7;
9
+ export const timeInYear = timeInDay * 365;
10
+
4
11
  export type Watchable<T> = (callback: (value: T) => void) => MaybePromise<void>;
5
12
 
6
13
  export function convertErrorStackToError(error: string): Error {
@@ -301,4 +308,9 @@ export function arrayFromOrderObject<T>(obj: { [order: number]: T }): T[] {
301
308
 
302
309
  export function last<T>(arr: T[]): T | undefined {
303
310
  return arr[arr.length - 1];
311
+ }
312
+
313
+ export type ObjectValues<T> = T[keyof T];
314
+ export function entries<Obj extends { [key: string]: unknown }>(obj: Obj): [keyof Obj, ObjectValues<Obj>][] {
315
+ return Object.entries(obj) as any;
304
316
  }
@@ -8,39 +8,18 @@ export type OwnTimeObj = {
8
8
  time: number;
9
9
  ownTime: number;
10
10
  };
11
- type OwnTimeObjInternal = OwnTimeObj & {
11
+ export type OwnTimeObjInternal = OwnTimeObj & {
12
12
  lastStartTime: number;
13
13
  firstStartTime: number;
14
- parent: OwnTimeObjInternal | undefined;
15
- child: OwnTimeObjInternal | undefined;
16
14
  };
17
15
 
18
- let pendingCallTime: OwnTimeObjInternal | undefined;
19
- export function getPendingOwnTimeObjs(): (OwnTimeObj & { source: OwnTimeObjInternal })[] | undefined {
20
- let time = now();
21
- let instances = getPendingOwnTimeInstances();
22
- if (!instances) return undefined;
23
- if (!pendingCallTime) return undefined;
24
- let results = instances.map((instance) => ({
25
- name: instance.name,
26
- ownTime: instance.ownTime,
27
- time: time - instance.firstStartTime,
28
- source: instance
29
- }));
30
- results[0].ownTime += time - pendingCallTime.lastStartTime;
31
- return results;
32
- }
33
- export function getPendingOwnTimeInstances(): OwnTimeObjInternal[] | undefined {
34
- if (!pendingCallTime) return undefined;
35
- let results: OwnTimeObjInternal[] = [];
36
- let current: OwnTimeObjInternal | undefined = pendingCallTime;
37
- while (current) {
38
- results.push(current);
39
- current = current.parent;
40
- }
41
- return results;
16
+ let openTimes: OwnTimeObjInternal[] = [];
17
+
18
+ export function getOpenTimesBase(): OwnTimeObjInternal[] {
19
+ return openTimes;
42
20
  }
43
- (global as any).pendingOwnCallTime = pendingCallTime;
21
+
22
+ (global as any).pendingOwnCallTime = openTimes;
44
23
 
45
24
  // NOTE: This overhead time is actually mostly for aggregate time, but it is needed,
46
25
  // otherwise we consistently underestimate the time spent.
@@ -85,39 +64,25 @@ export function getOwnTime<T>(
85
64
  ownTime: 0,
86
65
  firstStartTime: time,
87
66
  lastStartTime: time,
88
- parent: pendingCallTime,
89
- child: undefined,
90
67
  };
91
- if (pendingCallTime) {
92
- pendingCallTime.child = obj;
93
- }
94
- pendingCallTime = obj;
95
- if (obj.parent) {
96
- obj.parent.ownTime += obj.lastStartTime - obj.parent.lastStartTime;
68
+ let prevOwnTime = openTimes[openTimes.length - 1];
69
+ if (prevOwnTime) {
70
+ prevOwnTime.ownTime += time - prevOwnTime.lastStartTime;
97
71
  }
72
+ openTimes.push(obj);
98
73
 
99
74
  function finish() {
100
75
  let time = now();
101
76
  obj.time = time - obj.firstStartTime;
102
- if (pendingCallTime === obj) {
103
- // Good case, all of our children call ended before us.
104
-
105
- // End our own time calculation
77
+ if (obj === openTimes[openTimes.length - 1]) {
106
78
  obj.ownTime += time - obj.lastStartTime;
107
-
108
- // Our parent is now the last open call
109
- pendingCallTime = obj.parent;
110
- if (pendingCallTime) {
111
- // Resume our parent ownTime counting
112
- pendingCallTime.lastStartTime = time;
79
+ let newOwnTime = openTimes[openTimes.length - 2];
80
+ if (newOwnTime) {
81
+ newOwnTime.lastStartTime = time;
113
82
  }
114
83
  }
115
- if (obj.child && obj.parent) {
116
- obj.child.parent = obj.parent;
117
- obj.parent.child = obj.child;
118
- }
119
- obj.parent = undefined;
120
- obj.child = undefined;
84
+ let index = openTimes.indexOf(obj);
85
+ openTimes.splice(index, 1);
121
86
 
122
87
  obj.time += addMeasureOverheadTime;
123
88
  obj.ownTime += addMeasureOverheadTime;
@@ -2,12 +2,14 @@ import debugbreak from "debugbreak";
2
2
  import { formatTime, formatNumber } from "../formatting/format";
3
3
  import { red, yellow, blue, magenta } from "../formatting/logColors";
4
4
 
5
- import { getOwnTime, getPendingOwnTimeInstances, getPendingOwnTimeObjs, OwnTimeObj } from "./getOwnTime";
5
+ import { getOpenTimesBase, getOwnTime, OwnTimeObj } from "./getOwnTime";
6
6
  import { addToStats, addToStatsValue, createStatsValue, getStatsTop, StatsValue } from "./stats";
7
7
  import { white } from "../formatting/logColors";
8
8
  import { isNode } from "../misc";
9
9
 
10
- /** NOTE: Must be called BEFORE anything else is imported! */
10
+ /** NOTE: Must be called BEFORE anything else is imported!
11
+ * NOTE: Measurements on on by default now, so this doesn't really need to be called...
12
+ */
11
13
  export function enableMeasurements() {
12
14
  if (functionsSkipped) {
13
15
  console.warn(red(`Skipped measure shimming ${functionsSkipped} functions. Fix this by calling enableMeasurements before any other imports.`));
@@ -75,15 +77,25 @@ export function startMeasure(): {
75
77
  let profile: MeasureProfile = {
76
78
  entries: Object.create(null),
77
79
  };
78
- let openAtStart = new Set(getPendingOwnTimeInstances());
80
+ let openAtStart = new Set(getOpenTimesBase());
79
81
 
80
82
  outstandingProfiles.push(profile);
81
83
  return {
82
84
  finish() {
83
- let pending = getPendingOwnTimeObjs() || [];
85
+ let pending = getOpenTimesBase();
86
+ let last = pending[pending.length - 1];
87
+ let time = Date.now();
84
88
  for (let timeObj of pending) {
85
- if (openAtStart.has(timeObj.source)) continue;
86
- addToProfile(profile, timeObj, true);
89
+ // Ignore any values that were already open, as they are clearly not
90
+ // caused by our code.
91
+ if (openAtStart.has(timeObj)) continue;
92
+ timeObj = { ...timeObj };
93
+
94
+ if (timeObj === last) {
95
+ timeObj.ownTime += time - timeObj.lastStartTime;
96
+ }
97
+ timeObj.time = time - timeObj.firstStartTime;
98
+ addToProfile(profile, timeObj);
87
99
  }
88
100
  outstandingProfiles.splice(outstandingProfiles.indexOf(profile), 1);
89
101
  return profile;
@@ -96,6 +108,8 @@ export interface LogMeasureTableConfig {
96
108
  name?: string;
97
109
  // Defaults to 0.05
98
110
  thresholdInTable?: number;
111
+ // Details to 50
112
+ minTimeToLog?: number;
99
113
  }
100
114
 
101
115
  export function logMeasureTable(
@@ -106,6 +120,7 @@ export function logMeasureTable(
106
120
  if (thresholdInTable === undefined) {
107
121
  thresholdInTable = 0.05;
108
122
  }
123
+ let minTimeToLog = config?.minTimeToLog ?? 50;
109
124
 
110
125
  function getTime(entry: ProfileEntry) {
111
126
  return useTotalTime ? entry.totalTime : entry.ownTime;
@@ -114,6 +129,7 @@ export function logMeasureTable(
114
129
  entries.sort((a, b) => getTime(b).sum - getTime(a).sum);
115
130
 
116
131
  let totalTime = entries.map(x => getTime(x).sum).reduce((a, b) => a + b, 0);
132
+ if (totalTime < minTimeToLog) return;
117
133
 
118
134
  console.log();
119
135
  let title = yellow(`Profiled ${formatTime(totalTime)} (logged at ${new Date().toISOString()})`);
@@ -96,7 +96,11 @@ export async function startSocketServer(
96
96
  console.error(`Connection attempt error ${e.message}`);
97
97
  });
98
98
  httpsServer.on("tlsClientError", e => {
99
- console.error(`TLS client error ${e.message}`);
99
+ // NOTE: This happens a lot when we have tabs open that connected to an old
100
+ // server (with old certs, that the browser will reject?)
101
+ if (!SocketFunction.silent) {
102
+ console.error(`TLS client error ${e.message}`);
103
+ }
100
104
  });
101
105
 
102
106
  httpsServer.on("request", httpCallHandler);