sliftutils 1.7.71 → 1.7.73
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 +506 -257
- package/misc/https/dist/hostServer.ts.cache +5 -2
- package/package.json +1 -1
- package/spec.txt +10 -0
- package/storage/ArchivesDisk.d.ts +4 -13
- package/storage/ArchivesDisk.ts +6 -4
- package/storage/IArchives.d.ts +15 -10
- package/storage/IArchives.ts +19 -6
- package/storage/backblaze.d.ts +3 -9
- package/storage/backblaze.ts +22 -19
- package/storage/dist/ArchivesDisk.ts.cache +5 -2
- package/storage/dist/IArchives.ts.cache +17 -3
- package/storage/dist/backblaze.ts.cache +35 -26
- package/storage/remoteStorage/ArchivesRemote.d.ts +5 -9
- package/storage/remoteStorage/ArchivesRemote.ts +25 -20
- package/storage/remoteStorage/ArchivesUrl.d.ts +3 -9
- package/storage/remoteStorage/ArchivesUrl.ts +7 -5
- package/storage/remoteStorage/accessPage.tsx +4 -4
- package/storage/remoteStorage/accessStats.d.ts +2 -0
- package/storage/remoteStorage/accessStats.ts +32 -0
- package/storage/remoteStorage/blobStore.d.ts +193 -88
- package/storage/remoteStorage/blobStore.ts +535 -400
- package/storage/remoteStorage/bucketDisk.d.ts +18 -0
- package/storage/remoteStorage/bucketDisk.ts +66 -0
- package/storage/remoteStorage/createArchives.d.ts +4 -10
- package/storage/remoteStorage/createArchives.ts +103 -62
- package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +28 -19
- package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +7 -4
- package/storage/remoteStorage/dist/accessPage.tsx.cache +6 -6
- package/storage/remoteStorage/dist/accessStats.ts.cache +38 -3
- package/storage/remoteStorage/dist/blobStore.ts.cache +516 -374
- package/storage/remoteStorage/dist/bucketDisk.ts.cache +72 -0
- package/storage/remoteStorage/dist/createArchives.ts.cache +114 -57
- package/storage/remoteStorage/dist/intermediateSources.ts.cache +12 -12
- package/storage/remoteStorage/dist/remoteConfig.ts.cache +18 -2
- package/storage/remoteStorage/dist/serverConfig.ts.cache +116 -0
- package/storage/remoteStorage/dist/sourceWrapper.ts.cache +6 -5
- package/storage/remoteStorage/dist/sourcesList.ts.cache +5 -2
- package/storage/remoteStorage/dist/storageController.ts.cache +223 -190
- package/storage/remoteStorage/dist/storageServer.ts.cache +9 -9
- package/storage/remoteStorage/dist/storageServerState.ts.cache +329 -566
- package/storage/remoteStorage/dist/storePlan.ts.cache +149 -0
- package/storage/remoteStorage/dist/validation.ts.cache +40 -0
- package/storage/remoteStorage/grantAccessCli.ts +1 -1
- package/storage/remoteStorage/intermediateSources.d.ts +3 -5
- package/storage/remoteStorage/intermediateSources.ts +14 -16
- package/storage/remoteStorage/remoteConfig.d.ts +2 -2
- package/storage/remoteStorage/remoteConfig.ts +19 -3
- package/storage/remoteStorage/serverConfig.d.ts +27 -0
- package/storage/remoteStorage/serverConfig.ts +109 -0
- package/storage/remoteStorage/sourceWrapper.d.ts +3 -3
- package/storage/remoteStorage/sourceWrapper.ts +7 -6
- package/storage/remoteStorage/sourcesList.ts +3 -0
- package/storage/remoteStorage/storageController.d.ts +118 -36
- package/storage/remoteStorage/storageController.ts +166 -168
- package/storage/remoteStorage/storageServer.ts +1 -1
- package/storage/remoteStorage/storageServerState.d.ts +52 -63
- package/storage/remoteStorage/storageServerState.ts +340 -584
- package/storage/remoteStorage/storePlan.d.ts +34 -0
- package/storage/remoteStorage/storePlan.ts +166 -0
- package/storage/remoteStorage/validation.d.ts +4 -0
- package/storage/remoteStorage/validation.ts +31 -0
|
@@ -87,6 +87,9 @@ async function runMainPortAcquireLoop(domain, mainPort, servingPort, fallback) {
|
|
|
87
87
|
let acquired = await new Promise(resolve => {
|
|
88
88
|
let relay = net_1.default.createServer(client => {
|
|
89
89
|
let upstream = net_1.default.connect({ host: "127.0.0.1", port: servingPort });
|
|
90
|
+
// Without this every relayed request pays the ~40ms delayed-ACK timer: a call is a small write (often a header then a body), Nagle holds the second write until the first is acknowledged, and the peer has nothing to piggyback the ACK on. Measured as 43ms per call through the relay versus 1ms direct.
|
|
91
|
+
client.setNoDelay(true);
|
|
92
|
+
upstream.setNoDelay(true);
|
|
90
93
|
client.pipe(upstream);
|
|
91
94
|
upstream.pipe(client);
|
|
92
95
|
let cleanup = () => {
|
|
@@ -172,5 +175,5 @@ async function runCertRenewalLoop(domain, onNewCert) {
|
|
|
172
175
|
}
|
|
173
176
|
}
|
|
174
177
|
}
|
|
175
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaG9zdFNlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImhvc3RTZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsNENBQW9CO0FBQ3BCLDRDQUFvQjtBQUNwQiw4Q0FBc0I7QUFDdEIsbUVBQWdFO0FBQ2hFLDZEQUFrRTtBQUNsRSxtREFBd0Q7QUFDeEQsMkRBQXFEO0FBQ3JELCtEQUErRDtBQUMvRCxpRUFBOEQ7QUFDOUQsd0VBQW1FO0FBQ25FLG1DQUE0RTtBQUM1RSw2Q0FBc0U7QUFDdEUsK0JBQWtDO0FBRWxDLHlUQUF5VDtBQUN6VCxNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLG1CQUFtQixHQUFHLG1CQUFZLEdBQUcsRUFBRSxDQUFDO0FBRTlDLGlHQUFpRztBQUNqRyxNQUFNLGNBQWMsR0FBRyxtQkFBbUIsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxtQkFBbUIsR0FBRyxtQkFBbUIsQ0FBQyxDQUFDO0FBdUJ6RyxpVEFBaVQ7QUFDMVMsS0FBSyxVQUFVLFVBQVUsQ0FBQyxNQUF3Qjs7SUFDckQsSUFBSSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxNQUFNLENBQUM7SUFDOUIsZ0dBQWdHO0lBQ2hHLElBQUksVUFBVSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3ZELE1BQU0sSUFBQSxzQkFBYyxFQUFDLFVBQVUsQ0FBQyxDQUFDO0lBRWpDLElBQUksTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3RCLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxRQUFRLElBQUksTUFBTSxJQUFBLDBCQUFhLEdBQUUsQ0FBQztRQUNsRCxNQUFNLElBQUEsZUFBUyxFQUFDLEdB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QUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDcEcsT0FBTyxFQUFFLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDcEQsQ0FBQztBQXhCRCw4Q0F3QkM7QUFFRCxLQUFLLFVBQVUsa0JBQWtCLENBQUMsTUFBYyxFQUFFLFNBQTJEOztJQUN6RyxJQUFJLFFBQVEsR0FBRyxNQUFBLGdCQUFnQixDQUFDLE1BQU0sQ0FBQywwQ0FBRSxJQUFJLENBQUM7SUFDOUMsT0FBTyxJQUFJLEVBQUUsQ0FBQztRQUNWLE1BQU0sSUFBQSxnQkFBSyxFQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDakMsSUFBSSxDQUFDO1lBQ0QsSUFBSSxPQUFPLEdBQUcsTUFBTSxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUM5QyxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQzVCLFFBQVEsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDO2dCQUN4QixPQUFPLENBQUMsR0FBRyxDQUFDLElBQUEsbUJBQU8sRUFBQyxrQkFBa0IsTUFBTSxzQ0FBc0MsQ0FBQyxDQUFDLENBQUM7Z0JBQ3JGLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN2QixDQUFDO1FBQ0wsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDVCxPQUFPLENBQUMsS0FBSyxDQUFDLHdDQUF3QyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUN2RSxDQUFDO0lBQ0wsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgb3MgZnJvbSBcIm9zXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzXCI7XG5pbXBvcnQgbmV0IGZyb20gXCJuZXRcIjtcbmltcG9ydCB7IFNvY2tldEZ1bmN0aW9uIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9Tb2NrZXRGdW5jdGlvblwiO1xuaW1wb3J0IHsgZ2V0Tm9kZUlkTG9jYXRpb24gfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9ub2RlQ2FjaGVcIjtcbmltcG9ydCB7IHRpbWVJbk1pbnV0ZSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL21pc2NcIjtcbmltcG9ydCB7IGRlbGF5IH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvYmF0Y2hpbmdcIjtcbmltcG9ydCB7IGdldEV4dGVybmFsSVAgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9uZXR3b3JraW5nXCI7XG5pbXBvcnQgeyBmb3J3YXJkUG9ydCB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2ZvcndhcmRQb3J0XCI7XG5pbXBvcnQgeyBtYWdlbnRhIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvZm9ybWF0dGluZy9sb2dDb2xvcnNcIjtcbmltcG9ydCB7IGdldE93bk1hY2hpbmVJZCwgZ2V0VGhyZWFkS2V5Q2VydCwgbG9hZElkZW50aXR5Q0EgfSBmcm9tIFwiLi9jZXJ0c1wiO1xuaW1wb3J0IHsgZ2VuZXJhdGVDZXJ0LCBnZXRBY2NvdW50S2V5LCBwYXJzZUNlcnQgfSBmcm9tIFwiLi9odHRwc0NlcnRzXCI7XG5pbXBvcnQgeyBzZXRSZWNvcmQgfSBmcm9tIFwiLi9kbnNcIjtcblxuLy8gUmVuZXcgc29tZXdoZXJlIHJhbmRvbWx5IGJldHdlZW4gNDAlIGFuZCA2MCUgb2YgdGhlIHdheSB0aHJvdWdoIHRoZSBjZXJ0IGxpZmV0aW1lLiBUaGUgcmFuZG9tIHRocmVzaG9sZCBzdGFnZ2VycyBwYXJhbGxlbCBwcm9jZXNzZXMgb24gdGhlIHNhbWUgbWFjaGluZSwgc28gdXN1YWxseSBvbmUgcHJvY2VzcyByZW5ld3MgZWFybHksIGFuZCB0aGUgb3RoZXJzIHNlZSB0aGUgcmVuZXdlZCBjZXJ0IG9uIGRpc2sgKHdlIHJlLXJlYWQgdGhlIGRpc2sgYmVmb3JlIGV2ZXJ5IHJlbmV3YWwgY2hlY2spIGFuZCBuZXZlciByZW5ldyB0aGVtc2VsdmVzLlxuY29uc3QgUkVORVdfVEhSRVNIT0xEX01JTiA9IDAuNDtcbmNvbnN0IFJFTkVXX1RIUkVTSE9MRF9NQVggPSAwLjY7XG5jb25zdCBDRVJUX0NIRUNLX0lOVEVSVkFMID0gdGltZUluTWludXRlICogMTU7XG5cbi8vIE9uZSB0aHJlc2hvbGQgcGVyIHByb2Nlc3MsIHNvIGEgcHJvY2VzcyBpcyBjb25zaXN0ZW50bHkgZWFybHkgb3IgbGF0ZSByZWxhdGl2ZSB0byBpdHMgc2libGluZ3NcbmNvbnN0IHJlbmV3VGhyZXNob2xkID0gUkVORVdfVEhSRVNIT0xEX01JTiArIE1hdGgucmFuZG9tKCkgKiAoUkVORVdfVEhSRVNIT0xEX01BWCAtIFJFTkVXX1RIUkVTSE9MRF9NSU4pO1xuXG5leHBvcnQgdHlwZSBIb3N0U2VydmVyQ29uZmlnID0ge1xuICAgIC8qKiBGdWxsIGRvbWFpbiB0byBob3N0IG9uIChlLmcuIFwidGVzdHNpdGUuZXhhbXBsZS5jb21cIikuIFRoZSBIVFRQUyBjZXJ0IGlzIGNyZWF0ZWQgZm9yIHRoaXMgZG9tYWluIGFuZCAqLmRvbWFpbiwgc28gdXNpbmcgYSBzdWJkb21haW4gbmV2ZXIgdG91Y2hlcyB0aGUgcm9vdCBkb21haW4gKGJleW9uZCBpdHMgX2FjbWUtY2hhbGxlbmdlIFRYVCByZWNvcmQpLiAqL1xuICAgIGRvbWFpbjogc3RyaW5nO1xuICAgIHBvcnQ6IG51bWJlcjtcblxuICAgIC8vIFRPRE86IEV2ZW50dWFsbHkgd2Ugc2hvdWxkIHN1cHBvcnQgcnVubmluZyB3aXRob3V0IENsb3VkZmxhcmUgQVBJIHRva2Vucy4gSXQncyBhbm5veWluZyB0aG91Z2ggYXMgdGhlIHVzZXIgd2lsbCBoYXZlIHRvIGNyZWF0ZSBhIHNlbGYtc2lnbmVkIGNlcnRpZmljYXRlIGFuZCB0aGVuIHRoZXknbGwgaGF2ZSB0byBnbyB0aHJvdWdoIGFuZCB0cnVzdCBpdCBldmVyeXdoZXJlLCBhbmQgYSBsb3Qgb2YgdGhlIHN0dWZmIGlzIHRyYW5zcGFyZW50LCBhbmQgc28gaXQnbGwgaGF2ZSB0byBiZSBub24tdHJhbnNwYXJlbnQsIGdldHRpbmcgdGhlIHVzZXIgdG8gZ28gdG8gdGhlIHBhZ2UgdGhhdCBvd25zIHRoZSBkb21haW4gYW5kIHRydXN0IGl0IGZyb20gdGhlcmUuIEl0J3MgbXVjaCBiZXR0ZXIganVzdCBtYWtlIGEgQ2xvdWRmbGFyZSBhY2NvdW50LiBZb3UgY2FuIGJ1eSBhIGRvbWFpbiBmb3IgJDE1IGEgeWVhciwgYW5kIHRoZW4geW91IGNhbiB1c2UgaXQgZm9yIEdpdEh1YiBwYWdlcyB0byBob3N0IHlvdXIgb3duIHNpdGUgYW5kIGRvIGFsbCBraW5kcyBvZiB0aGluZ3MganVzdCBsaWtlIGFueSBvdGhlciByZWFsIHNpdGUuXG4gICAgLyoqIENyZWF0ZXMgYW4gdW5wcm94aWVkIEEgcmVjb3JkIHBvaW50aW5nIGRvbWFpbiBhdCB0aGlzIG1hY2hpbmUgKHB1YmxpY0lwLCBvciBvdXIgZGV0ZWN0ZWQgZXh0ZXJuYWwgSVApICovXG4gICAgc2V0RE5TUmVjb3JkPzogYm9vbGVhbjtcbiAgICBwdWJsaWNJcD86IHN0cmluZztcbiAgICBhbGxvd0hvc3RuYW1lcz86IHN0cmluZ1tdO1xuICAgIC8qKiBXaGVuIHRoZSBwb3J0IGlzIGJ1c3kgKGUuZy4gdGhlIHByZXZpb3VzIGRlcGxveSBzdGlsbCBob2xkcyBpdCksIG1vdW50IG9uIGFuIGFsdGVybmF0ZSBwb3J0IGluc3RlYWQgKHRoZSBzb2NrZXQgc2VydmVyJ3MgYnVpbHQtaW4gZnJlZS1wb3J0IHNjYW4pLCBhbmQga2VlcCB0cnlpbmcgdG8gdGFrZSB0aGUgcmVhbCBwb3J0IC0gb25jZSBpdCBmcmVlcywgYSByYXcgVENQIHJlbGF5IG9uIHRoZSByZWFsIHBvcnQgZm9yd2FyZHMgdG8gb3VyIGxpc3RlbmVyIChTb2NrZXRGdW5jdGlvbiBjYW4gb25seSBtb3VudCBvbmNlIHBlciBwcm9jZXNzKS4gKi9cbiAgICBwb3J0RmFsbGJhY2s/OiB7XG4gICAgICAgIC8qKiBEZWxheSB1bnRpbCB0aGUgbmV4dCBtYWluLXBvcnQgYWNxdWlzaXRpb24gYXR0ZW1wdCAodGlnaHRlbmVkIGFyb3VuZCB0aGUgcHJlZGVjZXNzb3IncyBzY2hlZHVsZWQgZGVhdGgpICovXG4gICAgICAgIGdldEFjcXVpcmVEZWxheTogKCkgPT4gbnVtYmVyO1xuICAgICAgICAvKiogQ2FsbGVkIHdoZW4gdGhlIG1haW4gcG9ydCB0dXJuZWQgb3V0IHRvIGJlIGJ1c3ksIGJlZm9yZSB3ZSBhY3QgYXMgaXRzIHN1Y2Nlc3NvciBpbiBhbnkgd2F5LiBUaHJvd2luZyBhYm9ydHMgc3RhcnR1cCAtIGEgYnVzeSBwb3J0IHdpdGggbm8gZGVwbG95IGluIHByb2dyZXNzIG1lYW5zIHNvbWV0aGluZyBlbHNlIGhvbGRzIGl0LCB3aGljaCBpcyBub3QgYSBzdGF0ZSB0byBrZWVwIHJ1bm5pbmcgaW4uICovXG4gICAgICAgIG9uUG9ydEluVXNlPzogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgICAgICAgLyoqIFJlcG9ydHMgZXZlcnkgcG9ydCB3ZSBiZWNvbWUgcmVhY2hhYmxlIG9uICh0aGUgYWx0ZXJuYXRlIGF0IG1vdW50LCB0aGUgbWFpbiBwb3J0IG9uY2UgcmVsYXllZCkgKi9cbiAgICAgICAgb25MaXN0ZW5pbmc6IChwb3J0OiBudW1iZXIsIGlzTWFpblBvcnQ6IGJvb2xlYW4pID0+IHZvaWQ7XG4gICAgfTtcbn07XG5cbi8qKiBIb3N0cyBhIFNvY2tldEZ1bmN0aW9uIHNlcnZlciBvbiBhIHJlYWwgZG9tYWluLCB3aXRoIGFuIGF1dG9tYXRpY2FsbHkgY3JlYXRlZCBhbmQgcmVuZXdlZCBMZXQncyBFbmNyeXB0IEhUVFBTIGNlcnRpZmljYXRlIChjYWNoZWQgaW4gdGhlIGhvbWUgZm9sZGVyLCBzaGFyZWQgYmV0d2VlbiBwcm9jZXNzZXMgb24gdGhlIG1hY2hpbmUpLiBFeHBvc2UgeW91ciBjb250cm9sbGVycyAoYW5kIGFueSBSZXF1aXJlQ29udHJvbGxlciBzZXR1cCkgYmVmb3JlIGNhbGxpbmcgdGhpcy4gUmV0dXJucyB0aGUgbW91bnRlZCBub2RlSWQuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaG9zdFNlcnZlcihjb25maWc6IEhvc3RTZXJ2ZXJDb25maWcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGxldCB7IGRvbWFpbiwgcG9ydCB9ID0gY29uZmlnO1xuICAgIC8vIFRoZSBpZGVudGl0eSBDQSBhbHdheXMgbGl2ZXMgb24gdGhlIHJvb3QgZG9tYWluIChub2RlSWRzIGFyZSB0aHJlYWRIYXNoLm1hY2hpbmVIYXNoLnJvb3QudGxkKVxuICAgIGxldCByb290RG9tYWluID0gZG9tYWluLnNwbGl0KFwiLlwiKS5zbGljZSgtMikuam9pbihcIi5cIik7XG4gICAgYXdhaXQgbG9hZElkZW50aXR5Q0Eocm9vdERvbWFpbik7XG5cbiAgICBpZiAoY29uZmlnLnNldEROU1JlY29yZCkge1xuICAgICAgICBsZXQgaXAgPSBjb25maWcucHVibGljSXAgfHwgYXdhaXQgZ2V0RXh0ZXJuYWxJUCgpO1xuICAgICAgICBhd2FpdCBzZXRSZWNvcmQoXCJBXCIsIGRvbWFpbiwgaXApO1xuICAgIH1cblxuICAgIGxldCBrZXlDZXJ0ID0gYXdhaXQgZ2V0RnJlc2hIVFRQU0NlcnQoZG9tYWluKTtcbiAgICBsZXQgY2VydExpc3RlbmVyczogKCh2YWx1ZTogeyBrZXk6IHN0cmluZzsgY2VydDogc3RyaW5nIH0pID0+IHZvaWQpW10gPSBbXTtcbiAgICB2b2lkIHJ1bkNlcnRSZW5ld2FsTG9vcChkb21haW4sIG5ld0tleUNlcnQgPT4ge1xuICAgICAgICBrZXlDZXJ0ID0gbmV3S2V5Q2VydDtcbiAgICAgICAgZm9yIChsZXQgbGlzdGVuZXIgb2YgY2VydExpc3RlbmVycykge1xuICAgICAgICAgICAgbGlzdGVuZXIobmV3S2V5Q2VydCk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIFdpdGggcG9ydEZhbGxiYWNrLCBhIGJ1c3kgcG9ydCBpcyBub3QgYW4gZXJyb3I6IHRoZSB1bmRlcmx5aW5nIHNlcnZlciBzY2FucyBmb3IgYSBmcmVlIHBvcnQgaW5zdGVhZCAodXNlQXZhaWxhYmxlUG9ydElmUG9ydEluVXNlKSwgYW5kIHRoZSBub2RlSWQgdGVsbHMgdXMgd2hpY2ggcG9ydCB3ZSBhY3R1YWxseSBnb3RcbiAgICBsZXQgbm9kZUlkID0gYXdhaXQgU29ja2V0RnVuY3Rpb24ubW91bnQoe1xuICAgICAgICBwdWJsaWM6IHRydWUsXG4gICAgICAgIGF1dG9Gb3J3YXJkUG9ydDogdHJ1ZSxcbiAgICAgICAgcG9ydCxcbiAgICAgICAgdXNlQXZhaWxhYmxlUG9ydElmUG9ydEluVXNlOiAhIWNvbmZpZy5wb3J0RmFsbGJhY2ssXG4gICAgICAgIC4uLmdldFRocmVhZEtleUNlcnQocm9vdERvbWFpbiksXG4gICAgICAgIFNOSUNlcnRzOiB7XG4gICAgICAgICAgICBbZG9tYWluXTogY2FsbGJhY2sgPT4ge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGtleUNlcnQpO1xuICAgICAgICAgICAgICAgIGNlcnRMaXN0ZW5lcnMucHVzaChjYWxsYmFjayk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgW2dldE93bk1hY2hpbmVJZChyb290RG9tYWluKSArIFwiLlwiICsgcm9vdERvbWFpbl06IGFzeW5jIGNhbGxiYWNrID0+IHtcbiAgICAgICAgICAgICAgICBsZXQgdGhyZWFkQ2VydCA9IGF3YWl0IGdldFRocmVhZEtleUNlcnQocm9vdERvbWFpbik7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soe1xuICAgICAgICAgICAgICAgICAgICBrZXk6IHRocmVhZENlcnQua2V5LFxuICAgICAgICAgICAgICAgICAgICBjZXJ0OiB0aHJlYWRDZXJ0LmNlcnQsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgW1wiMTI3LTAtMC0xLlwiICsgcm9vdERvbWFpbl06IGFzeW5jIGNhbGxiYWNrID0+IHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhrZXlDZXJ0KTtcbiAgICAgICAgICAgICAgICBjZXJ0TGlzdGVuZXJzLnB1c2goY2FsbGJhY2spO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgYWxsb3dIb3N0bmFtZXM6IGNvbmZpZy5hbGxvd0hvc3RuYW1lcyxcbiAgICB9KTtcbiAgICBsZXQgc2VydmluZ1BvcnQgPSBnZXROb2RlSWRMb2NhdGlvbihub2RlSWQpPy5wb3J0IHx8IHBvcnQ7XG4gICAgbGV0IGZhbGxiYWNrID0gY29uZmlnLnBvcnRGYWxsYmFjaztcbiAgICBpZiAoZmFsbGJhY2sgJiYgc2VydmluZ1BvcnQgIT09IHBvcnQpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGBQb3J0ICR7cG9ydH0gaXMgaW4gdXNlIChwcmVzdW1hYmx5IGJ5IG91ciBwcmVkZWNlc3Nvcik7IHNlcnZpbmcgb24gYWx0ZXJuYXRlIHBvcnQgJHtzZXJ2aW5nUG9ydH0gdW50aWwgaXQgZnJlZXNgKTtcbiAgICAgICAgYXdhaXQgZmFsbGJhY2sub25Qb3J0SW5Vc2U/LigpO1xuICAgICAgICB2b2lkIHJ1bk1haW5Qb3J0QWNxdWlyZUxvb3AoZG9tYWluLCBwb3J0LCBzZXJ2aW5nUG9ydCwgZmFsbGJhY2spO1xuICAgIH1cbiAgICBmYWxsYmFjaz8ub25MaXN0ZW5pbmcoc2VydmluZ1BvcnQsIHNlcnZpbmdQb3J0ID09PSBwb3J0KTtcbiAgICBjb25zb2xlLmxvZyhtYWdlbnRhKGBIb3N0aW5nIGh0dHBzOi8vJHtkb21haW59OiR7c2VydmluZ1BvcnR9IChub2RlSWQgJHtub2RlSWR9KWApKTtcbiAgICByZXR1cm4gbm9kZUlkO1xufVxuXG4vLyBTb2NrZXRGdW5jdGlvbiBjYW4gb25seSBtb3VudCBvbmNlIHBlciBwcm9jZXNzLCBzbyBcInRha2luZyBvdmVyXCIgdGhlIG1haW4gcG9ydCBpcyBhIHJhdyBUQ1AgcmVsYXkgZm9yd2FyZGluZyB0byBvdXIgcmVhbCBsaXN0ZW5lciAtIFRMUy9TTkkgcGFzc2VzIHN0cmFpZ2h0IHRocm91Z2gsIGFuZCBjbGllbnRzIGFkZHJlc3Mgc2VydmVycyBieSBpcCBkb21haW4gKHdpbGRjYXJkIG5lZ290aWF0aW9uKSwgc28gdGhlIGV4dHJhIGhvcCBpcyBpbnZpc2libGUuXG5hc3luYyBmdW5jdGlvbiBydW5NYWluUG9ydEFjcXVpcmVMb29wKGRvbWFpbjogc3RyaW5nLCBtYWluUG9ydDogbnVtYmVyLCBzZXJ2aW5nUG9ydDogbnVtYmVyLCBmYWxsYmFjazogTm9uTnVsbGFibGU8SG9zdFNlcnZlckNvbmZpZ1tcInBvcnRGYWxsYmFja1wiXT4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICBhd2FpdCBkZWxheShmYWxsYmFjay5nZXRBY3F1aXJlRGVsYXkoKSk7XG4gICAgICAgIGxldCBhY3F1aXJlZCA9IGF3YWl0IG5ldyBQcm9taXNlPGJvb2xlYW4+KHJlc29sdmUgPT4ge1xuICAgICAgICAgICAgbGV0IHJlbGF5ID0gbmV0LmNyZWF0ZVNlcnZlcihjbGllbnQgPT4ge1xuICAgICAgICAgICAgICAgIGxldCB1cHN0cmVhbSA9IG5ldC5jb25uZWN0KHsgaG9zdDogXCIxMjcuMC4wLjFcIiwgcG9ydDogc2VydmluZ1BvcnQgfSk7XG4gICAgICAgICAgICAgICAgY2xpZW50LnBpcGUodXBzdHJlYW0pO1xuICAgICAgICAgICAgICAgIHVwc3RyZWFtLnBpcGUoY2xpZW50KTtcbiAgICAgICAgICAgICAgICBsZXQgY2xlYW51cCA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY2xpZW50LmRlc3Ryb3koKTtcbiAgICAgICAgICAgICAgICAgICAgdXBzdHJlYW0uZGVzdHJveSgpO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgY2xpZW50Lm9uKFwiZXJyb3JcIiwgY2xlYW51cCk7XG4gICAgICAgICAgICAgICAgdXBzdHJlYW0ub24oXCJlcnJvclwiLCBjbGVhbnVwKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmVsYXkub25jZShcImVycm9yXCIsICgpID0+IHJlc29sdmUoZmFsc2UpKTtcbiAgICAgICAgICAgIHJlbGF5Lmxpc3RlbihtYWluUG9ydCwgKCkgPT4gcmVzb2x2ZSh0cnVlKSk7XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoYWNxdWlyZWQpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKG1hZ2VudGEoYEFjcXVpcmVkIG1haW4gcG9ydCAke21haW5Qb3J0fSBmb3IgaHR0cHM6Ly8ke2RvbWFpbn0gKHJlbGF5aW5nIHRvIG91ciBsaXN0ZW5lciBvbiAke3NlcnZpbmdQb3J0fSlgKSk7XG4gICAgICAgICAgICAvLyBUaGUgbW91bnQgb25seSBmb3J3YXJkZWQgT1VSIHNlcnZpbmcgcG9ydDsgdGhlIG1haW4gcG9ydCBuZWVkcyBpdHMgb3duIG1hcHBpbmcgKHRoZSBwcmVkZWNlc3NvcidzIG1hcHBpbmcgcG9pbnRlZCBhdCB0aGUgc2FtZSBtYWNoaW5lK3BvcnQsIGJ1dCBkaWVzIHdpdGggaXQpXG4gICAgICAgICAgICBhd2FpdCBmb3J3YXJkUG9ydCh7IGV4dGVybmFsUG9ydDogbWFpblBvcnQsIGludGVybmFsUG9ydDogbWFpblBvcnQgfSk7XG4gICAgICAgICAgICBmYWxsYmFjay5vbkxpc3RlbmluZyhtYWluUG9ydCwgdHJ1ZSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmZ1bmN0aW9uIGdldENlcnREaXNrUGF0aChkb21haW46IHN0cmluZykge1xuICAgIHJldHVybiBvcy5ob21lZGlyKCkgKyBgL2h0dHBzY2VydF8ke2RvbWFpbn0uanNvbmA7XG59XG5mdW5jdGlvbiByZWFkQ2VydEZyb21EaXNrKGRvbWFpbjogc3RyaW5nKTogeyBrZXk6IHN0cmluZzsgY2VydDogc3RyaW5nIH0gfCB1bmRlZmluZWQge1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhnZXRDZXJ0RGlza1BhdGgoZG9tYWluKSwgXCJ1dGY4XCIpKSBhcyB7IGtleTogc3RyaW5nOyBjZXJ0OiBzdHJpbmcgfTtcbiAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG59XG5mdW5jdGlvbiBnZXRSZW5ld1RpbWUoY2VydFBlbTogc3RyaW5nLCB0aHJlc2hvbGQ6IG51bWJlcikge1xuICAgIGxldCBjZXJ0T2JqID0gcGFyc2VDZXJ0KGNlcnRQZW0pO1xuICAgIGxldCBzdGFydCA9ICtuZXcgRGF0ZShjZXJ0T2JqLnZhbGlkaXR5Lm5vdEJlZm9yZSk7XG4gICAgbGV0IGVuZCA9ICtuZXcgRGF0ZShjZXJ0T2JqLnZhbGlkaXR5Lm5vdEFmdGVyKTtcbiAgICByZXR1cm4gc3RhcnQgKyAoZW5kIC0gc3RhcnQpICogdGhyZXNob2xkO1xufVxuXG4vKiogUmV0dXJucyB0aGUgY2FjaGVkIEhUVFBTIGNlcnQgZm9yIHRoZSBkb21haW4sIGNyZWF0aW5nL3JlbmV3aW5nIGl0IGZpcnN0IGlmIGl0IGlzIHBhc3QgdGhpcyBwcm9jZXNzJ3MgcmVuZXdhbCB0aHJlc2hvbGQuIFJlYWRzIHRoZSBkaXNrIGNhY2hlIG9uIGV2ZXJ5IGNhbGwsIHNvIGEgcmVuZXdhbCBkb25lIGJ5IGEgcGFyYWxsZWwgcHJvY2VzcyBpcyBwaWNrZWQgdXAgaW5zdGVhZCBvZiByZW5ld2luZyBhZ2Fpbi4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRGcmVzaEhUVFBTQ2VydChkb21haW46IHN0cmluZyk6IFByb21pc2U8eyBrZXk6IHN0cmluZzsgY2VydDogc3RyaW5nIH0+IHtcbiAgICBsZXQga2V5Q2VydCA9IHJlYWRDZXJ0RnJvbURpc2soZG9tYWluKTtcbiAgICBpZiAoa2V5Q2VydCAmJiBnZXRSZW5ld1RpbWUoa2V5Q2VydC5jZXJ0LCByZW5ld1RocmVzaG9sZCkgPiBEYXRlLm5vdygpKSB7XG4gICAgICAgIHJldHVybiBrZXlDZXJ0O1xuICAgIH1cbiAgICBpZiAoa2V5Q2VydCkge1xuICAgICAgICBjb25zb2xlLmxvZyhtYWdlbnRhKGBIVFRQUyBjZXJ0IGZvciAke2RvbWFpbn0gaXMgcGFzdCAkeyhyZW5ld1RocmVzaG9sZCAqIDEwMCkudG9GaXhlZCgwKX0lIG9mIGl0cyBsaWZldGltZSwgcmVuZXdpbmdgKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5sb2cobWFnZW50YShgTm8gSFRUUFMgY2VydCBvbiBkaXNrIGZvciAke2RvbWFpbn0sIGNyZWF0aW5nIG9uZWApKTtcbiAgICB9XG4gICAgbGV0IGFjY291bnRLZXkgPSBhd2FpdCBnZXRBY2NvdW50S2V5KGRvbWFpbik7XG4gICAgdHJ5IHtcbiAgICAgICAga2V5Q2VydCA9IGF3YWl0IGdlbmVyYXRlQ2VydCh7IGFjY291bnRLZXksIGRvbWFpbiwgYWx0RG9tYWluczogW1wiKi5cIiArIGRvbWFpbl0gfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBpZiAoU3RyaW5nKGUpLmluY2x1ZGVzKFwiYXV0aG9yaXphdGlvbiBtdXN0IGJlIHBlbmRpbmdcIikpIHtcbiAgICAgICAgICAgIC8vIEFub3RoZXIgcHJvY2VzcyBpcyBtaWQtcmVuZXdhbC4gV2FpdCBmb3IgaXQgdG8gZmluaXNoLCB0aGVuIHJlLWNoZWNrIHRoZSBkaXNrLlxuICAgICAgICAgICAgY29uc29sZS5sb2coYENlcnRpZmljYXRlIGF1dGhvcml6YXRpb24gaXMgcGVuZGluZyBpbiBhbm90aGVyIHByb2Nlc3MsIHdhaXRpbmcgMiBtaW51dGVzYCk7XG4gICAgICAgICAgICBhd2FpdCBkZWxheSh0aW1lSW5NaW51dGUgKiAyKTtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBnZXRGcmVzaEhUVFBTQ2VydChkb21haW4pO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IGU7XG4gICAgfVxuICAgIGZzLndyaXRlRmlsZVN5bmMoZ2V0Q2VydERpc2tQYXRoKGRvbWFpbiksIEpTT04uc3RyaW5naWZ5KHsga2V5OiBrZXlDZXJ0LmtleSwgY2VydDoga2V5Q2VydC5jZXJ0IH0pKTtcbiAgICByZXR1cm4geyBrZXk6IGtleUNlcnQua2V5LCBjZXJ0OiBrZXlDZXJ0LmNlcnQgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcnVuQ2VydFJlbmV3YWxMb29wKGRvbWFpbjogc3RyaW5nLCBvbk5ld0NlcnQ6IChrZXlDZXJ0OiB7IGtleTogc3RyaW5nOyBjZXJ0OiBzdHJpbmcgfSkgPT4gdm9pZCkge1xuICAgIGxldCBsYXN0Q2VydCA9IHJlYWRDZXJ0RnJvbURpc2soZG9tYWluKT8uY2VydDtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICBhd2FpdCBkZWxheShDRVJUX0NIRUNLX0lOVEVSVkFMKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGxldCBrZXlDZXJ0ID0gYXdhaXQgZ2V0RnJlc2hIVFRQU0NlcnQoZG9tYWluKTtcbiAgICAgICAgICAgIGlmIChrZXlDZXJ0LmNlcnQgIT09IGxhc3RDZXJ0KSB7XG4gICAgICAgICAgICAgICAgbGFzdENlcnQgPSBrZXlDZXJ0LmNlcnQ7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWFnZW50YShgSFRUUFMgY2VydCBmb3IgJHtkb21haW59IHVwZGF0ZWQsIGFwcGx5aW5nIHRvIHJ1bm5pbmcgc2VydmVyYCkpO1xuICAgICAgICAgICAgICAgIG9uTmV3Q2VydChrZXlDZXJ0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRmFpbGVkIHRvIGNoZWNrL3JlbmV3IEhUVFBTIGNlcnQgZm9yICR7ZG9tYWlufWAsIGUpO1xuICAgICAgICB9XG4gICAgfVxufVxuIl19
|
|
176
|
-
/* _JS_SOURCE_HASH = "
|
|
178
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaG9zdFNlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImhvc3RTZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsNENBQW9CO0FBQ3BCLDRDQUFvQjtBQUNwQiw4Q0FBc0I7QUFDdEIsbUVBQWdFO0FBQ2hFLDZEQUFrRTtBQUNsRSxtREFBd0Q7QUFDeEQsMkRBQXFEO0FBQ3JELCtEQUErRDtBQUMvRCxpRUFBOEQ7QUFDOUQsd0VBQW1FO0FBQ25FLG1DQUE0RTtBQUM1RSw2Q0FBc0U7QUFDdEUsK0JBQWtDO0FBRWxDLHlUQUF5VDtBQUN6VCxNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLG1CQUFtQixHQUFHLG1CQUFZLEdBQUcsRUFBRSxDQUFDO0FBRTlDLGlHQUFpRztBQUNqRyxNQUFNLGNBQWMsR0FBRyxtQkFBbUIsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxtQkFBbUIsR0FBRyxtQkFBbUIsQ0FBQyxDQUFDO0FBdUJ6RyxpVEFBaVQ7QUFDMVMsS0FBSyxVQUFVLFVBQVUsQ0FBQyxNQUF3Qjs7SUFDckQsSUFBSSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxNQUFNLENBQUM7SUFDOUIsZ0dBQWdHO0lBQ2hHLElBQUksVUFBVSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3ZELE1BQU0sSUFBQSxzQkFBYyxFQUFDLFVBQVUsQ0FBQyxDQUFDO0lBRWpDLElBQUksTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3RCLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxRQUFRLElBQUksTUFBTSxJQUFBLDBCQUFhLEdBQUUsQ0FBQztRQUNsRCxNQUFNLElBQUEsZUFBUyxFQUFDLEdB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bmltcG9ydCBmcyBmcm9tIFwiZnNcIjtcbmltcG9ydCBuZXQgZnJvbSBcIm5ldFwiO1xuaW1wb3J0IHsgU29ja2V0RnVuY3Rpb24gfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL1NvY2tldEZ1bmN0aW9uXCI7XG5pbXBvcnQgeyBnZXROb2RlSWRMb2NhdGlvbiB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL25vZGVDYWNoZVwiO1xuaW1wb3J0IHsgdGltZUluTWludXRlIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvbWlzY1wiO1xuaW1wb3J0IHsgZGVsYXkgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9iYXRjaGluZ1wiO1xuaW1wb3J0IHsgZ2V0RXh0ZXJuYWxJUCB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL25ldHdvcmtpbmdcIjtcbmltcG9ydCB7IGZvcndhcmRQb3J0IH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvZm9yd2FyZFBvcnRcIjtcbmltcG9ydCB7IG1hZ2VudGEgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9mb3JtYXR0aW5nL2xvZ0NvbG9yc1wiO1xuaW1wb3J0IHsgZ2V0T3duTWFjaGluZUlkLCBnZXRUaHJlYWRLZXlDZXJ0LCBsb2FkSWRlbnRpdHlDQSB9IGZyb20gXCIuL2NlcnRzXCI7XG5pbXBvcnQgeyBnZW5lcmF0ZUNlcnQsIGdldEFjY291bnRLZXksIHBhcnNlQ2VydCB9IGZyb20gXCIuL2h0dHBzQ2VydHNcIjtcbmltcG9ydCB7IHNldFJlY29yZCB9IGZyb20gXCIuL2Ruc1wiO1xuXG4vLyBSZW5ldyBzb21ld2hlcmUgcmFuZG9tbHkgYmV0d2VlbiA0MCUgYW5kIDYwJSBvZiB0aGUgd2F5IHRocm91Z2ggdGhlIGNlcnQgbGlmZXRpbWUuIFRoZSByYW5kb20gdGhyZXNob2xkIHN0YWdnZXJzIHBhcmFsbGVsIHByb2Nlc3NlcyBvbiB0aGUgc2FtZSBtYWNoaW5lLCBzbyB1c3VhbGx5IG9uZSBwcm9jZXNzIHJlbmV3cyBlYXJseSwgYW5kIHRoZSBvdGhlcnMgc2VlIHRoZSByZW5ld2VkIGNlcnQgb24gZGlzayAod2UgcmUtcmVhZCB0aGUgZGlzayBiZWZvcmUgZXZlcnkgcmVuZXdhbCBjaGVjaykgYW5kIG5ldmVyIHJlbmV3IHRoZW1zZWx2ZXMuXG5jb25zdCBSRU5FV19USFJFU0hPTERfTUlOID0gMC40O1xuY29uc3QgUkVORVdfVEhSRVNIT0xEX01BWCA9IDAuNjtcbmNvbnN0IENFUlRfQ0hFQ0tfSU5URVJWQUwgPSB0aW1lSW5NaW51dGUgKiAxNTtcblxuLy8gT25lIHRocmVzaG9sZCBwZXIgcHJvY2Vzcywgc28gYSBwcm9jZXNzIGlzIGNvbnNpc3RlbnRseSBlYXJseSBvciBsYXRlIHJlbGF0aXZlIHRvIGl0cyBzaWJsaW5nc1xuY29uc3QgcmVuZXdUaHJlc2hvbGQgPSBSRU5FV19USFJFU0hPTERfTUlOICsgTWF0aC5yYW5kb20oKSAqIChSRU5FV19USFJFU0hPTERfTUFYIC0gUkVORVdfVEhSRVNIT0xEX01JTik7XG5cbmV4cG9ydCB0eXBlIEhvc3RTZXJ2ZXJDb25maWcgPSB7XG4gICAgLyoqIEZ1bGwgZG9tYWluIHRvIGhvc3Qgb24gKGUuZy4gXCJ0ZXN0c2l0ZS5leGFtcGxlLmNvbVwiKS4gVGhlIEhUVFBTIGNlcnQgaXMgY3JlYXRlZCBmb3IgdGhpcyBkb21haW4gYW5kICouZG9tYWluLCBzbyB1c2luZyBhIHN1YmRvbWFpbiBuZXZlciB0b3VjaGVzIHRoZSByb290IGRvbWFpbiAoYmV5b25kIGl0cyBfYWNtZS1jaGFsbGVuZ2UgVFhUIHJlY29yZCkuICovXG4gICAgZG9tYWluOiBzdHJpbmc7XG4gICAgcG9ydDogbnVtYmVyO1xuXG4gICAgLy8gVE9ETzogRXZlbnR1YWxseSB3ZSBzaG91bGQgc3VwcG9ydCBydW5uaW5nIHdpdGhvdXQgQ2xvdWRmbGFyZSBBUEkgdG9rZW5zLiBJdCdzIGFubm95aW5nIHRob3VnaCBhcyB0aGUgdXNlciB3aWxsIGhhdmUgdG8gY3JlYXRlIGEgc2VsZi1zaWduZWQgY2VydGlmaWNhdGUgYW5kIHRoZW4gdGhleSdsbCBoYXZlIHRvIGdvIHRocm91Z2ggYW5kIHRydXN0IGl0IGV2ZXJ5d2hlcmUsIGFuZCBhIGxvdCBvZiB0aGUgc3R1ZmYgaXMgdHJhbnNwYXJlbnQsIGFuZCBzbyBpdCdsbCBoYXZlIHRvIGJlIG5vbi10cmFuc3BhcmVudCwgZ2V0dGluZyB0aGUgdXNlciB0byBnbyB0byB0aGUgcGFnZSB0aGF0IG93bnMgdGhlIGRvbWFpbiBhbmQgdHJ1c3QgaXQgZnJvbSB0aGVyZS4gSXQncyBtdWNoIGJldHRlciBqdXN0IG1ha2UgYSBDbG91ZGZsYXJlIGFjY291bnQuIFlvdSBjYW4gYnV5IGEgZG9tYWluIGZvciAkMTUgYSB5ZWFyLCBhbmQgdGhlbiB5b3UgY2FuIHVzZSBpdCBmb3IgR2l0SHViIHBhZ2VzIHRvIGhvc3QgeW91ciBvd24gc2l0ZSBhbmQgZG8gYWxsIGtpbmRzIG9mIHRoaW5ncyBqdXN0IGxpa2UgYW55IG90aGVyIHJlYWwgc2l0ZS5cbiAgICAvKiogQ3JlYXRlcyBhbiB1bnByb3hpZWQgQSByZWNvcmQgcG9pbnRpbmcgZG9tYWluIGF0IHRoaXMgbWFjaGluZSAocHVibGljSXAsIG9yIG91ciBkZXRlY3RlZCBleHRlcm5hbCBJUCkgKi9cbiAgICBzZXRETlNSZWNvcmQ/OiBib29sZWFuO1xuICAgIHB1YmxpY0lwPzogc3RyaW5nO1xuICAgIGFsbG93SG9zdG5hbWVzPzogc3RyaW5nW107XG4gICAgLyoqIFdoZW4gdGhlIHBvcnQgaXMgYnVzeSAoZS5nLiB0aGUgcHJldmlvdXMgZGVwbG95IHN0aWxsIGhvbGRzIGl0KSwgbW91bnQgb24gYW4gYWx0ZXJuYXRlIHBvcnQgaW5zdGVhZCAodGhlIHNvY2tldCBzZXJ2ZXIncyBidWlsdC1pbiBmcmVlLXBvcnQgc2NhbiksIGFuZCBrZWVwIHRyeWluZyB0byB0YWtlIHRoZSByZWFsIHBvcnQgLSBvbmNlIGl0IGZyZWVzLCBhIHJhdyBUQ1AgcmVsYXkgb24gdGhlIHJlYWwgcG9ydCBmb3J3YXJkcyB0byBvdXIgbGlzdGVuZXIgKFNvY2tldEZ1bmN0aW9uIGNhbiBvbmx5IG1vdW50IG9uY2UgcGVyIHByb2Nlc3MpLiAqL1xuICAgIHBvcnRGYWxsYmFjaz86IHtcbiAgICAgICAgLyoqIERlbGF5IHVudGlsIHRoZSBuZXh0IG1haW4tcG9ydCBhY3F1aXNpdGlvbiBhdHRlbXB0ICh0aWdodGVuZWQgYXJvdW5kIHRoZSBwcmVkZWNlc3NvcidzIHNjaGVkdWxlZCBkZWF0aCkgKi9cbiAgICAgICAgZ2V0QWNxdWlyZURlbGF5OiAoKSA9PiBudW1iZXI7XG4gICAgICAgIC8qKiBDYWxsZWQgd2hlbiB0aGUgbWFpbiBwb3J0IHR1cm5lZCBvdXQgdG8gYmUgYnVzeSwgYmVmb3JlIHdlIGFjdCBhcyBpdHMgc3VjY2Vzc29yIGluIGFueSB3YXkuIFRocm93aW5nIGFib3J0cyBzdGFydHVwIC0gYSBidXN5IHBvcnQgd2l0aCBubyBkZXBsb3kgaW4gcHJvZ3Jlc3MgbWVhbnMgc29tZXRoaW5nIGVsc2UgaG9sZHMgaXQsIHdoaWNoIGlzIG5vdCBhIHN0YXRlIHRvIGtlZXAgcnVubmluZyBpbi4gKi9cbiAgICAgICAgb25Qb3J0SW5Vc2U/OiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xuICAgICAgICAvKiogUmVwb3J0cyBldmVyeSBwb3J0IHdlIGJlY29tZSByZWFjaGFibGUgb24gKHRoZSBhbHRlcm5hdGUgYXQgbW91bnQsIHRoZSBtYWluIHBvcnQgb25jZSByZWxheWVkKSAqL1xuICAgICAgICBvbkxpc3RlbmluZzogKHBvcnQ6IG51bWJlciwgaXNNYWluUG9ydDogYm9vbGVhbikgPT4gdm9pZDtcbiAgICB9O1xufTtcblxuLyoqIEhvc3RzIGEgU29ja2V0RnVuY3Rpb24gc2VydmVyIG9uIGEgcmVhbCBkb21haW4sIHdpdGggYW4gYXV0b21hdGljYWxseSBjcmVhdGVkIGFuZCByZW5ld2VkIExldCdzIEVuY3J5cHQgSFRUUFMgY2VydGlmaWNhdGUgKGNhY2hlZCBpbiB0aGUgaG9tZSBmb2xkZXIsIHNoYXJlZCBiZXR3ZWVuIHByb2Nlc3NlcyBvbiB0aGUgbWFjaGluZSkuIEV4cG9zZSB5b3VyIGNvbnRyb2xsZXJzIChhbmQgYW55IFJlcXVpcmVDb250cm9sbGVyIHNldHVwKSBiZWZvcmUgY2FsbGluZyB0aGlzLiBSZXR1cm5zIHRoZSBtb3VudGVkIG5vZGVJZC4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBob3N0U2VydmVyKGNvbmZpZzogSG9zdFNlcnZlckNvbmZpZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgbGV0IHsgZG9tYWluLCBwb3J0IH0gPSBjb25maWc7XG4gICAgLy8gVGhlIGlkZW50aXR5IENBIGFsd2F5cyBsaXZlcyBvbiB0aGUgcm9vdCBkb21haW4gKG5vZGVJZHMgYXJlIHRocmVhZEhhc2gubWFjaGluZUhhc2gucm9vdC50bGQpXG4gICAgbGV0IHJvb3REb21haW4gPSBkb21haW4uc3BsaXQoXCIuXCIpLnNsaWNlKC0yKS5qb2luKFwiLlwiKTtcbiAgICBhd2FpdCBsb2FkSWRlbnRpdHlDQShyb290RG9tYWluKTtcblxuICAgIGlmIChjb25maWcuc2V0RE5TUmVjb3JkKSB7XG4gICAgICAgIGxldCBpcCA9IGNvbmZpZy5wdWJsaWNJcCB8fCBhd2FpdCBnZXRFeHRlcm5hbElQKCk7XG4gICAgICAgIGF3YWl0IHNldFJlY29yZChcIkFcIiwgZG9tYWluLCBpcCk7XG4gICAgfVxuXG4gICAgbGV0IGtleUNlcnQgPSBhd2FpdCBnZXRGcmVzaEhUVFBTQ2VydChkb21haW4pO1xuICAgIGxldCBjZXJ0TGlzdGVuZXJzOiAoKHZhbHVlOiB7IGtleTogc3RyaW5nOyBjZXJ0OiBzdHJpbmcgfSkgPT4gdm9pZClbXSA9IFtdO1xuICAgIHZvaWQgcnVuQ2VydFJlbmV3YWxMb29wKGRvbWFpbiwgbmV3S2V5Q2VydCA9PiB7XG4gICAgICAgIGtleUNlcnQgPSBuZXdLZXlDZXJ0O1xuICAgICAgICBmb3IgKGxldCBsaXN0ZW5lciBvZiBjZXJ0TGlzdGVuZXJzKSB7XG4gICAgICAgICAgICBsaXN0ZW5lcihuZXdLZXlDZXJ0KTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gV2l0aCBwb3J0RmFsbGJhY2ssIGEgYnVzeSBwb3J0IGlzIG5vdCBhbiBlcnJvcjogdGhlIHVuZGVybHlpbmcgc2VydmVyIHNjYW5zIGZvciBhIGZyZWUgcG9ydCBpbnN0ZWFkICh1c2VBdmFpbGFibGVQb3J0SWZQb3J0SW5Vc2UpLCBhbmQgdGhlIG5vZGVJZCB0ZWxscyB1cyB3aGljaCBwb3J0IHdlIGFjdHVhbGx5IGdvdFxuICAgIGxldCBub2RlSWQgPSBhd2FpdCBTb2NrZXRGdW5jdGlvbi5tb3VudCh7XG4gICAgICAgIHB1YmxpYzogdHJ1ZSxcbiAgICAgICAgYXV0b0ZvcndhcmRQb3J0OiB0cnVlLFxuICAgICAgICBwb3J0LFxuICAgICAgICB1c2VBdmFpbGFibGVQb3J0SWZQb3J0SW5Vc2U6ICEhY29uZmlnLnBvcnRGYWxsYmFjayxcbiAgICAgICAgLi4uZ2V0VGhyZWFkS2V5Q2VydChyb290RG9tYWluKSxcbiAgICAgICAgU05JQ2VydHM6IHtcbiAgICAgICAgICAgIFtkb21haW5dOiBjYWxsYmFjayA9PiB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soa2V5Q2VydCk7XG4gICAgICAgICAgICAgICAgY2VydExpc3RlbmVycy5wdXNoKGNhbGxiYWNrKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBbZ2V0T3duTWFjaGluZUlkKHJvb3REb21haW4pICsgXCIuXCIgKyByb290RG9tYWluXTogYXN5bmMgY2FsbGJhY2sgPT4ge1xuICAgICAgICAgICAgICAgIGxldCB0aHJlYWRDZXJ0ID0gYXdhaXQgZ2V0VGhyZWFkS2V5Q2VydChyb290RG9tYWluKTtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayh7XG4gICAgICAgICAgICAgICAgICAgIGtleTogdGhyZWFkQ2VydC5rZXksXG4gICAgICAgICAgICAgICAgICAgIGNlcnQ6IHRocmVhZENlcnQuY2VydCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBbXCIxMjctMC0wLTEuXCIgKyByb290RG9tYWluXTogYXN5bmMgY2FsbGJhY2sgPT4ge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGtleUNlcnQpO1xuICAgICAgICAgICAgICAgIGNlcnRMaXN0ZW5lcnMucHVzaChjYWxsYmFjayk7XG4gICAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBhbGxvd0hvc3RuYW1lczogY29uZmlnLmFsbG93SG9zdG5hbWVzLFxuICAgIH0pO1xuICAgIGxldCBzZXJ2aW5nUG9ydCA9IGdldE5vZGVJZExvY2F0aW9uKG5vZGVJZCk/LnBvcnQgfHwgcG9ydDtcbiAgICBsZXQgZmFsbGJhY2sgPSBjb25maWcucG9ydEZhbGxiYWNrO1xuICAgIGlmIChmYWxsYmFjayAmJiBzZXJ2aW5nUG9ydCAhPT0gcG9ydCkge1xuICAgICAgICBjb25zb2xlLndhcm4oYFBvcnQgJHtwb3J0fSBpcyBpbiB1c2UgKHByZXN1bWFibHkgYnkgb3VyIHByZWRlY2Vzc29yKTsgc2VydmluZyBvbiBhbHRlcm5hdGUgcG9ydCAke3NlcnZpbmdQb3J0fSB1bnRpbCBpdCBmcmVlc2ApO1xuICAgICAgICBhd2FpdCBmYWxsYmFjay5vblBvcnRJblVzZT8uKCk7XG4gICAgICAgIHZvaWQgcnVuTWFpblBvcnRBY3F1aXJlTG9vcChkb21haW4sIHBvcnQsIHNlcnZpbmdQb3J0LCBmYWxsYmFjayk7XG4gICAgfVxuICAgIGZhbGxiYWNrPy5vbkxpc3RlbmluZyhzZXJ2aW5nUG9ydCwgc2VydmluZ1BvcnQgPT09IHBvcnQpO1xuICAgIGNvbnNvbGUubG9nKG1hZ2VudGEoYEhvc3RpbmcgaHR0cHM6Ly8ke2RvbWFpbn06JHtzZXJ2aW5nUG9ydH0gKG5vZGVJZCAke25vZGVJZH0pYCkpO1xuICAgIHJldHVybiBub2RlSWQ7XG59XG5cbi8vIFNvY2tldEZ1bmN0aW9uIGNhbiBvbmx5IG1vdW50IG9uY2UgcGVyIHByb2Nlc3MsIHNvIFwidGFraW5nIG92ZXJcIiB0aGUgbWFpbiBwb3J0IGlzIGEgcmF3IFRDUCByZWxheSBmb3J3YXJkaW5nIHRvIG91ciByZWFsIGxpc3RlbmVyIC0gVExTL1NOSSBwYXNzZXMgc3RyYWlnaHQgdGhyb3VnaCwgYW5kIGNsaWVudHMgYWRkcmVzcyBzZXJ2ZXJzIGJ5IGlwIGRvbWFpbiAod2lsZGNhcmQgbmVnb3RpYXRpb24pLCBzbyB0aGUgZXh0cmEgaG9wIGlzIGludmlzaWJsZS5cbmFzeW5jIGZ1bmN0aW9uIHJ1bk1haW5Qb3J0QWNxdWlyZUxvb3AoZG9tYWluOiBzdHJpbmcsIG1haW5Qb3J0OiBudW1iZXIsIHNlcnZpbmdQb3J0OiBudW1iZXIsIGZhbGxiYWNrOiBOb25OdWxsYWJsZTxIb3N0U2VydmVyQ29uZmlnW1wicG9ydEZhbGxiYWNrXCJdPik6IFByb21pc2U8dm9pZD4ge1xuICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIGF3YWl0IGRlbGF5KGZhbGxiYWNrLmdldEFjcXVpcmVEZWxheSgpKTtcbiAgICAgICAgbGV0IGFjcXVpcmVkID0gYXdhaXQgbmV3IFByb21pc2U8Ym9vbGVhbj4ocmVzb2x2ZSA9PiB7XG4gICAgICAgICAgICBsZXQgcmVsYXkgPSBuZXQuY3JlYXRlU2VydmVyKGNsaWVudCA9PiB7XG4gICAgICAgICAgICAgICAgbGV0IHVwc3RyZWFtID0gbmV0LmNvbm5lY3QoeyBob3N0OiBcIjEyNy4wLjAuMVwiLCBwb3J0OiBzZXJ2aW5nUG9ydCB9KTtcbiAgICAgICAgICAgICAgICAvLyBXaXRob3V0IHRoaXMgZXZlcnkgcmVsYXllZCByZXF1ZXN0IHBheXMgdGhlIH40MG1zIGRlbGF5ZWQtQUNLIHRpbWVyOiBhIGNhbGwgaXMgYSBzbWFsbCB3cml0ZSAob2Z0ZW4gYSBoZWFkZXIgdGhlbiBhIGJvZHkpLCBOYWdsZSBob2xkcyB0aGUgc2Vjb25kIHdyaXRlIHVudGlsIHRoZSBmaXJzdCBpcyBhY2tub3dsZWRnZWQsIGFuZCB0aGUgcGVlciBoYXMgbm90aGluZyB0byBwaWdneWJhY2sgdGhlIEFDSyBvbi4gTWVhc3VyZWQgYXMgNDNtcyBwZXIgY2FsbCB0aHJvdWdoIHRoZSByZWxheSB2ZXJzdXMgMW1zIGRpcmVjdC5cbiAgICAgICAgICAgICAgICBjbGllbnQuc2V0Tm9EZWxheSh0cnVlKTtcbiAgICAgICAgICAgICAgICB1cHN0cmVhbS5zZXROb0RlbGF5KHRydWUpO1xuICAgICAgICAgICAgICAgIGNsaWVudC5waXBlKHVwc3RyZWFtKTtcbiAgICAgICAgICAgICAgICB1cHN0cmVhbS5waXBlKGNsaWVudCk7XG4gICAgICAgICAgICAgICAgbGV0IGNsZWFudXAgPSAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNsaWVudC5kZXN0cm95KCk7XG4gICAgICAgICAgICAgICAgICAgIHVwc3RyZWFtLmRlc3Ryb3koKTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGNsaWVudC5vbihcImVycm9yXCIsIGNsZWFudXApO1xuICAgICAgICAgICAgICAgIHVwc3RyZWFtLm9uKFwiZXJyb3JcIiwgY2xlYW51cCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJlbGF5Lm9uY2UoXCJlcnJvclwiLCAoKSA9PiByZXNvbHZlKGZhbHNlKSk7XG4gICAgICAgICAgICByZWxheS5saXN0ZW4obWFpblBvcnQsICgpID0+IHJlc29sdmUodHJ1ZSkpO1xuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGFjcXVpcmVkKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhtYWdlbnRhKGBBY3F1aXJlZCBtYWluIHBvcnQgJHttYWluUG9ydH0gZm9yIGh0dHBzOi8vJHtkb21haW59IChyZWxheWluZyB0byBvdXIgbGlzdGVuZXIgb24gJHtzZXJ2aW5nUG9ydH0pYCkpO1xuICAgICAgICAgICAgLy8gVGhlIG1vdW50IG9ubHkgZm9yd2FyZGVkIE9VUiBzZXJ2aW5nIHBvcnQ7IHRoZSBtYWluIHBvcnQgbmVlZHMgaXRzIG93biBtYXBwaW5nICh0aGUgcHJlZGVjZXNzb3IncyBtYXBwaW5nIHBvaW50ZWQgYXQgdGhlIHNhbWUgbWFjaGluZStwb3J0LCBidXQgZGllcyB3aXRoIGl0KVxuICAgICAgICAgICAgYXdhaXQgZm9yd2FyZFBvcnQoeyBleHRlcm5hbFBvcnQ6IG1haW5Qb3J0LCBpbnRlcm5hbFBvcnQ6IG1haW5Qb3J0IH0pO1xuICAgICAgICAgICAgZmFsbGJhY2sub25MaXN0ZW5pbmcobWFpblBvcnQsIHRydWUpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5mdW5jdGlvbiBnZXRDZXJ0RGlza1BhdGgoZG9tYWluOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gb3MuaG9tZWRpcigpICsgYC9odHRwc2NlcnRfJHtkb21haW59Lmpzb25gO1xufVxuZnVuY3Rpb24gcmVhZENlcnRGcm9tRGlzayhkb21haW46IHN0cmluZyk6IHsga2V5OiBzdHJpbmc7IGNlcnQ6IHN0cmluZyB9IHwgdW5kZWZpbmVkIHtcbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShmcy5yZWFkRmlsZVN5bmMoZ2V0Q2VydERpc2tQYXRoKGRvbWFpbiksIFwidXRmOFwiKSkgYXMgeyBrZXk6IHN0cmluZzsgY2VydDogc3RyaW5nIH07XG4gICAgfSBjYXRjaCB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxufVxuZnVuY3Rpb24gZ2V0UmVuZXdUaW1lKGNlcnRQZW06IHN0cmluZywgdGhyZXNob2xkOiBudW1iZXIpIHtcbiAgICBsZXQgY2VydE9iaiA9IHBhcnNlQ2VydChjZXJ0UGVtKTtcbiAgICBsZXQgc3RhcnQgPSArbmV3IERhdGUoY2VydE9iai52YWxpZGl0eS5ub3RCZWZvcmUpO1xuICAgIGxldCBlbmQgPSArbmV3IERhdGUoY2VydE9iai52YWxpZGl0eS5ub3RBZnRlcik7XG4gICAgcmV0dXJuIHN0YXJ0ICsgKGVuZCAtIHN0YXJ0KSAqIHRocmVzaG9sZDtcbn1cblxuLyoqIFJldHVybnMgdGhlIGNhY2hlZCBIVFRQUyBjZXJ0IGZvciB0aGUgZG9tYWluLCBjcmVhdGluZy9yZW5ld2luZyBpdCBmaXJzdCBpZiBpdCBpcyBwYXN0IHRoaXMgcHJvY2VzcydzIHJlbmV3YWwgdGhyZXNob2xkLiBSZWFkcyB0aGUgZGlzayBjYWNoZSBvbiBldmVyeSBjYWxsLCBzbyBhIHJlbmV3YWwgZG9uZSBieSBhIHBhcmFsbGVsIHByb2Nlc3MgaXMgcGlja2VkIHVwIGluc3RlYWQgb2YgcmVuZXdpbmcgYWdhaW4uICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0RnJlc2hIVFRQU0NlcnQoZG9tYWluOiBzdHJpbmcpOiBQcm9taXNlPHsga2V5OiBzdHJpbmc7IGNlcnQ6IHN0cmluZyB9PiB7XG4gICAgbGV0IGtleUNlcnQgPSByZWFkQ2VydEZyb21EaXNrKGRvbWFpbik7XG4gICAgaWYgKGtleUNlcnQgJiYgZ2V0UmVuZXdUaW1lKGtleUNlcnQuY2VydCwgcmVuZXdUaHJlc2hvbGQpID4gRGF0ZS5ub3coKSkge1xuICAgICAgICByZXR1cm4ga2V5Q2VydDtcbiAgICB9XG4gICAgaWYgKGtleUNlcnQpIHtcbiAgICAgICAgY29uc29sZS5sb2cobWFnZW50YShgSFRUUFMgY2VydCBmb3IgJHtkb21haW59IGlzIHBhc3QgJHsocmVuZXdUaHJlc2hvbGQgKiAxMDApLnRvRml4ZWQoMCl9JSBvZiBpdHMgbGlmZXRpbWUsIHJlbmV3aW5nYCkpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUubG9nKG1hZ2VudGEoYE5vIEhUVFBTIGNlcnQgb24gZGlzayBmb3IgJHtkb21haW59LCBjcmVhdGluZyBvbmVgKSk7XG4gICAgfVxuICAgIGxldCBhY2NvdW50S2V5ID0gYXdhaXQgZ2V0QWNjb3VudEtleShkb21haW4pO1xuICAgIHRyeSB7XG4gICAgICAgIGtleUNlcnQgPSBhd2FpdCBnZW5lcmF0ZUNlcnQoeyBhY2NvdW50S2V5LCBkb21haW4sIGFsdERvbWFpbnM6IFtcIiouXCIgKyBkb21haW5dIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKFN0cmluZyhlKS5pbmNsdWRlcyhcImF1dGhvcml6YXRpb24gbXVzdCBiZSBwZW5kaW5nXCIpKSB7XG4gICAgICAgICAgICAvLyBBbm90aGVyIHByb2Nlc3MgaXMgbWlkLXJlbmV3YWwuIFdhaXQgZm9yIGl0IHRvIGZpbmlzaCwgdGhlbiByZS1jaGVjayB0aGUgZGlzay5cbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBDZXJ0aWZpY2F0ZSBhdXRob3JpemF0aW9uIGlzIHBlbmRpbmcgaW4gYW5vdGhlciBwcm9jZXNzLCB3YWl0aW5nIDIgbWludXRlc2ApO1xuICAgICAgICAgICAgYXdhaXQgZGVsYXkodGltZUluTWludXRlICogMik7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2V0RnJlc2hIVFRQU0NlcnQoZG9tYWluKTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBlO1xuICAgIH1cbiAgICBmcy53cml0ZUZpbGVTeW5jKGdldENlcnREaXNrUGF0aChkb21haW4pLCBKU09OLnN0cmluZ2lmeSh7IGtleToga2V5Q2VydC5rZXksIGNlcnQ6IGtleUNlcnQuY2VydCB9KSk7XG4gICAgcmV0dXJuIHsga2V5OiBrZXlDZXJ0LmtleSwgY2VydDoga2V5Q2VydC5jZXJ0IH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJ1bkNlcnRSZW5ld2FsTG9vcChkb21haW46IHN0cmluZywgb25OZXdDZXJ0OiAoa2V5Q2VydDogeyBrZXk6IHN0cmluZzsgY2VydDogc3RyaW5nIH0pID0+IHZvaWQpIHtcbiAgICBsZXQgbGFzdENlcnQgPSByZWFkQ2VydEZyb21EaXNrKGRvbWFpbik/LmNlcnQ7XG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgYXdhaXQgZGVsYXkoQ0VSVF9DSEVDS19JTlRFUlZBTCk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQga2V5Q2VydCA9IGF3YWl0IGdldEZyZXNoSFRUUFNDZXJ0KGRvbWFpbik7XG4gICAgICAgICAgICBpZiAoa2V5Q2VydC5jZXJ0ICE9PSBsYXN0Q2VydCkge1xuICAgICAgICAgICAgICAgIGxhc3RDZXJ0ID0ga2V5Q2VydC5jZXJ0O1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKG1hZ2VudGEoYEhUVFBTIGNlcnQgZm9yICR7ZG9tYWlufSB1cGRhdGVkLCBhcHBseWluZyB0byBydW5uaW5nIHNlcnZlcmApKTtcbiAgICAgICAgICAgICAgICBvbk5ld0NlcnQoa2V5Q2VydCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEZhaWxlZCB0byBjaGVjay9yZW5ldyBIVFRQUyBjZXJ0IGZvciAke2RvbWFpbn1gLCBlKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiJdfQ==
|
|
179
|
+
/* _JS_SOURCE_HASH = "9baf70af1a68cebffec3371ab785502f6622d22b98fd99a3e0deb3d517091896"; */
|
package/package.json
CHANGED
package/spec.txt
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
Refactor
|
|
2
|
+
|
|
3
|
+
createArchives => storageController => storageServerState => BlobStore
|
|
4
|
+
|
|
5
|
+
So create Archives has to decide who we're going to talk to, and then Storage Controller, it just acts like adds security and stuff. and then it gets into load it bucket, and then load it bucket. It then decides what back-end store we're talking to, and the back-end store, it might talk to multiple sources.
|
|
6
|
+
So there's which server we're going to talk to, which bucket on the server it maps to once we get there, and then there's which back-end stores that we talk to. So I guess it's fine.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
1
11
|
TODO: Use wildcard certificates, and then expose urls which match up to the shard fraction, to 2 decimal places:
|
|
2
12
|
storageshard01.domain.com
|
|
3
13
|
storageshard26.domain.com
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
|
-
import { IArchives, ArchiveFileInfo, ArchivesConfig, ChangesAfterConfig, DelConfig, GetConfig, GetInfoConfig, SetConfig } from "./IArchives";
|
|
3
|
+
import { IArchives, ArchiveFileInfo, ArchivesConfig, ChangesAfterConfig, DelConfig, FindConfig, GetConfig, GetInfoConfig, SetConfig } from "./IArchives";
|
|
4
4
|
export declare class ArchivesDisk implements IArchives {
|
|
5
5
|
private folder;
|
|
6
6
|
constructor(folder: string);
|
|
@@ -31,14 +31,8 @@ export declare class ArchivesDisk implements IArchives {
|
|
|
31
31
|
writeTime: number;
|
|
32
32
|
size: number;
|
|
33
33
|
} | undefined>;
|
|
34
|
-
find(prefix: string, config?:
|
|
35
|
-
|
|
36
|
-
type: "files" | "folders";
|
|
37
|
-
}): Promise<string[]>;
|
|
38
|
-
findInfo(prefix: string, config?: {
|
|
39
|
-
shallow?: boolean;
|
|
40
|
-
type?: "files" | "folders";
|
|
41
|
-
}): Promise<ArchiveFileInfo[]>;
|
|
34
|
+
find(prefix: string, config?: FindConfig): Promise<string[]>;
|
|
35
|
+
findInfo(prefix: string, config?: FindConfig): Promise<ArchiveFileInfo[]>;
|
|
42
36
|
private collectFiles;
|
|
43
37
|
setLargeFile(config: {
|
|
44
38
|
path: string;
|
|
@@ -51,7 +45,4 @@ export declare class ArchivesDisk implements IArchives {
|
|
|
51
45
|
cancelLargeUpload(id: string): Promise<void>;
|
|
52
46
|
getURL(path: string): Promise<string>;
|
|
53
47
|
}
|
|
54
|
-
export declare function applyFindInfoShape(files: ArchiveFileInfo[], prefix: string, config?:
|
|
55
|
-
shallow?: boolean;
|
|
56
|
-
type?: "files" | "folders";
|
|
57
|
-
}): ArchiveFileInfo[];
|
|
48
|
+
export declare function applyFindInfoShape(files: ArchiveFileInfo[], prefix: string, config?: FindConfig): ArchiveFileInfo[];
|
package/storage/ArchivesDisk.ts
CHANGED
|
@@ -3,7 +3,7 @@ import path from "path";
|
|
|
3
3
|
import { lazy } from "socket-function/src/caching";
|
|
4
4
|
import { runInfinitePoll } from "socket-function/src/batching";
|
|
5
5
|
import { sort, binarySearchBasic } from "socket-function/src/misc";
|
|
6
|
-
import { IArchives, ArchiveFileInfo, ArchivesConfig, ChangesAfterConfig, DelConfig, GetConfig, GetInfoConfig, SetConfig, assertValidLastModified } from "./IArchives";
|
|
6
|
+
import { IArchives, ArchiveFileInfo, ArchivesConfig, ChangesAfterConfig, DelConfig, FindConfig, GetConfig, GetInfoConfig, SetConfig, assertValidLastModified } from "./IArchives";
|
|
7
7
|
import { filterChanges } from "./remoteStorage/remoteConfig";
|
|
8
8
|
|
|
9
9
|
// The base file-system IArchives: storage is one-to-one with the file system, every key is exactly one real file under <folder>/files, so the file system itself is the index. File handles are cached and reused, and closed once idle (see FileHandleCache). All operations on a file run in serial, so they can't collide with each other or with handle closing. Used as the disk synchronization source of BlobStore (see remoteStorage/blobStore.ts).
|
|
@@ -210,6 +210,8 @@ export class ArchivesDisk implements IArchives {
|
|
|
210
210
|
}
|
|
211
211
|
let stats = await handle.stat();
|
|
212
212
|
let size = stats.size;
|
|
213
|
+
// A size-0 file is a tombstone (an empty file IS a missing file) - absent, unless the caller asked for tombstones. Ranged reads of a REAL file can still legitimately return no bytes (range past EOF, below).
|
|
214
|
+
if (!size && !config?.includeTombstones) return undefined;
|
|
213
215
|
let start = range && Math.min(range.start, size) || 0;
|
|
214
216
|
let end = range && Math.min(range.end, size) || size;
|
|
215
217
|
if (end <= start) return { data: Buffer.alloc(0), writeTime: stats.mtimeMs, size };
|
|
@@ -233,11 +235,11 @@ export class ArchivesDisk implements IArchives {
|
|
|
233
235
|
});
|
|
234
236
|
}
|
|
235
237
|
|
|
236
|
-
public async find(prefix: string, config?:
|
|
238
|
+
public async find(prefix: string, config?: FindConfig): Promise<string[]> {
|
|
237
239
|
return (await this.findInfo(prefix, config)).map(x => x.path);
|
|
238
240
|
}
|
|
239
241
|
|
|
240
|
-
public async findInfo(prefix: string, config?:
|
|
242
|
+
public async findInfo(prefix: string, config?: FindConfig): Promise<ArchiveFileInfo[]> {
|
|
241
243
|
await this.init();
|
|
242
244
|
let infos = new Map<string, ArchiveFileInfo>();
|
|
243
245
|
await this.collectFiles("", prefix, infos);
|
|
@@ -362,7 +364,7 @@ async function statOrUndefined(filePath: string): Promise<fs.Stats | undefined>
|
|
|
362
364
|
}
|
|
363
365
|
|
|
364
366
|
// The folders/shallow post-processing shared by findInfo implementations that list flat files (used by ArchivesDisk on the raw disk walk, and by BlobStore on its index).
|
|
365
|
-
export function applyFindInfoShape(files: ArchiveFileInfo[], prefix: string, config?:
|
|
367
|
+
export function applyFindInfoShape(files: ArchiveFileInfo[], prefix: string, config?: FindConfig): ArchiveFileInfo[] {
|
|
366
368
|
if (config?.type === "folders") {
|
|
367
369
|
let folders = new Map<string, ArchiveFileInfo>();
|
|
368
370
|
for (let file of files) {
|
package/storage/IArchives.d.ts
CHANGED
|
@@ -18,7 +18,9 @@ export type RemoteConfig = {
|
|
|
18
18
|
|
|
19
19
|
NOTE: If we're in the browser, we should allow downloading the files via the URL form (if it's a public bucket), however, we won't allow writing, because their servers do not allow secure browser writes.
|
|
20
20
|
*/
|
|
21
|
-
export type RemoteConfigBase = string |
|
|
21
|
+
export type RemoteConfigBase = string | SourceConfig;
|
|
22
|
+
/** One configured source in a routing config: a hosted (our storage server) or backblaze entry. Requests carry the exact SourceConfig they selected, and the server matches it against its own entries to pick the backing store. */
|
|
23
|
+
export type SourceConfig = HostedConfig | BackblazeConfig;
|
|
22
24
|
export type CommonConfig = {
|
|
23
25
|
/** By default a server hosting this bucket eagerly copies this source's full contents onto its own disk (on top of the lazy read-through caching). Set this to be a front end for a very large database without copying the full database - reads still down-cache individual files on demand. */
|
|
24
26
|
noFullSync?: boolean;
|
|
@@ -57,6 +59,14 @@ export type GetConfig = {
|
|
|
57
59
|
noFallbacks?: boolean;
|
|
58
60
|
/** Store-to-store call: the serving node answers purely from its own disk, completely short-circuiting its index holders - chasing its own remote holders while answering another store is how infinite get loops between stores form (A asks B, B's index points back at A, ...). No window or route checks on reads: if the bytes are on its disk, the caller may have them. */
|
|
59
61
|
internal?: boolean;
|
|
62
|
+
/** Also return size-0 results (tombstones - an empty file IS a missing file) instead of treating them as absent. Off by default, matching getInfo's flag of the same name. Synchronization passes this so a DELETED file (with its write time) is distinguishable from a file that never existed. */
|
|
63
|
+
includeTombstones?: boolean;
|
|
64
|
+
};
|
|
65
|
+
export type FindConfig = {
|
|
66
|
+
shallow?: boolean;
|
|
67
|
+
type?: "files" | "folders";
|
|
68
|
+
/** Listings normally come ONLY from the authoritative sources (the same nodes writes go to - read-your-writes). With fallbacks, a failing shard's routes are covered by the next source holding them (e.g. a wide read replica) instead of the call failing - high availability at the cost of possibly missing just-written data. Single-source archives ignore the flag. */
|
|
69
|
+
fallbacks?: boolean;
|
|
60
70
|
};
|
|
61
71
|
export type DelConfig = {
|
|
62
72
|
/** Stamps the deletion (its tombstone) with this write time instead of now. Synchronization passes the ORIGINAL deletion time, so deletion ordering survives propagation exactly like any other write's ordering. */
|
|
@@ -79,7 +89,7 @@ export type SetConfig = {
|
|
|
79
89
|
lastModified?: number;
|
|
80
90
|
/** Makes the write acceptable on immutable targets: an existing path is simply kept (immutability wins - nothing is overwritten) instead of the write throwing. Requires lastModified. Synchronization MUST pass this on every push - a plain set throws on immutable targets, which would abort reconciliation whenever one source in a chain is immutable. */
|
|
81
91
|
forceSetImmutable?: boolean;
|
|
82
|
-
/** Skips
|
|
92
|
+
/** Skips REDUNDANT target-side safety reads around the write (backblaze: the post-upload existence poll). It does NOT skip checks that are the target's only ordering guard: backblaze's pre-write comparison stays, because b2 has no server of ours enforcing only-take-the-latest - without it a stale push lands over a newer value or tombstone and b2's self-stamped upload time launders it into the newest copy in the system (global resurrection). Hosted targets re-check server-side, so their client-side shortcuts are safe. */
|
|
83
93
|
noChecks?: boolean;
|
|
84
94
|
/** Store-to-store push: the receiving node writes purely to its own disk and index, with NO downstream fan-out (the pushing store owns propagation - fanning its pushes back out is how write loops between stores form). Window and route ARE still checked: the stamp must fall inside one of the receiver's configured windows and routes, so a confused peer cannot stuff data onto a node that was never meant to hold it. Requires lastModified. */
|
|
85
95
|
internal?: boolean;
|
|
@@ -141,6 +151,7 @@ export declare function copyArchiveFile(config: {
|
|
|
141
151
|
forceSetImmutable?: boolean;
|
|
142
152
|
noChecks?: boolean;
|
|
143
153
|
internal?: boolean;
|
|
154
|
+
noFallbacks?: boolean;
|
|
144
155
|
}): Promise<{
|
|
145
156
|
writeTime: number;
|
|
146
157
|
size: number;
|
|
@@ -218,15 +229,9 @@ export interface IArchives {
|
|
|
218
229
|
* their empty files - that is how scans learn of deletions - but nothing built on the index
|
|
219
230
|
* ever surfaces them.
|
|
220
231
|
*/
|
|
221
|
-
find(prefix: string, config?:
|
|
222
|
-
shallow?: boolean;
|
|
223
|
-
type: "files" | "folders";
|
|
224
|
-
}): Promise<string[]>;
|
|
232
|
+
find(prefix: string, config?: FindConfig): Promise<string[]>;
|
|
225
233
|
/** See find for the empty-file (tombstone) rule. */
|
|
226
|
-
findInfo(prefix: string, config?:
|
|
227
|
-
shallow?: boolean;
|
|
228
|
-
type: "files" | "folders";
|
|
229
|
-
}): Promise<ArchiveFileInfo[]>;
|
|
234
|
+
findInfo(prefix: string, config?: FindConfig): Promise<ArchiveFileInfo[]>;
|
|
230
235
|
/** Only works for public buckets (private buckets are API-access only). */
|
|
231
236
|
getURL(path: string): Promise<string>;
|
|
232
237
|
/** The bucket's configuration, which tells whether the optional functions are supported. */
|
package/storage/IArchives.ts
CHANGED
|
@@ -30,7 +30,10 @@ export type RemoteConfig = {
|
|
|
30
30
|
|
|
31
31
|
NOTE: If we're in the browser, we should allow downloading the files via the URL form (if it's a public bucket), however, we won't allow writing, because their servers do not allow secure browser writes.
|
|
32
32
|
*/
|
|
33
|
-
export type RemoteConfigBase = string |
|
|
33
|
+
export type RemoteConfigBase = string | SourceConfig;
|
|
34
|
+
|
|
35
|
+
/** One configured source in a routing config: a hosted (our storage server) or backblaze entry. Requests carry the exact SourceConfig they selected, and the server matches it against its own entries to pick the backing store. */
|
|
36
|
+
export type SourceConfig = HostedConfig | BackblazeConfig;
|
|
34
37
|
|
|
35
38
|
export type CommonConfig = {
|
|
36
39
|
/** By default a server hosting this bucket eagerly copies this source's full contents onto its own disk (on top of the lazy read-through caching). Set this to be a front end for a very large database without copying the full database - reads still down-cache individual files on demand. */
|
|
@@ -92,6 +95,15 @@ export type GetConfig = {
|
|
|
92
95
|
noFallbacks?: boolean;
|
|
93
96
|
/** Store-to-store call: the serving node answers purely from its own disk, completely short-circuiting its index holders - chasing its own remote holders while answering another store is how infinite get loops between stores form (A asks B, B's index points back at A, ...). No window or route checks on reads: if the bytes are on its disk, the caller may have them. */
|
|
94
97
|
internal?: boolean;
|
|
98
|
+
/** Also return size-0 results (tombstones - an empty file IS a missing file) instead of treating them as absent. Off by default, matching getInfo's flag of the same name. Synchronization passes this so a DELETED file (with its write time) is distinguishable from a file that never existed. */
|
|
99
|
+
includeTombstones?: boolean;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export type FindConfig = {
|
|
103
|
+
shallow?: boolean;
|
|
104
|
+
type?: "files" | "folders";
|
|
105
|
+
/** Listings normally come ONLY from the authoritative sources (the same nodes writes go to - read-your-writes). With fallbacks, a failing shard's routes are covered by the next source holding them (e.g. a wide read replica) instead of the call failing - high availability at the cost of possibly missing just-written data. Single-source archives ignore the flag. */
|
|
106
|
+
fallbacks?: boolean;
|
|
95
107
|
};
|
|
96
108
|
|
|
97
109
|
export type DelConfig = {
|
|
@@ -118,7 +130,7 @@ export type SetConfig = {
|
|
|
118
130
|
lastModified?: number;
|
|
119
131
|
/** Makes the write acceptable on immutable targets: an existing path is simply kept (immutability wins - nothing is overwritten) instead of the write throwing. Requires lastModified. Synchronization MUST pass this on every push - a plain set throws on immutable targets, which would abort reconciliation whenever one source in a chain is immutable. */
|
|
120
132
|
forceSetImmutable?: boolean;
|
|
121
|
-
/** Skips
|
|
133
|
+
/** Skips REDUNDANT target-side safety reads around the write (backblaze: the post-upload existence poll). It does NOT skip checks that are the target's only ordering guard: backblaze's pre-write comparison stays, because b2 has no server of ours enforcing only-take-the-latest - without it a stale push lands over a newer value or tombstone and b2's self-stamped upload time launders it into the newest copy in the system (global resurrection). Hosted targets re-check server-side, so their client-side shortcuts are safe. */
|
|
122
134
|
noChecks?: boolean;
|
|
123
135
|
/** Store-to-store push: the receiving node writes purely to its own disk and index, with NO downstream fan-out (the pushing store owns propagation - fanning its pushes back out is how write loops between stores form). Window and route ARE still checked: the stamp must fall inside one of the receiver's configured windows and routes, so a confused peer cannot stuff data onto a node that was never meant to hold it. Requires lastModified. */
|
|
124
136
|
internal?: boolean;
|
|
@@ -215,6 +227,7 @@ export async function copyArchiveFile(config: {
|
|
|
215
227
|
forceSetImmutable?: boolean;
|
|
216
228
|
noChecks?: boolean;
|
|
217
229
|
internal?: boolean;
|
|
230
|
+
noFallbacks?: boolean;
|
|
218
231
|
}): Promise<{ writeTime: number; size: number } | undefined> {
|
|
219
232
|
let { from, to, path } = config;
|
|
220
233
|
let size = config.size;
|
|
@@ -226,7 +239,7 @@ export async function copyArchiveFile(config: {
|
|
|
226
239
|
writeTime = info.writeTime;
|
|
227
240
|
}
|
|
228
241
|
if (size <= LARGE_COPY_THRESHOLD) {
|
|
229
|
-
let result = await from.get2(path, { internal: config.internal });
|
|
242
|
+
let result = await from.get2(path, { internal: config.internal, noFallbacks: config.noFallbacks });
|
|
230
243
|
// Empty counts as absent, never as content to copy: an empty file IS a deletion, set refuses empty buffers, and deletions travel through their own path (del / scan tombstones)
|
|
231
244
|
if (!result || !result.data || !result.data.length) return undefined;
|
|
232
245
|
await to.set(path, result.data, { lastModified: result.writeTime, forceSetImmutable: config.forceSetImmutable, noChecks: config.noChecks, internal: config.internal });
|
|
@@ -242,7 +255,7 @@ export async function copyArchiveFile(config: {
|
|
|
242
255
|
getNextData: async () => {
|
|
243
256
|
if (offset >= totalSize) return undefined;
|
|
244
257
|
let end = Math.min(offset + LARGE_COPY_CHUNK, totalSize);
|
|
245
|
-
let data = await from.get(path, { range: { start: offset, end }, internal: config.internal });
|
|
258
|
+
let data = await from.get(path, { range: { start: offset, end }, internal: config.internal, noFallbacks: config.noFallbacks });
|
|
246
259
|
if (!data || !data.length) {
|
|
247
260
|
throw new Error(`Ranged read of ${JSON.stringify(path)} from ${from.getDebugName()} returned ${data && data.length || "nothing"} at ${offset}-${end} (expected ${end - offset} bytes of a ${totalSize} byte file - it changed or vanished mid-copy)`);
|
|
248
261
|
}
|
|
@@ -312,9 +325,9 @@ export interface IArchives {
|
|
|
312
325
|
* their empty files - that is how scans learn of deletions - but nothing built on the index
|
|
313
326
|
* ever surfaces them.
|
|
314
327
|
*/
|
|
315
|
-
find(prefix: string, config?:
|
|
328
|
+
find(prefix: string, config?: FindConfig): Promise<string[]>;
|
|
316
329
|
/** See find for the empty-file (tombstone) rule. */
|
|
317
|
-
findInfo(prefix: string, config?:
|
|
330
|
+
findInfo(prefix: string, config?: FindConfig): Promise<ArchiveFileInfo[]>;
|
|
318
331
|
/** Only works for public buckets (private buckets are API-access only). */
|
|
319
332
|
getURL(path: string): Promise<string>;
|
|
320
333
|
/** The bucket's configuration, which tells whether the optional functions are supported. */
|
package/storage/backblaze.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
|
-
import { IArchives, ArchivesConfig, ChangesAfterConfig, ArchiveFileInfo, DelConfig, GetConfig, GetInfoConfig, SetConfig } from "./IArchives";
|
|
3
|
+
import { IArchives, ArchivesConfig, ChangesAfterConfig, ArchiveFileInfo, DelConfig, FindConfig, GetConfig, GetInfoConfig, SetConfig } from "./IArchives";
|
|
4
4
|
export declare class ArchivesBackblaze implements IArchives {
|
|
5
5
|
private config;
|
|
6
6
|
constructor(config: {
|
|
@@ -39,15 +39,9 @@ export declare class ArchivesBackblaze implements IArchives {
|
|
|
39
39
|
writeTime: number;
|
|
40
40
|
size: number;
|
|
41
41
|
} | undefined>;
|
|
42
|
-
find(prefix: string, config?:
|
|
43
|
-
shallow?: boolean;
|
|
44
|
-
type: "files" | "folders";
|
|
45
|
-
}): Promise<string[]>;
|
|
42
|
+
find(prefix: string, config?: FindConfig): Promise<string[]>;
|
|
46
43
|
getChangesAfter2(config: ChangesAfterConfig): Promise<ArchiveFileInfo[]>;
|
|
47
|
-
findInfo(prefix: string, config?: {
|
|
48
|
-
shallow?: boolean;
|
|
49
|
-
type: "files" | "folders";
|
|
50
|
-
}): Promise<{
|
|
44
|
+
findInfo(prefix: string, config?: FindConfig): Promise<{
|
|
51
45
|
path: string;
|
|
52
46
|
createTime: number;
|
|
53
47
|
size: number;
|
package/storage/backblaze.ts
CHANGED
|
@@ -9,7 +9,7 @@ import debugbreak from "debugbreak";
|
|
|
9
9
|
import dns from "dns";
|
|
10
10
|
import { getSecret } from "../misc/getSecret";
|
|
11
11
|
import { httpsRequest, HttpsResponseInfo } from "socket-function/src/https";
|
|
12
|
-
import { IArchives, ArchivesConfig, ChangesAfterConfig, ArchiveFileInfo, DelConfig, GetConfig, GetInfoConfig, SetConfig, assertValidLastModified, bufferChunkStream, IMMUTABLE_CACHE_TIME } from "./IArchives";
|
|
12
|
+
import { IArchives, ArchivesConfig, ChangesAfterConfig, ArchiveFileInfo, DelConfig, FindConfig, GetConfig, GetInfoConfig, SetConfig, assertValidLastModified, bufferChunkStream, IMMUTABLE_CACHE_TIME } from "./IArchives";
|
|
13
13
|
import { filterChanges } from "./remoteStorage/remoteConfig";
|
|
14
14
|
|
|
15
15
|
type BackblazeCreds = {
|
|
@@ -639,12 +639,12 @@ export class ArchivesBackblaze implements IArchives {
|
|
|
639
639
|
setTimeout(downloadPoll, 5000);
|
|
640
640
|
};
|
|
641
641
|
setTimeout(downloadPoll, 5000);
|
|
642
|
-
let result = await this.apiRetryLogic(`get ${fileName}`, async (api): Promise<{ data: Buffer; writeTime: number; size: number }> => {
|
|
642
|
+
let result = await this.apiRetryLogic(`get ${fileName}`, async (api): Promise<{ data: Buffer; writeTime: number; size: number } | undefined> => {
|
|
643
643
|
let range = config?.range;
|
|
644
644
|
if (range) {
|
|
645
|
-
// The clamp needs the file's size (and gives us its metadata for free)
|
|
646
|
-
let fileInfo = await this.getInfo(fileName);
|
|
647
|
-
if (!fileInfo)
|
|
645
|
+
// The clamp needs the file's size (and gives us its metadata for free). The tombstone flag forwards: without it a deleted file's info is hidden, so the ranged read reports absent too.
|
|
646
|
+
let fileInfo = await this.getInfo(fileName, { includeTombstones: config?.includeTombstones });
|
|
647
|
+
if (!fileInfo) return undefined;
|
|
648
648
|
let rangeStart = range.start;
|
|
649
649
|
let rangeEnd = Math.min(range.end, fileInfo.size);
|
|
650
650
|
// NOTE: I think if we request nothing, it confuses Backblaze and ends up giving us the entire file.
|
|
@@ -666,9 +666,15 @@ export class ArchivesBackblaze implements IArchives {
|
|
|
666
666
|
fileName,
|
|
667
667
|
outResponse: response,
|
|
668
668
|
});
|
|
669
|
+
// Backblaze stores this system's deletions as REAL empty files (its hide would make them invisible to scans), so an empty download IS a tombstone - absent, unless the caller asked to see tombstones
|
|
670
|
+
if (!data.length && !config?.includeTombstones) {
|
|
671
|
+
this.log(`backblaze file is a tombstone (deleted) ${fileName}`);
|
|
672
|
+
return undefined;
|
|
673
|
+
}
|
|
669
674
|
let meta = parseFileMetadataHeaders(response);
|
|
670
675
|
return { data, writeTime: meta.uploadTimestamp, size: data.length };
|
|
671
676
|
});
|
|
677
|
+
if (!result) return undefined;
|
|
672
678
|
let timeStr = formatTime(Date.now() - time);
|
|
673
679
|
let rateStr = formatNumber(result.data.length / (Date.now() - time) * 1000) + "B/s";
|
|
674
680
|
this.log(`backblaze download (${formatNumber(result.data.length)}B${config?.range && `, ${formatNumber(config.range.start)} - ${formatNumber(config.range.end)}` || ""}) in ${timeStr} (${rateStr}, ${fileName})`);
|
|
@@ -713,14 +719,12 @@ export class ArchivesBackblaze implements IArchives {
|
|
|
713
719
|
}
|
|
714
720
|
if (config?.lastModified) {
|
|
715
721
|
assertValidLastModified(config.lastModified);
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
if (existing && config.forceSetImmutable && this.config.immutable) return fileName;
|
|
723
|
-
}
|
|
722
|
+
// This comparison deliberately IGNORES noChecks: backblaze has no server of ours to enforce only-take-the-latest (unlike hosted targets, where the receiving store re-checks), so this comparison IS the ordering guard. Skipping it lets a stale push land over a newer value or tombstone - and because b2 stamps its own upload times, the stale data then becomes the newest-timestamped copy in the whole system, resurrecting globally through everyone's scans. includeTombstones: a deletion on b2 is a real size-0 file and must win this comparison too.
|
|
723
|
+
let existing = await this.getInfo(fileName, { includeTombstones: true });
|
|
724
|
+
// An older write never overwrites a newer one (see IArchives.set). B2 stamps its own upload time, so the exact lastModified is not preserved on the stored file.
|
|
725
|
+
if (existing && config.lastModified < existing.writeTime) return fileName;
|
|
726
|
+
// Immutability wins: a synchronization push never overwrites an existing path on an immutable bucket (see SetConfig.forceSetImmutable)
|
|
727
|
+
if (existing && config.forceSetImmutable && this.config.immutable) return fileName;
|
|
724
728
|
}
|
|
725
729
|
// Big buffers stream through the large-file API: a failed part retries alone instead of restarting the whole upload. The threshold MUST stay at two full chunks - below that setLargeFile falls back to plain set, which would recurse right back here.
|
|
726
730
|
if (data.length >= LARGE_FILE_MIN_CHUNK_SIZE * 2) {
|
|
@@ -750,10 +754,9 @@ export class ArchivesBackblaze implements IArchives {
|
|
|
750
754
|
public async del(fileName: string, config?: DelConfig): Promise<void> {
|
|
751
755
|
if (config?.lastModified) {
|
|
752
756
|
// A synchronized deletion: b2's hide removes the file from listings entirely, so peers scanning the bucket could never learn of it. Instead the tombstone is stored as a REAL empty file (an empty file IS a missing file), which listings show and scans ingest as a deletion. (b2 stamps its own upload time, so the exact deletion time is not preserved here - same as every b2 write.)
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
}
|
|
757
|
+
// The comparison ignores noChecks for the same reason as in set: on b2 it IS the ordering guard
|
|
758
|
+
let existing = await this.getInfo(fileName, { includeTombstones: true });
|
|
759
|
+
if (existing && config.lastModified < existing.writeTime) return;
|
|
757
760
|
this.log(`backblaze tombstone upload ${fileName}`);
|
|
758
761
|
await this.apiRetryLogic(`del ${fileName}`, async (api) => {
|
|
759
762
|
await api.uploadFile({ bucketId: this.bucketId, fileName, data: Buffer.alloc(0) });
|
|
@@ -929,7 +932,7 @@ export class ArchivesBackblaze implements IArchives {
|
|
|
929
932
|
}
|
|
930
933
|
|
|
931
934
|
// For example findFileNames("ips/")
|
|
932
|
-
public async find(prefix: string, config?:
|
|
935
|
+
public async find(prefix: string, config?: FindConfig): Promise<string[]> {
|
|
933
936
|
let result = await this.findInfo(prefix, config);
|
|
934
937
|
return result.map(x => x.path);
|
|
935
938
|
}
|
|
@@ -938,7 +941,7 @@ export class ArchivesBackblaze implements IArchives {
|
|
|
938
941
|
return filterChanges(await this.findInfo(""), config);
|
|
939
942
|
}
|
|
940
943
|
|
|
941
|
-
public async findInfo(prefix: string, config?:
|
|
944
|
+
public async findInfo(prefix: string, config?: FindConfig): Promise<{ path: string; createTime: number; size: number; }[]> {
|
|
942
945
|
return await this.apiRetryLogic(`findInfo ${prefix}`, async (api) => {
|
|
943
946
|
if (!config?.shallow && config?.type === "folders") {
|
|
944
947
|
let allFiles = await this.findInfo(prefix);
|