querysub 0.549.0 → 0.550.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.
|
|
3
|
+
"version": "0.550.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",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"node-forge": "https://github.com/sliftist/forge#e618181b469b07bdc70b968b0391beb8ef5fecd6",
|
|
72
72
|
"pako": "^2.1.0",
|
|
73
73
|
"peggy": "^5.0.6",
|
|
74
|
-
"sliftutils": "^1.7.
|
|
74
|
+
"sliftutils": "^1.7.36",
|
|
75
75
|
"socket-function": "^1.2.26",
|
|
76
76
|
"terser": "^5.31.0",
|
|
77
77
|
"typenode": "^6.6.1",
|
|
@@ -4,14 +4,13 @@ import { css } from "typesafecss";
|
|
|
4
4
|
import { sort } from "socket-function/src/misc";
|
|
5
5
|
import { formatNumber, formatDateTime, formatTime } from "socket-function/src/formatting/format";
|
|
6
6
|
import { parseHostedUrl, parseBackblazeUrl } from "sliftutils/storage/remoteStorage/remoteConfig";
|
|
7
|
-
import {
|
|
8
|
-
import { STORAGE_ACCOUNT } from "../../-a-archives/archives2";
|
|
7
|
+
import { SocketFunction } from "socket-function/SocketFunction";
|
|
9
8
|
import { FULL_VALID_WINDOW, FULL_ROUTE } from "sliftutils/storage/IArchives";
|
|
10
9
|
import type { RemoteConfig, RemoteConfigBase, HostedConfig, BackblazeConfig } from "sliftutils/storage/IArchives";
|
|
11
10
|
import { showModal } from "../../5-diagnostics/Modal";
|
|
12
11
|
import { FullscreenModal } from "../../5-diagnostics/FullscreenModal";
|
|
13
12
|
import { Button } from "../../library-components/Button";
|
|
14
|
-
import type
|
|
13
|
+
import { StorageSynced, type StorageServerBuckets } from "./StoragePage";
|
|
15
14
|
|
|
16
15
|
module.hotreload = true;
|
|
17
16
|
|
|
@@ -250,24 +249,32 @@ async function refreshWatch(key: string): Promise<void> {
|
|
|
250
249
|
let current = liveWatchData().watches[key];
|
|
251
250
|
if (current) current.loading = true;
|
|
252
251
|
});
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
252
|
+
try {
|
|
253
|
+
// Proxied through our server, which holds the identity the storage servers authenticate against
|
|
254
|
+
let live = await StorageSynced(SocketFunction.browserNodeId()).getActiveBucket.promise(serverUrl, bucketName);
|
|
255
|
+
// "Not loaded here" comes back as a string - it's a normal result, not an error
|
|
256
|
+
let error: string | undefined;
|
|
257
|
+
let result: RemoteConfig | undefined;
|
|
258
|
+
if (typeof live === "string") {
|
|
259
|
+
error = live;
|
|
260
|
+
} else {
|
|
261
|
+
result = live.routing;
|
|
262
|
+
}
|
|
263
|
+
Querysub.commit(() => {
|
|
264
|
+
let current = liveWatchData().watches[key];
|
|
265
|
+
// The watch may have been removed while the call was in flight
|
|
266
|
+
if (!current) return;
|
|
267
|
+
current.routing = result;
|
|
268
|
+
current.error = error;
|
|
269
|
+
current.updatedTime = Date.now();
|
|
270
|
+
});
|
|
271
|
+
} finally {
|
|
272
|
+
// Without this a throw would leave the watch stuck showing "refreshing..."
|
|
273
|
+
Querysub.commit(() => {
|
|
274
|
+
let current = liveWatchData().watches[key];
|
|
275
|
+
if (current) current.loading = false;
|
|
276
|
+
});
|
|
261
277
|
}
|
|
262
|
-
Querysub.commit(() => {
|
|
263
|
-
let current = liveWatchData().watches[key];
|
|
264
|
-
// The watch may have been removed while the call was in flight
|
|
265
|
-
if (!current) return;
|
|
266
|
-
current.loading = false;
|
|
267
|
-
current.routing = result;
|
|
268
|
-
current.error = error;
|
|
269
|
-
current.updatedTime = Date.now();
|
|
270
|
-
});
|
|
271
278
|
}
|
|
272
279
|
|
|
273
280
|
function isWatched(serverUrl: string, bucketName: string): boolean {
|
|
@@ -5,8 +5,8 @@ import { formatNumber, formatTime, formatDateTimeDetailed } from "socket-functio
|
|
|
5
5
|
import { sort, timeInSecond } from "socket-function/src/misc";
|
|
6
6
|
import preact from "preact";
|
|
7
7
|
import { Querysub } from "../../4-querysub/Querysub";
|
|
8
|
-
import { listServerBuckets, clearServerWriteStats, activateServerBucket } from "sliftutils/storage/remoteStorage/createArchives";
|
|
9
|
-
import type { ServerBucketInfo, BucketDiskInfo, BucketWriteStats } from "sliftutils/storage/remoteStorage/storageServerState";
|
|
8
|
+
import { listServerBuckets, clearServerWriteStats, activateServerBucket, getServerActiveBucket } from "sliftutils/storage/remoteStorage/createArchives";
|
|
9
|
+
import type { ServerBucketInfo, BucketDiskInfo, BucketWriteStats, ActiveBucketInfo } from "sliftutils/storage/remoteStorage/storageServerState";
|
|
10
10
|
import type { ArchivesConfig } from "sliftutils/storage/IArchives";
|
|
11
11
|
import { UsageBar, getUsageThresholds } from "../../library-components/UsageBar";
|
|
12
12
|
import { getSyncedController } from "../../library-components/SyncedController";
|
|
@@ -86,11 +86,21 @@ export function getStorageServices(servers: StorageServer[]): StorageService[] {
|
|
|
86
86
|
return [...byKey.values()];
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/** Every storage call is proxied through here: they authenticate with this machine's identity CA, which the browser has no access to. */
|
|
89
90
|
class StoragePageControllerBase {
|
|
90
|
-
/**
|
|
91
|
+
/** One call per server, so each caches and refreshes on its own. */
|
|
91
92
|
public async getServerBuckets(url: string): Promise<ServerBucketInfo[]> {
|
|
92
93
|
return await listServerBuckets({ url, account: STORAGE_ACCOUNT });
|
|
93
94
|
}
|
|
95
|
+
public async activateBucket(url: string, bucketName: string): Promise<ActiveBucketInfo | string> {
|
|
96
|
+
return await activateServerBucket({ url, account: STORAGE_ACCOUNT, bucketName });
|
|
97
|
+
}
|
|
98
|
+
public async getActiveBucket(url: string, bucketName: string): Promise<ActiveBucketInfo | string> {
|
|
99
|
+
return await getServerActiveBucket({ url, account: STORAGE_ACCOUNT, bucketName });
|
|
100
|
+
}
|
|
101
|
+
public async clearWriteStats(url: string): Promise<{ clearedBuckets: number }> {
|
|
102
|
+
return await clearServerWriteStats({ url, account: STORAGE_ACCOUNT });
|
|
103
|
+
}
|
|
94
104
|
}
|
|
95
105
|
|
|
96
106
|
export const StoragePageController = SocketFunction.register(
|
|
@@ -98,6 +108,9 @@ export const StoragePageController = SocketFunction.register(
|
|
|
98
108
|
new StoragePageControllerBase(),
|
|
99
109
|
() => ({
|
|
100
110
|
getServerBuckets: {},
|
|
111
|
+
activateBucket: {},
|
|
112
|
+
getActiveBucket: {},
|
|
113
|
+
clearWriteStats: {},
|
|
101
114
|
}),
|
|
102
115
|
() => ({
|
|
103
116
|
hooks: [assertIsManagementUser],
|
|
@@ -106,7 +119,7 @@ export const StoragePageController = SocketFunction.register(
|
|
|
106
119
|
}
|
|
107
120
|
);
|
|
108
121
|
|
|
109
|
-
const StorageSynced = getSyncedController(StoragePageController, {
|
|
122
|
+
export const StorageSynced = getSyncedController(StoragePageController, {
|
|
110
123
|
reads: {},
|
|
111
124
|
writes: {},
|
|
112
125
|
});
|
|
@@ -219,22 +232,28 @@ class ActivateBucketButton extends qreact.Component<{ serverUrl: string; bucketN
|
|
|
219
232
|
this.state.activating = true;
|
|
220
233
|
this.state.error = "";
|
|
221
234
|
Querysub.onCommitFinished(async () => {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
Querysub.commit(() => {
|
|
231
|
-
this.state.activating = false;
|
|
232
|
-
this.state.error = refusal;
|
|
233
|
-
// Only this server's buckets changed
|
|
234
|
-
if (!refusal) {
|
|
235
|
-
StorageSynced(SocketFunction.browserNodeId()).getServerBuckets.reset(serverUrl);
|
|
235
|
+
try {
|
|
236
|
+
let result = await StorageSynced(SocketFunction.browserNodeId()).activateBucket.promise(serverUrl, bucketName);
|
|
237
|
+
// A refusal comes back as a string - it's a normal result, not an error
|
|
238
|
+
let refusal = typeof result === "string" && result || "";
|
|
239
|
+
if (refusal) {
|
|
240
|
+
console.log(`Activating bucket ${bucketName} on ${serverUrl} was refused: ${refusal}`);
|
|
241
|
+
} else {
|
|
242
|
+
console.log(`Activated bucket ${bucketName} on ${serverUrl}`);
|
|
236
243
|
}
|
|
237
|
-
|
|
244
|
+
Querysub.commit(() => {
|
|
245
|
+
this.state.error = refusal;
|
|
246
|
+
// Only this server's buckets changed
|
|
247
|
+
if (!refusal) {
|
|
248
|
+
StorageSynced(SocketFunction.browserNodeId()).getServerBuckets.reset(serverUrl);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
} finally {
|
|
252
|
+
// Without this a throw would leave the button disabled and stuck on "Activating..."
|
|
253
|
+
Querysub.commit(() => {
|
|
254
|
+
this.state.activating = false;
|
|
255
|
+
});
|
|
256
|
+
}
|
|
238
257
|
});
|
|
239
258
|
}}
|
|
240
259
|
>
|
|
@@ -403,7 +422,7 @@ class DeployNotices extends qreact.Component<{ services: StorageService[] }> {
|
|
|
403
422
|
async function resetWriteStats(servers: StorageServerBuckets[]): Promise<void> {
|
|
404
423
|
await Promise.all(servers.map(async server => {
|
|
405
424
|
if (server.loading) return;
|
|
406
|
-
let { clearedBuckets } = await
|
|
425
|
+
let { clearedBuckets } = await StorageSynced(SocketFunction.browserNodeId()).clearWriteStats.promise(server.url);
|
|
407
426
|
console.log(`Cleared write stats for ${clearedBuckets} buckets on ${server.url}`);
|
|
408
427
|
}));
|
|
409
428
|
Querysub.commit(() => {
|