socket-function 0.9.3 → 0.9.4

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 -280
  3. package/SocketFunctionTypes.ts +90 -90
  4. package/hot/HotReloadController.ts +105 -105
  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 +1 -1
  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 -462
  15. package/spec.txt +115 -115
  16. package/src/CallFactory.ts +389 -389
  17. package/src/JSONLACKS/JSONLACKS.generated.js +17 -17
  18. package/src/JSONLACKS/JSONLACKS.pegjs +247 -247
  19. package/src/JSONLACKS/JSONLACKS.ts +429 -429
  20. package/src/args.ts +21 -21
  21. package/src/batching.ts +170 -170
  22. package/src/caching.ts +324 -318
  23. package/src/callHTTPHandler.ts +203 -203
  24. package/src/callManager.ts +134 -134
  25. package/src/certStore.ts +29 -29
  26. package/src/fixLargeNetworkCalls.ts +8 -8
  27. package/src/formatting/colors.ts +78 -78
  28. package/src/formatting/format.ts +160 -160
  29. package/src/formatting/logColors.ts +17 -17
  30. package/src/misc.ts +303 -302
  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 -273
  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 -250
  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 -52
  45. package/tsconfig.json +26 -26
package/src/nodeCache.ts CHANGED
@@ -1,93 +1,93 @@
1
- import { CallFactory, createCallFactory } from "./CallFactory";
2
- import { MaybePromise } from "./types";
3
- import { lazy } from "./caching";
4
- import { SocketFunction } from "../SocketFunction";
5
-
6
- // TODO: Add CallInstanceFactory.isClosed, so nodeCache can clean up old entries.
7
- // This is only needed for memory management, and not for correctness. Entries never
8
- // need to be refreshed, because NetworkLocation.listeningPorts shouldn't really change.
9
- // Either we will have listeningPorts and re-establish the connection, or we won't, and
10
- // then it is a client, in which case we cannot re-establish the connection (and we just
11
- // have to wait for the client to re-establish it). AND, if the listeningPorts change from
12
- // a value to a new value... then they should be obtained using connect() anyway,
13
- // and so whatever way the user got the NetworkLocation to begin with, they should use again.
14
-
15
- export function getNodeId(domain: string, port: number): string {
16
- // NOTE: As domains are never reused, this doesn't need any randomness
17
- return `${domain}:${port}`;
18
- }
19
-
20
- /** A nodeId not available for reconnecting. */
21
- export function getClientNodeId(address: string): string {
22
- return `client:${address}:${Date.now()}:${Math.random()}`;
23
- }
24
- export function isClientNodeId(nodeId: string): boolean {
25
- return nodeId.startsWith("client:");
26
- }
27
- /** Will always be available, even if getNodeIdLocation is not (as we don't always have the port,
28
- * but we should always have an address).
29
- * - Rarely used, as for logging you can just log the nodeId. ALSO, it isn't sufficient to reconnect, as the port is also needed!
30
- * */
31
- export function getNodeIdIP(nodeId: string): string {
32
- if (isClientNodeId(nodeId)) {
33
- return nodeId.split(":")[1];
34
- }
35
- return getNodeIdLocation(nodeId)!.address;
36
- }
37
-
38
- export function getNodeIdLocation(nodeId: string): { address: string, port: number; } | undefined {
39
- if (isClientNodeId(nodeId)) {
40
- return undefined;
41
- }
42
- let [address, port] = nodeId.split(":");
43
- return { address, port: parseInt(port) };
44
- }
45
-
46
- export function getNodeIdDomain(nodeId: string): string {
47
- let location = getNodeIdLocation(nodeId);
48
- if (!location) {
49
- throw new Error(`Cannot get domain from nodeId, which is only usable as a client. NodeId: ${JSON.stringify(nodeId)}`);
50
- }
51
- return new URL(location.address).hostname.split(".").slice(-2).join(".");
52
- }
53
-
54
- // NOTE: CallFactory turns into an actual CallFactory when registerNodeClient is called
55
- // nodeId =>
56
- const nodeCache = new Map<string, MaybePromise<CallFactory>>();
57
-
58
- // NOTE: Should be called directly inside call factory constructor whenever
59
- // their nodeId changes (and on construction).
60
- export function registerNodeClient(callFactory: CallFactory) {
61
- nodeCache.set(callFactory.nodeId, callFactory);
62
- startCleanupLoop();
63
- }
64
-
65
- export function getCreateCallFactory(nodeId: string): MaybePromise<CallFactory> {
66
- let callFactory = nodeCache.get(nodeId);
67
- if (callFactory === undefined) {
68
- callFactory = createCallFactory(undefined, nodeId);
69
- nodeCache.set(nodeId, callFactory);
70
- }
71
- return callFactory;
72
- }
73
- export function getCallFactory(nodeId: string): MaybePromise<CallFactory | undefined> {
74
- return nodeCache.get(nodeId);
75
- }
76
-
77
- const startCleanupLoop = lazy(() => {
78
- (async () => {
79
- while (true) {
80
- for (let [key, value] of Array.from(nodeCache.entries())) {
81
- let factory = value;
82
- if (!(factory instanceof Promise)) {
83
- if (factory.closedForever) {
84
- nodeCache.delete(key);
85
- }
86
- }
87
- }
88
- await new Promise(resolve => setTimeout(resolve, 1000 * 60 * 5));
89
- }
90
- })().catch(e => {
91
- console.error(`nodeCache cleanup loop failed, ${e.stack}`);
92
- });
1
+ import { CallFactory, createCallFactory } from "./CallFactory";
2
+ import { MaybePromise } from "./types";
3
+ import { lazy } from "./caching";
4
+ import { SocketFunction } from "../SocketFunction";
5
+
6
+ // TODO: Add CallInstanceFactory.isClosed, so nodeCache can clean up old entries.
7
+ // This is only needed for memory management, and not for correctness. Entries never
8
+ // need to be refreshed, because NetworkLocation.listeningPorts shouldn't really change.
9
+ // Either we will have listeningPorts and re-establish the connection, or we won't, and
10
+ // then it is a client, in which case we cannot re-establish the connection (and we just
11
+ // have to wait for the client to re-establish it). AND, if the listeningPorts change from
12
+ // a value to a new value... then they should be obtained using connect() anyway,
13
+ // and so whatever way the user got the NetworkLocation to begin with, they should use again.
14
+
15
+ export function getNodeId(domain: string, port: number): string {
16
+ // NOTE: As domains are never reused, this doesn't need any randomness
17
+ return `${domain}:${port}`;
18
+ }
19
+
20
+ /** A nodeId not available for reconnecting. */
21
+ export function getClientNodeId(address: string): string {
22
+ return `client:${address}:${Date.now()}:${Math.random()}`;
23
+ }
24
+ export function isClientNodeId(nodeId: string): boolean {
25
+ return nodeId.startsWith("client:");
26
+ }
27
+ /** Will always be available, even if getNodeIdLocation is not (as we don't always have the port,
28
+ * but we should always have an address).
29
+ * - Rarely used, as for logging you can just log the nodeId. ALSO, it isn't sufficient to reconnect, as the port is also needed!
30
+ * */
31
+ export function getNodeIdIP(nodeId: string): string {
32
+ if (isClientNodeId(nodeId)) {
33
+ return nodeId.split(":")[1];
34
+ }
35
+ return getNodeIdLocation(nodeId)!.address;
36
+ }
37
+
38
+ export function getNodeIdLocation(nodeId: string): { address: string, port: number; } | undefined {
39
+ if (isClientNodeId(nodeId)) {
40
+ return undefined;
41
+ }
42
+ let [address, port] = nodeId.split(":");
43
+ return { address, port: parseInt(port) };
44
+ }
45
+
46
+ export function getNodeIdDomain(nodeId: string): string {
47
+ let location = getNodeIdLocation(nodeId);
48
+ if (!location) {
49
+ throw new Error(`Cannot get domain from nodeId, which is only usable as a client. NodeId: ${JSON.stringify(nodeId)}`);
50
+ }
51
+ return new URL(location.address).hostname.split(".").slice(-2).join(".");
52
+ }
53
+
54
+ // NOTE: CallFactory turns into an actual CallFactory when registerNodeClient is called
55
+ // nodeId =>
56
+ const nodeCache = new Map<string, MaybePromise<CallFactory>>();
57
+
58
+ // NOTE: Should be called directly inside call factory constructor whenever
59
+ // their nodeId changes (and on construction).
60
+ export function registerNodeClient(callFactory: CallFactory) {
61
+ nodeCache.set(callFactory.nodeId, callFactory);
62
+ startCleanupLoop();
63
+ }
64
+
65
+ export function getCreateCallFactory(nodeId: string): MaybePromise<CallFactory> {
66
+ let callFactory = nodeCache.get(nodeId);
67
+ if (callFactory === undefined) {
68
+ callFactory = createCallFactory(undefined, nodeId);
69
+ nodeCache.set(nodeId, callFactory);
70
+ }
71
+ return callFactory;
72
+ }
73
+ export function getCallFactory(nodeId: string): MaybePromise<CallFactory | undefined> {
74
+ return nodeCache.get(nodeId);
75
+ }
76
+
77
+ const startCleanupLoop = lazy(() => {
78
+ (async () => {
79
+ while (true) {
80
+ for (let [key, value] of Array.from(nodeCache.entries())) {
81
+ let factory = value;
82
+ if (!(factory instanceof Promise)) {
83
+ if (factory.closedForever) {
84
+ nodeCache.delete(key);
85
+ }
86
+ }
87
+ }
88
+ await new Promise(resolve => setTimeout(resolve, 1000 * 60 * 5));
89
+ }
90
+ })().catch(e => {
91
+ console.error(`nodeCache cleanup loop failed, ${e.stack}`);
92
+ });
93
93
  });
package/src/nodeProxy.ts CHANGED
@@ -1,55 +1,55 @@
1
- import { lazy } from "./caching";
2
- import { FullCallType, SocketExposedInterface, SocketInternalInterface } from "../SocketFunctionTypes";
3
-
4
- type CallProxyType = {
5
- [nodeId: string]: SocketInternalInterface;
6
- };
7
-
8
- export const getCallObj = Symbol.for("getCallObj");
9
-
10
- let proxyCache = new Map<string, CallProxyType>();
11
- export function getCallProxy(id: string, callback: (callType: FullCallType) => Promise<unknown>): CallProxyType {
12
- let value = proxyCache.get(id);
13
- if (!value) {
14
- let nodeCache = new Map<string, CallProxyType[""]>();
15
- value = new Proxy(Object.create(null), {
16
- get(target, nodeId) {
17
- if (typeof nodeId !== "string") return undefined;
18
- let nodeProxy = nodeCache.get(nodeId);
19
- if (!nodeProxy) {
20
- nodeProxy = new Proxy(Object.create(null), {
21
- get(target, functionName) {
22
- if (typeof functionName !== "string") return undefined;
23
- return Object.assign(
24
- (...args: unknown[]) => {
25
- let call: FullCallType = {
26
- classGuid: id,
27
- nodeId,
28
- functionName,
29
- args,
30
- };
31
- return callback(call);
32
- },
33
- {
34
- [getCallObj]: (...args: unknown[]) => {
35
- let call: FullCallType = {
36
- classGuid: id,
37
- nodeId,
38
- functionName,
39
- args,
40
- };
41
- return call;
42
- }
43
- }
44
- );
45
- }
46
- }) as CallProxyType[""];
47
- nodeCache.set(nodeId, nodeProxy);
48
- }
49
- return nodeProxy;
50
- },
51
- }) as CallProxyType;
52
- proxyCache.set(id, value);
53
- }
54
- return value;
1
+ import { lazy } from "./caching";
2
+ import { FullCallType, SocketExposedInterface, SocketInternalInterface } from "../SocketFunctionTypes";
3
+
4
+ type CallProxyType = {
5
+ [nodeId: string]: SocketInternalInterface;
6
+ };
7
+
8
+ export const getCallObj = Symbol.for("getCallObj");
9
+
10
+ let proxyCache = new Map<string, CallProxyType>();
11
+ export function getCallProxy(id: string, callback: (callType: FullCallType) => Promise<unknown>): CallProxyType {
12
+ let value = proxyCache.get(id);
13
+ if (!value) {
14
+ let nodeCache = new Map<string, CallProxyType[""]>();
15
+ value = new Proxy(Object.create(null), {
16
+ get(target, nodeId) {
17
+ if (typeof nodeId !== "string") return undefined;
18
+ let nodeProxy = nodeCache.get(nodeId);
19
+ if (!nodeProxy) {
20
+ nodeProxy = new Proxy(Object.create(null), {
21
+ get(target, functionName) {
22
+ if (typeof functionName !== "string") return undefined;
23
+ return Object.assign(
24
+ (...args: unknown[]) => {
25
+ let call: FullCallType = {
26
+ classGuid: id,
27
+ nodeId,
28
+ functionName,
29
+ args,
30
+ };
31
+ return callback(call);
32
+ },
33
+ {
34
+ [getCallObj]: (...args: unknown[]) => {
35
+ let call: FullCallType = {
36
+ classGuid: id,
37
+ nodeId,
38
+ functionName,
39
+ args,
40
+ };
41
+ return call;
42
+ }
43
+ }
44
+ );
45
+ }
46
+ }) as CallProxyType[""];
47
+ nodeCache.set(nodeId, nodeProxy);
48
+ }
49
+ return nodeProxy;
50
+ },
51
+ }) as CallProxyType;
52
+ proxyCache.set(id, value);
53
+ }
54
+ return value;
55
55
  }
@@ -1,143 +1,143 @@
1
- import debugbreak from "debugbreak";
2
- // TODO: We could probably make this an optional / dev dependency, to allow
3
- // for use on machines without the ability to compile?
4
- import { now } from "rdtsc-now";
5
-
6
- export type OwnTimeObj = {
7
- name: string;
8
- time: number;
9
- ownTime: number;
10
- };
11
- type OwnTimeObjInternal = OwnTimeObj & {
12
- lastStartTime: number;
13
- firstStartTime: number;
14
- parent: OwnTimeObjInternal | undefined;
15
- child: OwnTimeObjInternal | undefined;
16
- };
17
-
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;
42
- }
43
- (global as any).pendingOwnCallTime = pendingCallTime;
44
-
45
- // NOTE: This overhead time is actually mostly for aggregate time, but it is needed,
46
- // otherwise we consistently underestimate the time spent.
47
- // ALSO! This forces high count lines to be at the top of the aggregate time list, which is really important!
48
- // NOTE: The overhead time greatly varies, but even if it only takes 100ns, if 10X of that
49
- // is significant, you are probably spending too much timing profiling anyway!
50
- export const measureOverheadTime = 500 / 1000 / 1000;
51
- // We internally add, because of where we measure time, there is time spent before we grab the
52
- // current time, and after we record the last time, that is lost, but should be added.
53
- let addMeasureOverheadTime = 0;
54
- {
55
- // NOTE: This is going to vary considerably. I assume because sometimes we are on a core
56
- // that is free, and other times we are on a core that is hyperthreading with another hardware
57
- // thread. This really hurts us because our timing uses rdtsc, which really hates hyper threading,
58
- // and can easily get 50% slower because of it.
59
- let results: number[] = [];
60
- for (let j = 0; j < 10; j++) {
61
- const measureCount = 1000 * 10;
62
- let time = now();
63
- for (let i = 0; i < measureCount; i++) {
64
- getOwnTime("test", () => { }, () => { });
65
- }
66
- time = now() - time;
67
- let overhead = time / measureCount;
68
- results.push(overhead);
69
- }
70
- results.sort((a, b) => a - b);
71
- addMeasureOverheadTime = results[results.length / 2];
72
- }
73
-
74
- // TIMING: About 60ns, of which 40ns is just now() calls.
75
- // If async is closer to 300ns.
76
- export function getOwnTime<T>(
77
- name: string,
78
- code: () => T,
79
- onTime: (obj: OwnTimeObj) => void
80
- ): T {
81
- let time = now();
82
- let obj: OwnTimeObjInternal = {
83
- name,
84
- time: 0,
85
- ownTime: 0,
86
- firstStartTime: time,
87
- lastStartTime: time,
88
- parent: pendingCallTime,
89
- child: undefined,
90
- };
91
- if (pendingCallTime) {
92
- pendingCallTime.child = obj;
93
- }
94
- pendingCallTime = obj;
95
- if (obj.parent) {
96
- obj.parent.ownTime += obj.lastStartTime - obj.parent.lastStartTime;
97
- }
98
-
99
- function finish() {
100
- let time = now();
101
- 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
106
- 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;
113
- }
114
- }
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;
121
-
122
- obj.time += addMeasureOverheadTime;
123
- obj.ownTime += addMeasureOverheadTime;
124
-
125
- onTime(obj);
126
- }
127
-
128
- let isAsync = false;
129
- try {
130
- let result = code();
131
- if (result && typeof result === "object" && result instanceof Promise) {
132
- isAsync = true;
133
- return result.finally(() => {
134
- finish();
135
- }) as any;
136
- }
137
- return result;
138
- } finally {
139
- if (!isAsync) {
140
- finish();
141
- }
142
- }
1
+ import debugbreak from "debugbreak";
2
+ // TODO: We could probably make this an optional / dev dependency, to allow
3
+ // for use on machines without the ability to compile?
4
+ import { now } from "rdtsc-now";
5
+
6
+ export type OwnTimeObj = {
7
+ name: string;
8
+ time: number;
9
+ ownTime: number;
10
+ };
11
+ type OwnTimeObjInternal = OwnTimeObj & {
12
+ lastStartTime: number;
13
+ firstStartTime: number;
14
+ parent: OwnTimeObjInternal | undefined;
15
+ child: OwnTimeObjInternal | undefined;
16
+ };
17
+
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;
42
+ }
43
+ (global as any).pendingOwnCallTime = pendingCallTime;
44
+
45
+ // NOTE: This overhead time is actually mostly for aggregate time, but it is needed,
46
+ // otherwise we consistently underestimate the time spent.
47
+ // ALSO! This forces high count lines to be at the top of the aggregate time list, which is really important!
48
+ // NOTE: The overhead time greatly varies, but even if it only takes 100ns, if 10X of that
49
+ // is significant, you are probably spending too much timing profiling anyway!
50
+ export const measureOverheadTime = 500 / 1000 / 1000;
51
+ // We internally add, because of where we measure time, there is time spent before we grab the
52
+ // current time, and after we record the last time, that is lost, but should be added.
53
+ let addMeasureOverheadTime = 0;
54
+ {
55
+ // NOTE: This is going to vary considerably. I assume because sometimes we are on a core
56
+ // that is free, and other times we are on a core that is hyperthreading with another hardware
57
+ // thread. This really hurts us because our timing uses rdtsc, which really hates hyper threading,
58
+ // and can easily get 50% slower because of it.
59
+ let results: number[] = [];
60
+ for (let j = 0; j < 10; j++) {
61
+ const measureCount = 1000 * 10;
62
+ let time = now();
63
+ for (let i = 0; i < measureCount; i++) {
64
+ getOwnTime("test", () => { }, () => { });
65
+ }
66
+ time = now() - time;
67
+ let overhead = time / measureCount;
68
+ results.push(overhead);
69
+ }
70
+ results.sort((a, b) => a - b);
71
+ addMeasureOverheadTime = results[results.length / 2];
72
+ }
73
+
74
+ // TIMING: About 60ns, of which 40ns is just now() calls.
75
+ // If async is closer to 300ns.
76
+ export function getOwnTime<T>(
77
+ name: string,
78
+ code: () => T,
79
+ onTime: (obj: OwnTimeObj) => void
80
+ ): T {
81
+ let time = now();
82
+ let obj: OwnTimeObjInternal = {
83
+ name,
84
+ time: 0,
85
+ ownTime: 0,
86
+ firstStartTime: time,
87
+ lastStartTime: time,
88
+ parent: pendingCallTime,
89
+ child: undefined,
90
+ };
91
+ if (pendingCallTime) {
92
+ pendingCallTime.child = obj;
93
+ }
94
+ pendingCallTime = obj;
95
+ if (obj.parent) {
96
+ obj.parent.ownTime += obj.lastStartTime - obj.parent.lastStartTime;
97
+ }
98
+
99
+ function finish() {
100
+ let time = now();
101
+ 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
106
+ 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;
113
+ }
114
+ }
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;
121
+
122
+ obj.time += addMeasureOverheadTime;
123
+ obj.ownTime += addMeasureOverheadTime;
124
+
125
+ onTime(obj);
126
+ }
127
+
128
+ let isAsync = false;
129
+ try {
130
+ let result = code();
131
+ if (result && typeof result === "object" && result instanceof Promise) {
132
+ isAsync = true;
133
+ return result.finally(() => {
134
+ finish();
135
+ }) as any;
136
+ }
137
+ return result;
138
+ } finally {
139
+ if (!isAsync) {
140
+ finish();
141
+ }
142
+ }
143
143
  }