querysub 0.433.0 → 0.437.0
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/bin/deploy.js +0 -0
- package/bin/function.js +0 -0
- package/bin/server.js +0 -0
- package/costsBenefits.txt +115 -115
- package/deploy.ts +2 -2
- package/package.json +1 -1
- package/spec.txt +1192 -1192
- package/src/-a-archives/archives.ts +202 -202
- package/src/-a-archives/archivesDisk.ts +454 -454
- package/src/-a-auth/certs.ts +540 -540
- package/src/-a-auth/node-forge-ed25519.d.ts +16 -16
- package/src/-b-authorities/dnsAuthority.ts +138 -138
- package/src/-c-identity/IdentityController.ts +258 -258
- package/src/-d-trust/NetworkTrust2.ts +180 -180
- package/src/-e-certs/EdgeCertController.ts +252 -252
- package/src/-e-certs/certAuthority.ts +201 -201
- package/src/-f-node-discovery/NodeDiscovery.ts +640 -640
- package/src/-g-core-values/NodeCapabilities.ts +200 -200
- package/src/-h-path-value-serialize/stringSerializer.ts +175 -175
- package/src/0-path-value-core/PathValueCommitter.ts +468 -468
- package/src/0-path-value-core/pathValueCore.ts +2 -2
- package/src/2-proxy/PathValueProxyWatcher.ts +2542 -2542
- package/src/2-proxy/TransactionDelayer.ts +94 -94
- package/src/2-proxy/pathDatabaseProxyBase.ts +36 -36
- package/src/2-proxy/pathValueProxy.ts +159 -159
- package/src/3-path-functions/PathFunctionRunnerMain.ts +87 -87
- package/src/3-path-functions/pathFunctionLoader.ts +516 -516
- package/src/3-path-functions/tests/rejectTest.ts +76 -76
- package/src/4-deploy/deployCheck.ts +6 -6
- package/src/4-dom/css.tsx +29 -29
- package/src/4-dom/cssTypes.d.ts +211 -211
- package/src/4-dom/qreact.tsx +2799 -2799
- package/src/4-dom/qreactTest.tsx +410 -410
- package/src/4-querysub/permissions.ts +335 -335
- package/src/4-querysub/querysubPrediction.ts +483 -483
- package/src/5-diagnostics/qreactDebug.tsx +346 -346
- package/src/TestController.ts +34 -34
- package/src/bits.ts +104 -104
- package/src/buffers.ts +69 -69
- package/src/diagnostics/ActionsHistory.ts +57 -57
- package/src/diagnostics/listenOnDebugger.ts +71 -71
- package/src/diagnostics/periodic.ts +111 -111
- package/src/diagnostics/trackResources.ts +91 -91
- package/src/diagnostics/watchdog.ts +120 -120
- package/src/errors.ts +133 -133
- package/src/forceProduction.ts +2 -2
- package/src/fs.ts +80 -80
- package/src/functional/diff.ts +857 -857
- package/src/functional/promiseCache.ts +78 -78
- package/src/functional/random.ts +8 -8
- package/src/functional/stats.ts +60 -60
- package/src/heapDumps.ts +665 -665
- package/src/https.ts +1 -1
- package/src/library-components/AspectSizedComponent.tsx +87 -87
- package/src/library-components/ButtonSelector.tsx +64 -64
- package/src/library-components/DropdownCustom.tsx +150 -150
- package/src/library-components/DropdownSelector.tsx +31 -31
- package/src/library-components/InlinePopup.tsx +66 -66
- package/src/misc/color.ts +29 -29
- package/src/misc/hash.ts +83 -83
- package/src/misc/ipPong.js +13 -13
- package/src/misc/networking.ts +1 -1
- package/src/misc/random.ts +44 -44
- package/src/misc.ts +196 -196
- package/src/path.ts +255 -255
- package/src/persistentLocalStore.ts +41 -41
- package/src/promise.ts +14 -14
- package/src/storage/fileSystemPointer.ts +71 -71
- package/src/test/heapProcess.ts +35 -35
- package/src/zip.ts +15 -15
- package/tsconfig.json +26 -26
- package/yarnSpec.txt +56 -56
|
@@ -1,201 +1,201 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Find nodes that implement a specific controller.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { SocketFunction } from "socket-function/SocketFunction";
|
|
6
|
-
import { SocketRegistered } from "socket-function/SocketFunctionTypes";
|
|
7
|
-
import { errorToUndefined, errorToUndefinedSilent, timeoutToUndefinedSilent } from "../errors";
|
|
8
|
-
import { getAllNodeIds, isNodeIdOnOwnMachineId } from "../-f-node-discovery/NodeDiscovery";
|
|
9
|
-
import { green, red, yellow } from "socket-function/src/formatting/logColors";
|
|
10
|
-
import { shuffle } from "../misc/random";
|
|
11
|
-
import { delay } from "socket-function/src/batching";
|
|
12
|
-
import debugbreak from "debugbreak";
|
|
13
|
-
import { formatTime } from "socket-function/src/formatting/format";
|
|
14
|
-
import type { DebugFunctionShardInfo } from "../3-path-functions/PathFunctionRunner";
|
|
15
|
-
import { requiresNetworkTrustHook } from "../-d-trust/NetworkTrust2";
|
|
16
|
-
import { isNoNetwork } from "../config";
|
|
17
|
-
import { getDebuggerUrl } from "../diagnostics/listenOnDebugger";
|
|
18
|
-
import { hackDevtoolsWebsocketForward } from "./oneTimeForward";
|
|
19
|
-
import { getOwnMachineId, decodeNodeId, decodeNodeIdAssert, getMachineId } from "../-a-auth/certs";
|
|
20
|
-
import { sort } from "socket-function/src/misc";
|
|
21
|
-
import { getPathStr2 } from "../path";
|
|
22
|
-
import { PromiseObj } from "../promise";
|
|
23
|
-
import { getTrueTimeOffset } from "socket-function/time/trueTimeShim";
|
|
24
|
-
setImmediate(() => {
|
|
25
|
-
import("../diagnostics/MachineThreadInfo");
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
let controllerNodeIdCache = new Map<string, string | Promise<string | undefined>>();
|
|
29
|
-
|
|
30
|
-
// NOTE: If this becomes slow (because we are just trying all servers), we could start to store capabilities
|
|
31
|
-
// in PersistedStorage. However, I don't think it will be a problem for quite some time.
|
|
32
|
-
export async function getControllerNodeId(
|
|
33
|
-
controller: SocketRegistered<{}>,
|
|
34
|
-
quiet = false,
|
|
35
|
-
retryCount = 1,
|
|
36
|
-
initialTime = Date.now(),
|
|
37
|
-
): Promise<string | undefined> {
|
|
38
|
-
let cached = controllerNodeIdCache.get(controller._classGuid);
|
|
39
|
-
if (cached && typeof cached !== "string") {
|
|
40
|
-
cached = await cached;
|
|
41
|
-
}
|
|
42
|
-
// TODO: We are relying on is node connected to do a lot of work here. If the node's connected, but somehow doesn't work, we can get in an unrecoverable state, even if there are plenty of other working nodes.
|
|
43
|
-
if (cached && !SocketFunction.isNodeConnected(cached)) {
|
|
44
|
-
controllerNodeIdCache.delete(controller._classGuid);
|
|
45
|
-
cached = undefined;
|
|
46
|
-
}
|
|
47
|
-
if (cached) return cached;
|
|
48
|
-
let promise = getInternal(retryCount);
|
|
49
|
-
controllerNodeIdCache.set(controller._classGuid, promise);
|
|
50
|
-
return promise;
|
|
51
|
-
|
|
52
|
-
async function getInternal(retryCount: number) {
|
|
53
|
-
let nodeIdsToTest = await getAllNodeIds();
|
|
54
|
-
// Shuffle, so we aren't always using the same node!
|
|
55
|
-
nodeIdsToTest = shuffle(nodeIdsToTest, Date.now());
|
|
56
|
-
let resolvedNode = new PromiseObj<string>();
|
|
57
|
-
|
|
58
|
-
if (!quiet) {
|
|
59
|
-
console.log(`Checking ${nodeIdsToTest.length} nodes for capability ${controller._classGuid}`);
|
|
60
|
-
}
|
|
61
|
-
let allFinished = Promise.all(nodeIdsToTest.map(async nodeId => {
|
|
62
|
-
if (await doesNodeExposeController(nodeId, controller)) {
|
|
63
|
-
if (!quiet) {
|
|
64
|
-
let duration = Date.now() - initialTime;
|
|
65
|
-
console.log(green(`Resolved capability ${controller._classGuid} with node ${nodeId}, in ${formatTime(duration)}`));
|
|
66
|
-
}
|
|
67
|
-
resolvedNode.resolve(nodeId);
|
|
68
|
-
}
|
|
69
|
-
}));
|
|
70
|
-
let result = await Promise.race([allFinished, resolvedNode.promise]);
|
|
71
|
-
if (typeof result === "string") {
|
|
72
|
-
return result;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (retryCount > 0) {
|
|
76
|
-
if (!quiet) {
|
|
77
|
-
console.log(`Did not find capability in ${nodeIdsToTest.length} nodes, retrying... ${controller._classGuid}`);
|
|
78
|
-
}
|
|
79
|
-
await delay(2000);
|
|
80
|
-
return getInternal(retryCount - 1);
|
|
81
|
-
}
|
|
82
|
-
if (!quiet) {
|
|
83
|
-
console.warn(yellow(`Could not find a node that exposes controller ${controller._classGuid}, tried: ${JSON.stringify(nodeIdsToTest)}`));
|
|
84
|
-
}
|
|
85
|
-
return undefined;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export async function getControllerNodeIdList(
|
|
90
|
-
controller: SocketRegistered<{}>,
|
|
91
|
-
): Promise<{ nodeId: string; entryPoint: string }[]> {
|
|
92
|
-
let nodeIdsToTest = await getAllNodeIds();
|
|
93
|
-
let passedNodeIds = new Map<string, { machineId: string; entryPoint: string }>();
|
|
94
|
-
await Promise.all(nodeIdsToTest.map(async nodeId => {
|
|
95
|
-
let result = await doesNodeExposeController(nodeId, controller);
|
|
96
|
-
if (result) {
|
|
97
|
-
let entryPoint = await NodeCapabilitiesController.nodes[nodeId].getEntryPoint();
|
|
98
|
-
passedNodeIds.set(nodeId, {
|
|
99
|
-
machineId: getMachineId(nodeId),
|
|
100
|
-
entryPoint,
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
}));
|
|
104
|
-
|
|
105
|
-
let results = Array.from(passedNodeIds.entries());
|
|
106
|
-
// Prefer localhost connections as they're faster.
|
|
107
|
-
sort(results, (x) => isNodeIdOnOwnMachineId(x[0]) ? 0 : 1);
|
|
108
|
-
let lookup = new Map<string, { nodeId: string; entryPoint: string }>();
|
|
109
|
-
for (let x of results) {
|
|
110
|
-
let key = getPathStr2(x[1].machineId, decodeNodeIdAssert(x[0]).port.toString());
|
|
111
|
-
if (key in lookup) continue;
|
|
112
|
-
lookup.set(key, { nodeId: x[0], entryPoint: x[1].entryPoint });
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return Array.from(lookup.values());
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
export async function doesNodeExposeController(reconnectNodeId: string, controller: SocketRegistered<{}>): Promise<boolean> {
|
|
120
|
-
let exposedControllers = await timeoutToUndefinedSilent(10_000, NodeCapabilitiesController.nodes[reconnectNodeId].getExposedControllers());
|
|
121
|
-
|
|
122
|
-
if (exposedControllers?.includes(controller._classGuid)) {
|
|
123
|
-
return true;
|
|
124
|
-
}
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const startupTime = Date.now();
|
|
129
|
-
class NodeCapabilitiesControllerBase {
|
|
130
|
-
public async getExposedControllers() {
|
|
131
|
-
return Array.from(SocketFunction.exposedClasses);
|
|
132
|
-
}
|
|
133
|
-
public async getEntryPoint() {
|
|
134
|
-
return process.argv[1];
|
|
135
|
-
}
|
|
136
|
-
public async getStartupTime() {
|
|
137
|
-
return startupTime;
|
|
138
|
-
}
|
|
139
|
-
public async getMemoryUsage() {
|
|
140
|
-
return process.memoryUsage();
|
|
141
|
-
}
|
|
142
|
-
public async getFunctionRunnerShards() {
|
|
143
|
-
return getFunctionRunnerShards();
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
public async getTrueTimeOffset() {
|
|
147
|
-
return getTrueTimeOffset();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
public async getInspectURL() {
|
|
151
|
-
return await getDebuggerUrl();
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
public async exposeExternalDebugPortOnce(forExternalIP: string) {
|
|
155
|
-
// https://notdevtools.com/devtools/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:62448/22895aed-f8da-4dfb-8d50-e432a9c2d827
|
|
156
|
-
let debugURL = await this.getInspectURL();
|
|
157
|
-
|
|
158
|
-
const outerUrl = new URL(debugURL);
|
|
159
|
-
const wsParam = outerUrl.searchParams.get("ws");
|
|
160
|
-
if (!wsParam) throw new Error("No ws parameter found");
|
|
161
|
-
|
|
162
|
-
// Add ws:// protocol to make it parseable by URL
|
|
163
|
-
const innerUrl = new URL(`ws://${wsParam}`);
|
|
164
|
-
const port = innerUrl.port;
|
|
165
|
-
if (!port) throw new Error("No port found");
|
|
166
|
-
|
|
167
|
-
const portNumber = parseInt(port, 10);
|
|
168
|
-
if (isNaN(portNumber)) throw new Error("Invalid port number");
|
|
169
|
-
|
|
170
|
-
let { externalPort, cancel } = await hackDevtoolsWebsocketForward({ internalPort: portNumber, externalIP: forExternalIP });
|
|
171
|
-
lastExposed?.();
|
|
172
|
-
lastExposed = cancel;
|
|
173
|
-
return { externalPort, internalPort: portNumber, internalInspectURL: debugURL };
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
let lastExposed: (() => void) | undefined;
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
let getFunctionRunnerShards = () => [] as DebugFunctionShardInfo[];
|
|
180
|
-
export function set_debug_getFunctionRunnerShards(fnc: () => DebugFunctionShardInfo[]) {
|
|
181
|
-
getFunctionRunnerShards = fnc;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export const NodeCapabilitiesController = SocketFunction.register(
|
|
185
|
-
"NodeCapabilitiesController-399b7067-75c3-4d92-8be3-8470bde32d3c",
|
|
186
|
-
new NodeCapabilitiesControllerBase(),
|
|
187
|
-
() => ({
|
|
188
|
-
getExposedControllers: {},
|
|
189
|
-
getEntryPoint: {},
|
|
190
|
-
getStartupTime: {},
|
|
191
|
-
getMemoryUsage: {},
|
|
192
|
-
getFunctionRunnerShards: {},
|
|
193
|
-
getTrueTimeOffset: {},
|
|
194
|
-
getInspectURL: { hooks: [requiresNetworkTrustHook] },
|
|
195
|
-
exposeExternalDebugPortOnce: { hooks: [requiresNetworkTrustHook] },
|
|
196
|
-
}),
|
|
197
|
-
() => ({
|
|
198
|
-
// I think assert is management user didn't exist when we wrote these functions, and so we just made them public. But now that it does exist, we might as well use it. Servers will count as management users anyway, and I don't see any reason a non-management user or a non-server needs to access any of these functions.
|
|
199
|
-
hooks: [(require("../diagnostics/managementPages") as typeof import("../diagnostics/managementPages")).assertIsManagementUser],
|
|
200
|
-
})
|
|
1
|
+
/*
|
|
2
|
+
Find nodes that implement a specific controller.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { SocketFunction } from "socket-function/SocketFunction";
|
|
6
|
+
import { SocketRegistered } from "socket-function/SocketFunctionTypes";
|
|
7
|
+
import { errorToUndefined, errorToUndefinedSilent, timeoutToUndefinedSilent } from "../errors";
|
|
8
|
+
import { getAllNodeIds, isNodeIdOnOwnMachineId } from "../-f-node-discovery/NodeDiscovery";
|
|
9
|
+
import { green, red, yellow } from "socket-function/src/formatting/logColors";
|
|
10
|
+
import { shuffle } from "../misc/random";
|
|
11
|
+
import { delay } from "socket-function/src/batching";
|
|
12
|
+
import debugbreak from "debugbreak";
|
|
13
|
+
import { formatTime } from "socket-function/src/formatting/format";
|
|
14
|
+
import type { DebugFunctionShardInfo } from "../3-path-functions/PathFunctionRunner";
|
|
15
|
+
import { requiresNetworkTrustHook } from "../-d-trust/NetworkTrust2";
|
|
16
|
+
import { isNoNetwork } from "../config";
|
|
17
|
+
import { getDebuggerUrl } from "../diagnostics/listenOnDebugger";
|
|
18
|
+
import { hackDevtoolsWebsocketForward } from "./oneTimeForward";
|
|
19
|
+
import { getOwnMachineId, decodeNodeId, decodeNodeIdAssert, getMachineId } from "../-a-auth/certs";
|
|
20
|
+
import { sort } from "socket-function/src/misc";
|
|
21
|
+
import { getPathStr2 } from "../path";
|
|
22
|
+
import { PromiseObj } from "../promise";
|
|
23
|
+
import { getTrueTimeOffset } from "socket-function/time/trueTimeShim";
|
|
24
|
+
setImmediate(() => {
|
|
25
|
+
import("../diagnostics/MachineThreadInfo");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
let controllerNodeIdCache = new Map<string, string | Promise<string | undefined>>();
|
|
29
|
+
|
|
30
|
+
// NOTE: If this becomes slow (because we are just trying all servers), we could start to store capabilities
|
|
31
|
+
// in PersistedStorage. However, I don't think it will be a problem for quite some time.
|
|
32
|
+
export async function getControllerNodeId(
|
|
33
|
+
controller: SocketRegistered<{}>,
|
|
34
|
+
quiet = false,
|
|
35
|
+
retryCount = 1,
|
|
36
|
+
initialTime = Date.now(),
|
|
37
|
+
): Promise<string | undefined> {
|
|
38
|
+
let cached = controllerNodeIdCache.get(controller._classGuid);
|
|
39
|
+
if (cached && typeof cached !== "string") {
|
|
40
|
+
cached = await cached;
|
|
41
|
+
}
|
|
42
|
+
// TODO: We are relying on is node connected to do a lot of work here. If the node's connected, but somehow doesn't work, we can get in an unrecoverable state, even if there are plenty of other working nodes.
|
|
43
|
+
if (cached && !SocketFunction.isNodeConnected(cached)) {
|
|
44
|
+
controllerNodeIdCache.delete(controller._classGuid);
|
|
45
|
+
cached = undefined;
|
|
46
|
+
}
|
|
47
|
+
if (cached) return cached;
|
|
48
|
+
let promise = getInternal(retryCount);
|
|
49
|
+
controllerNodeIdCache.set(controller._classGuid, promise);
|
|
50
|
+
return promise;
|
|
51
|
+
|
|
52
|
+
async function getInternal(retryCount: number) {
|
|
53
|
+
let nodeIdsToTest = await getAllNodeIds();
|
|
54
|
+
// Shuffle, so we aren't always using the same node!
|
|
55
|
+
nodeIdsToTest = shuffle(nodeIdsToTest, Date.now());
|
|
56
|
+
let resolvedNode = new PromiseObj<string>();
|
|
57
|
+
|
|
58
|
+
if (!quiet) {
|
|
59
|
+
console.log(`Checking ${nodeIdsToTest.length} nodes for capability ${controller._classGuid}`);
|
|
60
|
+
}
|
|
61
|
+
let allFinished = Promise.all(nodeIdsToTest.map(async nodeId => {
|
|
62
|
+
if (await doesNodeExposeController(nodeId, controller)) {
|
|
63
|
+
if (!quiet) {
|
|
64
|
+
let duration = Date.now() - initialTime;
|
|
65
|
+
console.log(green(`Resolved capability ${controller._classGuid} with node ${nodeId}, in ${formatTime(duration)}`));
|
|
66
|
+
}
|
|
67
|
+
resolvedNode.resolve(nodeId);
|
|
68
|
+
}
|
|
69
|
+
}));
|
|
70
|
+
let result = await Promise.race([allFinished, resolvedNode.promise]);
|
|
71
|
+
if (typeof result === "string") {
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (retryCount > 0) {
|
|
76
|
+
if (!quiet) {
|
|
77
|
+
console.log(`Did not find capability in ${nodeIdsToTest.length} nodes, retrying... ${controller._classGuid}`);
|
|
78
|
+
}
|
|
79
|
+
await delay(2000);
|
|
80
|
+
return getInternal(retryCount - 1);
|
|
81
|
+
}
|
|
82
|
+
if (!quiet) {
|
|
83
|
+
console.warn(yellow(`Could not find a node that exposes controller ${controller._classGuid}, tried: ${JSON.stringify(nodeIdsToTest)}`));
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function getControllerNodeIdList(
|
|
90
|
+
controller: SocketRegistered<{}>,
|
|
91
|
+
): Promise<{ nodeId: string; entryPoint: string }[]> {
|
|
92
|
+
let nodeIdsToTest = await getAllNodeIds();
|
|
93
|
+
let passedNodeIds = new Map<string, { machineId: string; entryPoint: string }>();
|
|
94
|
+
await Promise.all(nodeIdsToTest.map(async nodeId => {
|
|
95
|
+
let result = await doesNodeExposeController(nodeId, controller);
|
|
96
|
+
if (result) {
|
|
97
|
+
let entryPoint = await NodeCapabilitiesController.nodes[nodeId].getEntryPoint();
|
|
98
|
+
passedNodeIds.set(nodeId, {
|
|
99
|
+
machineId: getMachineId(nodeId),
|
|
100
|
+
entryPoint,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}));
|
|
104
|
+
|
|
105
|
+
let results = Array.from(passedNodeIds.entries());
|
|
106
|
+
// Prefer localhost connections as they're faster.
|
|
107
|
+
sort(results, (x) => isNodeIdOnOwnMachineId(x[0]) ? 0 : 1);
|
|
108
|
+
let lookup = new Map<string, { nodeId: string; entryPoint: string }>();
|
|
109
|
+
for (let x of results) {
|
|
110
|
+
let key = getPathStr2(x[1].machineId, decodeNodeIdAssert(x[0]).port.toString());
|
|
111
|
+
if (key in lookup) continue;
|
|
112
|
+
lookup.set(key, { nodeId: x[0], entryPoint: x[1].entryPoint });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return Array.from(lookup.values());
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
export async function doesNodeExposeController(reconnectNodeId: string, controller: SocketRegistered<{}>): Promise<boolean> {
|
|
120
|
+
let exposedControllers = await timeoutToUndefinedSilent(10_000, NodeCapabilitiesController.nodes[reconnectNodeId].getExposedControllers());
|
|
121
|
+
|
|
122
|
+
if (exposedControllers?.includes(controller._classGuid)) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const startupTime = Date.now();
|
|
129
|
+
class NodeCapabilitiesControllerBase {
|
|
130
|
+
public async getExposedControllers() {
|
|
131
|
+
return Array.from(SocketFunction.exposedClasses);
|
|
132
|
+
}
|
|
133
|
+
public async getEntryPoint() {
|
|
134
|
+
return process.argv[1];
|
|
135
|
+
}
|
|
136
|
+
public async getStartupTime() {
|
|
137
|
+
return startupTime;
|
|
138
|
+
}
|
|
139
|
+
public async getMemoryUsage() {
|
|
140
|
+
return process.memoryUsage();
|
|
141
|
+
}
|
|
142
|
+
public async getFunctionRunnerShards() {
|
|
143
|
+
return getFunctionRunnerShards();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public async getTrueTimeOffset() {
|
|
147
|
+
return getTrueTimeOffset();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public async getInspectURL() {
|
|
151
|
+
return await getDebuggerUrl();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public async exposeExternalDebugPortOnce(forExternalIP: string) {
|
|
155
|
+
// https://notdevtools.com/devtools/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:62448/22895aed-f8da-4dfb-8d50-e432a9c2d827
|
|
156
|
+
let debugURL = await this.getInspectURL();
|
|
157
|
+
|
|
158
|
+
const outerUrl = new URL(debugURL);
|
|
159
|
+
const wsParam = outerUrl.searchParams.get("ws");
|
|
160
|
+
if (!wsParam) throw new Error("No ws parameter found");
|
|
161
|
+
|
|
162
|
+
// Add ws:// protocol to make it parseable by URL
|
|
163
|
+
const innerUrl = new URL(`ws://${wsParam}`);
|
|
164
|
+
const port = innerUrl.port;
|
|
165
|
+
if (!port) throw new Error("No port found");
|
|
166
|
+
|
|
167
|
+
const portNumber = parseInt(port, 10);
|
|
168
|
+
if (isNaN(portNumber)) throw new Error("Invalid port number");
|
|
169
|
+
|
|
170
|
+
let { externalPort, cancel } = await hackDevtoolsWebsocketForward({ internalPort: portNumber, externalIP: forExternalIP });
|
|
171
|
+
lastExposed?.();
|
|
172
|
+
lastExposed = cancel;
|
|
173
|
+
return { externalPort, internalPort: portNumber, internalInspectURL: debugURL };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
let lastExposed: (() => void) | undefined;
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
let getFunctionRunnerShards = () => [] as DebugFunctionShardInfo[];
|
|
180
|
+
export function set_debug_getFunctionRunnerShards(fnc: () => DebugFunctionShardInfo[]) {
|
|
181
|
+
getFunctionRunnerShards = fnc;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export const NodeCapabilitiesController = SocketFunction.register(
|
|
185
|
+
"NodeCapabilitiesController-399b7067-75c3-4d92-8be3-8470bde32d3c",
|
|
186
|
+
new NodeCapabilitiesControllerBase(),
|
|
187
|
+
() => ({
|
|
188
|
+
getExposedControllers: {},
|
|
189
|
+
getEntryPoint: {},
|
|
190
|
+
getStartupTime: {},
|
|
191
|
+
getMemoryUsage: {},
|
|
192
|
+
getFunctionRunnerShards: {},
|
|
193
|
+
getTrueTimeOffset: {},
|
|
194
|
+
getInspectURL: { hooks: [requiresNetworkTrustHook] },
|
|
195
|
+
exposeExternalDebugPortOnce: { hooks: [requiresNetworkTrustHook] },
|
|
196
|
+
}),
|
|
197
|
+
() => ({
|
|
198
|
+
// I think assert is management user didn't exist when we wrote these functions, and so we just made them public. But now that it does exist, we might as well use it. Servers will count as management users anyway, and I don't see any reason a non-management user or a non-server needs to access any of these functions.
|
|
199
|
+
hooks: [(require("../diagnostics/managementPages") as typeof import("../diagnostics/managementPages")).assertIsManagementUser],
|
|
200
|
+
})
|
|
201
201
|
);
|