querysub 0.460.0 → 0.462.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.
Files changed (33) hide show
  1. package/package.json +2 -2
  2. package/src/-b-authorities/dnsAuthority.ts +23 -15
  3. package/src/-g-core-values/NodeCapabilities.ts +3 -0
  4. package/src/-h-path-value-serialize/PathValueSerializer.ts +11 -3
  5. package/src/0-path-value-core/PathRouter.ts +6 -0
  6. package/src/0-path-value-core/PathWatcher.ts +1 -1
  7. package/src/0-path-value-core/pathValueCore.ts +4 -7
  8. package/src/1-path-client/RemoteWatcher.ts +8 -3
  9. package/src/1-path-client/pathValueClientWatcher.ts +3 -0
  10. package/src/2-proxy/PathValueProxyWatcher.ts +1 -1
  11. package/src/2-proxy/TransactionDelayer.ts +1 -1
  12. package/src/3-path-functions/PathFunctionHelpers.ts +13 -8
  13. package/src/3-path-functions/PathFunctionRunner.ts +2 -0
  14. package/src/4-querysub/Querysub.ts +0 -1
  15. package/src/4-querysub/QuerysubController.ts +1 -7
  16. package/src/config.ts +6 -0
  17. package/src/config2.ts +7 -1
  18. package/src/deployManager/components/MachinePicker.tsx +40 -0
  19. package/src/deployManager/components/ServiceDetailPage.tsx +2 -5
  20. package/src/deployManager/components/ServicesListPage.tsx +2 -0
  21. package/src/deployManager/components/Tools.tsx +165 -0
  22. package/src/deployManager/machineApplyMainCode.ts +2 -2
  23. package/src/deployManager/setupMachineMain.ts +65 -23
  24. package/src/diagnostics/charts/Chart.tsx +240 -0
  25. package/src/diagnostics/grossStats/GrossStatsPage.tsx +48 -83
  26. package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +3 -3
  27. package/src/diagnostics/logs/IndexedLogs/MCPIndexedLogs.ts +18 -3
  28. package/src/diagnostics/logs/IndexedLogs/MCPIndexedLogsEntry.ts +1 -0
  29. package/src/diagnostics/managementPages.tsx +58 -58
  30. package/src/diagnostics/misc-pages/DNSPage.tsx +344 -0
  31. package/test.ts +29 -170
  32. package/src/diagnostics/AuditLogPage.tsx +0 -147
  33. package/src/diagnostics/NodeConnectionsPage.tsx +0 -167
package/test.ts CHANGED
@@ -1,197 +1,56 @@
1
1
  import { chdir } from "process";
2
2
  chdir("D:/repos/qs-cyoa/");
3
3
 
4
- import { isPublic, setIsPublic } from "./src/config";
5
- setIsPublic(true);
4
+ import { setIsPublic } from "./src/config";
5
+ setIsPublic(false);
6
6
 
7
7
  import "./inject";
8
8
  import { Querysub } from "./src/4-querysub/Querysub";
9
9
  import { getLoggers2Async, LogDatum } from "./src/diagnostics/logs/diskLogger";
10
- import { IndexedLogs } from "./src/diagnostics/logs/IndexedLogs/IndexedLogs";
11
10
  import { SearchParams } from "./src/diagnostics/logs/IndexedLogs/BufferIndexHelpers";
12
- import { formatDateTimeDetailed, formatNumber, formatTime } from "socket-function/src/formatting/format";
11
+ import { formatDateTimeDetailed, formatTime } from "socket-function/src/formatting/format";
13
12
 
14
- // Pulled verbatim from the URLs the user shared.
15
13
  const START_TIME = 1779598800000;
16
14
  const END_TIME = 1779604200000;
17
15
  const LIMIT = 1600;
18
- const SEARCH_BROAD = `wvupofthbgq & "__threadId":"1f72e0ea774fcc81"`;
19
- const SEARCH_NARROW = `wvupofthbgq & "__threadId":"1f72e0ea774fcc81" & new`;
16
+ const SEARCH = `wvupofthbgq & "__threadId":"1f72e0ea774fcc81"`;
17
+ const NODE_ID = "46456fa53a7392cf.a794fbcf7b104c68.querysubtest.com:44173";
20
18
 
21
- type Emit = {
22
- time: number;
23
- logger: string;
24
- datum: LogDatum;
25
- };
26
-
27
- // Stable identity for cross-query comparison. `time` alone isn't unique (many
28
- // entries share the same ms), so we fold in threadId + entry text.
29
- function emitKey(e: Emit): string {
30
- return `${e.time}|${e.datum.__threadId ?? ""}|${e.datum.__entry ?? ""}|${e.datum.param0 ?? ""}`;
31
- }
19
+ async function main() {
20
+ await Querysub.hostService("test");
32
21
 
33
- async function runQuery(label: string, searchText: string, limit: number = LIMIT): Promise<Emit[]> {
34
- console.log(`\n=== ${label}: ${JSON.stringify(searchText)} (limit=${limit}) ===`);
35
22
  let loggers = await getLoggers2Async();
36
- let allLoggers: { name: string; logger: IndexedLogs<LogDatum> }[] = [
37
- { name: "info", logger: loggers.infoLogs },
38
- ];
23
+ let infoLogs = loggers.infoLogs;
39
24
 
40
25
  let params: SearchParams = {
41
26
  startTime: START_TIME,
42
27
  endTime: END_TIME,
43
- limit,
44
- findBuffer: Buffer.from(searchText, "utf8"),
28
+ limit: LIMIT,
29
+ findBuffer: Buffer.from(SEARCH, "utf8"),
45
30
  searchFromStart: true,
46
- only: "public",
31
+ forceReadProduction: true,
47
32
  };
48
33
 
49
- let allEmits: Emit[] = [];
50
- let queryStart = Date.now();
51
-
52
- await Promise.all(allLoggers.map(async ({ name, logger }) => {
53
- let perLoggerEmits: Emit[] = [];
54
- let loggerStart = Date.now();
55
- let result = await logger.find({
56
- params,
57
- onResult: (match: LogDatum) => {
58
- perLoggerEmits.push({ time: match.time, logger: name, datum: match });
59
- },
60
- });
61
-
62
- let earliest = perLoggerEmits.length > 0 ? Math.min(...perLoggerEmits.map(e => e.time)) : undefined;
63
- let latest = perLoggerEmits.length > 0 ? Math.max(...perLoggerEmits.map(e => e.time)) : undefined;
64
- console.log(
65
- ` [${name}] emits=${perLoggerEmits.length} ` +
66
- `matchCount=${result.matchCount} ` +
67
- `blocksChecked=${result.blockCheckedCount}/${result.totalBlockCount} ` +
68
- `filesScanned=${result.backblazeFilesSearched}/${result.totalBackblazeFiles} ` +
69
- `earliest=${earliest !== undefined ? formatDateTimeDetailed(earliest) : "—"} ` +
70
- `latest=${latest !== undefined ? formatDateTimeDetailed(latest) : "—"} ` +
71
- `time=${formatTime(Date.now() - loggerStart)}`
72
- );
73
- allEmits.push(...perLoggerEmits);
74
- }));
75
-
76
- console.log(` total emits=${allEmits.length} in ${formatTime(Date.now() - queryStart)}`);
77
-
78
- // Sort + trim to limit (mirroring the client-side display).
79
- allEmits.sort((a, b) => a.time - b.time);
80
- if (allEmits.length > limit) allEmits.length = limit;
81
-
34
+ let emits: LogDatum[] = [];
35
+ let start = Date.now();
36
+ let result = await infoLogs.clientFind({
37
+ params,
38
+ nodeId: NODE_ID,
39
+ onResult: (match) => {
40
+ emits.push(match);
41
+ },
42
+ });
43
+ let elapsed = Date.now() - start;
44
+ let earliest = emits.length > 0 ? Math.min(...emits.map(e => e.time)) : undefined;
45
+ let latest = emits.length > 0 ? Math.max(...emits.map(e => e.time)) : undefined;
82
46
  console.log(
83
- ` kept top-${allEmits.length} ` +
84
- `earliest=${allEmits.length > 0 ? formatDateTimeDetailed(allEmits[0].time) : "—"} ` +
85
- `latest=${allEmits.length > 0 ? formatDateTimeDetailed(allEmits[allEmits.length - 1].time) : "—"}`
47
+ `emits=${emits.length} matchCount=${result?.matchCount} ` +
48
+ `blocksChecked=${result?.blockCheckedCount}/${result?.totalBlockCount} ` +
49
+ `filesScanned=${result?.backblazeFilesSearched}/${result?.totalBackblazeFiles} ` +
50
+ `earliest=${earliest !== undefined ? formatDateTimeDetailed(earliest) : "—"} ` +
51
+ `latest=${latest !== undefined ? formatDateTimeDetailed(latest) : "—"} ` +
52
+ `time=${formatTime(elapsed)}`
86
53
  );
87
- return allEmits;
88
- }
89
-
90
- async function main() {
91
- await Querysub.hostService("test");
92
-
93
- // Dump every info file in range — declared startTime / endTime — so we
94
- // can spot files whose declared range disagrees with the entries inside.
95
- let loggers = await getLoggers2Async();
96
- let paths = await loggers.infoLogs.getPaths({
97
- startTime: START_TIME,
98
- endTime: END_TIME,
99
- only: "public",
100
- });
101
- paths.sort((a, b) => a.startTime - b.startTime);
102
- console.log(`\n=== INFO FILES IN RANGE (${paths.length}) — declared ranges ===`);
103
- for (let p of paths) {
104
- console.log(` start=${formatDateTimeDetailed(p.startTime)} end=${formatDateTimeDetailed(p.endTime)} logCount=${p.logCount ?? "?"} ${p.fullPath}`);
105
- }
106
-
107
- let broad = await runQuery("BROAD", SEARCH_BROAD);
108
- let narrow = await runQuery("NARROW", SEARCH_NARROW);
109
- // Sanity: run broad again with a huge limit. If those 4 entries appear
110
- // here but not in the limit=1600 run, the per-file `stopIterating` cap is
111
- // skipping the block that contains them. If they're still missing, the
112
- // bug is upstream (index pre-filter or block scanner missing them).
113
- let broadHuge = await runQuery("BROAD_HUGE", SEARCH_BROAD, 1_000_000);
114
-
115
- // The diagnostic: narrow ⊂ broad by definition. So every narrow result
116
- // whose time falls inside broad's kept window MUST appear in broad. If any
117
- // are missing, the broad scan dropped them — that's the bug.
118
- if (broad.length === 0 || narrow.length === 0) {
119
- console.log(`\nSkipping comparison: broad=${broad.length} narrow=${narrow.length}`);
120
- return;
121
- }
122
-
123
- let broadKeys = new Set(broad.map(emitKey));
124
- let broadCutoff = broad[broad.length - 1].time;
125
- let broadEarliest = broad[0].time;
126
-
127
- console.log(`\n=== COMPARE ===`);
128
- console.log(`broad window: [${formatDateTimeDetailed(broadEarliest)}, ${formatDateTimeDetailed(broadCutoff)}]`);
129
-
130
- let narrowInWindow = narrow.filter(n => n.time <= broadCutoff);
131
- let missing = narrowInWindow.filter(n => !broadKeys.has(emitKey(n)));
132
-
133
- console.log(`narrow total: ${narrow.length}`);
134
- console.log(`narrow within broad window (<= broad cutoff): ${narrowInWindow.length}`);
135
- console.log(`narrow missing from broad kept top-K: ${missing.length}`);
136
-
137
- if (missing.length > 0) {
138
- console.log(`\nFirst ${Math.min(20, missing.length)} missing entries (these prove broad dropped them):`);
139
- for (let m of missing.slice(0, 20)) {
140
- console.log(
141
- ` time=${formatDateTimeDetailed(m.time)} ` +
142
- `logger=${m.logger} ` +
143
- `entry=${(m.datum.__entry ?? "").slice(0, 80)} ` +
144
- `param0=${String(m.datum.param0 ?? "").slice(0, 80)}`
145
- );
146
- }
147
-
148
- // Group missing by logger so we can tell which scan dropped them.
149
- let byLogger = new Map<string, number>();
150
- for (let m of missing) byLogger.set(m.logger, (byLogger.get(m.logger) ?? 0) + 1);
151
- console.log(`\nMissing by logger:`);
152
- for (let [k, v] of byLogger) console.log(` ${k}: ${formatNumber(v)}`);
153
- } else {
154
- console.log(`\nNo missing entries — broad correctly contains all narrow results in its window.`);
155
- }
156
-
157
- // For each missing entry, identify the file whose declared range *should*
158
- // cover its time, and find the file whose declared range *doesn't* cover
159
- // it (the bug indicator).
160
- if (missing.length > 0) {
161
- let missingTimes = missing.map(m => m.time);
162
- let minMissing = Math.min(...missingTimes);
163
- let maxMissing = Math.max(...missingTimes);
164
- console.log(`\nMissing entry times span: [${formatDateTimeDetailed(minMissing)}, ${formatDateTimeDetailed(maxMissing)}]`);
165
- console.log(`Files whose declared range overlaps [${formatDateTimeDetailed(minMissing)}, ${formatDateTimeDetailed(maxMissing)}]:`);
166
- for (let p of paths) {
167
- if (p.endTime < minMissing || p.startTime > maxMissing) continue;
168
- console.log(` start=${formatDateTimeDetailed(p.startTime)} end=${formatDateTimeDetailed(p.endTime)} ${p.fullPath}`);
169
- }
170
- // Also: any file whose declared startTime > broad cutoff (and so would
171
- // be isSourceRelevant-pruned) — these are candidates for the bug.
172
- console.log(`Files whose declared startTime > broad cutoff (${formatDateTimeDetailed(broadCutoff)}) — these would be pruned by isSourceRelevant once broad fills:`);
173
- for (let p of paths) {
174
- if (p.startTime > broadCutoff) {
175
- let overlap = p.startTime <= maxMissing && p.endTime >= minMissing ? " <- OVERLAPS MISSING" : "";
176
- console.log(` start=${formatDateTimeDetailed(p.startTime)} end=${formatDateTimeDetailed(p.endTime)} ${p.fullPath}${overlap}`);
177
- }
178
- }
179
- }
180
-
181
- // Check whether broad-with-huge-limit catches the missing entries.
182
- let broadHugeKeys = new Set(broadHuge.map(emitKey));
183
- let stillMissingFromHuge = narrow.filter(n => !broadHugeKeys.has(emitKey(n)));
184
- console.log(`\n=== BROAD_HUGE check ===`);
185
- console.log(`narrow missing from broad_huge: ${stillMissingFromHuge.length}`);
186
- if (stillMissingFromHuge.length > 0) {
187
- console.log(`First ${Math.min(20, stillMissingFromHuge.length)} still-missing:`);
188
- for (let m of stillMissingFromHuge.slice(0, 20)) {
189
- console.log(` time=${formatDateTimeDetailed(m.time)} param0=${String(m.datum.param0 ?? "").slice(0, 60)}`);
190
- }
191
- console.log(`-> bug is NOT (only) the per-file cap; the scanner / index pre-filter is dropping entries even without the cap.`);
192
- } else {
193
- console.log(`-> all narrow entries are in broad_huge; the per-file stopIterating cap is the culprit for the limit=1600 miss.`);
194
- }
195
54
  }
196
55
 
197
56
  main().catch(e => console.error((e as Error).stack ?? e))
@@ -1,147 +0,0 @@
1
- import { SocketFunction } from "socket-function/SocketFunction";
2
- import { qreact } from "../4-dom/qreact";
3
- import { assertIsManagementUser } from "./managementPages";
4
- import { css } from "typesafecss";
5
- import { getSyncedController } from "../library-components/SyncedController";
6
- import { DebugLog, DebugLogController, getLogHistoryEquals, getLogHistoryIncludes } from "../0-path-value-core/auditLogs";
7
- import { remoteWatcher } from "../1-path-client/RemoteWatcher";
8
- import { getBrowserUrlNode, getOwnNodeId } from "../-f-node-discovery/NodeDiscovery";
9
- import { nextId, sort } from "socket-function/src/misc";
10
- import { t } from "../2-proxy/schema2";
11
- import { InputLabelURL } from "../library-components/InputLabel";
12
- import { URLParam } from "../library-components/URLParam";
13
- import { Table } from "../5-diagnostics/Table";
14
- import { ObjectDisplay } from "./logs/ObjectDisplay";
15
- import { PathRouter } from "../0-path-value-core/PathRouter";
16
-
17
- /**
18
- TODO:
19
- 1) Support watching multiple paths at once
20
- 2) Show extra metadata for the paths
21
- - Current value (raw, as in, don't sync it)
22
- - If it is synced
23
- - The authority of it
24
- - An expander which shows a table of the full history of values, with valid state, etc
25
- */
26
-
27
- type DebugLogWithSource = DebugLog & {
28
- sourceType: "local" | "remote";
29
- sourceNodeId: string;
30
- }
31
-
32
- let path = new URLParam("path", "");
33
- let includeDescendants = new URLParam("includeDescendants", false);
34
- export class AuditLogPage extends qreact.Component {
35
- loadId = nextId();
36
- state = t.state({
37
- loadedId: t.string
38
- });
39
- render() {
40
- let logs: DebugLogWithSource[] = [];
41
- let loaded = this.loadId === this.state.loadedId;
42
- if (loaded) {
43
- let obj = auditLogController(getBrowserUrlNode()).getPathHistory({
44
- path: path.value,
45
- includeDescendants: includeDescendants.value,
46
- });
47
- if (obj) {
48
- logs = obj.fullLogs;
49
- }
50
- }
51
- return (
52
- <div class={css.pad2(10).vbox(10).fillWidth}>
53
- <InputLabelURL
54
- label="Path"
55
- url={path}
56
- fillWidth
57
- onChange={() => this.loadId = nextId()}
58
- />
59
- <InputLabelURL
60
- label="Include Descendants"
61
- url={includeDescendants}
62
- checkbox
63
- onChange={() => this.loadId = nextId()}
64
- />
65
- {!loaded && <button onClick={() => this.state.loadedId = this.loadId}>Load</button>}
66
- <Table
67
- rows={logs}
68
- columns={{
69
- type: {},
70
- time: {},
71
- sourceType: {},
72
- sourceNodeId: {},
73
- values: {
74
- formatter(value) {
75
- return <ObjectDisplay value={value} />;
76
- },
77
- },
78
- }}
79
- />
80
- </div>
81
- );
82
- }
83
- }
84
-
85
-
86
- class AuditLogControllerBase {
87
- public async getPathHistory(config: {
88
- path: string;
89
- includeDescendants?: boolean;
90
- }) {
91
- let { path, includeDescendants } = config;
92
- let authorityNodeId = remoteWatcher.getExistingWatchRemoteNodeId(path);
93
- if (!authorityNodeId) {
94
- authorityNodeId = await PathRouter.getReadyAuthority(path)?.nodeId;
95
- }
96
- let logs: DebugLog[] = [];
97
- let remoteLogs: DebugLog[] = [];
98
- if (includeDescendants) {
99
- // Also look for the parent, so we can capture keys() syncs as well
100
- // (this should give us child paths too, because that's how includes works)
101
- logs = getLogHistoryIncludes(path);
102
- if (authorityNodeId) {
103
- remoteLogs = await DebugLogController.nodes[authorityNodeId].getLogHistoryEquals(path);
104
- }
105
- } else {
106
- logs = getLogHistoryEquals(path);
107
- if (authorityNodeId) {
108
- remoteLogs = await DebugLogController.nodes[authorityNodeId].getLogHistoryEquals(path);
109
- }
110
- }
111
-
112
- let fullLogs: DebugLogWithSource[] = [];
113
- let ownNodeId = getOwnNodeId();
114
- for (let log of logs) {
115
- fullLogs.push({
116
- ...log,
117
- sourceType: "local",
118
- sourceNodeId: ownNodeId,
119
- });
120
- }
121
- if (authorityNodeId) {
122
- for (let log of remoteLogs) {
123
- fullLogs.push({
124
- ...log,
125
- sourceType: "remote",
126
- sourceNodeId: authorityNodeId,
127
- });
128
- }
129
- }
130
- sort(fullLogs, x => x.time);
131
- return {
132
- fullLogs,
133
- };
134
- }
135
- }
136
-
137
- export const AuditLogController = SocketFunction.register(
138
- "AuditLogController-bf798faf-c803-4add-ac2c-99d0f44e753a",
139
- new AuditLogControllerBase(),
140
- () => ({
141
- getPathHistory: {},
142
- }),
143
- () => ({
144
- hooks: [assertIsManagementUser],
145
- })
146
- );
147
- export const auditLogController = getSyncedController(AuditLogController);
@@ -1,167 +0,0 @@
1
- import { SocketFunction } from "socket-function/SocketFunction";
2
- import { qreact } from "../4-dom/qreact";
3
- import { assertIsManagementUser } from "./managementPages";
4
- import { css } from "typesafecss";
5
- import { getSyncedController } from "../library-components/SyncedController";
6
- import { getAllNodeIds, getBrowserUrlNode } from "../-f-node-discovery/NodeDiscovery";
7
- import { debugGetAllCallFactories } from "socket-function/src/nodeCache";
8
- import { debugNodeId } from "../-c-identity/IdentityController";
9
- import { fastHash } from "../misc/hash";
10
- import { NodeCapabilitiesController } from "../-g-core-values/NodeCapabilities";
11
- import { sort } from "socket-function/src/misc";
12
-
13
-
14
-
15
- function getColorForNodeId(friendlyNodeId: string): string {
16
- let hash = fastHash(friendlyNodeId);
17
- let hue = hash % 360;
18
- return `hsl(${hue}, 70%, 60%)`;
19
- }
20
-
21
- export class NodeConnectionsPage extends qreact.Component {
22
- render() {
23
- let browserNode = getBrowserUrlNode();
24
- let controller = nodeConnectionsController(browserNode);
25
-
26
- let nodeIds = controller.getAllNodeIds();
27
- if (!nodeIds) {
28
- return <div class={css.pad2(10)}>Loading...</div>;
29
- }
30
-
31
- let connectableNodes: Array<{ nodeId: string; friendlyNodeId: string; entryPoint: string | undefined; connections: Array<{ nodeId: string; friendlyNodeId: string }> }> = [];
32
- let nonConnectableNodes: string[] = [];
33
-
34
- for (let nodeId of nodeIds) {
35
- try {
36
- let result = controller.getNodeConnections_forBrowser(nodeId);
37
- if (result) {
38
- let friendlyNodeId = debugNodeId(nodeId);
39
- let entryPoint: string | undefined;
40
- try {
41
- entryPoint = controller.getEntryPoint_forBrowser(nodeId);
42
- } catch (e) {
43
- entryPoint = undefined;
44
- }
45
- connectableNodes.push({
46
- nodeId,
47
- friendlyNodeId,
48
- entryPoint,
49
- connections: result.connections,
50
- });
51
- }
52
- } catch (e) {
53
- nonConnectableNodes.push(nodeId);
54
- }
55
- }
56
-
57
- return (
58
- <div class={css.pad2(10).vbox(20).fillWidth}>
59
- <h1>Connectable Nodes</h1>
60
- <div class={css.hbox(20).wrap.fillWidth}>
61
- {connectableNodes.map(node => {
62
- let color = getColorForNodeId(node.friendlyNodeId);
63
- return (
64
- <div class={css.vbox(5).pad2(10).maxHeight(400).overflowAuto.bord(1, { h: 0, s: 0, l: 80 })}>
65
- <div class={css.vbox(3)}>
66
- {node.entryPoint && (
67
- <div class={css.fontSize(14).fontWeight("bold")}>
68
- {node.entryPoint}
69
- </div>
70
- )}
71
- <div class={css.hbox(5)}>
72
- <span class={css.background(color).pad2(4, 2).fontWeight("bold")}>
73
- {node.friendlyNodeId}
74
- </span>
75
- <span class={css.color("gray").fontSize(12)}>
76
- ({node.nodeId})
77
- </span>
78
- </div>
79
- </div>
80
- <div class={css.vbox(3).paddingLeft(20)}>
81
- {node.connections.length === 0 && (
82
- <div class={css.color("gray")}>No connections</div>
83
- )}
84
- {node.connections.map(conn => {
85
- let connColor = getColorForNodeId(conn.friendlyNodeId);
86
- return (
87
- <div class={css.hbox(5)}>
88
- <span>→ Connected to:</span>
89
- <span class={css.background(connColor).pad2(4, 2).fontWeight("bold")}>
90
- {conn.friendlyNodeId}
91
- </span>
92
- <span class={css.color("gray").fontSize(12)}>
93
- ({conn.nodeId})
94
- </span>
95
- </div>
96
- );
97
- })}
98
- </div>
99
- </div>
100
- );
101
- })}
102
- </div>
103
-
104
- <div class={css.vbox(10).fillWidth}>
105
- <h1>Non-Connectable Nodes</h1>
106
- <div class={css.vbox(5).pad2(10).maxHeight(600).overflowAuto.bord(1, { h: 0, s: 0, l: 80 })}>
107
- {nonConnectableNodes.map(nodeId => {
108
- let friendlyNodeId = debugNodeId(nodeId);
109
- return (
110
- <div class={css.hbox(5)}>
111
- <span class={css.background("lightgray").pad2(4, 2).fontWeight("bold")}>
112
- {friendlyNodeId}
113
- </span>
114
- <span class={css.color("gray").fontSize(12)}>
115
- ({nodeId})
116
- </span>
117
- <span class={css.color("gray")}>- Can't connect</span>
118
- </div>
119
- );
120
- })}
121
- </div>
122
- </div>
123
- </div>
124
- );
125
- }
126
- }
127
-
128
- class NodeConnectionsControllerBase {
129
- public async getNodeConnections() {
130
- let factories = debugGetAllCallFactories();
131
- let connections = factories.filter(x => x.isConnected).map(factory => ({
132
- nodeId: factory.nodeId,
133
- friendlyNodeId: debugNodeId(factory.nodeId),
134
- }));
135
- return { connections };
136
- }
137
-
138
- public async getNodeConnections_forBrowser(nodeId: string) {
139
- let result = await NodeConnectionsController.nodes[nodeId].getNodeConnections();
140
- sort(result.connections, x => x.friendlyNodeId);
141
- return result;
142
- }
143
-
144
- public async getEntryPoint_forBrowser(nodeId: string) {
145
- return (await NodeCapabilitiesController.nodes[nodeId].getMetadata()).entryPoint;
146
- }
147
-
148
- public async getAllNodeIds() {
149
- return await getAllNodeIds();
150
- }
151
- }
152
-
153
- export const NodeConnectionsController = SocketFunction.register(
154
- "NodeConnectionsController-8f3e2a1b-4c5d-4f2e-9a3b-7c8d1e2f3a4b",
155
- new NodeConnectionsControllerBase(),
156
- () => ({
157
- getNodeConnections: {},
158
- getNodeConnections_forBrowser: {},
159
- getEntryPoint_forBrowser: {},
160
- getAllNodeIds: {},
161
- }),
162
- () => ({
163
- hooks: [assertIsManagementUser],
164
- })
165
- );
166
-
167
- export const nodeConnectionsController = getSyncedController(NodeConnectionsController);