querysub 0.358.0 → 0.359.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.358.0",
3
+ "version": "0.359.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,4 +1,5 @@
1
1
  import { isNode } from "socket-function/src/misc";
2
+ import os from "os";
2
3
  import { fsExistsAsync, getSubFolder } from "../fs";
3
4
  import fs from "fs";
4
5
  import { blue, red, yellow } from "socket-function/src/formatting/logColors";
@@ -440,5 +441,15 @@ export const getArchivesLocal = cache((domain: string): Archives => {
440
441
  archivesLocal.LOCAL_ARCHIVE_FOLDER = getSubFolder(domain).replaceAll("\\", "/");
441
442
  }
442
443
 
444
+ return archivesLocal;
445
+ });
446
+
447
+ export const getArchivesHome = cache((domain: string): Archives => {
448
+ const archivesLocal = new ArchivesDisk();
449
+
450
+ if (isNode()) {
451
+ archivesLocal.LOCAL_ARCHIVE_FOLDER = os.homedir() + "/querysub/" + domain + "/";
452
+ }
453
+
443
454
  return archivesLocal;
444
455
  });
@@ -118,8 +118,8 @@ export class MachineDetailPage extends qreact.Component {
118
118
  <div className={css.vbox(10)}>
119
119
  {Object.entries(machine.info).map(([key, value]) => (
120
120
  <div key={key} className={css.hbox(10).hsla(0, 0, 0, 0.1).pad2(10, 2)}>
121
- <b>{key}:</b>
122
- <ShowMore className={css.whiteSpace("pre-wrap")} maxHeight={40}>
121
+ <b className={css.flexShrink0}>{key}:</b>
122
+ <ShowMore className={css.whiteSpace("pre-wrap")} maxHeight={80}>
123
123
  {(() => {
124
124
  if (typeof value === "object") {
125
125
  return <div className={css.pad2(6, 2).hsla(0, 0, 0, 0.1).relative}>
@@ -157,9 +157,11 @@ export class ServiceDetailPage extends qreact.Component {
157
157
  let index = nextIndexes.get(machineId) || 0;
158
158
  nextIndexes.set(machineId, index + 1);
159
159
  let machineInfo = controller.getMachineInfo(machineId);
160
+ let machineConfig = controller.getMachineConfig(machineId);
160
161
  const serviceInfo = machineInfo?.services[selectedServiceId || ""];
161
162
  const isMachineDead = machineInfo ? Date.now() - machineInfo.heartbeat > (MACHINE_RESYNC_INTERVAL * 4) : true;
162
163
  const hasError = serviceInfo?.errorFromLastRun;
164
+ const isDisabled = machineConfig?.disabled || false;
163
165
 
164
166
  return {
165
167
  machineId,
@@ -167,11 +169,12 @@ export class ServiceDetailPage extends qreact.Component {
167
169
  serviceInfo,
168
170
  isMachineDead,
169
171
  hasError,
172
+ isDisabled,
170
173
  heartbeat: machineInfo?.heartbeat || 0,
171
174
  index
172
175
  };
173
176
  });
174
- sort(machineStatuses, x => (x.hasError ? 0 : x.isMachineDead ? 1 : 2) * 1000000 + x.heartbeat);
177
+ sort(machineStatuses, x => (x.isDisabled ? 3 : x.hasError ? 0 : x.isMachineDead ? 1 : 2) * 1000000 + x.heartbeat);
175
178
  let now = Date.now();
176
179
 
177
180
  let machines = (controller.getMachineList() || []).map(x => controller.getMachineInfo(x)).filter(isDefined);
@@ -253,11 +256,13 @@ export class ServiceDetailPage extends qreact.Component {
253
256
  {configT.parameters.deploy && <div className={css.vbox(8).fillWidth}>
254
257
  <h3>Deployed Machines ({config.machineIds.length})</h3>
255
258
  <div className={css.vbox(4).fillWidth}>
256
- {machineStatuses.map(({ machineId, machineInfo, serviceInfo, isMachineDead, hasError, index }) => {
259
+ {machineStatuses.map(({ machineId, machineInfo, serviceInfo, isMachineDead, hasError, isDisabled, index }) => {
257
260
  if (!machineInfo) return <div key={machineId}>Loading {machineId}...</div>;
258
261
 
259
262
  let backgroundColor = css.hsl(0, 0, 100); // Default: white
260
- if (hasError) {
263
+ if (isDisabled) {
264
+ backgroundColor = css.hsl(0, 0, 50); // Gray for disabled machines
265
+ } else if (hasError) {
261
266
  backgroundColor = css.hsl(0, 70, 90); // Red-ish for errors
262
267
  } else if (isMachineDead) {
263
268
  backgroundColor = css.hsl(0, 0, 50); // Gray for dead machines
@@ -281,6 +286,11 @@ export class ServiceDetailPage extends qreact.Component {
281
286
  {machineId} ({machineInfo.info["getExternalIP"]})
282
287
  </div>
283
288
  </div>
289
+ {isDisabled && (
290
+ <div className={css.colorhsl(0, 0, 30)}>
291
+ 🚫 Machine Disabled
292
+ </div>
293
+ )}
284
294
  {isMachineDead && (
285
295
  <div className={css.colorhsl(0, 80, 50)}>
286
296
  ⚠️ Machine Dead
@@ -21,6 +21,7 @@ export class ServicesListPage extends qreact.Component {
21
21
  render() {
22
22
  let controller = MachineServiceController(SocketFunction.browserNodeId());
23
23
  let serviceList = controller.getServiceList();
24
+ let machineConfigList = controller.getMachineConfigList();
24
25
 
25
26
  if (!serviceList) return <div>Loading services...</div>;
26
27
 
@@ -28,6 +29,7 @@ export class ServicesListPage extends qreact.Component {
28
29
  sort(services, x => -(x[1]?.info.lastUpdatedTime || Date.now()) - (x[1]?.parameters.deploy && (Number.MAX_SAFE_INTEGER / 2) || 0));
29
30
 
30
31
  let getMachineInfo = cache((machineId: string) => controller.getMachineInfo(machineId));
32
+ let getMachineConfig = cache((machineId: string) => controller.getMachineConfig(machineId));
31
33
 
32
34
  let keyCounts = new Map<string, number>();
33
35
  for (let [serviceId, config] of services) {
@@ -75,24 +77,34 @@ export class ServicesListPage extends qreact.Component {
75
77
  <div className={css.vbox(8)}>
76
78
  {services.map(([serviceId, config]) => {
77
79
  if (!config) return <div key={serviceId}>Config is broken? Missing value for service? Is the file corrupted?</div>;
78
- let failingMachines = config.machineIds.filter(machineId => {
80
+
81
+ let disabledMachines = config.machineIds.filter(machineId => {
82
+ let machineConfig = getMachineConfig(machineId);
83
+ return machineConfig?.disabled;
84
+ });
85
+ let enabledMachineIds = config.machineIds.filter(machineId => {
86
+ let machineConfig = getMachineConfig(machineId);
87
+ return !machineConfig?.disabled;
88
+ });
89
+
90
+ let failingMachines = enabledMachineIds.filter(machineId => {
79
91
  let machineInfo = getMachineInfo(machineId);
80
92
  return machineInfo?.services[serviceId]?.errorFromLastRun;
81
93
  });
82
- let runningMachines = config.machineIds.filter(machineId => {
94
+ let runningMachines = enabledMachineIds.filter(machineId => {
83
95
  let machineInfo = getMachineInfo(machineId);
84
96
  let serviceInfo = machineInfo?.services[serviceId];
85
97
  return serviceInfo && !serviceInfo.errorFromLastRun;
86
98
  });
87
- let missingMachines = config.machineIds.filter(machineId => {
99
+ let missingMachines = enabledMachineIds.filter(machineId => {
88
100
  let machineInfo = getMachineInfo(machineId);
89
101
  return !machineInfo?.services[serviceId];
90
102
  });
91
- let totalLaunches = config.machineIds.reduce((acc, machineId) => {
103
+ let totalLaunches = enabledMachineIds.reduce((acc, machineId) => {
92
104
  let machineInfo = getMachineInfo(machineId);
93
105
  return acc + (machineInfo?.services[serviceId]?.totalTimesLaunched || 0);
94
106
  }, 0);
95
- let unknown = config.machineIds.length - runningMachines.length - failingMachines.length - missingMachines.length;
107
+ let unknown = enabledMachineIds.length - runningMachines.length - failingMachines.length - missingMachines.length;
96
108
  let duplicateKey = (keyCounts.get(config.parameters.key || "") || 0) > 1;
97
109
  return <div className={css.hbox(10)}>
98
110
  <Anchor noStyles key={serviceId}
@@ -118,7 +130,7 @@ export class ServicesListPage extends qreact.Component {
118
130
  {config.parameters.key}
119
131
  </div>
120
132
  <div>
121
- {config.machineIds.length} configured {failingMachines.length > 0 && `(${failingMachines.length} failing)`} {missingMachines.length > 0 && `(${missingMachines.length} machine hasn't run service yet)`} {unknown > 0 && `(${unknown} unknown)`} • {totalLaunches} launches •
133
+ {enabledMachineIds.length} configured {disabledMachines.length > 0 && `(+${disabledMachines.length} on disabled machines)`} {failingMachines.length > 0 && `(${failingMachines.length} failing)`} {missingMachines.length > 0 && `(${missingMachines.length} machine hasn't run service yet)`} {unknown > 0 && `(${unknown} unknown)`} • {totalLaunches} launches •
122
134
  Deploy: {config.parameters.deploy ? "enabled" : "disabled"}
123
135
  </div>
124
136
  </div>
@@ -5,7 +5,7 @@ import { BufferIndex } from "./BufferIndex";
5
5
  import { delay, runInParallel, runInSerial, runInfinitePoll } from "socket-function/src/batching";
6
6
  import { IndexedLogResults, Reader, SearchParams, addReadToResults, createEmptyIndexedLogResults, INDEX_EXTENSION } from "./BufferIndexHelpers";
7
7
  import { getDomain, isPublic } from "../../../config";
8
- import { getArchivesLocal } from "../../../-a-archives/archivesDisk";
8
+ import { getArchivesHome, getArchivesLocal } from "../../../-a-archives/archivesDisk";
9
9
  import { getArchivesBackblaze, getArchivesBackblazePrivateImmutable } from "../../../-a-archives/archivesBackBlaze";
10
10
  import { getOwnThreadId } from "../../../-a-auth/certs";
11
11
  import { ArchivesMemoryCacheStats, createArchivesMemoryCache } from "../../../-a-archives/archivesMemoryCache";
@@ -53,78 +53,6 @@ export class IndexedLogs<T> {
53
53
  }
54
54
  }
55
55
 
56
- private findCallbacks = new Map<string, (match: T) => void>();
57
- private resultsCallbacks = new Map<string, (results: IndexedLogResults) => void>();
58
- public async clientFind(config: {
59
- params: SearchParams;
60
- onResult: (match: T) => void;
61
- onResults?: (results: IndexedLogResults) => void;
62
- }): Promise<IndexedLogResults> {
63
- let controller = IndexedLogShimController.nodes[SocketFunction.getBrowserNodeId()];
64
- let findId = nextId();
65
- let callback = (match: T) => {
66
- config.onResult(match);
67
- };
68
- this.findCallbacks.set(findId, callback);
69
- if (config.onResults) {
70
- this.resultsCallbacks.set(findId, config.onResults);
71
- }
72
- try {
73
- return await controller.find({
74
- findId,
75
- indexedLogsName: this.config.name,
76
- params: config.params,
77
- });
78
- } finally {
79
- // There's some trailing time after the controller call finishes when the results will be trickling back to us.
80
- setTimeout(() => {
81
- this.findCallbacks.delete(findId);
82
- this.resultsCallbacks.delete(findId);
83
- }, timeInMinute * 30);
84
- }
85
- }
86
- public clientCancelAllCallbacks() {
87
- this.findCallbacks.clear();
88
- this.resultsCallbacks.clear();
89
- }
90
- public async clientGetPaths(config: {
91
- startTime: number;
92
- endTime: number;
93
- only?: "local" | "public";
94
- }): Promise<TimeFilePathWithSize[]> {
95
- let controller = IndexedLogShimController.nodes[SocketFunction.getBrowserNodeId()];
96
- return await controller.getPaths({
97
- indexedLogsName: this.config.name,
98
- startTime: config.startTime,
99
- endTime: config.endTime,
100
- only: config.only,
101
- });
102
- }
103
- public onFindResult(config: {
104
- findId: string;
105
- result: unknown;
106
- }) {
107
- let callback = this.findCallbacks.get(config.findId);
108
- if (!callback) throw new Error(`Find callback ${config.findId} not found`);
109
- callback(config.result as T);
110
- }
111
- public async onResults(config: {
112
- findId: string;
113
- results: IndexedLogResults;
114
- }): Promise<boolean> {
115
- let callback = this.resultsCallbacks.get(config.findId);
116
- if (!callback) throw new Error(`Results callback ${config.findId} not found`);
117
- callback(config.results);
118
- return true;
119
- }
120
-
121
- public async clientForceMoveLogsToPublic() {
122
- let controller = IndexedLogShimController.nodes[SocketFunction.getBrowserNodeId()];
123
- await controller.forceMoveLogsToPublic({
124
- indexedLogsName: this.config.name,
125
- });
126
- }
127
-
128
56
  private localLogsStats = {
129
57
  cachedReads: 0,
130
58
  uncachedReads: 0,
@@ -145,7 +73,7 @@ export class IndexedLogs<T> {
145
73
  private fileSizeCache = new Map<string, number>();
146
74
 
147
75
  private getLocalLogs = lazy((): Archives => {
148
- let baseDisk = getArchivesLocal(getDomain());
76
+ let baseDisk = getArchivesHome(getDomain());
149
77
  let archives = nestArchives("indexed-logs/" + this.config.name, baseDisk);
150
78
  archives = createArchivesMemoryCache(archives, {
151
79
  maxSize: 1024 * 1024 * 512,
@@ -158,7 +86,7 @@ export class IndexedLogs<T> {
158
86
  return archives;
159
87
  });
160
88
  private getPublicLogs = lazy((): Archives => {
161
- let basePublic: Archives = getArchivesLocal(getDomain());
89
+ let basePublic: Archives = getArchivesHome(getDomain());
162
90
  // NOTE: The local disk is so fast that reading in 10 megabytes is nothing, And if we read in too small of a value, the overhead per read ends up making this take forever.
163
91
  let extraReadSize = 1024 * 1024 * 10;
164
92
  if (this.config.forceUsePublicLogs || isPublic()) {
@@ -547,6 +475,80 @@ export class IndexedLogs<T> {
547
475
  }
548
476
 
549
477
 
478
+ // #region Client Calls
479
+ private findCallbacks = new Map<string, (match: T) => void>();
480
+ private resultsCallbacks = new Map<string, (results: IndexedLogResults) => void>();
481
+ public async clientFind(config: {
482
+ params: SearchParams;
483
+ onResult: (match: T) => void;
484
+ onResults?: (results: IndexedLogResults) => void;
485
+ }): Promise<IndexedLogResults> {
486
+ let controller = IndexedLogShimController.nodes[SocketFunction.getBrowserNodeId()];
487
+ let findId = nextId();
488
+ let callback = (match: T) => {
489
+ config.onResult(match);
490
+ };
491
+ this.findCallbacks.set(findId, callback);
492
+ if (config.onResults) {
493
+ this.resultsCallbacks.set(findId, config.onResults);
494
+ }
495
+ try {
496
+ return await controller.find({
497
+ findId,
498
+ indexedLogsName: this.config.name,
499
+ params: config.params,
500
+ });
501
+ } finally {
502
+ // There's some trailing time after the controller call finishes when the results will be trickling back to us.
503
+ setTimeout(() => {
504
+ this.findCallbacks.delete(findId);
505
+ this.resultsCallbacks.delete(findId);
506
+ }, timeInMinute * 30);
507
+ }
508
+ }
509
+ public clientCancelAllCallbacks() {
510
+ this.findCallbacks.clear();
511
+ this.resultsCallbacks.clear();
512
+ }
513
+ public async clientGetPaths(config: {
514
+ startTime: number;
515
+ endTime: number;
516
+ only?: "local" | "public";
517
+ }): Promise<TimeFilePathWithSize[]> {
518
+ let controller = IndexedLogShimController.nodes[SocketFunction.getBrowserNodeId()];
519
+ return await controller.getPaths({
520
+ indexedLogsName: this.config.name,
521
+ startTime: config.startTime,
522
+ endTime: config.endTime,
523
+ only: config.only,
524
+ });
525
+ }
526
+ public onFindResult(config: {
527
+ findId: string;
528
+ result: unknown;
529
+ }) {
530
+ let callback = this.findCallbacks.get(config.findId);
531
+ if (!callback) throw new Error(`Find callback ${config.findId} not found`);
532
+ callback(config.result as T);
533
+ }
534
+ public async onResults(config: {
535
+ findId: string;
536
+ results: IndexedLogResults;
537
+ }): Promise<boolean> {
538
+ let callback = this.resultsCallbacks.get(config.findId);
539
+ if (!callback) throw new Error(`Results callback ${config.findId} not found`);
540
+ callback(config.results);
541
+ return true;
542
+ }
543
+
544
+ public async clientForceMoveLogsToPublic() {
545
+ let controller = IndexedLogShimController.nodes[SocketFunction.getBrowserNodeId()];
546
+ await controller.forceMoveLogsToPublic({
547
+ indexedLogsName: this.config.name,
548
+ });
549
+ }
550
+ // #endregion
551
+
550
552
 
551
553
  // TEST functions
552
554
  public async TEST_flushNow() {
@@ -854,6 +854,11 @@ export class LogViewer3 extends qreact.Component {
854
854
  >
855
855
  {savedPathsURL.value ? `Clear Frozen Files (${this.getPaths().length})` : `Freeze Files (${this.state.paths.length})`}
856
856
  </Button>
857
+ {!savedPathsURL.value && (
858
+ <div className={css.pad2(8, 4).hsl(40, 60, 50).colorhsl(40, 0, 100)}>
859
+ Files frozen in memory. Click Preview Files to refresh.
860
+ </div>
861
+ )}
857
862
  {(() => {
858
863
  if (!savedPathsURL.value) return undefined;
859
864
  const paths = this.getPaths();
@@ -19,12 +19,11 @@ IMPORTANT! Now I am properly calling shutdown, so none of the streamed logs shou
19
19
 
20
20
 
21
21
 
22
- 4) Make it easy to enable or disable an entire server, regardless of what services are on it.
23
- - This is annoying, but it would be very useful. I think the apply loop can probably figure it out. We should probably ask the AI to do it. I'm sure it'll fuck it up, but it'll give us a start at least. And we can also just tell it, okay, find the actual code that we're going to need to change, but not change it, and just keep and maybe even have it put a comment there. And then we just keep doing that until we're absolutely certain that we found every place that we need to change to make this work. And then the AI might be able to help with the refactor.
24
- 3) Start the servers again, and deploy all of our code
22
+ OH! The archives have to be put in the home folder. They aren't?
25
23
 
26
- 2) Create lot of remote server logs
27
- - Via our refresh loop
24
+
25
+ Hmm... why are not enough logs appearing?
26
+ - We only have logs for server.ts? Wtf?
28
27
 
29
28
  2.0) SUPPORT reading pending from multiple servers
30
29
  - The main controller has to find a node on each other machine, and call it. Only one node per machine though, so it shouldn't be too difficult.
@@ -35,6 +34,14 @@ IMPORTANT! Now I am properly calling shutdown, so none of the streamed logs shou
35
34
  2) Add a UI toggle to read public logs (only shows up on a non-public server though, as otherwise it wouldn't make sense)
36
35
  - Basically, just changes the code we're reading from multiple servers to select public servers instead, and then, of course, skip ourselves.
37
36
 
37
+ BUG: UGH... live logs for the remote server isn't working...
38
+ "new non-local WATCH"
39
+ - UGH... it being pending logs is annoying, as that's hard to debug locally...
40
+ AH! Why do we have so few logs?
41
+
42
+ 2) Create lot of remote server logs
43
+ - Via our refresh loop
44
+
38
45
  3) Verify true remote reads are reasonable fast
39
46
 
40
47
  3) Deploy service for movelogs
@@ -63,10 +70,12 @@ Rewrite error notification code
63
70
  AND, the only watcher will be the watcher service. You can't get recent errors, or any errors, without going through one of those
64
71
  NO dev errors. They are usually red-herrings anyways... and we should just be using public servers for regular usage
65
72
  - And we still have dev logs we can check if to see if an error happened locally
73
+ ALSO owns the discord messaging code
66
74
 
67
75
 
68
76
 
69
77
  Remove all old LogViewer/FastArchiveAppendable code
78
+ - Make sure to find all links and update them as well
70
79
 
71
80
 
72
81
  0) Add LZ4 compression to socket-function by default