querysub 0.403.0 → 0.405.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/.cursorrules +2 -0
- package/bin/audit-imports.js +4 -0
- package/bin/join.js +1 -1
- package/package.json +7 -4
- package/spec.txt +77 -0
- package/src/-a-archives/archiveCache.ts +9 -4
- package/src/-a-archives/archivesBackBlaze.ts +1039 -1039
- package/src/-a-auth/certs.ts +0 -12
- package/src/-c-identity/IdentityController.ts +12 -3
- package/src/-f-node-discovery/NodeDiscovery.ts +32 -26
- package/src/-g-core-values/NodeCapabilities.ts +12 -2
- package/src/0-path-value-core/AuthorityLookup.ts +239 -0
- package/src/0-path-value-core/LockWatcher2.ts +150 -0
- package/src/0-path-value-core/PathRouter.ts +543 -0
- package/src/0-path-value-core/PathRouterRouteOverride.ts +72 -0
- package/src/0-path-value-core/PathRouterServerAuthoritySpec.tsx +73 -0
- package/src/0-path-value-core/PathValueCommitter.ts +222 -488
- package/src/0-path-value-core/PathValueController.ts +277 -239
- package/src/0-path-value-core/PathWatcher.ts +534 -0
- package/src/0-path-value-core/ShardPrefixes.ts +31 -0
- package/src/0-path-value-core/ValidStateComputer.ts +303 -0
- package/src/0-path-value-core/archiveLocks/ArchiveLocks.ts +1 -1
- package/src/0-path-value-core/archiveLocks/ArchiveLocks2.ts +80 -44
- package/src/0-path-value-core/archiveLocks/archiveSnapshots.ts +13 -16
- package/src/0-path-value-core/auditLogs.ts +2 -0
- package/src/0-path-value-core/hackedPackedPathParentFiltering.ts +97 -0
- package/src/0-path-value-core/pathValueArchives.ts +491 -492
- package/src/0-path-value-core/pathValueCore.ts +195 -1496
- package/src/0-path-value-core/startupAuthority.ts +74 -0
- package/src/1-path-client/RemoteWatcher.ts +90 -82
- package/src/1-path-client/pathValueClientWatcher.ts +808 -815
- package/src/2-proxy/PathValueProxyWatcher.ts +10 -8
- package/src/2-proxy/archiveMoveHarness.ts +182 -214
- package/src/2-proxy/garbageCollection.ts +9 -8
- package/src/2-proxy/schema2.ts +21 -1
- package/src/3-path-functions/PathFunctionHelpers.ts +206 -180
- package/src/3-path-functions/PathFunctionRunner.ts +943 -766
- package/src/3-path-functions/PathFunctionRunnerMain.ts +5 -3
- package/src/3-path-functions/pathFunctionLoader.ts +2 -2
- package/src/3-path-functions/syncSchema.ts +596 -521
- package/src/4-deploy/deployFunctions.ts +19 -4
- package/src/4-deploy/deployGetFunctionsInner.ts +8 -2
- package/src/4-deploy/deployMain.ts +51 -68
- package/src/4-deploy/edgeClientWatcher.tsx +6 -1
- package/src/4-deploy/edgeNodes.ts +2 -2
- package/src/4-dom/qreact.tsx +2 -4
- package/src/4-dom/qreactTest.tsx +7 -13
- package/src/4-querysub/Querysub.ts +21 -8
- package/src/4-querysub/QuerysubController.ts +45 -29
- package/src/4-querysub/permissions.ts +2 -2
- package/src/4-querysub/querysubPrediction.ts +80 -70
- package/src/4-querysub/schemaHelpers.ts +5 -1
- package/src/5-diagnostics/GenericFormat.tsx +14 -9
- package/src/archiveapps/archiveGCEntry.tsx +9 -2
- package/src/archiveapps/archiveJoinEntry.ts +96 -84
- package/src/bits.ts +19 -0
- package/src/config.ts +21 -3
- package/src/config2.ts +23 -48
- package/src/deployManager/components/DeployPage.tsx +7 -3
- package/src/deployManager/machineSchema.ts +4 -1
- package/src/diagnostics/ActionsHistory.ts +3 -8
- package/src/diagnostics/AuditLogPage.tsx +2 -3
- package/src/diagnostics/FunctionCallInfo.tsx +141 -0
- package/src/diagnostics/FunctionCallInfoState.ts +162 -0
- package/src/diagnostics/MachineThreadInfo.tsx +1 -1
- package/src/diagnostics/NodeViewer.tsx +37 -48
- package/src/diagnostics/SyncTestPage.tsx +241 -0
- package/src/diagnostics/auditImportViolations.ts +185 -0
- package/src/diagnostics/listenOnDebugger.ts +3 -3
- package/src/diagnostics/logs/IndexedLogs/BufferUnitSet.ts +10 -4
- package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +2 -2
- package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +24 -22
- package/src/diagnostics/logs/IndexedLogs/moveIndexLogsToPublic.ts +1 -1
- package/src/diagnostics/logs/diskLogGlobalContext.ts +1 -0
- package/src/diagnostics/logs/errorNotifications2/logWatcher.ts +1 -3
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleEntryEditor.tsx +34 -16
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleEntryReadMode.tsx +4 -6
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleInstanceTableView.tsx +36 -5
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePage.tsx +19 -5
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleRenderer.tsx +15 -7
- package/src/diagnostics/logs/lifeCycleAnalysis/NestedLifeCycleInfo.tsx +28 -106
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleMatching.ts +2 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleMisc.ts +0 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleSearch.tsx +18 -7
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +3 -0
- package/src/diagnostics/managementPages.tsx +10 -3
- package/src/diagnostics/misc-pages/ArchiveViewer.tsx +20 -26
- package/src/diagnostics/misc-pages/ArchiveViewerTree.tsx +6 -4
- package/src/diagnostics/misc-pages/ComponentSyncStats.tsx +2 -2
- package/src/diagnostics/misc-pages/LocalWatchViewer.tsx +7 -9
- package/src/diagnostics/misc-pages/SnapshotViewer.tsx +23 -12
- package/src/diagnostics/misc-pages/archiveViewerShared.tsx +1 -1
- package/src/diagnostics/pathAuditer.ts +486 -0
- package/src/diagnostics/pathAuditerCallback.ts +20 -0
- package/src/diagnostics/watchdog.ts +8 -1
- package/src/library-components/URLParam.ts +1 -1
- package/src/misc/hash.ts +1 -0
- package/src/path.ts +21 -7
- package/src/server.ts +54 -47
- package/src/user-implementation/loginEmail.tsx +1 -1
- package/tempnotes.txt +65 -0
- package/test.ts +298 -97
- package/src/0-path-value-core/NodePathAuthorities.ts +0 -1057
- package/src/0-path-value-core/PathController.ts +0 -1
- package/src/5-diagnostics/diskValueAudit.ts +0 -218
- package/src/5-diagnostics/memoryValueAudit.ts +0 -438
- package/src/archiveapps/archiveMergeEntry.tsx +0 -48
- package/src/archiveapps/lockTest.ts +0 -127
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import { magenta } from "socket-function/src/formatting/logColors";
|
|
2
2
|
import { FunctionSpec, preloadFunctions } from "../3-path-functions/PathFunctionRunner";
|
|
3
3
|
import { Querysub } from "../4-querysub/QuerysubController";
|
|
4
|
-
import { errorify } from "../errors";
|
|
4
|
+
import { errorify, timeoutToError } from "../errors";
|
|
5
5
|
import { runPromise } from "../functional/runCommand";
|
|
6
6
|
import path from "path";
|
|
7
7
|
import { preloadUI } from "./edgeNodes";
|
|
8
8
|
import { proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
|
|
9
9
|
import { replaceFunctions } from "../3-path-functions/PathFunctionHelpers";
|
|
10
10
|
import { setLiveDeployedHash } from "./deploySchema";
|
|
11
|
+
import { timeInMinute } from "socket-function/src/misc";
|
|
12
|
+
import { setShardPrefixes } from "../0-path-value-core/ShardPrefixes";
|
|
11
13
|
|
|
12
|
-
export async function deployGetFunctions(): Promise<
|
|
14
|
+
export async function deployGetFunctions(): Promise<{
|
|
15
|
+
functionSpecs: FunctionSpec[];
|
|
16
|
+
prefixes: string[];
|
|
17
|
+
}> {
|
|
13
18
|
let innerPath = path.resolve(__dirname + "/deployGetFunctionsInner.ts").replaceAll("\\", "/");
|
|
14
|
-
let result = await runPromise(`yarn typenode ${innerPath}`);
|
|
19
|
+
let result = await timeoutToError(timeInMinute * 7, runPromise(`yarn typenode ${innerPath}`), () => new Error("deployGetFunctions timed out"));
|
|
15
20
|
let functionSpecs: FunctionSpec[] = [];
|
|
21
|
+
let prefixes: string[] = [];
|
|
16
22
|
for (let line of result.split("\n")) {
|
|
17
23
|
if (line.startsWith("ERROR:")) {
|
|
18
24
|
throw errorify(line.slice("ERROR:".length));
|
|
@@ -21,8 +27,11 @@ export async function deployGetFunctions(): Promise<FunctionSpec[]> {
|
|
|
21
27
|
let spec = JSON.parse(line.slice("FUNCTION_SPEC:".length));
|
|
22
28
|
functionSpecs.push(spec);
|
|
23
29
|
}
|
|
30
|
+
if (line.startsWith("PREFIX:")) {
|
|
31
|
+
prefixes.push(line.slice("PREFIX:".length));
|
|
32
|
+
}
|
|
24
33
|
}
|
|
25
|
-
return functionSpecs;
|
|
34
|
+
return { functionSpecs, prefixes };
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
export type DeployProgress = {
|
|
@@ -31,6 +40,7 @@ export type DeployProgress = {
|
|
|
31
40
|
|
|
32
41
|
export async function deployFunctions(config: {
|
|
33
42
|
functionSpecs: FunctionSpec[];
|
|
43
|
+
prefixes: string[];
|
|
34
44
|
notifyRefreshDelay: number;
|
|
35
45
|
deployOnlyCode?: boolean;
|
|
36
46
|
deployOnlyUI?: boolean;
|
|
@@ -75,5 +85,10 @@ export async function deployFunctions(config: {
|
|
|
75
85
|
});
|
|
76
86
|
config.progress?.({ section: "Deploying Functions", progress: 1 });
|
|
77
87
|
|
|
88
|
+
config.progress?.({ section: "Deploying Prefixes", progress: 0 });
|
|
89
|
+
// NOTE: This is only used by the path value server, and if it's out of sync with the code, it doesn't really matter. The path value server only uses the prefixes on startup, and it only needs prefixes at least newer than the ones last used by the gc code. And the gc code gets it's prefixes from the same source, so... We can technically write this anywhere we want, or just randomly not write it, and it would be fine (If we never update it, then the client accesses will get more and more inefficient and start accessing every single path value server, but it won't break anything).
|
|
90
|
+
await setShardPrefixes(config.prefixes);
|
|
91
|
+
config.progress?.({ section: "Deploying Prefixes", progress: 1 });
|
|
92
|
+
|
|
78
93
|
console.log(magenta(`FINISHED DEPLOY (${gitRef})`));
|
|
79
94
|
}
|
|
@@ -3,12 +3,13 @@ import { deployBlock } from "./deployBlock";
|
|
|
3
3
|
import { SocketFunction } from "socket-function/SocketFunction";
|
|
4
4
|
import { getThreadKeyCert } from "../-a-auth/certs";
|
|
5
5
|
import { getDomain, isPublic } from "../config";
|
|
6
|
-
import {
|
|
7
|
-
import { getSchemaObject, getModuleRelativePath, PERMISSIONS_FUNCTION_ID, getExportPath } from "../3-path-functions/syncSchema";
|
|
6
|
+
import { getSchemaObject, getModuleRelativePath, PERMISSIONS_FUNCTION_ID, getExportPath, getPrefixesForDeploy } from "../3-path-functions/syncSchema";
|
|
8
7
|
import { getPathStr2 } from "../path";
|
|
9
8
|
import { FunctionSpec } from "../3-path-functions/PathFunctionRunner";
|
|
10
9
|
import fs from "fs";
|
|
11
10
|
import { getGitRefLive, getGitURLLive } from "./git";
|
|
11
|
+
import { LOCAL_DOMAIN } from "../0-path-value-core/PathRouter";
|
|
12
|
+
import { delay } from "socket-function/src/batching";
|
|
12
13
|
|
|
13
14
|
async function main() {
|
|
14
15
|
let domainName = getDomain();
|
|
@@ -24,6 +25,7 @@ async function main() {
|
|
|
24
25
|
let folderRoot = path.resolve(".").replaceAll("\\", "/");
|
|
25
26
|
const deployPath = path.resolve("./deploy.ts");
|
|
26
27
|
await import(deployPath);
|
|
28
|
+
await delay(1);
|
|
27
29
|
|
|
28
30
|
const querysubRoot = path.resolve(__dirname + "/../").replaceAll("\\", "/");
|
|
29
31
|
|
|
@@ -91,6 +93,10 @@ async function main() {
|
|
|
91
93
|
console.log(`FUNCTION_SPEC:${JSON.stringify(spec)}`);
|
|
92
94
|
}
|
|
93
95
|
}
|
|
96
|
+
|
|
97
|
+
for (let prefix of getPrefixesForDeploy()) {
|
|
98
|
+
console.log(`PREFIX:${prefix}`);
|
|
99
|
+
}
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
main().catch(e => console.error("ERROR:" + String(e?.stack || e).replaceAll("\n", "\\n"))).finally(() => process.exit(0));
|
|
@@ -1,69 +1,52 @@
|
|
|
1
|
-
import "../inject";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
if (yargObj.dryrun) {
|
|
54
|
-
console.log(red("Dry run, not actually deploying"));
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
await deployFunctions({
|
|
59
|
-
functionSpecs: currentFunctions,
|
|
60
|
-
notifyRefreshDelay: yargObj.notifyrefreshdelay,
|
|
61
|
-
deployOnlyCode: yargObj.deployonlycode,
|
|
62
|
-
deployOnlyUI: yargObj.deployonlyui,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
await shutdown();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
1
|
+
import "../inject";
|
|
2
|
+
|
|
3
|
+
import { setIsDeploy } from "./deployCheck";
|
|
4
|
+
|
|
5
|
+
import yargs from "yargs";
|
|
6
|
+
import { blue, red } from "socket-function/src/formatting/logColors";
|
|
7
|
+
import { timeInHour } from "socket-function/src/misc";
|
|
8
|
+
import { shutdown } from "../diagnostics/periodic";
|
|
9
|
+
import { deployFunctions, deployGetFunctions } from "./deployFunctions";
|
|
10
|
+
import { Querysub } from "../4-querysub/QuerysubController";
|
|
11
|
+
import { setShardPrefixes } from "../0-path-value-core/ShardPrefixes";
|
|
12
|
+
|
|
13
|
+
let yargObj = yargs(process.argv)
|
|
14
|
+
.option("deployonlycode", { type: "boolean", desc: "Only deploy code, not ui" })
|
|
15
|
+
.option("deployonlyui", { type: "boolean", desc: "Only deploy ui, not code" })
|
|
16
|
+
.option("notifyrefreshdelay", { type: "number", default: timeInHour * 12, desc: "The time clients have to refresh their UI after a deploy." })
|
|
17
|
+
.option("dryrun", { type: "boolean", desc: "Dry run, don't actually deploy" })
|
|
18
|
+
.argv
|
|
19
|
+
;
|
|
20
|
+
|
|
21
|
+
setIsDeploy();
|
|
22
|
+
|
|
23
|
+
export async function deployMain() {
|
|
24
|
+
//SocketFunction.logMessages = true;
|
|
25
|
+
//quietCoreMode();
|
|
26
|
+
//ClientWatcher.DEBUG_READS = true;
|
|
27
|
+
//ClientWatcher.DEBUG_WRITES = true;
|
|
28
|
+
|
|
29
|
+
await Querysub.hostService("deployMain");
|
|
30
|
+
|
|
31
|
+
const { functionSpecs, prefixes } = await deployGetFunctions();
|
|
32
|
+
for (let fnc of functionSpecs) {
|
|
33
|
+
console.log(blue(`${fnc.DomainName}.${fnc.ModuleId}.${fnc.FunctionId}`));
|
|
34
|
+
}
|
|
35
|
+
if (yargObj.dryrun) {
|
|
36
|
+
console.log(red("Dry run, not actually deploying"));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
await deployFunctions({
|
|
41
|
+
functionSpecs: functionSpecs,
|
|
42
|
+
notifyRefreshDelay: yargObj.notifyrefreshdelay,
|
|
43
|
+
deployOnlyCode: yargObj.deployonlycode,
|
|
44
|
+
deployOnlyUI: yargObj.deployonlyui,
|
|
45
|
+
prefixes: prefixes,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
await shutdown();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
69
52
|
deployMain().catch(e => console.error(e)).finally(() => process.exit());
|
|
@@ -6,7 +6,6 @@ import { throttleFunction, timeInMinute, timeInSecond } from "socket-function/sr
|
|
|
6
6
|
import { isNode } from "typesafecss";
|
|
7
7
|
import { logErrors, timeoutToError } from "../errors";
|
|
8
8
|
import { blue, red, yellow } from "socket-function/src/formatting/logColors";
|
|
9
|
-
import { showModal } from "../5-diagnostics/Modal";
|
|
10
9
|
import { qreact } from "../4-dom/qreact";
|
|
11
10
|
import { liveHashOverrideURL } from "./edgeBootstrap";
|
|
12
11
|
import { css } from "typesafecss";
|
|
@@ -17,6 +16,11 @@ import { lazy } from "socket-function/src/caching";
|
|
|
17
16
|
import { Button } from "../library-components/Button";
|
|
18
17
|
import { updateRootDiscoveryLocation } from "../-f-node-discovery/NodeDiscovery";
|
|
19
18
|
|
|
19
|
+
setImmediate(() => {
|
|
20
|
+
// Modal
|
|
21
|
+
import("../5-diagnostics/Modal");
|
|
22
|
+
});
|
|
23
|
+
|
|
20
24
|
const SWITCH_SERVER_TIMEOUT = timeInSecond * 15;
|
|
21
25
|
const MAX_DISPLAY_INTERVAL = timeInMinute * 5;
|
|
22
26
|
const FINAL_DELAY = timeInSecond * 30;
|
|
@@ -78,6 +82,7 @@ function onLiveHashChange(liveHash: string, refreshThresholdTime: number) {
|
|
|
78
82
|
|
|
79
83
|
// Start notification loop
|
|
80
84
|
void (async () => {
|
|
85
|
+
const { showModal } = await import("../5-diagnostics/Modal");
|
|
81
86
|
// Show notifications at intervals
|
|
82
87
|
for (let delayTime of delays) {
|
|
83
88
|
await delayTime;
|
|
@@ -116,7 +116,7 @@ export async function registerEdgeNode(config: {
|
|
|
116
116
|
|
|
117
117
|
await waitForFirstTimeSync();
|
|
118
118
|
|
|
119
|
-
if (
|
|
119
|
+
if (isPublic() && !noSyncing()) {
|
|
120
120
|
let loadedHash = "";
|
|
121
121
|
let firstLoad = new PromiseObj<void>();
|
|
122
122
|
Querysub.createWatcher(() => {
|
|
@@ -342,7 +342,7 @@ class EdgeNodeControllerBase {
|
|
|
342
342
|
public async preloadUI(config: {
|
|
343
343
|
hash: string;
|
|
344
344
|
}) {
|
|
345
|
-
if (
|
|
345
|
+
if (!isPublic()) return;
|
|
346
346
|
const { hash } = config;
|
|
347
347
|
if (!registeredEdgeNode || !canHaveChildren(registeredEdgeNode)) {
|
|
348
348
|
throw new Error(`Somehow we have no registered edge node. How did we even expose this controller?`);
|
package/src/4-dom/qreact.tsx
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type preact from "preact";
|
|
2
2
|
import { compareArray, isNode, sort, timeInSecond } from "socket-function/src/misc";
|
|
3
|
-
import { isDeploy } from "../4-deploy/deployCheck";
|
|
4
|
-
import { PermissionsCheck } from "../4-querysub/permissions";
|
|
5
3
|
import { ClientWatcher, clientWatcher } from "../1-path-client/pathValueClientWatcher";
|
|
6
|
-
import { LOCAL_DOMAIN } from "../0-path-value-core/PathController";
|
|
7
4
|
import { rawSchema } from "../2-proxy/pathDatabaseProxyBase";
|
|
8
5
|
import { SyncWatcher, atomic, atomicObjectWrite, atomicObjectWriteNoFreeze, doProxyOptions, doUnatomicWrites, proxyWatcher, registerSchemaPrefix, unregisterSchemaPrefix } from "../2-proxy/PathValueProxyWatcher";
|
|
9
6
|
import { createPathValueProxy, getProxyPath, isValueProxy, isValueProxy2 } from "../2-proxy/pathValueProxy";
|
|
@@ -2798,4 +2795,5 @@ function triggerGlobalAfterRenderWatch(component: QRenderClass) {
|
|
|
2798
2795
|
// NOTE: Import Querysub at the end, so we can export qreact before we require it. That way Querysub
|
|
2799
2796
|
// can statically access qreact.
|
|
2800
2797
|
import { Querysub } from "../4-querysub/Querysub";
|
|
2801
|
-
import { logDisk } from "../diagnostics/logs/diskLogger";
|
|
2798
|
+
import { logDisk } from "../diagnostics/logs/diskLogger"; import { LOCAL_DOMAIN } from "../0-path-value-core/PathRouter";
|
|
2799
|
+
|
package/src/4-dom/qreactTest.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { disableMeasurements, measureBlock, measureCode
|
|
1
|
+
import { disableMeasurements, measureBlock, measureCode } from "socket-function/src/profiling/measure";
|
|
2
2
|
disableMeasurements();
|
|
3
3
|
|
|
4
4
|
import preact from "preact";
|
|
5
|
-
import { isNode, list
|
|
5
|
+
import { isNode, list } from "socket-function/src/misc";
|
|
6
6
|
import { ClientWatcher, clientWatcher } from "../1-path-client/pathValueClientWatcher";
|
|
7
7
|
import { isDeploy } from "../4-deploy/deployCheck";
|
|
8
8
|
import { logErrors } from "../errors";
|
|
@@ -10,18 +10,12 @@ import { watchFilesAndTriggerHotReloading } from "socket-function/hot/HotReloadC
|
|
|
10
10
|
import { qreact } from "./qreact";
|
|
11
11
|
import { Querysub } from "../4-querysub/QuerysubController";
|
|
12
12
|
import { PermissionsCheck } from "../4-querysub/permissions";
|
|
13
|
-
import {
|
|
14
|
-
import { setFlag } from "socket-function/require/compileFlags";
|
|
15
|
-
import { rawSchema } from "../2-proxy/pathDatabaseProxyBase";
|
|
16
|
-
import { LOCAL_DOMAIN } from "../0-path-value-core/PathController";
|
|
17
|
-
import { batchFunction, delay } from "socket-function/src/batching";
|
|
13
|
+
import { delay } from "socket-function/src/batching";
|
|
18
14
|
import { formatTime } from "socket-function/src/formatting/format";
|
|
19
|
-
import { pathValueAuthority2 } from "../0-path-value-core/NodePathAuthorities";
|
|
20
|
-
import { schema } from "../3-path-functions/tests/rejectTest";
|
|
21
|
-
import { pathValueSerializer } from "../-h-path-value-serialize/PathValueSerializer";
|
|
22
15
|
import { getPathFromStr } from "../path";
|
|
23
|
-
import { PromiseObj } from "../promise";
|
|
24
16
|
import { css } from "./css";
|
|
17
|
+
import { isSuperUserPERMISSIONS } from "../user-implementation/userData";
|
|
18
|
+
import { authorityLookup } from "../0-path-value-core/AuthorityLookup";
|
|
25
19
|
|
|
26
20
|
|
|
27
21
|
|
|
@@ -264,7 +258,7 @@ async function browserMain() {
|
|
|
264
258
|
|
|
265
259
|
//*
|
|
266
260
|
await new Promise(resolve => setTimeout(resolve, 0));
|
|
267
|
-
await
|
|
261
|
+
await authorityLookup.startSyncing();
|
|
268
262
|
|
|
269
263
|
let benchmarkComponents = [
|
|
270
264
|
// ONLY run with devtools closed AND disableMeasurements (at the top of the file)! Otherwise the timings will be wrong.
|
|
@@ -334,7 +328,7 @@ let { data, functions } = Querysub.createSchema<{
|
|
|
334
328
|
moduleId: "qreactTest",
|
|
335
329
|
functionMetadata: {},
|
|
336
330
|
permissions: {
|
|
337
|
-
PERMISSIONS:
|
|
331
|
+
PERMISSIONS: isSuperUserPERMISSIONS
|
|
338
332
|
}
|
|
339
333
|
});
|
|
340
334
|
|
|
@@ -18,8 +18,7 @@ import { RequireController, setRequireBootRequire } from "socket-function/requir
|
|
|
18
18
|
import { cache, cacheLimited, lazy } from "socket-function/src/caching";
|
|
19
19
|
import { getOwnMachineId, getOwnThreadId, getThreadKeyCert, verifyMachineIdForPublicKey } from "../-a-auth/certs";
|
|
20
20
|
import { getHostedIP, getSNICerts, publishMachineARecords } from "../-e-certs/EdgeCertController";
|
|
21
|
-
import {
|
|
22
|
-
import { debugCoreMode, registerGetCompressNetwork, encodeParentFilter, authorityStorage } from "../0-path-value-core/pathValueCore";
|
|
21
|
+
import { debugCoreMode, registerGetCompressNetwork, authorityStorage } from "../0-path-value-core/pathValueCore";
|
|
23
22
|
import { clientWatcher, ClientWatcher } from "../1-path-client/pathValueClientWatcher";
|
|
24
23
|
import { SyncWatcher, proxyWatcher, specialObjectWriteValue, isSynced, PathValueProxyWatcher, atomic, doAtomicWrites, noAtomicSchema, undeleteFromLookup, registerSchemaPrefix, WatcherOptions, doProxyOptions } from "../2-proxy/PathValueProxyWatcher";
|
|
25
24
|
import { isInProxyDatabase, rawSchema } from "../2-proxy/pathDatabaseProxyBase";
|
|
@@ -178,7 +177,6 @@ export class Querysub {
|
|
|
178
177
|
public static WILDCARD_NUM = "*" as any as number;
|
|
179
178
|
public static createLocalSchema = createLocalSchema;
|
|
180
179
|
public static flushDelayedFunctions = () => flushDelayedFunctions();
|
|
181
|
-
public static LOCAL_DOMAIN = LOCAL_DOMAIN;
|
|
182
180
|
public static DEBUG_CALLS = false;
|
|
183
181
|
public static DEBUG_PREDICTIONS = false;
|
|
184
182
|
public static PREDICT_CALLS = true;
|
|
@@ -201,6 +199,11 @@ export class Querysub {
|
|
|
201
199
|
*/
|
|
202
200
|
public static MAX_FUTURE_CALL_TIME = 10_000;
|
|
203
201
|
|
|
202
|
+
/** NOTE: Is required for the function runner to work. Eventually, we should allow you to request the full history on just specific paths.
|
|
203
|
+
* - It's not *actually* the full history, As the underlying path value storage will delete values that are past the golden threshold anyways.
|
|
204
|
+
*/
|
|
205
|
+
public static SEND_FULL_HISTORY_ON_INITIAL_SYNC = false;
|
|
206
|
+
|
|
204
207
|
|
|
205
208
|
public static COMPRESS_NETWORK = true;
|
|
206
209
|
|
|
@@ -210,6 +213,7 @@ export class Querysub {
|
|
|
210
213
|
|
|
211
214
|
public static getCallTime = getSyncedTime;
|
|
212
215
|
public static getFunctionCallTime = getSyncedTime;
|
|
216
|
+
// NOTE: This is just an ID inside of a call that will be unique. It's not the call ID that the function uses when it's running. That's something that's different, and that's defined in PathFunctionHelpers
|
|
213
217
|
public static getCallId = () => Querysub.getCallerMachineId() + "_" + Querysub.getCallTime();
|
|
214
218
|
// Returns a random value between 0 and 1. The value depends on the callId, and index (being identical for
|
|
215
219
|
// the same callid and index).
|
|
@@ -284,7 +288,7 @@ export class Querysub {
|
|
|
284
288
|
await measureBlock(async () => {
|
|
285
289
|
await waitForFirstTimeSync();
|
|
286
290
|
}, "waitForFirstTimeSync");
|
|
287
|
-
await
|
|
291
|
+
await authorityLookup.startSyncing();
|
|
288
292
|
}
|
|
289
293
|
|
|
290
294
|
public static createWatcher(watcher: (obj: SyncWatcher) => void, options?: Partial<WatcherOptions<unknown>>): {
|
|
@@ -788,6 +792,8 @@ export class Querysub {
|
|
|
788
792
|
|
|
789
793
|
|
|
790
794
|
RequireController.injectHTMLBeforeStartup(async () => {
|
|
795
|
+
const { getEdgeBootstrapScript } = await import("../4-deploy/edgeBootstrap");
|
|
796
|
+
const { getEdgeNodeConfigURL } = await import("../4-deploy/edgeNodes");
|
|
791
797
|
let edgeBootstrapFile = await getEdgeBootstrapScript({
|
|
792
798
|
edgeNodeConfigURL: await getEdgeNodeConfigURL(),
|
|
793
799
|
});
|
|
@@ -830,6 +836,7 @@ export class Querysub {
|
|
|
830
836
|
let { ip, ipDomain } = await publishMachineARecords();
|
|
831
837
|
|
|
832
838
|
if (!isBootstrapOnly()) {
|
|
839
|
+
const { registerEdgeNode } = await import("../4-deploy/edgeNodes");
|
|
833
840
|
await registerEdgeNode({
|
|
834
841
|
host: ipDomain + ":" + port,
|
|
835
842
|
entryPaths,
|
|
@@ -1050,9 +1057,14 @@ export class Querysub {
|
|
|
1050
1057
|
* (otherwise likely does filtering serverside, which is still somewhat efficient).
|
|
1051
1058
|
*/
|
|
1052
1059
|
startFraction?: number;
|
|
1053
|
-
/** Value between 0 and 1
|
|
1060
|
+
/** Value between 0 and 1.
|
|
1061
|
+
* BOTH start and end must be provided, otherwise if only one is provided we will ignore it.
|
|
1062
|
+
*/
|
|
1054
1063
|
endFraction?: number;
|
|
1055
1064
|
}): (keyof T)[] {
|
|
1065
|
+
if (!isNode()) {
|
|
1066
|
+
console.warn(`keys() is unlikely to work clientside. If we need to emulate how the server does the filtering, we should add an additional function to help with that. But there are issues with how query sub proxies watches, which make proxying partial key watches too difficult. ALSO, this is mostly for watching very large data streams with dynamic sharding (in FunctionRunner), and so shouldn't be needed clientside (the application can handle filtering at a schema level if it really wants something similar to this).`);
|
|
1067
|
+
}
|
|
1056
1068
|
let { startFraction, endFraction } = config || {};
|
|
1057
1069
|
if (startFraction === undefined || endFraction === undefined) {
|
|
1058
1070
|
return Object.keys(obj);
|
|
@@ -1284,6 +1296,7 @@ setImmediate(() => {
|
|
|
1284
1296
|
setImmediate(async () => {
|
|
1285
1297
|
// Import, so it registers addStatPeriodic
|
|
1286
1298
|
await import("../5-diagnostics/nodeMetadata");
|
|
1299
|
+
await import("../diagnostics/pathAuditer");
|
|
1287
1300
|
});
|
|
1288
1301
|
|
|
1289
1302
|
setImmediate(async () => {
|
|
@@ -1300,10 +1313,7 @@ registerGetCompressNetwork(() => Querysub.COMPRESS_NETWORK);
|
|
|
1300
1313
|
import "../diagnostics/watchdog";
|
|
1301
1314
|
import "../diagnostics/trackResources";
|
|
1302
1315
|
import "../diagnostics/benchmark";
|
|
1303
|
-
import { getEdgeNodeConfigURL, registerEdgeNode } from "../4-deploy/edgeNodes";
|
|
1304
|
-
import { getEdgeBootstrapScript } from "../4-deploy/edgeBootstrap";
|
|
1305
1316
|
import { formatNumber, formatTime } from "socket-function/src/formatting/format";
|
|
1306
|
-
import { css } from "../4-dom/css";
|
|
1307
1317
|
import { getCountPerPaint } from "../functional/onNextPaint";
|
|
1308
1318
|
import { addEpsilons } from "../bits";
|
|
1309
1319
|
import { blue, magenta } from "socket-function/src/formatting/logColors";
|
|
@@ -1312,4 +1322,7 @@ import { getRecords, setRecord } from "../-b-authorities/dnsAuthority";
|
|
|
1312
1322
|
import { testTCPIsListening } from "socket-function/src/networking";
|
|
1313
1323
|
import { getNodeId, getNodeIdLocation } from "socket-function/src/nodeCache";
|
|
1314
1324
|
import { onAllPredictionsFinished } from "../-0-hooks/hooks";
|
|
1325
|
+
import { LOCAL_DOMAIN } from "../0-path-value-core/PathRouter";
|
|
1326
|
+
import { authorityLookup } from "../0-path-value-core/AuthorityLookup";
|
|
1327
|
+
import { encodeParentFilter } from "../0-path-value-core/hackedPackedPathParentFiltering";
|
|
1315
1328
|
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import { SocketFunction } from "socket-function/SocketFunction";
|
|
2
2
|
import { cache, lazy } from "socket-function/src/caching";
|
|
3
|
-
import { appendToPathStr, getPathDepth,
|
|
4
|
-
import {
|
|
5
|
-
import { RemoteWatcher
|
|
3
|
+
import { appendToPathStr, getPathDepth, getPathStr1, getPathStr3 } from "../path";
|
|
4
|
+
import { FunctionMetadata } from "../3-path-functions/syncSchema";
|
|
5
|
+
import { RemoteWatcher } from "../1-path-client/RemoteWatcher";
|
|
6
6
|
import { getProxyPath } from "../2-proxy/pathValueProxy";
|
|
7
|
-
import { atomic,
|
|
8
|
-
import { CallSpec, DEPTH_TO_DATA,
|
|
9
|
-
import { PathValueController } from "../0-path-value-core/PathValueController";
|
|
10
|
-
import { epochTime, MAX_ACCEPTED_CHANGE_AGE, PathValue,
|
|
7
|
+
import { atomic, proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
|
|
8
|
+
import { CallSpec, DEPTH_TO_DATA, commitCall, debugCallSpec, functionSchema, getDevFunctionSpecFromCall } from "../3-path-functions/PathFunctionRunner";
|
|
9
|
+
import { PathValueController, PathValueControllerBase } from "../0-path-value-core/PathValueController";
|
|
10
|
+
import { epochTime, MAX_ACCEPTED_CHANGE_AGE, PathValue, WatchConfig, debugTime, MAX_CHANGE_AGE } from "../0-path-value-core/pathValueCore";
|
|
11
|
+
import { pathWatcher } from "../0-path-value-core/PathWatcher";
|
|
11
12
|
import { IdentityController_getMachineId, IdentityController_getPubKeyShort, IdentityController_getSecureIP } from "../-c-identity/IdentityController";
|
|
12
13
|
import { getControllerNodeId } from "../-g-core-values/NodeCapabilities";
|
|
13
14
|
import { getModuleFromConfig, watchModuleHotreloads } from "../3-path-functions/pathFunctionLoader";
|
|
14
15
|
import { errorToUndefined, ignoreErrors, logErrors } from "../errors";
|
|
15
16
|
import { blue, green, magenta, red } from "socket-function/src/formatting/logColors";
|
|
16
17
|
import { PermissionsCheck } from "./permissions";
|
|
17
|
-
import {
|
|
18
|
+
import { writeCall } from "../3-path-functions/PathFunctionHelpers";
|
|
18
19
|
import { delay } from "socket-function/src/batching";
|
|
19
|
-
import {
|
|
20
|
+
import { isNodeTrue } from "socket-function/src/misc";
|
|
20
21
|
import { registerResource } from "../diagnostics/trackResources";
|
|
21
22
|
|
|
22
23
|
// Always whitelist preact, as most of the time we want it clientside
|
|
@@ -24,27 +25,21 @@ import "preact";
|
|
|
24
25
|
import { setFlag } from "socket-function/require/compileFlags";
|
|
25
26
|
import { CallerContextBase } from "socket-function/SocketFunctionTypes";
|
|
26
27
|
import { isTrustedByNode } from "../-d-trust/NetworkTrust2";
|
|
27
|
-
import { pathValueSerializer } from "../-h-path-value-serialize/PathValueSerializer";
|
|
28
28
|
import { Querysub, id } from "./Querysub";
|
|
29
|
-
import { measureBlock } from "socket-function/src/profiling/measure";
|
|
30
|
-
import debugbreak from "debugbreak";
|
|
31
29
|
import { isDefined } from "../misc";
|
|
32
30
|
import { isClient, isServer } from "../config2";
|
|
33
31
|
import { PromiseObj } from "../promise";
|
|
34
32
|
import { LoggingClient } from "../0-path-value-core/LoggingClient";
|
|
35
33
|
import * as prediction from "./querysubPrediction";
|
|
36
|
-
import { getCallResultPath } from "./querysubPrediction";
|
|
37
|
-
import { nodePathAuthority, pathValueAuthority2 } from "../0-path-value-core/NodePathAuthorities";
|
|
38
|
-
import { assertIsManagementUser } from "../diagnostics/managementPages";
|
|
39
|
-
import { getBrowserUrlNode } from "../-f-node-discovery/NodeDiscovery";
|
|
40
34
|
setFlag(require, "preact", "allowclient", true);
|
|
41
35
|
|
|
42
36
|
import yargs from "yargs";
|
|
43
37
|
import { mergeFilterables, parseFilterable, serializeFilterable } from "../misc/filterable";
|
|
44
38
|
import { isManagementUser, onAllPredictionsFinished } from "../-0-hooks/hooks";
|
|
45
|
-
import { getDomain, isBootstrapOnly
|
|
46
|
-
import { logDisk } from "../diagnostics/logs/diskLogger";
|
|
39
|
+
import { getDomain, isBootstrapOnly } from "../config";
|
|
47
40
|
import { flushPredictionQueueBase, runInPredictionQueue, syncHasPendingPredictionsBase } from "./predictionQueue";
|
|
41
|
+
import { PathRouter } from "../0-path-value-core/PathRouter";
|
|
42
|
+
import { authorityLookup } from "../0-path-value-core/AuthorityLookup";
|
|
48
43
|
|
|
49
44
|
let yargObj = isNodeTrue() && yargs(process.argv)
|
|
50
45
|
.option("fncfilter", { type: "string", default: "", desc: `Sets the filterable state for function calls, causing them to target specific FunctionRunners. If no FunctionRunner matches, all functions will fail to run. For example: "devtestserver" will match a FunctionRunner that uses the "devtestserver" filter. Merges with the existing filterable state if a client sets it explicitly.` })
|
|
@@ -59,7 +54,7 @@ export { Querysub, id };
|
|
|
59
54
|
// TODO: Eventually this will be split by domain, which required nodeIds to be split by domain, so that getControllerNodeId can check nodeIds on a specific domain.
|
|
60
55
|
export async function querysubNodeId() {
|
|
61
56
|
if (isClient()) {
|
|
62
|
-
return
|
|
57
|
+
return PathRouter.getReadyAuthority(getPathStr1(getDomain()))?.nodeId;
|
|
63
58
|
} else {
|
|
64
59
|
return getControllerNodeId(QuerysubController);
|
|
65
60
|
}
|
|
@@ -482,12 +477,14 @@ export class QuerysubControllerBase {
|
|
|
482
477
|
|
|
483
478
|
console.info("Disallowing PathValue watches due to disallowed permissions", { count: newPathsNotAllowed.length, callerId });
|
|
484
479
|
|
|
485
|
-
ignoreErrors(
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
480
|
+
ignoreErrors(PathValueControllerBase.sendValues({
|
|
481
|
+
nodeId: callerId,
|
|
482
|
+
pathValues: undefinedValues,
|
|
483
|
+
initialTriggers: {
|
|
484
|
+
values: new Set(undefinedValues.map(value => value.path)),
|
|
485
|
+
parentPaths: new Set(newParentPathsNotAllowed)
|
|
486
|
+
},
|
|
487
|
+
}));
|
|
491
488
|
}
|
|
492
489
|
|
|
493
490
|
if (removedPaths.size > 0) {
|
|
@@ -497,8 +494,10 @@ export class QuerysubControllerBase {
|
|
|
497
494
|
if (allowedPaths.size > 0) {
|
|
498
495
|
let [newParentPathsAllowed, newPathsAllowed] = splitParentPaths(allowedPaths);
|
|
499
496
|
let watchConfig: WatchConfig = { paths: newPathsAllowed, parentPaths: newParentPathsAllowed };
|
|
500
|
-
pathWatcher.watchPath({
|
|
501
|
-
|
|
497
|
+
pathWatcher.watchPath({
|
|
498
|
+
nodeId: callerId,
|
|
499
|
+
...watchConfig
|
|
500
|
+
});
|
|
502
501
|
}
|
|
503
502
|
};
|
|
504
503
|
}
|
|
@@ -541,6 +540,13 @@ export class QuerysubControllerBase {
|
|
|
541
540
|
}
|
|
542
541
|
Querysub.assertDomainAllowed(getPathStr1(call.DomainName));
|
|
543
542
|
|
|
543
|
+
console.info(`Querysub starting to add function call`, {
|
|
544
|
+
callId: call.CallId,
|
|
545
|
+
timeId: call.runAtTime.time,
|
|
546
|
+
functionId: call.FunctionId,
|
|
547
|
+
moduleId: call.ModuleId,
|
|
548
|
+
});
|
|
549
|
+
|
|
544
550
|
let caller = SocketFunction.getCaller();
|
|
545
551
|
let callerMachineId = IdentityController_getMachineId(caller);
|
|
546
552
|
let callerCreatorId = IdentityController_getPubKeyShort(caller);
|
|
@@ -608,6 +614,9 @@ export class QuerysubControllerBase {
|
|
|
608
614
|
throw new Error(`Caller does not have permission to call ${call.DomainName}.${call.ModuleId}`);
|
|
609
615
|
}
|
|
610
616
|
|
|
617
|
+
console.info(`Querysub committing call`, {
|
|
618
|
+
callId: call.CallId,
|
|
619
|
+
});
|
|
611
620
|
commitCall(call);
|
|
612
621
|
// NOTE: We don't wait for our writes to actually commit, because... there isn't any reason they shouldn't
|
|
613
622
|
// except the server being down, in which case, the client will gracefully timeout when it doesn't receive the confirmation
|
|
@@ -654,11 +663,17 @@ export class QuerysubControllerBase {
|
|
|
654
663
|
|
|
655
664
|
// NOTE: Maybe remove this? It's very useful for debugging though...
|
|
656
665
|
public async debugGetSingleReadNode(path: string) {
|
|
657
|
-
return
|
|
666
|
+
return PathRouter.getReadyAuthority(path)?.nodeId;
|
|
658
667
|
}
|
|
659
668
|
|
|
660
669
|
public async debugGetPathAuthorities(nodeId: string) {
|
|
661
|
-
|
|
670
|
+
let authorities = await authorityLookup.getTopology();
|
|
671
|
+
return authorities.find(x => x.nodeId === nodeId)?.authoritySpec;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
public async debugGetTopologyEntry(nodeId: string) {
|
|
675
|
+
let topology = await authorityLookup.getTopology();
|
|
676
|
+
return topology.find(x => x.nodeId === nodeId);
|
|
662
677
|
}
|
|
663
678
|
}
|
|
664
679
|
|
|
@@ -672,6 +687,7 @@ export const QuerysubController = SocketFunction.register(
|
|
|
672
687
|
addCall: { compress: true, },
|
|
673
688
|
debugGetSingleReadNode: {},
|
|
674
689
|
debugGetPathAuthorities: {},
|
|
690
|
+
debugGetTopologyEntry: {},
|
|
675
691
|
getModulePath: {},
|
|
676
692
|
getDevFunctionSpecFromCall: {},
|
|
677
693
|
}),
|
|
@@ -13,7 +13,7 @@ import { isClient } from "../config2";
|
|
|
13
13
|
import { sort } from "socket-function/src/misc";
|
|
14
14
|
import { Querysub } from "./QuerysubController";
|
|
15
15
|
import { CALL_PERMISSIONS_KEY } from "./permissionsShared";
|
|
16
|
-
import { getDomain, isLocal } from "../config";
|
|
16
|
+
import { getDomain, isLocal, isPublic } from "../config";
|
|
17
17
|
|
|
18
18
|
function watchModule(config: FunctionSpec): NodeJS.Module | undefined {
|
|
19
19
|
let module = getModuleFromConfig(config);
|
|
@@ -52,7 +52,7 @@ export class PermissionsCheck {
|
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
private getModulePermissions(domainName: string) {
|
|
55
|
-
if (
|
|
55
|
+
if (!isPublic() && domainName === getDomain()) {
|
|
56
56
|
return function (moduleId: string): {
|
|
57
57
|
schema: SchemaObject;
|
|
58
58
|
fnc: FunctionSpec;
|