querysub 0.20.0 → 0.23.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "querysub",
3
- "version": "0.20.0",
3
+ "version": "0.23.0",
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",
@@ -351,6 +351,8 @@ async function runMainSyncLoops(discoveryReady: PromiseObj<void>) {
351
351
  await timeoutToUndefinedSilent(timeInSecond * 5, errorToUndefinedSilent(NodeDiscoveryController.nodes[nodeId].addNode(getOwnNodeId())));
352
352
  }));
353
353
 
354
+ console.log(magenta(`Node discovery is ready and first heartbeat + sync is done`));
355
+
354
356
  await runInfinitePoll(HEARTBEAT_INTERVAL, async function nodeDiscoverHeartbeat() {
355
357
  // If we waited too long, other nodes might think we are dead. In which case, we SHOULD terminate.
356
358
  if (!isNoNetwork()) {
@@ -230,6 +230,7 @@ class NodePathAuthorities {
230
230
  return;
231
231
  }
232
232
 
233
+ let time = Date.now();
233
234
  let createTime = await errorToUndefinedSilent(PathController.nodes[nodeId].getCreateTime());
234
235
  if (createTime === undefined) {
235
236
  // Don't log for 127-0-0-1, as it usually fails, and is mostly a development optimization
@@ -238,7 +239,8 @@ class NodePathAuthorities {
238
239
  }
239
240
  return;
240
241
  }
241
- console.log(blue(`Identifying ${nodeId} as a path authority`));
242
+ time = Date.now() - time;
243
+ console.log(blue(`Identifying ${nodeId} as a path authority. ping latency = ${formatTime(time)}`));
242
244
  this.authorities.set(nodeId, {
243
245
  nodeId,
244
246
  self: nodeId.startsWith("127-0-0-1."),
@@ -23,7 +23,7 @@ import { LOCAL_DOMAIN_PATH } from "../0-path-value-core/NodePathAuthorities";
23
23
  import { registerPeriodic } from "../diagnostics/periodic";
24
24
  import { remoteWatcher } from "../1-path-client/RemoteWatcher";
25
25
  import { Schema2, Schema2Fncs } from "./schema2";
26
- import { devDebugbreak, getDomain } from "../config";
26
+ import { devDebugbreak, getDomain, isPublic } from "../config";
27
27
 
28
28
  import type { CallSpec } from "../3-path-functions/PathFunctionRunner";
29
29
  import type { FunctionMetadata } from "../3-path-functions/syncSchema";
@@ -1813,9 +1813,9 @@ export function registerSchemaPrefix(config: {
1813
1813
  if (!list) {
1814
1814
  schemaPrefixes.push(list = { len, prefixes: new Map() });
1815
1815
  }
1816
- if (isNode()) {
1816
+ if (isNode() && !globalThis.isHotReloading?.()) {
1817
1817
  if (list.prefixes.has(config.prefixPathStr)) {
1818
- throw new Error(`Prefix matches only work due to only having one version of the code ever load (except for during hot reloading development clientside). If we try to render multiple versions of the same code serverside (ex, because we pre-loaded new code during a deploy), it will break, as we can't distinguish them. ADD GIT HASH TO PREFIX SCHEMAS TO FIX THIS!`);
1818
+ throw new Error(`Prefix matches only work due to only having one version of the code ever load (except for during hot reloading development clientside). If we try to render multiple versions of the same code serverside (ex, because we pre-loaded new code during a deploy), it will break, as we can't distinguish them. ADD GIT HASH TO PREFIX SCHEMAS TO FIX THIS! Tried to double load ${config.prefixPathStr}`);
1819
1819
  }
1820
1820
  }
1821
1821
  list.prefixes.set(config.prefixPathStr, config.schema);
@@ -16,7 +16,7 @@ import { isNode, isNodeTrue, nextId, timeInSecond } from "socket-function/src/mi
16
16
  import { getPathStr2, getPathStr3 } from "../path";
17
17
  import { consistentHash } from "../misc/hash";
18
18
  import { setExternalHotReloading } from "socket-function/hot/HotReloadController";
19
- import { isPublic } from "../config";
19
+ import { devDebugbreak, isPublic } from "../config";
20
20
  import { SocketFunction } from "socket-function/SocketFunction";
21
21
  import { requiresNetworkTrustHook } from "../-d-trust/NetworkTrust2";
22
22
  import { getControllerNodeId, getControllerNodeIdList } from "../-g-core-values/NodeCapabilities";
@@ -281,6 +281,10 @@ async function getModuleFromSpecBase(
281
281
  deployPath = packagePath + "deploy.ts";
282
282
  }
283
283
 
284
+ if (path.startsWith("/root")) {
285
+ devDebugbreak();
286
+ }
287
+
284
288
  console.log(blue(`require(${JSON.stringify(path)})`));
285
289
 
286
290
  // Set functionSpec for the next synchronous evaluation
@@ -6,10 +6,11 @@ import { requiresNetworkTrustHook } from "../-d-trust/NetworkTrust2";
6
6
  import { cache } from "socket-function/src/caching";
7
7
  import { TimeGrouper } from "./TimeGrouper";
8
8
  import { runInfinitePollCallAtStart } from "socket-function/src/batching";
9
- import { timeInMinute } from "socket-function/src/misc";
9
+ import { throttleFunction, timeInMinute } from "socket-function/src/misc";
10
10
  import { formatNumber, formatPercent, formatTime } from "socket-function/src/formatting/format";
11
11
  import os from "os";
12
12
  import { isNode } from "typesafecss";
13
+ import { diskLog } from "../diagnostics/logs/diskLogger";
13
14
 
14
15
  // Undefined means we infer the column
15
16
  // Null means the column is removed
@@ -40,8 +41,12 @@ export function registerNodeMetadata(getter: ExtraMetadata) {
40
41
 
41
42
  let stateValues = cache((title: string, format: (value: number) => string): { (value: number): void } => {
42
43
  let timeGrouper = new TimeGrouper();
44
+ let logToDisk = throttleFunction(timeInMinute, (value: number) => {
45
+ diskLog(title, { value, formatted: format(value) });
46
+ });
43
47
  function onValue(value: number) {
44
48
  timeGrouper.onValueChanged(value);
49
+ void logToDisk(value);
45
50
  }
46
51
  registerNodeMetadata({
47
52
  columnName: title,
@@ -54,8 +59,12 @@ let stateValues = cache((title: string, format: (value: number) => string): { (v
54
59
  });
55
60
  let eventValues = cache((title: string, format: (value: number) => string): { (value: number): void } => {
56
61
  let timeGrouper = new TimeGrouper();
62
+ let logToDisk = throttleFunction(timeInMinute, (value: number) => {
63
+ diskLog(title, { value, formatted: format(value) });
64
+ });
57
65
  function onValue(value: number) {
58
66
  timeGrouper.onValueChanged(value);
67
+ void logToDisk(value);
59
68
  }
60
69
  registerNodeMetadata({
61
70
  columnName: title,
@@ -81,11 +90,11 @@ if (isNode()) {
81
90
  const free = os.freemem();
82
91
  const total = os.totalmem();
83
92
 
84
- let constrainedMemory = process.constrainedMemory();
85
-
86
93
  logNodeStateStats("System|Memory Free", x => formatNumber(x) + "B")(free);
87
94
  logNodeStateStats("System|Memory Free %", formatPercent)(free / total);
88
- if (constrainedMemory !== undefined) {
95
+
96
+ let constrainedMemory = process.constrainedMemory();
97
+ if (constrainedMemory !== undefined && constrainedMemory < 2 ** 48) {
89
98
  logNodeStateStats("System|Constrained Memory", x => formatNumber(x) + "B")(constrainedMemory);
90
99
  }
91
100
 
@@ -97,7 +106,8 @@ if (isNode()) {
97
106
  logNodeStateStats("System|CPU Count", formatNumber)(cpuCount);
98
107
 
99
108
  let load = os.loadavg();
100
- logNodeStateStats("System|Average Free Cores", formatPercent)((1 - load[0]) * os.cpus().length);
109
+ logNodeStateStats("System|Average Load", formatPercent)(load[0]);
110
+ logNodeStateStats("System|Average Free Cores", formatPercent)((os.cpus().length - load[0]));
101
111
 
102
112
  });
103
113
  }
@@ -54,7 +54,7 @@ type NodeData = {
54
54
  columns: ColumnsType;
55
55
  row: RowType;
56
56
  };
57
-
57
+ loadTime?: number;
58
58
  };
59
59
 
60
60
  module.hotreload = true;
@@ -81,6 +81,7 @@ export class NodeViewer extends qreact.Component {
81
81
  let ourIP = await controller.getCallerIP();
82
82
 
83
83
  await Promise.allSettled(nodeIds.map(async nodeId => {
84
+ let time = Date.now();
84
85
  let data: NodeData = { nodeId };
85
86
  try {
86
87
  data.table = await controller.getMiscInfo(nodeId);
@@ -100,6 +101,8 @@ export class NodeViewer extends qreact.Component {
100
101
  } catch (e: any) {
101
102
  data.apiError = "Error: " + e.stack;
102
103
  }
104
+ time = Date.now() - time;
105
+ data.loadTime = time;
103
106
  Querysub.commit(() => {
104
107
  this.state.nodes[nodeId] = atomicObjectWrite(data);
105
108
  });
@@ -182,7 +185,7 @@ export class NodeViewer extends qreact.Component {
182
185
  }
183
186
 
184
187
  let builtinGroups = {
185
- "Default": ["buttons", "devToolsURL", "nodeId", "ip", "uptime", "Heap", "All Memory", "Blocking Lag", "port", "threadId", "machineId", "apiError", "live_entryPoint"],
188
+ "Default": ["buttons", "devToolsURL", "nodeId", "ip", "uptime", "loadTime", "Heap", "All Memory", "Blocking Lag", "port", "threadId", "machineId", "apiError", "live_entryPoint"],
186
189
  };
187
190
  // Column => group
188
191
  let builtInGroupsLookup = new Map<string, string>();
@@ -263,7 +266,6 @@ export class NodeViewer extends qreact.Component {
263
266
  formatter: (obj) => {
264
267
  let str = String(obj);
265
268
  if (str.startsWith("http")) return formatValue(obj);
266
- https://noproxy.querysub.com:1111/?page=test&showingmanagement&managementpage=DiskLoggerPage&nodeId=b4d19fba5f79d48c3.b68f46ffaffad0636.querysub.com%3A41863&filter=%22%5C%22__nodeId%5C%22%3A%5C%22b654f522bf3a67c49.b68f46ffaffad0636.querysub.com%3A33473%5C%22%22
267
269
 
268
270
  return (
269
271
  <ATag values={[
@@ -277,6 +279,7 @@ export class NodeViewer extends qreact.Component {
277
279
  },
278
280
  },
279
281
  ip: {},
282
+ loadTime: { formatter: "timeSpan" },
280
283
  ...x.table?.columns,
281
284
  //capabilities: null,
282
285
  apiError: { formatter: "error" },
@@ -353,8 +356,12 @@ class NodeViewerControllerBase {
353
356
  await forwardPort({ internalPort: externalPort, externalPort: externalPort, });
354
357
 
355
358
  tlsServer.on("secureConnection", (socket) => {
356
- if (socket.remoteAddress !== callerIP) {
357
- console.error(`Rejecting connection from ${socket.remoteAddress}, expected ${callerIP}`);
359
+ let matchedIP = (
360
+ socket.remoteAddress === callerIP ||
361
+ callerIP === "127.0.0.1" && socket.remoteAddress === ourIP
362
+ );
363
+ if (!matchedIP) {
364
+ console.error(`Rejecting connection from ${socket.remoteAddress}, expected ${callerIP} ${callerIP === "127.0.0.1" && `or ${ourIP}` || ""}`);
358
365
  socket.end();
359
366
  return;
360
367
  }
@@ -375,7 +382,7 @@ class NodeViewerControllerBase {
375
382
  let ourDomain = ourIP.replaceAll(".", "-") + "." + getDomain();
376
383
  await setRecord("A", ourDomain, ourIP);
377
384
 
378
- console.log(`${ourDomain}:${finalPort} => ${baseNodeIPResolved}:${externalPort} => 127.0.0.1:${internalPort}, for ${callerIP}`);
385
+ console.log(`Inspect forward ${ourDomain}:${finalPort} => ${baseNodeIPResolved}:${externalPort} => 127.0.0.1:${internalPort}, for ${callerIP}`);
379
386
 
380
387
  return internalInspectURL.replace(`ws=127.0.0.1:${internalPort}`, `wss=${ourDomain}:${finalPort}`);
381
388
  }
@@ -182,7 +182,7 @@ export class DiskLoggerPage extends qreact.Component {
182
182
  if (!canHaveChildren(value)) {
183
183
  // Add to search as well
184
184
  if (filterURL.value.trim()) {
185
- filterURL.value += " | ";
185
+ filterURL.value += " & ";
186
186
  }
187
187
  filterURL.value += String(value);
188
188
  }
@@ -244,17 +244,17 @@ export class DiskLoggerPage extends qreact.Component {
244
244
  };
245
245
 
246
246
  table.columns["remaining"] = {
247
+ title: "Object",
247
248
  formatter(value, context) {
248
249
  return <ObjectDisplay
249
250
  value={context?.row}
250
- excludedFields={fullSelectedFields}
251
251
  onClickKey={path => addPath(path)}
252
252
  onClickValue={(path, value) => {
253
253
  addPath(path);
254
254
  if (!canHaveChildren(value)) {
255
255
  // Add to search as well
256
256
  if (filterURL.value.trim()) {
257
- filterURL.value += " | ";
257
+ filterURL.value += " & ";
258
258
  }
259
259
  filterURL.value += String(value);
260
260
  }
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { batchFunction, runInfinitePoll } from "socket-function/src/batching";
3
- import { timeInDay, timeInHour } from "socket-function/src/misc";
3
+ import { nextId, timeInDay, timeInHour } from "socket-function/src/misc";
4
4
  import { getStorageDir, getStorageFolder } from "../../fs";
5
5
  import fs from "fs";
6
6
  import { canHaveChildren } from "socket-function/src/types";
@@ -188,9 +188,11 @@ function safeCopyObject<T>(obj: T): T {
188
188
  return { errorCopying: e.messsage } as any;
189
189
  }
190
190
  }
191
+ let __baseThreadId = nextId();
191
192
  function packageLogObj(args: unknown[]): LogObj {
192
193
  let logObj: LogObj = {
193
194
  time: Date.now(),
195
+ __baseThreadId,
194
196
  };
195
197
  for (let part of globalContextParts) {
196
198
  Object.assign(logObj, safeCopyObject(part()));
@@ -76,7 +76,7 @@ function logResourcesNow() {
76
76
  }
77
77
 
78
78
  registerMeasureInfo(() => {
79
- return formatNumber(getUsedHeapSize()) + "B";
79
+ return formatNumber(getHeapSize()) + "B";
80
80
  });
81
81
 
82
82
  registerPeriodic(logResourcesNow);