querysub 0.252.0 → 0.254.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.
@@ -1,62 +1,4 @@
1
- Ugh...
2
- 1) Our local http server can't talk to the remote PathValueServer server?
3
- 2) The remote http server isn't loading the modules?
4
- - Which... come from permissions, and so the PathValueServer?
5
- - Ah, and, it can't find the PathValueServer either?
6
-
7
- OH! It is... that we keep picking the wrong server, thinking it is working, but it has an old config?
8
-
9
- bd6cf9eb4accffba8
10
-
11
- 4) Add 2X redundancy to PathValueServer, and... FunctionRunner?
12
-
13
-
14
- 5) Setup on our regular digital ocean server
15
- - Setup all the services in the new UI
16
- - Copy from the previous startup.sh, running the same services
17
- - Changing the UI if anything is extremely annoying, but... I don't see how it would be...
18
- tmux send-keys -t server1 "cd ~/cyoa && yarn server-public" Enter
19
- tmux send-keys -t server2 "cd ~/cyoa && yarn server-public" Enter
20
- tmux send-keys -t fnc "cd ~/cyoa && yarn function-public --verbosecalls" Enter
21
-
22
- tmux send-keys -t http "cd ~/cyoa && yarn cyoa-public --verbosecalls" Enter
23
- tmux send-keys -t watch "cd ~/cyoa && yarn gc-watch-public" Enter
24
- tmux send-keys -t join "cd ~/cyoa && yarn join-public" Enter
25
- 5) Verify the editor works
26
-
27
-
28
-
29
-
30
- 8) REIMPLEMENT yarn do-update functionality, with UI on the configuration page
31
- - Components
32
- <UpdateButtons />
33
- - Commit all (add, commit, push)
34
- - Only shows up if there are unsaved changes
35
- - Commit querysub (publish, add, commit, push querysub, update package.json of app, add, commit, push)
36
- - Only shows up if there are unsaved changes
37
- - Deploy all (set hash to latest and save)
38
- - Only shows up if (any) deployed hashes differ from latest for app
39
- <UpdateServiceButtons service={serviceConfig} />
40
- - Commit (add, commit, push)
41
- - Only shows up if there are unsaved changes
42
- - Deploy (set hash to latest and save)
43
- - Only shows up if deployed hash differ from latest for app
44
- - Endpoints
45
- - anyQuerysubUnsaved
46
- - anyAppUnsaved
47
- - querysubLatestHash
48
- - appLatestHash (already have this)
49
- - publish, add, commit, and push querysub (and update app package.json reference)
50
- - add, commit and push app
51
-
52
- - On services list page, and individual service page
53
- - So... maybe the button a component
54
- - MULTIPLE buttons, to just update the main site, just querysub, or both
55
- - Button to update on each service where the repoUrl === the repoUrl of the server
56
- - Only from a non-public server
57
- - ALSO, button to update all (that match repoUrl)
58
- - Commit, push, update hash
59
- - Also with an option to also update querysub (it'll tell us if querysub has changes), updating package.json to
1
+ OH, okay, so... we DO need machine update support, because... we will need to update them
60
2
 
61
3
 
62
4
  7) Quick node removal on process crash OR removal
@@ -67,6 +9,8 @@ bd6cf9eb4accffba8
67
9
 
68
10
 
69
11
  In general, hit our servers hard, to make sure we can launch them, they can talk to each other, etc. Even with entirely new folders (to somewhat emulate another machine), and they can all startup smoothly.
12
+
13
+ AH, I think I fixed that bug. I think it was an issue with using old hosts?
70
14
  6) BUG! On startup, new nodes might take a poll interval to be fully ready? Hmm... we should restart our servers a lot again to make sure they come back up QUICKLY
71
15
  - OH! It might be that the identity takes some time to propagate (the DNS), which causes us to require a second poll to be alive? Maybe... our local machine deleted it, because it couldn't see the DNS? No... none of these are reasonable...
72
16
  - Try changing the key, so it syncs again, so we start fresh with the server
@@ -76,9 +20,6 @@ In general, hit our servers hard, to make sure we can launch them, they can talk
76
20
  FORTUNATELY, looking at logs is now very simple, as well as updating nodes, so... this shouldn't be too hard to debug
77
21
 
78
22
 
79
- 6) Verify PathValueServer gracefully shutdowns, not losing any values (because it delays and flushes writes before shutting down, detecting the ctrl+c).
80
-
81
-
82
23
  8) Fix deploy user notification issue, where the refresh button doesn't work?
83
24
 
84
25
  9) Rolling service updates
@@ -2,7 +2,6 @@ import { URLParam } from "../library-components/URLParam";
2
2
 
3
3
  export type ViewType = "services" | "machines" | "service-detail" | "machine-detail";
4
4
 
5
- // URL Parameters for navigation state
6
5
  export const currentViewParam = new URLParam<ViewType>("machineview", "machines");
7
6
  export const selectedServiceIdParam = new URLParam("serviceId", "");
8
7
  export const selectedMachineIdParam = new URLParam("machineId", "");
@@ -140,6 +140,7 @@ let ensureBlocksFlushing = lazy(() => {
140
140
  let pendingLogs: { log: LogRaw; type: LogType }[] = [];
141
141
  let logClassifier: ((log: LogRaw, typeHint: LogType) => LogClass) | undefined;
142
142
  let initLogClassifier = lazy(async () => {
143
+ if (!isNode()) return null as never;
143
144
  let logClasses = await new ErrorLogControllerBase().getClasses();
144
145
  logClassifier = getLogClassCategorizer(logClasses);
145
146
  if (pendingLogs.length > 0) {
@@ -284,6 +284,12 @@ export class SuppressUntil extends qreact.Component<{
284
284
  </>
285
285
  )}
286
286
  </div>
287
+ {type !== "info" && <Button
288
+ onClick={() => updateClass({ suppressUntil: changeTime })}
289
+ class={css.hsl(infoColor.h, infoColor.s, infoColor.l)}
290
+ >
291
+ Fixed
292
+ </Button>}
287
293
  {type !== "info" && <Button
288
294
  onClick={() => updateClass({ type: "info" })}
289
295
  class={css.hsl(infoColor.h, infoColor.s, infoColor.l)}
@@ -8,12 +8,16 @@ import { formatTime } from "socket-function/src/formatting/format";
8
8
  import { nextId } from "socket-function/src/misc";
9
9
  import { getCallObj } from "socket-function/src/nodeProxy";
10
10
  import { MaybePromise } from "socket-function/src/types";
11
+ import { isNode } from "typesafecss";
11
12
 
12
13
  // IMPORTANT! See cacheAsyncSynced if you just want to run promise functions
13
14
 
14
15
  let controllerIds = new Set<string>();
15
16
 
16
17
  module.hotreload = false;
18
+ // NOTE: Most SyncedController are defined in files we don't hotreload anyways, so the page will refresh on changes. And if they aren't... they should be.
19
+ // - And if we reload all the calls on hot reload, it makes iterating on the UI extremely annoying. So... we don't anymore.
20
+ /*
17
21
  onHotReload(() => {
18
22
  Querysub.commitLocal(() => {
19
23
  let root = syncedData();
@@ -31,14 +35,15 @@ onHotReload(() => {
31
35
  }
32
36
  });
33
37
  });
38
+ */
34
39
 
35
40
  export function syncedIsAnyLoading() {
36
41
  return Querysub.fastRead(() => {
37
42
  for (let controllerId in syncedData()) {
38
- for (let nodeId in syncedData()[controllerId]) {
39
- for (let fnc in syncedData()[controllerId][nodeId]) {
40
- for (let argsHash in syncedData()[controllerId][nodeId][fnc]) {
41
- if (atomic(syncedData()[controllerId][nodeId][fnc][argsHash].promise)) {
43
+ for (let fncs of Object.values(syncedData()[controllerId])) {
44
+ for (let fnc of Object.values(fncs)) {
45
+ for (let obj of Object.values(fnc)) {
46
+ if (atomic(obj.promise)) {
42
47
  return true;
43
48
  }
44
49
  }
@@ -103,6 +108,58 @@ export function getSyncedController<T extends SocketRegistered>(
103
108
  refreshAll(): void;
104
109
  isAnyLoading(): boolean;
105
110
  } {
111
+ if (isNode()) {
112
+ let result = cache((nodeId: string) => {
113
+ let proxy = new Proxy({}, {
114
+ get: (target, fncNameUntyped) => {
115
+ if (typeof fncNameUntyped !== "string") return undefined;
116
+ if (fncNameUntyped === "resetAll" || fncNameUntyped === "refreshAll" || fncNameUntyped === "isAnyLoading") {
117
+ return notAllowedOnServer;
118
+ }
119
+ let fncName = fncNameUntyped;
120
+ function call(...args: any[]) {
121
+ notAllowedOnServer();
122
+ }
123
+ call.promise = (...args: any[]) => {
124
+ return controller.nodes[nodeId][fncName](...args);
125
+ };
126
+ call.reset = (...args: any[]) => {
127
+ notAllowedOnServer();
128
+ };
129
+ call.resetAll = () => {
130
+ notAllowedOnServer();
131
+ };
132
+ call.refresh = (...args: any[]) => {
133
+ notAllowedOnServer();
134
+ };
135
+ call.refreshAll = () => {
136
+ notAllowedOnServer();
137
+ };
138
+ call.isAnyLoading = () => {
139
+ notAllowedOnServer();
140
+ };
141
+ call.setCache = (config: { args: any[], result: any }) => {
142
+ notAllowedOnServer();
143
+ };
144
+ return call;
145
+ }
146
+ }) as any;
147
+ return proxy;
148
+ }) as any;
149
+ function notAllowedOnServer() {
150
+ throw new Error(`Syncing with getSyncedController is not allowed on the server. If we absolutely need this we can support it, but... you should just be using raw synced state anyways.`);
151
+ }
152
+ result.resetAll = () => {
153
+ notAllowedOnServer();
154
+ };
155
+ result.refreshAll = () => {
156
+ notAllowedOnServer();
157
+ };
158
+ result.isAnyLoading = () => {
159
+ notAllowedOnServer();
160
+ };
161
+ return result;
162
+ }
106
163
  let id = nextId();
107
164
  controllerIds.add(id);
108
165
 
@@ -151,9 +208,9 @@ export function getSyncedController<T extends SocketRegistered>(
151
208
  if (fncNameUntyped === "refreshAll") {
152
209
  return () => {
153
210
  return Querysub.commitLocal(() => {
154
- for (let fnc in syncedData()[id][nodeId]) {
155
- for (let argsHash in syncedData()[id][nodeId][fnc]) {
156
- syncedData()[id][nodeId][fnc][argsHash].invalidated = true;
211
+ for (let fnc of Object.values(syncedData()[id][nodeId])) {
212
+ for (let obj of Object.values(fnc)) {
213
+ obj.invalidated = true;
157
214
  }
158
215
  }
159
216
  });
@@ -162,9 +219,9 @@ export function getSyncedController<T extends SocketRegistered>(
162
219
  if (fncNameUntyped === "isAnyLoading") {
163
220
  return () => {
164
221
  return Querysub.commitLocal(() => {
165
- for (let fnc in syncedData()[id][nodeId]) {
166
- for (let argsHash in syncedData()[id][nodeId][fnc]) {
167
- if (atomic(syncedData()[id][nodeId][fnc][argsHash].promise)) {
222
+ for (let fnc of Object.values(syncedData()[id][nodeId])) {
223
+ for (let obj of Object.values(fnc)) {
224
+ if (atomic(obj.promise)) {
168
225
  return true;
169
226
  }
170
227
  }
@@ -195,14 +252,13 @@ export function getSyncedController<T extends SocketRegistered>(
195
252
  doAtomicWrites(() => {
196
253
  obj.promise = promise;
197
254
  });
198
- function invalidateAll() {
255
+ function invalidateReaders() {
199
256
  let root = syncedData();
200
257
  for (let writesTo of config?.writes?.[fncName] || []) {
201
258
  for (let watcher of writeWatchers.get(writesTo) || []) {
202
- for (let nodeId in root[watcher.controllerId]) {
203
- for (let fnc in root[watcher.controllerId][nodeId]) {
204
- for (let argsHash in root[watcher.controllerId][nodeId][fnc]) {
205
- let obj = root[watcher.controllerId][nodeId][fnc][argsHash];
259
+ for (let fncs of Object.values(root[watcher.controllerId])) {
260
+ for (let fnc of Object.values(fncs)) {
261
+ for (let obj of Object.values(fnc)) {
206
262
  obj.invalidated = true;
207
263
  }
208
264
  }
@@ -216,7 +272,7 @@ export function getSyncedController<T extends SocketRegistered>(
216
272
  Querysub.commitLocal(() => {
217
273
  obj.result = atomicObjectWriteNoFreeze({ result });
218
274
  obj.promise = undefined;
219
- invalidateAll();
275
+ invalidateReaders();
220
276
  });
221
277
  },
222
278
  error => {
@@ -224,7 +280,7 @@ export function getSyncedController<T extends SocketRegistered>(
224
280
  Querysub.commitLocal(() => {
225
281
  obj.result = atomicObjectWriteNoFreeze({ error });
226
282
  obj.promise = undefined;
227
- invalidateAll();
283
+ invalidateReaders();
228
284
  });
229
285
  }
230
286
  );
@@ -243,9 +299,13 @@ export function getSyncedController<T extends SocketRegistered>(
243
299
  }
244
300
  call.promise = (...args: any[]) => {
245
301
  return Querysub.fastRead(() => {
246
- call(...args);
247
302
  let argsHash = JSON.stringify(args);
248
- let promise = atomic(syncedData()[id][nodeId][fncName][argsHash].promise);
303
+ let obj = syncedData()[id][nodeId][fncName][argsHash];
304
+ // Reset promise, to force it to not use the cache, as promise functions should never be cached. This might result in the results being set out of order, but... generally functions called with promise and accessed inside a watcher, so this should be fine.
305
+ obj.promise = undefined;
306
+ obj.invalidated = true;
307
+ call(...args);
308
+ let promise = atomic(obj.promise);
249
309
  if (!promise) {
250
310
  debugger;
251
311
  throw new Error(`Impossible, called function, but promise is not found for ${fncName}`);
@@ -279,15 +339,15 @@ export function getSyncedController<T extends SocketRegistered>(
279
339
  };
280
340
  call.refreshAll = () => {
281
341
  return Querysub.commitLocal(() => {
282
- for (let argsHash in syncedData()[id][nodeId][fncName]) {
283
- syncedData()[id][nodeId][fncName][argsHash].invalidated = true;
342
+ for (let obj of Object.values(syncedData()[id][nodeId][fncName])) {
343
+ obj.invalidated = true;
284
344
  }
285
345
  });
286
346
  };
287
347
  call.isAnyLoading = () => {
288
348
  return Querysub.commitLocal(() => {
289
- for (let argsHash in syncedData()[id][nodeId][fncName]) {
290
- if (atomic(syncedData()[id][nodeId][fncName][argsHash].promise)) {
349
+ for (let obj of Object.values(syncedData()[id][nodeId][fncName])) {
350
+ if (atomic(obj.promise)) {
291
351
  return true;
292
352
  }
293
353
  }
@@ -320,10 +380,10 @@ export function getSyncedController<T extends SocketRegistered>(
320
380
  };
321
381
  result.refreshAll = () => {
322
382
  return Querysub.commitLocal(() => {
323
- for (let nodeId in syncedData()[id]) {
324
- for (let fnc in syncedData()[id][nodeId]) {
325
- for (let argsHash in syncedData()[id][nodeId][fnc]) {
326
- syncedData()[id][nodeId][fnc][argsHash].invalidated = true;
383
+ for (let fncs of Object.values(syncedData()[id])) {
384
+ for (let fnc of Object.values(fncs)) {
385
+ for (let obj of Object.values(fnc)) {
386
+ obj.invalidated = true;
327
387
  }
328
388
  }
329
389
  }
@@ -331,10 +391,10 @@ export function getSyncedController<T extends SocketRegistered>(
331
391
  };
332
392
  result.isAnyLoading = () => {
333
393
  return Querysub.commitLocal(() => {
334
- for (let nodeId in syncedData()[id]) {
335
- for (let fnc in syncedData()[id][nodeId]) {
336
- for (let argsHash in syncedData()[id][nodeId][fnc]) {
337
- if (atomic(syncedData()[id][nodeId][fnc][argsHash].promise)) {
394
+ for (let fncs of Object.values(syncedData()[id])) {
395
+ for (let fnc of Object.values(fncs)) {
396
+ for (let obj of Object.values(fnc)) {
397
+ if (atomic(obj.promise)) {
338
398
  return true;
339
399
  }
340
400
  }
@@ -0,0 +1,6 @@
1
+ import { qreact } from "../4-dom/qreact";
2
+ import { formatTime, formatVeryNiceDateTime } from "socket-function/src/formatting/format";
3
+
4
+ export function formatTimeJSX(time: number) {
5
+ return <span title={formatVeryNiceDateTime(time)}>({formatTime(Date.now() - time)})</span>;
6
+ }