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.
- package/package.json +2 -2
- package/src/3-path-functions/PathFunctionRunner.ts +1 -0
- package/src/4-deploy/git.ts +34 -1
- package/src/deployManager/MachinesPage.tsx +7 -10
- package/src/deployManager/components/MachineDetailPage.tsx +13 -21
- package/src/deployManager/components/MachinesListPage.tsx +59 -48
- package/src/deployManager/components/ServiceDetailPage.tsx +7 -9
- package/src/deployManager/components/ServicesListPage.tsx +41 -31
- package/src/deployManager/components/deployButtons.tsx +217 -0
- package/src/deployManager/machineApplyMainCode.ts +10 -4
- package/src/deployManager/machineController.ts +36 -4
- package/src/deployManager/machineSchema.ts +134 -45
- package/src/deployManager/spec.txt +3 -62
- package/src/deployManager/urlParams.ts +0 -1
- package/src/diagnostics/errorLogs/ErrorLogController.ts +1 -0
- package/src/diagnostics/errorLogs/LogClassifiers.tsx +6 -0
- package/src/library-components/SyncedController.ts +91 -31
- package/src/misc/formatJSX.tsx +6 -0
|
@@ -1,62 +1,4 @@
|
|
|
1
|
-
|
|
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
|
|
39
|
-
for (let fnc
|
|
40
|
-
for (let
|
|
41
|
-
if (atomic(
|
|
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
|
|
155
|
-
for (let
|
|
156
|
-
|
|
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
|
|
166
|
-
for (let
|
|
167
|
-
if (atomic(
|
|
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
|
|
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
|
|
203
|
-
for (let fnc
|
|
204
|
-
for (let
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
283
|
-
|
|
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
|
|
290
|
-
if (atomic(
|
|
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
|
|
324
|
-
for (let fnc
|
|
325
|
-
for (let
|
|
326
|
-
|
|
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
|
|
335
|
-
for (let fnc
|
|
336
|
-
for (let
|
|
337
|
-
if (atomic(
|
|
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
|
+
}
|