querysub 0.126.0 → 0.127.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.126.0",
3
+ "version": "0.127.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",
@@ -1,11 +1,11 @@
1
1
  import { delay, runInfinitePoll } from "socket-function/src/batching";
2
2
  import { cache } from "socket-function/src/caching";
3
- import { magenta, red, yellow } from "socket-function/src/formatting/logColors";
3
+ import { blue, magenta, red, yellow } from "socket-function/src/formatting/logColors";
4
4
  import { sha256HashBuffer, timeInHour } from "socket-function/src/misc";
5
5
  import { measureFnc } from "socket-function/src/profiling/measure";
6
6
  import { getLowUint32, getShortNumber } from "../bits";
7
7
  import { registerDynamicResource } from "../diagnostics/trackResources";
8
- import { logErrors } from "../errors";
8
+ import { errorToUndefined, logErrors } from "../errors";
9
9
  import { getPathDepth, getPathFromStr, getPathIndex, trimPathStrToDepth } from "../path";
10
10
  import { rawSchema } from "../2-proxy/pathDatabaseProxyBase";
11
11
  import { ClientWatcher } from "../1-path-client/pathValueClientWatcher";
@@ -17,9 +17,11 @@ import debugbreak from "debugbreak";
17
17
  import { parseArgs } from "./PathFunctionHelpers";
18
18
  import { PERMISSIONS_FUNCTION_ID, getExportPath } from "./syncSchema";
19
19
  import { formatTime } from "socket-function/src/formatting/format";
20
- import { set_debug_getFunctionRunnerShards } from "../-g-core-values/NodeCapabilities";
20
+ import { getControllerNodeIdList, set_debug_getFunctionRunnerShards } from "../-g-core-values/NodeCapabilities";
21
21
  import { diskLog } from "../diagnostics/logs/diskLogger";
22
22
  import { FilterSelector, Filterable, doesMatch } from "../misc/filterable";
23
+ import { SocketFunction } from "socket-function/SocketFunction";
24
+ import { requiresNetworkTrustHook } from "../-d-trust/NetworkTrust2";
23
25
 
24
26
  export const functionSchema = rawSchema<{
25
27
  [domainName: string]: {
@@ -176,6 +178,7 @@ export class PathFunctionRunner {
176
178
  PermissionsChecker: PermissionsCheckType | undefined;
177
179
  filterSelector?: FilterSelector;
178
180
  }) {
181
+ SocketFunction.expose(FunctionPreloadController);
179
182
  debugFunctionRunnerShards.push({
180
183
  domainName: config.domainName,
181
184
  shardRange: config.shardRange,
@@ -655,4 +658,36 @@ export class PathFunctionRunner {
655
658
  });
656
659
  PathFunctionRunner.RUN_FINISH_COUNT++;
657
660
  }
658
- }
661
+ }
662
+
663
+ export async function preloadFunctions(specs: FunctionSpec[]) {
664
+ let nodeIds = await getControllerNodeIdList(FunctionPreloadController);
665
+ await Promise.allSettled(nodeIds.map(async nodeId => {
666
+ let controller = FunctionPreloadController.nodes[nodeId.nodeId];
667
+ console.log(blue(`Preloading functions on ${nodeId}`));
668
+ await errorToUndefined(controller.preloadFunctions(specs));
669
+ console.log(blue(`Finished preloading functions on ${nodeId}`));
670
+ }));
671
+ }
672
+
673
+ class FunctionPreloaderBase {
674
+ async preloadFunctions(specs: FunctionSpec[]) {
675
+ for (let spec of specs) {
676
+ await getModuleFromSpec(spec);
677
+ }
678
+ }
679
+ }
680
+
681
+ const FunctionPreloadController = SocketFunction.register(
682
+ "FunctionPreloader-c966a1a6-5d3f-4453-bd03-ae84b574ec00",
683
+ new FunctionPreloaderBase(),
684
+ () => ({
685
+ preloadFunctions: {},
686
+ }),
687
+ () => ({
688
+ hooks: [requiresNetworkTrustHook],
689
+ }),
690
+ {
691
+ noAutoExpose: true,
692
+ }
693
+ );
@@ -263,7 +263,6 @@ function getCallstackFiles(): string[] {
263
263
  async function getModuleFromSpecBase(
264
264
  spec: LoadFunctionSpec
265
265
  ): Promise<NodeJS.Module> {
266
- everLoadedRepos.add(spec.gitURL);
267
266
  let hotReloadPackagePath = "";
268
267
  let path = gitURLRefMappings.get(getSpecKey(spec));
269
268
  let deployPath = "";
@@ -459,37 +458,3 @@ async function executeCommand(command: string, args: string[], options?: {
459
458
  });
460
459
  });
461
460
  }
462
-
463
- // Helps us exclude non-function loaders (PathValueServer), which really shouldn't
464
- // be loading code anyways!
465
- let everLoadedRepos = new Set<string>();
466
-
467
- export async function preloadFunctions(specs: FunctionSpec[]) {
468
- let nodeIds = await getControllerNodeIdList(functionPreloadController);
469
- await Promise.all(nodeIds.map(async nodeId => {
470
- let controller = functionPreloadController.nodes[nodeId.nodeId];
471
- console.log(blue(`Preloading functions on ${nodeId}`));
472
- await errorToUndefined(controller.preloadFunctions(specs));
473
- console.log(blue(`Finished preloading functions on ${nodeId}`));
474
- }));
475
- }
476
-
477
- class FunctionPreloaderBase {
478
- async preloadFunctions(specs: FunctionSpec[]) {
479
- specs = specs.filter(spec => everLoadedRepos.has(spec.gitURL));
480
- for (let spec of specs) {
481
- await getModuleFromSpec(spec);
482
- }
483
- }
484
- }
485
-
486
- const functionPreloadController = SocketFunction.register(
487
- "FunctionPreloader-c966a1a6-5d3f-4453-bd03-ae84b574ec00",
488
- new FunctionPreloaderBase(),
489
- () => ({
490
- preloadFunctions: {},
491
- }),
492
- () => ({
493
- hooks: [requiresNetworkTrustHook],
494
- })
495
- );
@@ -1,6 +1,6 @@
1
1
  import "../inject";
2
2
 
3
- import { FunctionSpec } from "../3-path-functions/PathFunctionRunner";
3
+ import { FunctionSpec, preloadFunctions } from "../3-path-functions/PathFunctionRunner";
4
4
  import path from "path";
5
5
  import { getExportPath, getSchemaObject, PERMISSIONS_FUNCTION_ID } from "../3-path-functions/syncSchema";
6
6
  import { getModuleRelativePath } from "../3-path-functions/syncSchema";
@@ -15,17 +15,20 @@ import yargs from "yargs";
15
15
  import { isPublic } from "../config";
16
16
  import { deployBlock } from "./deployBlock";
17
17
  import { LOCAL_DOMAIN } from "../0-path-value-core/PathController";
18
- import { preloadFunctions } from "../3-path-functions/pathFunctionLoader";
19
18
  import { magenta } from "socket-function/src/formatting/logColors";
20
19
  import { getGitRef } from "./git";
21
20
  import { getGitURL } from "./git";
22
21
  import { setLiveDeployedHash } from "./deploySchema";
23
22
  import { proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
23
+ import debugbreak from "debugbreak";
24
+ import { timeInHour } from "socket-function/src/misc";
25
+ import { preloadUI } from "./edgeNodes";
24
26
 
25
- //todonext;
26
- // - deployonlycode / deployonlyui / deploynotifyforced
27
27
  let yargObj = yargs(process.argv)
28
28
  .option("domain", { type: "string", required: true, desc: "Domain to deploy to" })
29
+ .option("deployonlycode", { type: "boolean", desc: "Only deploy code, not ui" })
30
+ .option("deployonlyui", { type: "boolean", desc: "Only deploy ui, not code" })
31
+ .option("notifyrefreshdelay", { type: "number", default: timeInHour * 12, desc: "The time clients have to refresh their UI after a deploy." })
29
32
  .argv
30
33
  ;
31
34
 
@@ -116,26 +119,35 @@ export async function deployMain() {
116
119
 
117
120
  console.log();
118
121
  console.log();
119
- console.log(magenta(`Preloading ${currentFunctions.length} functions`));
120
- await preloadFunctions(currentFunctions);
122
+ console.log(magenta(`Preloading ${currentFunctions.length} functions & UI`));
123
+ await Promise.all([
124
+ preloadFunctions(currentFunctions),
125
+ preloadUI(gitRef),
126
+ ]);
121
127
 
122
128
  console.log();
123
129
  console.log();
124
130
  console.log(magenta(`Deploying ${currentFunctions.length} functions`));
125
131
 
132
+ let refreshThresholdTime = Date.now() + yargObj.notifyrefreshdelay;
133
+
134
+ debugbreak(2);
135
+ debugger;
126
136
  //todonext;
127
- // We SHOULD be able to wrap two of the commit functions in one
137
+ // VERIFY that the nested commit functions run correctly WITH the correct (atomic) flags
128
138
  await proxyWatcher.commitFunction({
129
139
  debugName: "setLiveDeployedHash",
130
140
  inlineNestedWatchers: true,
131
141
  watchFunction: () => {
132
- void setLiveDeployedHash(gitRef);
133
- void replaceFunctions({ domainName, functions: currentFunctions, });
142
+ if (!yargObj.deployonlycode) {
143
+ void setLiveDeployedHash({ hash: gitRef, refreshThresholdTime, });
144
+ }
145
+ if (!yargObj.deployonlyui) {
146
+ void replaceFunctions({ domainName, functions: currentFunctions, });
147
+ }
134
148
  },
135
149
  });
136
150
 
137
- await replaceFunctions({ domainName, functions: currentFunctions, });
138
-
139
151
  console.log(magenta(`FINISHED DEPLOY`));
140
152
  }
141
153
 
@@ -20,15 +20,21 @@ export const deploySchema = rawSchema<{
20
20
  export interface DeployedHash {
21
21
  hash: string;
22
22
  time: number;
23
+ refreshThresholdTime: number;
23
24
  }
24
25
 
25
26
 
26
- export function setLiveDeployedHash(hash: string) {
27
+ export function setLiveDeployedHash(config: {
28
+ hash: string;
29
+ refreshThresholdTime: number;
30
+ }) {
31
+ const { hash, refreshThresholdTime } = config;
27
32
  proxyWatcher.writeOnly({
28
33
  watchFunction: function writeCall() {
29
34
  let hashObj: DeployedHash = {
30
35
  hash,
31
36
  time: Date.now(),
37
+ refreshThresholdTime,
32
38
  };
33
39
  deploySchema()[getDomain()].deploy.live = hashObj;
34
40
  deploySchema()[getDomain()].deploy.history[nextId()] = hashObj;
@@ -16,6 +16,10 @@ import { getGitRef, getGitURL } from "./git";
16
16
  import { getModuleFromConfig } from "../3-path-functions/pathFunctionLoader";
17
17
  import path from "path";
18
18
  import debugbreak from "debugbreak";
19
+ import { requiresNetworkTrustHook } from "../-d-trust/NetworkTrust2";
20
+ import { getControllerNodeIdList } from "../-g-core-values/NodeCapabilities";
21
+ import { blue } from "socket-function/src/formatting/logColors";
22
+ import { errorToUndefined } from "../errors";
19
23
 
20
24
  const UPDATE_POLL_INTERVAL = timeInMinute;
21
25
  const DEAD_NODE_COUNT_THRESHOLD = 15;
@@ -51,6 +55,7 @@ export type EdgeNodesIndex = {
51
55
  edgeNodes: EdgeNodeConfig[];
52
56
  };
53
57
 
58
+
54
59
  // IMPORTANT! The EdgeNodeConfig MUST be immutable, otherwise every node has to read every EdgeNodeConfig
55
60
  // every poll, which is too much reading.
56
61
  export type EdgeNodeConfig = {
@@ -127,24 +132,6 @@ async function loadEntryPointsByHash(config: {
127
132
  FunctionId: "entryPoint",
128
133
  });
129
134
 
130
- //todonext;
131
- // 3) Setup the deployMain code to set the live hash
132
- // - Flags to decide what to set
133
- // - Inside of replaceFunctions, via passing a callback function to it. The nested commits SHOULD
134
- // just work?
135
- // - IMPORTANT! Step through the code, to ensure the nested flags are set correctly. If not...
136
- // update the proxy watcher to set them properly...
137
- // - With all the flags (that only do one or the other)
138
- // - Add preloading capability, so we can preload the hashes before we deploy
139
- // 3) Dynamically watch the live hash, and load new hashes (deploying their services)
140
- // - Test by pushing, deploying, and refreshing (we should prefer to latest service)
141
- // 3.1) If local, DO NOT watch the live hash
142
- // 5) Write the live hash to public backblaze, and have the client read it, and prefer that hash
143
- // 6) Pass the live hash to the client with the edge node
144
- // 7) Client live hash watch code + notify + refresh + flag to ignore the baked in live hash + edge node
145
- // - Test by pushing, deploying, and then we should immediately see a notify to refresh
146
-
147
-
148
135
  let depth = entryPaths[0].replaceAll("\\", "/").split("/").filter(x => x && x !== ".").length;
149
136
 
150
137
  let firstPath = path.resolve(module.filename);
@@ -167,6 +154,8 @@ async function loadEntryPointsByHash(config: {
167
154
  registeredEdgeNode = edgeNodeConfig;
168
155
 
169
156
  await edgeNodeStorage.set(getNextNodePath(), Buffer.from(JSON.stringify(edgeNodeConfig)));
157
+
158
+ SocketFunction.expose(EdgeNodeController);
170
159
  }
171
160
 
172
161
  export const getEdgeNodeConfigURL = lazy(async () => {
@@ -244,6 +233,46 @@ async function updateEdgeNodesFile() {
244
233
  await edgeNodeStorage.set("edge-nodes-index.json", Buffer.from(JSON.stringify(newEdgeNodeIndex)));
245
234
  }
246
235
 
236
+ export async function preloadUI(hash: string) {
237
+ let nodeIds = await getControllerNodeIdList(EdgeNodeController);
238
+ await Promise.allSettled(nodeIds.map(async nodeId => {
239
+ let controller = EdgeNodeController.nodes[nodeId.nodeId];
240
+ console.log(blue(`Preloading functions on ${nodeId}`));
241
+ await errorToUndefined(controller.preloadUI({ hash }));
242
+ console.log(blue(`Finished preloading functions on ${nodeId}`));
243
+ }));
244
+ }
245
+
246
+ class EdgeNodeControllerBase {
247
+ public async preloadUI(config: {
248
+ hash: string;
249
+ }) {
250
+ const { hash } = config;
251
+ if (!registeredEdgeNode || !canHaveChildren(registeredEdgeNode)) {
252
+ throw new Error(`Somehow we have no registered edge node. How did we even expose this controller?`);
253
+ }
254
+ await loadEntryPointsByHash({
255
+ host: registeredEdgeNode.host,
256
+ entryPaths: registeredEdgeNode.entryPaths,
257
+ hash,
258
+ });
259
+ }
260
+ }
261
+
262
+ const EdgeNodeController = SocketFunction.register(
263
+ "EdgeNodeController-e0110af9-f8c4-42f3-ad11-633f8e43abdd",
264
+ new EdgeNodeControllerBase(),
265
+ () => ({
266
+ preloadUI: {},
267
+ }),
268
+ () => ({
269
+ hooks: [requiresNetworkTrustHook],
270
+ }),
271
+ {
272
+ noAutoExpose: true,
273
+ }
274
+ );
275
+
247
276
  // async function main() {
248
277
  // await loadEntryPointsByHash({
249
278
  // host: "127-0-0-1.querysub.com:1111",
@@ -251,4 +280,26 @@ async function updateEdgeNodesFile() {
251
280
  // hash: "7b1eb4934d5bdfe6d0f7076049c4b7decad4e645",
252
281
  // });
253
282
  // }
254
- // main().catch(console.error).finally(() => process.exit());
283
+ // main().catch(console.error).finally(() => process.exit());
284
+
285
+
286
+
287
+ //todonext;
288
+ // 3) Setup the deployMain code to set the live hash
289
+ // - Flags to decide what to set
290
+ // - Inside of replaceFunctions, via passing a callback function to it. The nested commits SHOULD
291
+ // just work?
292
+ // - IMPORTANT! Step through the code, to ensure the nested flags are set correctly. If not...
293
+ // update the proxy watcher to set them properly...
294
+ // - With all the flags (that only do one or the other)
295
+ // - Add preloading capability, so we can preload the hashes before we deploy
296
+
297
+ // 3) Dynamically watch the live hash, and load new hashes (deploying their services)
298
+ // - Test by pushing, deploying, and refreshing (we should prefer to latest service)
299
+ // 3.1) If local, DO NOT watch the live hash
300
+
301
+ // 5) Write the live hash to public backblaze, and have the client read it, and prefer that hash
302
+ // 6) Pass the live hash to the client with the edge node
303
+ // 7) Client live hash watch code + notify + refresh + flag to ignore the baked in live hash + edge node
304
+ // - Test by pushing, deploying, and then we should immediately see a notify to refresh
305
+ // 8) VERIFY writing and permissions stillw orks
@@ -90,8 +90,6 @@ export class PermissionsCheck {
90
90
  }>();
91
91
  // IMPORTANT! This function USED TO BE a major hotspot for function evaluation, and so is heavily optimized.
92
92
  public checkPermissions(path: string): { permissionsPath: string; allowed: boolean; } {
93
- //todonext
94
- //return { permissionsPath: path, allowed: true };
95
93
  if (this.dead) throw new Error("PermissionsCheck MUST be used synchronously, after which it cannot be reused");
96
94
  if (PermissionsCheck.skippingChecks) return { permissionsPath: rootPathStr, allowed: true };
97
95