sliftutils 1.7.28 → 1.7.32
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/index.d.ts +14 -0
- package/package.json +1 -1
- package/storage/dist/IArchives.ts.cache +2 -2
- package/storage/remoteStorage/createArchives.d.ts +2 -0
- package/storage/remoteStorage/createArchives.ts +51 -0
- package/storage/remoteStorage/dist/createArchives.ts.cache +60 -3
- package/storage/remoteStorage/dist/storageClientController.ts.cache +34 -0
- package/storage/remoteStorage/dist/storageController.ts.cache +32 -4
- package/storage/remoteStorage/dist/storageServerState.ts.cache +8 -4
- package/storage/remoteStorage/storageClientController.d.ts +5 -0
- package/storage/remoteStorage/storageClientController.ts +35 -0
- package/storage/remoteStorage/storageController.d.ts +3 -0
- package/storage/remoteStorage/storageController.ts +29 -1
- package/storage/remoteStorage/storageServerState.ts +5 -0
|
@@ -36,6 +36,9 @@ export type AccessState = {
|
|
|
36
36
|
grantAccessCommand?: string;
|
|
37
37
|
trustedMachines?: TrustRecord[];
|
|
38
38
|
};
|
|
39
|
+
/** Called by storageServerState the moment any routing config is applied - clients must never
|
|
40
|
+
* have to wait for a poll to learn the topology changed. */
|
|
41
|
+
export declare function broadcastRoutingChanged(): void;
|
|
39
42
|
export declare const RemoteStorageController: import("socket-function/SocketFunctionTypes").SocketRegistered<{
|
|
40
43
|
ping: () => Promise<{
|
|
41
44
|
takeover?: string;
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
deleteBucketFile, assertWritesAllowed, assertMutable, LoadedBucket,
|
|
17
17
|
getBucketConfig, listAccountBuckets, ServerBucketInfo,
|
|
18
18
|
} from "./storageServerState";
|
|
19
|
+
import { StorageClientController } from "./storageClientController";
|
|
19
20
|
|
|
20
21
|
// The remote storage server's API. Authentication uses certs.ts machine identities: a client
|
|
21
22
|
// proves it owns its machine key by signing a timestamped token (bound to this server, so tokens
|
|
@@ -105,6 +106,31 @@ function assertValidPath(path: string) {
|
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
// Every client pings us (immediately on connect, then continuously), so pings tell us exactly who
|
|
110
|
+
// our currently-connected clients are. Client nodeIds never reconnect (a reconnect is a NEW
|
|
111
|
+
// nodeId), so the disconnect callback fully cleans an entry up.
|
|
112
|
+
const connectedClients = new Set<string>();
|
|
113
|
+
function trackCaller(): void {
|
|
114
|
+
let nodeId = SocketFunction.getCaller().nodeId;
|
|
115
|
+
if (connectedClients.has(nodeId)) return;
|
|
116
|
+
connectedClients.add(nodeId);
|
|
117
|
+
SocketFunction.onNextDisconnect(nodeId, () => {
|
|
118
|
+
connectedClients.delete(nodeId);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Called by storageServerState the moment any routing config is applied - clients must never
|
|
123
|
+
* have to wait for a poll to learn the topology changed. */
|
|
124
|
+
export function broadcastRoutingChanged(): void {
|
|
125
|
+
console.log(`Broadcasting routing config change to ${connectedClients.size} connected clients`);
|
|
126
|
+
for (let nodeId of [...connectedClients]) {
|
|
127
|
+
void StorageClientController.nodes[nodeId].routingConfigChanged().catch(() => {
|
|
128
|
+
// The client is gone (or too old to know the controller); the disconnect callback
|
|
129
|
+
// cleans the registry, nothing to do here
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
108
134
|
function getCallerMachineId(): string {
|
|
109
135
|
let caller = SocketFunction.getCaller();
|
|
110
136
|
let machineId = sessions.get(caller.nodeId);
|
|
@@ -155,8 +181,10 @@ async function getBucket(account: string, bucketName: string): Promise<LoadedBuc
|
|
|
155
181
|
class RemoteStorageControllerBase {
|
|
156
182
|
// Latency measurement (see SourceWrapper's pinging); no auth, it measures the transport. The
|
|
157
183
|
// takeover stamp piggybacks on it so every connected client learns of a deploy takeover
|
|
158
|
-
// within one ping interval.
|
|
184
|
+
// within one ping interval. Pings also tell us who our clients ARE - the trackCaller
|
|
185
|
+
// registry is what routing-change broadcasts push to.
|
|
159
186
|
async ping(): Promise<{ takeover?: string }> {
|
|
187
|
+
trackCaller();
|
|
160
188
|
return { takeover: getTakeoverStamp() };
|
|
161
189
|
}
|
|
162
190
|
|
|
@@ -14,6 +14,7 @@ import { ROUTING_FILE, parseRoutingData, parseHostedUrl, buildFileUrl, getConfig
|
|
|
14
14
|
import { applyDeployRemap, getTakeoverAltPort, getOwnWindowEndClip, onTakeoverEvent } from "./deployTakeover";
|
|
15
15
|
import { createApiArchives } from "./createArchives";
|
|
16
16
|
import type { IStorage } from "../IStorage";
|
|
17
|
+
import { broadcastRoutingChanged } from "./storageController";
|
|
17
18
|
import type { AccessRequest, TrustRecord } from "./storageController";
|
|
18
19
|
import { getArg } from "./cliArgs";
|
|
19
20
|
|
|
@@ -563,6 +564,7 @@ export function getLoadedBucket(account: string, bucketName: string): Promise<Lo
|
|
|
563
564
|
return loaded;
|
|
564
565
|
}
|
|
565
566
|
|
|
567
|
+
|
|
566
568
|
// Routing reloads are serialized per bucket, so concurrent writes/syncs can't rebuild the same
|
|
567
569
|
// store twice in parallel
|
|
568
570
|
const routingReloads = new Map<string, Promise<void>>();
|
|
@@ -610,6 +612,7 @@ async function checkRoutingChanged(account: string, bucketName: string, config?:
|
|
|
610
612
|
buckets.set(key, Promise.resolve(updated));
|
|
611
613
|
scheduleWindowBoundaryRebuild(updated);
|
|
612
614
|
scheduleBoundaryScans(updated);
|
|
615
|
+
broadcastRoutingChanged();
|
|
613
616
|
return;
|
|
614
617
|
}
|
|
615
618
|
console.log(`Rebuilding the store for bucket ${key} (${reason})`);
|
|
@@ -617,6 +620,7 @@ async function checkRoutingChanged(account: string, bucketName: string, config?:
|
|
|
617
620
|
await loaded.store.dispose();
|
|
618
621
|
}
|
|
619
622
|
buckets.set(key, Promise.resolve(buildBucket(account, bucketName, routing, plan)));
|
|
623
|
+
broadcastRoutingChanged();
|
|
620
624
|
}
|
|
621
625
|
|
|
622
626
|
// Per-write options are evaluated at the WRITE's time (and the key's route), not the current
|
|
@@ -657,6 +661,7 @@ async function writeRoutingConfig(account: string, bucketName: string, data: Buf
|
|
|
657
661
|
if (!loaded) {
|
|
658
662
|
await new ArchivesDisk(getBucketFolder(account, bucketName)).set(ROUTING_FILE, data, { lastModified: config?.lastModified });
|
|
659
663
|
buckets.set(key, Promise.resolve(buildBucket(account, bucketName, incoming)));
|
|
664
|
+
broadcastRoutingChanged();
|
|
660
665
|
console.log(`Created bucket ${key}`);
|
|
661
666
|
return;
|
|
662
667
|
}
|