querysub 0.2.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 (169) hide show
  1. package/.dependency-cruiser.js +304 -0
  2. package/.eslintrc.js +51 -0
  3. package/.github/copilot-instructions.md +1 -0
  4. package/.vscode/settings.json +25 -0
  5. package/bin/deploy.js +4 -0
  6. package/bin/function.js +4 -0
  7. package/bin/server.js +4 -0
  8. package/costsBenefits.txt +112 -0
  9. package/deploy.ts +3 -0
  10. package/inject.ts +1 -0
  11. package/package.json +60 -0
  12. package/prompts.txt +54 -0
  13. package/spec.txt +820 -0
  14. package/src/-a-archives/archiveCache.ts +913 -0
  15. package/src/-a-archives/archives.ts +148 -0
  16. package/src/-a-archives/archivesBackBlaze.ts +792 -0
  17. package/src/-a-archives/archivesDisk.ts +418 -0
  18. package/src/-a-archives/copyLocalToBackblaze.ts +24 -0
  19. package/src/-a-auth/certs.ts +517 -0
  20. package/src/-a-auth/der.ts +122 -0
  21. package/src/-a-auth/ed25519.ts +1015 -0
  22. package/src/-a-auth/node-forge-ed25519.d.ts +17 -0
  23. package/src/-b-authorities/dnsAuthority.ts +203 -0
  24. package/src/-b-authorities/emailAuthority.ts +57 -0
  25. package/src/-c-identity/IdentityController.ts +200 -0
  26. package/src/-d-trust/NetworkTrust2.ts +150 -0
  27. package/src/-e-certs/EdgeCertController.ts +288 -0
  28. package/src/-e-certs/certAuthority.ts +192 -0
  29. package/src/-f-node-discovery/NodeDiscovery.ts +543 -0
  30. package/src/-g-core-values/NodeCapabilities.ts +134 -0
  31. package/src/-g-core-values/oneTimeForward.ts +91 -0
  32. package/src/-h-path-value-serialize/PathValueSerializer.ts +769 -0
  33. package/src/-h-path-value-serialize/stringSerializer.ts +176 -0
  34. package/src/0-path-value-core/LoggingClient.tsx +24 -0
  35. package/src/0-path-value-core/NodePathAuthorities.ts +978 -0
  36. package/src/0-path-value-core/PathController.ts +1 -0
  37. package/src/0-path-value-core/PathValueCommitter.ts +565 -0
  38. package/src/0-path-value-core/PathValueController.ts +231 -0
  39. package/src/0-path-value-core/archiveLocks/ArchiveLocks.ts +154 -0
  40. package/src/0-path-value-core/archiveLocks/ArchiveLocks2.ts +820 -0
  41. package/src/0-path-value-core/archiveLocks/archiveSnapshots.ts +180 -0
  42. package/src/0-path-value-core/debugLogs.ts +90 -0
  43. package/src/0-path-value-core/pathValueArchives.ts +483 -0
  44. package/src/0-path-value-core/pathValueCore.ts +2217 -0
  45. package/src/1-path-client/RemoteWatcher.ts +558 -0
  46. package/src/1-path-client/pathValueClientWatcher.ts +702 -0
  47. package/src/2-proxy/PathValueProxyWatcher.ts +1857 -0
  48. package/src/2-proxy/archiveMoveHarness.ts +376 -0
  49. package/src/2-proxy/garbageCollection.ts +753 -0
  50. package/src/2-proxy/pathDatabaseProxyBase.ts +37 -0
  51. package/src/2-proxy/pathValueProxy.ts +139 -0
  52. package/src/2-proxy/schema2.ts +518 -0
  53. package/src/3-path-functions/PathFunctionHelpers.ts +129 -0
  54. package/src/3-path-functions/PathFunctionRunner.ts +619 -0
  55. package/src/3-path-functions/PathFunctionRunnerMain.ts +67 -0
  56. package/src/3-path-functions/deployBlock.ts +10 -0
  57. package/src/3-path-functions/deployCheck.ts +7 -0
  58. package/src/3-path-functions/deployMain.ts +160 -0
  59. package/src/3-path-functions/pathFunctionLoader.ts +282 -0
  60. package/src/3-path-functions/syncSchema.ts +475 -0
  61. package/src/3-path-functions/tests/functionsTest.ts +135 -0
  62. package/src/3-path-functions/tests/rejectTest.ts +77 -0
  63. package/src/4-dom/css.tsx +29 -0
  64. package/src/4-dom/cssTypes.d.ts +212 -0
  65. package/src/4-dom/qreact.tsx +2322 -0
  66. package/src/4-dom/qreactTest.tsx +417 -0
  67. package/src/4-querysub/Querysub.ts +877 -0
  68. package/src/4-querysub/QuerysubController.ts +620 -0
  69. package/src/4-querysub/copyEvent.ts +0 -0
  70. package/src/4-querysub/permissions.ts +289 -0
  71. package/src/4-querysub/permissionsShared.ts +1 -0
  72. package/src/4-querysub/querysubPrediction.ts +525 -0
  73. package/src/5-diagnostics/FullscreenModal.tsx +67 -0
  74. package/src/5-diagnostics/GenericFormat.tsx +165 -0
  75. package/src/5-diagnostics/Modal.tsx +79 -0
  76. package/src/5-diagnostics/Table.tsx +183 -0
  77. package/src/5-diagnostics/TimeGrouper.tsx +114 -0
  78. package/src/5-diagnostics/diskValueAudit.ts +216 -0
  79. package/src/5-diagnostics/memoryValueAudit.ts +442 -0
  80. package/src/5-diagnostics/nodeMetadata.ts +135 -0
  81. package/src/5-diagnostics/qreactDebug.tsx +309 -0
  82. package/src/5-diagnostics/shared.ts +26 -0
  83. package/src/5-diagnostics/synchronousLagTracking.ts +47 -0
  84. package/src/TestController.ts +35 -0
  85. package/src/allowclient.flag +0 -0
  86. package/src/bits.ts +86 -0
  87. package/src/buffers.ts +69 -0
  88. package/src/config.ts +53 -0
  89. package/src/config2.ts +48 -0
  90. package/src/diagnostics/ActionsHistory.ts +56 -0
  91. package/src/diagnostics/NodeViewer.tsx +503 -0
  92. package/src/diagnostics/SizeLimiter.ts +62 -0
  93. package/src/diagnostics/TimeDebug.tsx +18 -0
  94. package/src/diagnostics/benchmark.ts +139 -0
  95. package/src/diagnostics/errorLogs/ErrorLogController.ts +515 -0
  96. package/src/diagnostics/errorLogs/ErrorLogCore.ts +274 -0
  97. package/src/diagnostics/errorLogs/LogClassifiers.tsx +302 -0
  98. package/src/diagnostics/errorLogs/LogFilterUI.tsx +84 -0
  99. package/src/diagnostics/errorLogs/LogNotify.tsx +101 -0
  100. package/src/diagnostics/errorLogs/LogTimeSelector.tsx +724 -0
  101. package/src/diagnostics/errorLogs/LogViewer.tsx +757 -0
  102. package/src/diagnostics/errorLogs/hookErrors.ts +60 -0
  103. package/src/diagnostics/errorLogs/logFiltering.tsx +149 -0
  104. package/src/diagnostics/heapTag.ts +13 -0
  105. package/src/diagnostics/listenOnDebugger.ts +77 -0
  106. package/src/diagnostics/logs/DiskLoggerPage.tsx +572 -0
  107. package/src/diagnostics/logs/ObjectDisplay.tsx +165 -0
  108. package/src/diagnostics/logs/ansiFormat.ts +108 -0
  109. package/src/diagnostics/logs/diskLogGlobalContext.ts +38 -0
  110. package/src/diagnostics/logs/diskLogger.ts +305 -0
  111. package/src/diagnostics/logs/diskShimConsoleLogs.ts +32 -0
  112. package/src/diagnostics/logs/injectFileLocationToConsole.ts +50 -0
  113. package/src/diagnostics/logs/logGitHashes.ts +30 -0
  114. package/src/diagnostics/managementPages.tsx +289 -0
  115. package/src/diagnostics/periodic.ts +89 -0
  116. package/src/diagnostics/runSaturationTest.ts +416 -0
  117. package/src/diagnostics/satSchema.ts +64 -0
  118. package/src/diagnostics/trackResources.ts +82 -0
  119. package/src/diagnostics/watchdog.ts +55 -0
  120. package/src/errors.ts +132 -0
  121. package/src/forceProduction.ts +3 -0
  122. package/src/fs.ts +72 -0
  123. package/src/heapDumps.ts +666 -0
  124. package/src/https.ts +2 -0
  125. package/src/inject.ts +1 -0
  126. package/src/library-components/ATag.tsx +84 -0
  127. package/src/library-components/Button.tsx +344 -0
  128. package/src/library-components/ButtonSelector.tsx +64 -0
  129. package/src/library-components/DropdownCustom.tsx +151 -0
  130. package/src/library-components/DropdownSelector.tsx +32 -0
  131. package/src/library-components/Input.tsx +334 -0
  132. package/src/library-components/InputLabel.tsx +198 -0
  133. package/src/library-components/InputPicker.tsx +125 -0
  134. package/src/library-components/LazyComponent.tsx +62 -0
  135. package/src/library-components/MeasureHeightCSS.tsx +48 -0
  136. package/src/library-components/MeasuredDiv.tsx +47 -0
  137. package/src/library-components/ShowMore.tsx +51 -0
  138. package/src/library-components/SyncedController.ts +171 -0
  139. package/src/library-components/TimeRangeSelector.tsx +407 -0
  140. package/src/library-components/URLParam.ts +263 -0
  141. package/src/library-components/colors.tsx +14 -0
  142. package/src/library-components/drag.ts +114 -0
  143. package/src/library-components/icons.tsx +692 -0
  144. package/src/library-components/niceStringify.ts +50 -0
  145. package/src/library-components/renderToString.ts +52 -0
  146. package/src/misc/PromiseRace.ts +101 -0
  147. package/src/misc/color.ts +30 -0
  148. package/src/misc/getParentProcessId.cs +53 -0
  149. package/src/misc/getParentProcessId.ts +53 -0
  150. package/src/misc/hash.ts +83 -0
  151. package/src/misc/ipPong.js +13 -0
  152. package/src/misc/networking.ts +2 -0
  153. package/src/misc/random.ts +45 -0
  154. package/src/misc.ts +19 -0
  155. package/src/noserverhotreload.flag +0 -0
  156. package/src/path.ts +226 -0
  157. package/src/persistentLocalStore.ts +37 -0
  158. package/src/promise.ts +15 -0
  159. package/src/server.ts +73 -0
  160. package/src/src.d.ts +1 -0
  161. package/src/test/heapProcess.ts +36 -0
  162. package/src/test/mongoSatTest.tsx +55 -0
  163. package/src/test/satTest.ts +193 -0
  164. package/src/test/test.tsx +552 -0
  165. package/src/zip.ts +92 -0
  166. package/src/zipThreaded.ts +106 -0
  167. package/src/zipThreadedWorker.js +19 -0
  168. package/tsconfig.json +27 -0
  169. package/yarnSpec.txt +56 -0
package/src/path.ts ADDED
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Overview
3
+ * We escape path segments so we can quickly create a str representing
4
+ * that path. We do this by escaping some special character and then using a that
5
+ * character to indicate special values.
6
+ * - This appears to be faster than JSON.stringify
7
+ * - A random benchmark showed 140ns per, compared to 260ns for a JSON.stringify call
8
+ * - ALSO, using "appendToPathStr(rootPathStr, str)" instead of getPathStr([str]) is even
9
+ * faster, about 70ns per.
10
+ * - This lets us extend existing stres without recreating the entire str,
11
+ * which is significantly faster than JSON.stringify.
12
+ * - ALSO, escapes "." and "$", letting us use this to escape keys for mongodb usage.
13
+ */
14
+
15
+ // TODO: Change our escaping so we can turn paths into valid mongodb key names see:
16
+ // https://stackoverflow.com/questions/7975185/mongodb-query-over-a-str-with-special-chars-in-keys/7976235#7976235
17
+
18
+ const specialChar = ".";
19
+
20
+ // The character after this character is special, forming a 2 character sequence.
21
+ export const PATH_SPECIAL_CHAR = specialChar;
22
+
23
+ const pathDelimitChar = ",";
24
+ const specialCharEscape = specialChar + "_";
25
+
26
+
27
+ // NOTE: Our paths end up looking something like: pathDelimitEscaped + arr[0] + pathDelimitEscaped + arr[1] + pathDelimitEscaped,
28
+ // with the delimitter at both ends and between all elements (and with everything escaped properly).
29
+
30
+ const pathDelimitEscaped = specialChar + pathDelimitChar;
31
+
32
+ const afterChildSuffix = specialChar + String.fromCharCode(pathDelimitChar.charCodeAt(0) + 1);
33
+
34
+ export const rootPathStr = getPathStr([]);
35
+
36
+ function regexEscape(text: string) {
37
+ text = text.replace(/\./g, "\\.");
38
+ text = text.replace(/\$/g, "\\$");
39
+ return text;
40
+ }
41
+
42
+ let regexSpecialChar = new RegExp(regexEscape(specialChar), "g");
43
+ let regexUnescapeSpecialChar = new RegExp(regexEscape(specialCharEscape), "g");
44
+
45
+ export function escapePathPart(part: string | number | boolean | undefined | null) {
46
+ if (typeof part !== "string") return part;
47
+ if (isValidPathStr(part)) {
48
+ if (part.indexOf(specialChar) < 0) {
49
+ return part;
50
+ }
51
+ }
52
+ return part.replace(regexSpecialChar, specialCharEscape);
53
+ }
54
+ function unescapePathPart(part: string) {
55
+ part = part.replace(regexUnescapeSpecialChar, specialChar);
56
+ return part;
57
+ }
58
+
59
+
60
+
61
+ export function getPathStr(path: (string | number | boolean | undefined | null)[]) {
62
+ return pathDelimitEscaped + path.map(x => escapePathPart(x) + pathDelimitEscaped).join("");
63
+ }
64
+ /** Equivalent to getPathStr([path0]), except a bit faster */
65
+ export function getPathStr1(path0: string) {
66
+ return appendToPathStr(rootPathStr, path0);
67
+ }
68
+ /** Equivalent to getPathStr([path0, path1]), except a bit faster */
69
+ export function getPathStr2(path0: string, path1: string) {
70
+ // TODO: Benchmark this again. If I recall correctly, if we are ONLY string paths, this is about
71
+ // twice as fast as getPathStr([path0, path1])? This is because allocating arrays is slow.
72
+ return appendToPathStr(appendToPathStr(rootPathStr, path0), path1);
73
+ }
74
+ /** Equivalent to getPathStr([path0, path1, path2]), except a bit faster */
75
+ export function getPathStr3(path0: string, path1: string, path2: string) {
76
+ return appendToPathStr(appendToPathStr(appendToPathStr(rootPathStr, path0), path1), path2);
77
+ }
78
+ export function getPathStr4(path0: string, path1: string, path2: string, path3: string) {
79
+ let value = rootPathStr;
80
+ value = appendToPathStr(value, path0);
81
+ value = appendToPathStr(value, path1);
82
+ value = appendToPathStr(value, path2);
83
+ value = appendToPathStr(value, path3);
84
+ return value;
85
+ }
86
+
87
+ export function appendToPathStr(pathStr: string, pathPart: string) {
88
+ return pathStr + escapePathPart(pathPart) + pathDelimitEscaped;
89
+ }
90
+ export function prependToPathStr(pathStr: string, pathPart: string) {
91
+ return pathDelimitEscaped + escapePathPart(pathPart) + pathStr;
92
+ }
93
+
94
+ export function pathStrIncludesValue(pathStr: string, value: string) {
95
+ value = String(escapePathPart(value));
96
+ return pathStr.includes(value);
97
+ }
98
+
99
+ export function joinPathStres(lhsStr: string, rhsStr: string) {
100
+ return lhsStr + rhsStr.slice(rootPathStr.length);
101
+ }
102
+
103
+ export function getPathIndexAssert(pathStr: string, index: number): string {
104
+ let value = getPathIndex(pathStr, index);
105
+ if (value === undefined) {
106
+ throw new Error(`Path index ${index} was undefined in pathStr ${pathStr}`);
107
+ }
108
+ return value;
109
+ }
110
+ export function getPathIndex(pathStr: string, index: number) {
111
+ let parts = pathStr.split(pathDelimitEscaped);
112
+ if (parts.length - 2 <= index) {
113
+ return undefined;
114
+ }
115
+ let part = parts[index + 1];
116
+ if (part === undefined) {
117
+ return undefined;
118
+ }
119
+ return unescapePathPart(part);
120
+ }
121
+ export function getPathFromStr(pathStr: string) {
122
+ return pathStr.split(pathDelimitEscaped).slice(1, -1).map(x => unescapePathPart(x));
123
+ }
124
+
125
+ export function isValidPathStr(pathStr: string) {
126
+ return pathStr.startsWith(pathDelimitEscaped) && pathStr.endsWith(pathDelimitEscaped);
127
+ }
128
+
129
+ /** Gets the path after all children of the pathStr, BUT, before the next sibling (when sorting lexicographically by path str). */
130
+ export function getPathAfterLastChild(pathStr: string) {
131
+ if (pathStr === "") {
132
+ return afterChildSuffix;
133
+ }
134
+ // NOTE: assertArg isn't used, to reduce the readLocks of path.ts, which is used itself by assertArg.
135
+ if (!pathStr.endsWith(pathDelimitEscaped)) {
136
+ throw new Error(`pathStr must end with ${JSON.stringify(pathDelimitEscaped)}, was ${JSON.stringify(pathStr)}`);
137
+ }
138
+ // Any sibling before us, will lexicographically be < us BEFORE the last character, the same as any sibling after us.
139
+ // However, children't will match all the way to our suffix, and then be < our modified suffix.
140
+ return pathStr.slice(0, -pathDelimitEscaped.length) + afterChildSuffix;
141
+ }
142
+
143
+ /** === getPathStr(getPathFromStr(pathStr).slice(0, -1)), getParentPathStr(rootPathStr) === rootPathStr */
144
+ export function getParentPathStr(pathStr: string) {
145
+ // Allow empty string? Better than throwing on it, I guess
146
+ if (pathStr === "") {
147
+ return "";
148
+ }
149
+ // NOTE: If pathStr.length is too small, our index start becomes negative, and so this works without
150
+ // an additional check.
151
+ let index = pathStr.lastIndexOf(pathDelimitEscaped, pathStr.length - pathDelimitEscaped.length - pathDelimitEscaped.length + 1);
152
+ return pathStr.slice(0, index + pathDelimitEscaped.length);
153
+ }
154
+
155
+ /** === getPathFromStr(pathStr).slice(-1)[0] */
156
+ export function getLastPathPart(pathStr: string) {
157
+ let index = pathStr.lastIndexOf(pathDelimitEscaped, pathStr.length - pathDelimitEscaped.length - pathDelimitEscaped.length + 1);
158
+ return unescapePathPart(pathStr.slice(index + pathDelimitEscaped.length, -pathDelimitEscaped.length));
159
+ }
160
+
161
+ /** === getPathStr(getPathFromStr(pathStr).slice(0, -1)) */
162
+ export function removePathLastPart(pathStr: string) {
163
+ let index = pathStr.lastIndexOf(pathDelimitEscaped, pathStr.length - pathDelimitEscaped.length - pathDelimitEscaped.length + 1);
164
+ return pathStr.slice(0, index + pathDelimitEscaped.length);
165
+ }
166
+
167
+ /** getPathDepth(pathStr) === getPathFromStr(pathStr).length */
168
+ export function getPathDepth(pathStr: string): number {
169
+ // Start at 1, to skip the first pathDelimit
170
+ let index = 1;
171
+ // Start at -1, as the last loop doesn't have pathDelimitEscaped, but is still incremented
172
+ let count = -1;
173
+ while (index > 0) {
174
+ count++;
175
+ index = pathStr.indexOf(pathDelimitEscaped, index) + 1;
176
+ }
177
+ return count;
178
+ }
179
+
180
+ export const getPathPrefix = trimPathStrToDepth;
181
+ export function trimPathStrToDepth(pathStr: string, depth: number): string {
182
+ let index = 0;
183
+ let count = 0;
184
+ while (count < depth) {
185
+ let nextIndex = pathStr.indexOf(pathDelimitEscaped, index + 1);
186
+ if (nextIndex < 0) break;
187
+ count++;
188
+ index = nextIndex;
189
+ }
190
+ return pathStr.slice(0, index + pathDelimitEscaped.length);
191
+ }
192
+ export const slicePathStrToDepth = trimPathStrToDepth;
193
+ export function getPathSuffix(pathStr: string, depth: number): string {
194
+ let index = 0;
195
+ let count = 0;
196
+ while (count < depth) {
197
+ let nextIndex = pathStr.indexOf(pathDelimitEscaped, index + 1);
198
+ if (nextIndex < 0) break;
199
+ count++;
200
+ index = nextIndex;
201
+ }
202
+ return pathStr.slice(index);
203
+ }
204
+
205
+ /** A hack, which breaks some path functions, but... which works with enough to save a
206
+ * lot of code and time when we need a bit more information that shouldn't count as
207
+ * path information. */
208
+ export function hack_setPackedPathSuffix(path: string, suffix: string): string {
209
+ return path + suffix;
210
+ }
211
+ export function hack_isPackedPath(path: string) {
212
+ return !path.endsWith(pathDelimitEscaped);
213
+ }
214
+ export function hack_getPackedPathSuffix(path: string): string {
215
+ if (!hack_isPackedPath(path)) {
216
+ return "";
217
+ }
218
+ return getPathSuffix(path, getPathDepth(path)).slice(pathDelimitEscaped.length);
219
+ }
220
+ export function hack_stripPackedPath(path: string): string {
221
+ if (!hack_isPackedPath(path)) {
222
+ return path;
223
+ }
224
+ let suffix = hack_getPackedPathSuffix(path);
225
+ return path.slice(0, -suffix.length);
226
+ }
@@ -0,0 +1,37 @@
1
+ module.allowclient = true;
2
+
3
+ import { isNode } from "socket-function/src/misc";
4
+ import fs from "fs";
5
+ import { getStorageDir, getSubFolder } from "./fs";
6
+ import { isClient } from "./config2";
7
+ import { getDomain } from "./config";
8
+
9
+ export function createKeyStore<T>(key: string): {
10
+ value: T | null;
11
+ } {
12
+ if (isNode()) {
13
+ let path = getStorageDir() + key + ".json";
14
+ return {
15
+ get value() {
16
+ let contents: string | undefined = undefined;
17
+ try { contents = fs.readFileSync(path, "utf8"); } catch { }
18
+ if (!contents) return null;
19
+ return JSON.parse(contents) as T;
20
+ },
21
+ set value(value: T | null) {
22
+ fs.writeFileSync(path, JSON.stringify(value));
23
+ }
24
+ };
25
+ } else {
26
+ return {
27
+ get value() {
28
+ let json = localStorage.getItem(key);
29
+ if (!json) return null;
30
+ return JSON.parse(json) as T;
31
+ },
32
+ set value(value: T | null) {
33
+ localStorage.setItem(key, JSON.stringify(value));
34
+ }
35
+ };
36
+ }
37
+ }
package/src/promise.ts ADDED
@@ -0,0 +1,15 @@
1
+ export class PromiseObj<T = void> {
2
+ public promise: Promise<T>;
3
+ public resolve!: (value: T | PromiseLike<T>) => void;
4
+ public reject!: (reason?: any) => void;
5
+ public resolved = false;
6
+ public rejected = false;
7
+ constructor() {
8
+ this.promise = new Promise<T>((resolve, reject) => {
9
+ this.resolve = resolve;
10
+ this.reject = reject;
11
+ });
12
+ this.promise.finally(() => this.resolved = true);
13
+ this.promise.catch(() => this.rejected = true);
14
+ }
15
+ }
package/src/server.ts ADDED
@@ -0,0 +1,73 @@
1
+ import "./forceProduction";
2
+ import "./inject";
3
+
4
+ import { deepCloneJSON, isBufferType, isNode, isNodeTrue } from "socket-function/src/misc";
5
+ import { SocketFunction } from "socket-function/SocketFunction";
6
+ import { getOwnMachineId, getThreadKeyCert } from "./-a-auth/certs";
7
+ import { logErrors } from "./errors";
8
+ import { publishMachineARecords, verifyServicesAlive } from "./-e-certs/EdgeCertController";
9
+ import { getPathStr, getPathStr1, prependToPathStr, rootPathStr } from "./path";
10
+ import { authorityStorage, debugCoreMode, debugRejections, enableDebugRejections, pathValueArchives } from "./0-path-value-core/pathValueCore";
11
+ import { listenOnDebugger } from "./diagnostics/listenOnDebugger";
12
+ import fs from "fs";
13
+ import { AuthorityPath, pathValueAuthority2 } from "./0-path-value-core/NodePathAuthorities";
14
+ import { Querysub } from "./4-querysub/QuerysubController";
15
+ import { ClientWatcher } from "./1-path-client/pathValueClientWatcher";
16
+ import { delay } from "socket-function/src/batching";
17
+ import yargs from "yargs";
18
+ import { JSONLACKS } from "socket-function/src/JSONLACKS/JSONLACKS";
19
+ import { green } from "socket-function/src/formatting/logColors";
20
+ import { formatTime } from "socket-function/src/formatting/format";
21
+
22
+ // As nice as it is that Querysub doesn't get imported, because our import hierarchy is so strict...
23
+ // we DO want to register some static diagnostics from Querysub, so... import it explicitly.
24
+ import "./4-querysub/Querysub";
25
+ import { getOwnThreadId } from "./-f-node-discovery/NodeDiscovery";
26
+ import { getOurAuthorities } from "./config2";
27
+ import { isPublic } from "./config";
28
+
29
+ let yargObj = isNodeTrue() && yargs(process.argv)
30
+ .option("authority", { type: "string", desc: `Defines the base paths we are an authority on (the domain is prepended to them). Either a file path to a JSON(AuthorityPath[]), or a base64 representation of the JSON(AuthorityPath[]).` })
31
+ .argv || {}
32
+ ;
33
+
34
+ logErrors(main());
35
+
36
+ async function main() {
37
+ if (!isNode()) return;
38
+
39
+ console.log(`Time before main ${green(formatTime(process.uptime() * 1000))}`);
40
+
41
+ Error.stackTraceLimit = 20;
42
+
43
+ //SocketFunction.logMessages = true;
44
+
45
+ // ClientWatcher.DEBUG_READS = true;
46
+ // ClientWatcher.DEBUG_WRITES = true;
47
+
48
+ SocketFunction.WIRE_WARN_TIME = 50;
49
+
50
+ //setMaxChangeAge(1000 * 15);
51
+
52
+ //ActionsHistory.LOG_ACTION_HISTORY = "server";
53
+ listenOnDebugger("PathValueServer");
54
+
55
+ //debugCoreMode();
56
+ //enableDebugRejections();
57
+
58
+ for (let authority of getOurAuthorities()) {
59
+ pathValueAuthority2.becomePathAuthority(authority);
60
+ }
61
+
62
+ let keyPair = await getThreadKeyCert();
63
+ await SocketFunction.mount({
64
+ port: 0, ...keyPair, public: isPublic(),
65
+ // SHOULD be safe, because trust is still required. Otherwise we run into issues when we have some
66
+ // public services, and some private, but still want to run things locally.
67
+ autoForwardPort: true,
68
+ });
69
+
70
+ verifyServicesAlive();
71
+
72
+ await publishMachineARecords();
73
+ }
package/src/src.d.ts ADDED
@@ -0,0 +1 @@
1
+ /// <reference path="./-a-auth/node-forge-ed25519.d.ts" />
@@ -0,0 +1,36 @@
1
+ import { formatNumber } from "socket-function/src/formatting/format";
2
+ import { parseHeapSnapshot, processAndSummarizeHeapsnapshot } from "../heapDumps";
3
+ import fs from "fs";
4
+
5
+ async function heapProcess() {
6
+ /*
7
+ let targetRatePerSecond = 50;
8
+ let startTime = Date.now();
9
+
10
+ for(let i = 0; i < 300 * 300; i++) {
11
+ sat_functions.setValues([i]);
12
+
13
+ while (true) {
14
+ let rate = i / (Date.now() - startTime) * 1000;
15
+ if(rate < targetRatePerSecond) break;
16
+ await delay(16);
17
+ }
18
+ }
19
+ */
20
+
21
+ let buffer = fs.readFileSync("./heapdump.heapsnapshot");
22
+ let parsed = await parseHeapSnapshot("stressTest", buffer, () => { });
23
+
24
+ let snapshot = await processAndSummarizeHeapsnapshot(parsed, () => { }, {
25
+
26
+ });
27
+ console.log();
28
+
29
+ console.log(`Total ${formatNumber(snapshot.total)}`);
30
+ let values = Object.values(snapshot.summary);
31
+ values.sort((a, b) => b.sum - a.sum);
32
+ for (let value of values.slice(0, 100)) {
33
+ console.log(`${formatNumber(value.sum)} (${value.count})`.padEnd(20, "") + " " + value.key + ` (ex id ${value.firstId})`);
34
+ }
35
+ }
36
+ heapProcess().catch(e => console.error(e)).finally(() => process.exit());
@@ -0,0 +1,55 @@
1
+ // import * as mongodb from "mongodb";
2
+ // import { lazy } from "socket-function/src/caching";
3
+ // import { BenchmarkFunctions, DriftValues, runSaturationTests } from "../diagnostics/runSaturationTest";
4
+
5
+ // export type MongoRow = {
6
+ // _id: string;
7
+ // [prop: string]: unknown;
8
+ // };
9
+
10
+ // let getMongoClient = lazy(async (): Promise<mongodb.MongoClient> => {
11
+ // let client = await mongodb.MongoClient.connect(
12
+ // `mongodb://admin:password@127.0.0.1:33208/?authSource=admin&readPreference=primary&appname=MongoDB%20Compass&ssl=false`,
13
+ // {
14
+ // ignoreUndefined: true
15
+ // }
16
+ // );
17
+ // return client;
18
+ // });
19
+ // async function getCollection(database: string, collection: string) {
20
+ // let client = await getMongoClient();
21
+ // return await client.db(database).collection<MongoRow>(collection);
22
+ // }
23
+
24
+ // export async function createBenchmarkFunctions(): Promise<BenchmarkFunctions> {
25
+ // let collection = await getCollection("TEST_DB", "TEST_COLLECTION");
26
+ // return {
27
+ // async setValues(indexes: number[], value?: number) {
28
+ // if (value !== undefined) {
29
+ // await collection.updateMany({ _id: { $in: indexes.map(i => i.toString()) } }, { $set: { value } }, { upsert: true });
30
+ // } else if (indexes.length === 1) {
31
+ // await collection.updateOne({ _id: indexes[0].toString() }, { $inc: { value: 1 } }, {});
32
+ // } else {
33
+ // await collection.updateMany({ _id: { $in: indexes.map(i => i.toString()) } }, { $inc: { value: 1 } as any }, {});
34
+ // }
35
+ // },
36
+ // async getValues(indexes: number[]): Promise<number[]> {
37
+ // let rows = await collection.find({ _id: { $in: indexes.map(i => i.toString()) } }).toArray();
38
+ // return rows.map(row => row.value as number);
39
+ // },
40
+ // };
41
+ // }
42
+
43
+
44
+ // export async function main() {
45
+ // await runSaturationTests({
46
+ // durationPer: 1000,
47
+ // //writeSpec: new DriftValues({ count: 77, modulus: INDEX_EXTENT, driftFraction: 0.1 }),
48
+ // //writeSpec: new DriftValues({ count: 10, modulus: INDEX_EXTENT, driftFraction: 0.1 }),
49
+ // //writeSpec: new DriftValues({ count: 9, modulus: 50 * 50, driftFraction: 0.1 }),
50
+ // writeSpec: new DriftValues({ count: 9, modulus: 50 * 50, driftFraction: 0.1 }),
51
+ // functions: await createBenchmarkFunctions(),
52
+ // });
53
+ // }
54
+
55
+ // main().catch(e => console.error(e)).finally(() => process.exit());
@@ -0,0 +1,193 @@
1
+ import debugbreak from "debugbreak";
2
+ import { configRootDiscoveryLocation } from "../-f-node-discovery/NodeDiscovery";
3
+ import { ClientWatcher } from "../1-path-client/pathValueClientWatcher";
4
+ import { Querysub } from "../4-querysub/QuerysubController";
5
+ configRootDiscoveryLocation({ domain: "querysub.com", port: 5050 });
6
+
7
+ import { Benchmark } from "../diagnostics/benchmark";
8
+ import { createBenchmarkFunctions, sat_functions } from "../diagnostics/satSchema";
9
+ import { runSaturationTests, DriftValues, runSingleSaturationTest } from "../diagnostics/runSaturationTest";
10
+ import { PermissionsCheck } from "../4-querysub/permissions";
11
+ import { appendToPathStr, getPathIndex, getPathStr, getPathSuffix, rootPathStr, trimPathStrToDepth } from "../path";
12
+ import { runCodeWithDatabase } from "../2-proxy/pathDatabaseProxyBase";
13
+ import { createPathValueProxy } from "../2-proxy/pathValueProxy";
14
+ import { proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
15
+ import { measureCode, measureFnc, measureWrap } from "socket-function/src/profiling/measure";
16
+ import { DEPTH_TO_DATA, DOMAIN_INDEX, MODULE_INDEX, overrideCurrentCall } from "../3-path-functions/PathFunctionRunner";
17
+ import { cache } from "socket-function/src/caching";
18
+ import { timeInHour, timeInMinute } from "socket-function/src/misc";
19
+ import { delay } from "socket-function/src/batching";
20
+ import { parseHeapSnapshot, processAndSummarizeHeapsnapshot, writeHeapSnapshot } from "../heapDumps";
21
+ import { formatNumber } from "socket-function/src/formatting/format";
22
+ import fs from "fs";
23
+
24
+
25
+ // A stress test with a single watcher
26
+ /*
27
+ (watchdog at 12/31/2023) Profiled 684ms (logged at 2023-12-31T07:05:41.871Z)
28
+ ClientWatcher().setWatches(async) 34.47% ( 236ms = 85 * 2.73ms + 114 * 33.2us )
29
+ findFunctionsToCall 16.12% ( 110ms = 85 * 1.3ms )
30
+ PathWatcher().watchPath 15.25% ( 104ms = 85 * 1.22ms + 114 * 8.68us )
31
+ watchLatest|getSingleReadNode 7.23% ( 49.5ms = 85 * 570us + 114 * 9.35us )
32
+ PathWatcher().triggerLatestWatcher 5.95% ( 40.7ms = 169 * 241us )
33
+
34
+ (watchdog at 12/31/2023) Profiled 1.21s (logged at 2023-12-31T07:23:31.501Z)
35
+ findFunctionsToCall 21.14% ( 256ms = 5 * 42.1ms + 19 * 2.39ms )
36
+ PathWatcher().triggerLatestWatcher 15.39% ( 186ms = 919 * 203us )
37
+ PathValueCommitter().commitValues 12.14% ( 147ms = 898 * 164us )
38
+ RemoteWatcher().watchLatest(async) 11.21% ( 136ms = 922 * 147us )
39
+ AuthorityPathValueStorage().ingestValues 6.22% ( 75.3ms = 52 * 696us + 869 * 45us )
40
+ */
41
+ // The proxyWatcher is taking most of the time, specifically due to the fact that it does not natively
42
+ // support delta based functions.
43
+
44
+ async function stressTest() {
45
+ let targetRatePerSecond = 200;
46
+ let startTime = Date.now();
47
+
48
+ for (let i = 0; i < 300 * 300; i++) {
49
+ sat_functions.setValues([i]);
50
+
51
+ while (true) {
52
+ let rate = i / (Date.now() - startTime) * 1000;
53
+ if (rate < targetRatePerSecond) break;
54
+ await delay(16);
55
+ }
56
+ }
57
+
58
+ }
59
+ stressTest().catch(e => console.error(e)).finally(() => process.exit());
60
+
61
+ async function timeTest() {
62
+ await Querysub.hostService("test");
63
+
64
+ await proxyWatcher.commitFunction({
65
+ watchFunction() {
66
+ const check = new PermissionsCheck({ callerMachineId: "", callerIP: "" });
67
+ let allowed = check.checkPermissions(getPathStr(["querysub.com", "PathFunctionRunner", "test", "Data", "test", "1"]));
68
+ console.log({ allowed });
69
+ },
70
+ });
71
+
72
+ // ~1.62us, so... if we can optimize this code... that would be good...
73
+ // AND, it doesn't even emit any specific paths, so... we can probably cache it a lot...
74
+ let cache = new Map<string, { domainName: string; moduleId: string; pathPrefix: string; rootKey: string }>();
75
+ function splitParts(path: string): { domainName: string; moduleId: string; pathPrefix: string; rootKey: string } {
76
+ let pathPrefix = trimPathStrToDepth(path, DEPTH_TO_DATA);
77
+ let result = cache.get(pathPrefix);
78
+ if (!result) {
79
+ const domainName = getPathIndex(path, DOMAIN_INDEX) || "";
80
+ const moduleId = getPathIndex(path, MODULE_INDEX) || "";
81
+ let rootKey = getPathIndex(path, DEPTH_TO_DATA - 1) || "";
82
+ result = { domainName, moduleId, pathPrefix, rootKey };
83
+ cache.set(pathPrefix, result);
84
+ }
85
+ return result;
86
+ }
87
+
88
+ const simulateCheckPermissions = measureWrap(function simulateCheckPermissions(path: string) {
89
+ return trimPathStrToDepth(path, DEPTH_TO_DATA);
90
+
91
+ // let obj = splitParts(path);
92
+ // if (!obj.domainName) return { permissionsPath: trimPathStrToDepth(path, DOMAIN_INDEX + 1), allowed: false };
93
+ // if (!obj.moduleId) return { permissionsPath: trimPathStrToDepth(path, MODULE_INDEX + 1), allowed: false };
94
+ // if (!obj.rootKey) return { permissionsPath: trimPathStrToDepth(path, DEPTH_TO_DATA), allowed: false };
95
+
96
+ // let pathInModule = getPathSuffix(path, DEPTH_TO_DATA - 1);
97
+ // if (!pathInModule) return { permissionsPath: path, allowed: false };
98
+ // if (pathInModule === rootPathStr) return { permissionsPath: path, allowed: false };
99
+
100
+ // return obj;
101
+ });
102
+
103
+
104
+ await measureCode(async function permissionsCheckTest() {
105
+ await proxyWatcher.commitFunction({
106
+ watchFunction() {
107
+ console.log(`Start perf test`);
108
+
109
+ const check = new PermissionsCheck({ callerMachineId: "", callerIP: "127.0.0.1" });
110
+ let paths: string[] = [];
111
+ for (let i = 0; i < 1000 * 100; i++) {
112
+ paths.push(getPathStr(["querysub.com", "PathFunctionRunner", "test", "Results", i.toString()]));
113
+ //paths.push(getPathStr(["querysub.com", "PathFunctionRunner", "test", "Data", i.toString()]));
114
+ }
115
+ for (let path of paths) {
116
+ check.checkPermissions(path);
117
+ }
118
+ },
119
+ });
120
+ });
121
+ }
122
+ //timeTest().catch(e => console.error(e)).finally(() => process.exit());
123
+
124
+ export async function main() {
125
+ // let values = new DriftValues({ count: 9, modulus: 50 * 50, driftFraction: 0.1 });
126
+ // for (let i = 0; i < 10; i++) {
127
+ // let calls = Array(100).fill(0).map(() =>
128
+ // Benchmark.waitForCallToFinish(sat_functions.setValues(values.getNextValues()))
129
+ // );
130
+ // await Promise.all(calls);
131
+ // }
132
+
133
+
134
+ // await runSingleSaturationTest({
135
+ // duration: 5000,
136
+ // saturation: 100,
137
+ // writeSpec: new DriftValues({ count: 9, modulus: 50 * 50, driftFraction: 0.1 }),
138
+ // functions: createBenchmarkFunctions(),
139
+ // });
140
+
141
+ await runSaturationTests({
142
+ durationPer: 1000,
143
+ //writeSpec: new DriftValues({ count: 77, modulus: INDEX_EXTENT, driftFraction: 0.1 }),
144
+ //writeSpec: new DriftValues({ count: 10, modulus: INDEX_EXTENT, driftFraction: 0.1 }),
145
+ //writeSpec: new DriftValues({ count: 9, modulus: 50 * 50, driftFraction: 0.1 }),
146
+ writeSpec: new DriftValues({ count: 1, modulus: 50 * 50, driftFraction: 0.1 }),
147
+ functions: createBenchmarkFunctions(),
148
+ });
149
+ }
150
+ //main().catch(e => console.error(e)).finally(() => process.exit());
151
+
152
+
153
+ /* 1s test time, 0 watchers (more watchers is slower)
154
+ new DriftValues({ count: 9, modulus: 50 * 50, driftFraction: 0.1 })
155
+ Suggestions
156
+ Min latency 60.7/s latency = 16.5ms (24.68% saturation) (15 count)
157
+ *** Min latency 2X 259/s latency = 30.9ms (799.51% saturation) (264 count)
158
+ 100ms latency 348/s latency = 91.6ms (3190.90% saturation) (352 count)
159
+ */
160
+
161
+ /* 1s test time
162
+ new DriftValues({ count: 1, modulus: 50 * 50, driftFraction: 0.1 })
163
+ Suggestions
164
+ Min latency 42.6/s latency = 23.4ms (25.45% saturation) (11 count)
165
+ *** Min latency 2X 303/s latency = 52.7ms (1596.21% saturation) (304 count)
166
+ 100ms latency 368/s latency = 86.8ms (3191.19% saturation) (384 count)
167
+ */
168
+
169
+
170
+ /* Same test on MongoDB
171
+ 1s test time
172
+ writeSpec: new DriftValues({ count: 1, modulus: 50 * 50, driftFraction: 0.1 }),
173
+ Suggestions
174
+ Min latency 214/s latency = 4.68ms (24.53% saturation) (53 count)
175
+ *** Min latency 2X 4467/s latency = 7.14ms (3190.04% saturation) (4485 count)
176
+ 100ms latency 4768/s latency = 104ms (49459.71% saturation) (4983 count)
177
+ !!!! ERROR !!!!: 534 indexes were wrong, 1.80% of operations were missed
178
+
179
+ So mongo has about 1/4 the latency and 15X the throughput.
180
+ - Although, only 10X the throughput if we oversaturate our server and allow our latency to jump to 76.6ms.
181
+ WHICH, is fair, because the clientside predicts all the values, so the perceived latency will still usually be 0ms.
182
+ - ALSO, technically our perceived latency will be 0ms, at least for writes, due to client side prediction.
183
+ - ALSO, on any reasonable network the latency will be MUCH higher than 7ms, or 26ms, due to the network latency.
184
+ Except due to clientside prediction, Querysub will again, have 0ms perceived latency, so... our latency is
185
+ actually MUCH better.
186
+ - The throughput different is promising, considering how we use javascript (and worse, Proxies) for everything. Also,
187
+ we are bottlenecked on function evaluation, which technically evaluates arbitrary application functions, which makes
188
+ it significantly more powerful than what mongodb support.
189
+ - The overwhelming majority of our time is spent in function evaluation (~80%), which is quite isolated, so
190
+ optimization should be possible (ex, rewriting FunctionRunner to run in another language, to run
191
+ specially application optimized functions in that other language).
192
+ */
193
+