@fluidframework/container-loader 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.4.1.0.148229
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/.eslintrc.js +18 -21
- package/.mocharc.js +2 -2
- package/README.md +65 -44
- package/api-extractor.json +2 -2
- package/closeAndGetPendingLocalState.md +51 -0
- package/dist/audience.d.ts +0 -1
- package/dist/audience.d.ts.map +1 -1
- package/dist/audience.js.map +1 -1
- package/dist/catchUpMonitor.d.ts.map +1 -1
- package/dist/catchUpMonitor.js.map +1 -1
- package/dist/collabWindowTracker.d.ts.map +1 -1
- package/dist/collabWindowTracker.js.map +1 -1
- package/dist/connectionManager.d.ts +5 -5
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +107 -44
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionState.d.ts.map +1 -1
- package/dist/connectionState.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +7 -7
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +50 -21
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +64 -5
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +329 -137
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +19 -8
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +58 -14
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +41 -2
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +88 -14
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +3 -3
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts +21 -8
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +112 -37
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaManagerProxy.d.ts +10 -22
- package/dist/deltaManagerProxy.d.ts.map +1 -1
- package/dist/deltaManagerProxy.js +14 -50
- package/dist/deltaManagerProxy.js.map +1 -1
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js +4 -2
- package/dist/deltaQueue.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +13 -4
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +38 -24
- package/dist/loader.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +2 -1
- package/dist/protocol.js.map +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts +6 -2
- package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/dist/protocolTreeDocumentStorageService.js +7 -4
- package/dist/protocolTreeDocumentStorageService.js.map +1 -1
- package/dist/quorum.d.ts.map +1 -1
- package/dist/quorum.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +6 -2
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +8 -5
- package/dist/utils.js.map +1 -1
- package/lib/audience.d.ts +0 -1
- package/lib/audience.d.ts.map +1 -1
- package/lib/audience.js.map +1 -1
- package/lib/catchUpMonitor.d.ts.map +1 -1
- package/lib/catchUpMonitor.js.map +1 -1
- package/lib/collabWindowTracker.d.ts.map +1 -1
- package/lib/collabWindowTracker.js.map +1 -1
- package/lib/connectionManager.d.ts +5 -5
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +110 -47
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionState.d.ts.map +1 -1
- package/lib/connectionState.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +7 -7
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +50 -21
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +64 -5
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +336 -144
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +19 -8
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +59 -15
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +41 -2
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +86 -14
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +3 -3
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts +21 -8
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +114 -39
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaManagerProxy.d.ts +10 -22
- package/lib/deltaManagerProxy.d.ts.map +1 -1
- package/lib/deltaManagerProxy.js +14 -50
- package/lib/deltaManagerProxy.js.map +1 -1
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js +4 -2
- package/lib/deltaQueue.js.map +1 -1
- package/lib/index.d.ts +4 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/loader.d.ts +13 -4
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +37 -24
- package/lib/loader.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +2 -1
- package/lib/protocol.js.map +1 -1
- package/lib/protocolTreeDocumentStorageService.d.ts +6 -2
- package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/lib/protocolTreeDocumentStorageService.js +7 -4
- package/lib/protocolTreeDocumentStorageService.js.map +1 -1
- package/lib/quorum.d.ts.map +1 -1
- package/lib/quorum.js.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js +6 -2
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +8 -5
- package/lib/utils.js.map +1 -1
- package/package.json +67 -56
- package/prettier.config.cjs +1 -1
- package/src/audience.ts +51 -46
- package/src/catchUpMonitor.ts +39 -37
- package/src/collabWindowTracker.ts +75 -70
- package/src/connectionManager.ts +1040 -941
- package/src/connectionState.ts +19 -19
- package/src/connectionStateHandler.ts +557 -463
- package/src/container.ts +2147 -1784
- package/src/containerContext.ts +417 -345
- package/src/containerStorageAdapter.ts +268 -154
- package/src/contracts.ts +155 -153
- package/src/deltaManager.ts +1074 -945
- package/src/deltaManagerProxy.ts +88 -137
- package/src/deltaQueue.ts +155 -151
- package/src/index.ts +13 -17
- package/src/loader.ts +434 -427
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +93 -87
- package/src/protocolTreeDocumentStorageService.ts +34 -34
- package/src/quorum.ts +34 -34
- package/src/retriableDocumentStorageService.ts +118 -102
- package/src/utils.ts +93 -83
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +8 -12
|
@@ -4,129 +4,176 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { IDisposable, ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
7
|
-
import { assert } from "@fluidframework/common-utils";
|
|
7
|
+
import { assert, bufferToString, stringToBuffer } from "@fluidframework/common-utils";
|
|
8
8
|
import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions";
|
|
9
9
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
FetchSource,
|
|
11
|
+
IDocumentService,
|
|
12
|
+
IDocumentStorageService,
|
|
13
|
+
IDocumentStorageServicePolicies,
|
|
14
|
+
ISummaryContext,
|
|
15
15
|
} from "@fluidframework/driver-definitions";
|
|
16
16
|
import { UsageError } from "@fluidframework/driver-utils";
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
ICreateBlobResponse,
|
|
19
|
+
ISnapshotTree,
|
|
20
|
+
ISummaryHandle,
|
|
21
|
+
ISummaryTree,
|
|
22
|
+
IVersion,
|
|
23
23
|
} from "@fluidframework/protocol-definitions";
|
|
24
24
|
import { IDetachedBlobStorage } from "./loader";
|
|
25
25
|
import { ProtocolTreeStorageService } from "./protocolTreeDocumentStorageService";
|
|
26
26
|
import { RetriableDocumentStorageService } from "./retriableDocumentStorageService";
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Stringified blobs from a summary/snapshot tree.
|
|
30
|
+
* @deprecated this is an internal interface and will not longer be exported in future versions
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
export interface ISerializableBlobContents {
|
|
34
|
+
[id: string]: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
28
37
|
/**
|
|
29
38
|
* This class wraps the actual storage and make sure no wrong apis are called according to
|
|
30
39
|
* container attach state.
|
|
31
40
|
*/
|
|
32
41
|
export class ContainerStorageAdapter implements IDocumentStorageService, IDisposable {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
42
|
+
private _storageService: IDocumentStorageService & Partial<IDisposable>;
|
|
43
|
+
|
|
44
|
+
private _summarizeProtocolTree: boolean | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Whether the adapter will enforce sending combined summary trees.
|
|
47
|
+
*/
|
|
48
|
+
public get summarizeProtocolTree() {
|
|
49
|
+
return this._summarizeProtocolTree === true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* An adapter that ensures we're using detachedBlobStorage up until we connect to a real service, and then
|
|
54
|
+
* after connecting to a real service augments it with retry and combined summary tree enforcement.
|
|
55
|
+
* @param detachedBlobStorage - The detached blob storage to use up until we connect to a real service
|
|
56
|
+
* @param logger - Telemetry logger
|
|
57
|
+
* @param addProtocolSummaryIfMissing - a callback to permit the container to inspect the summary we're about to
|
|
58
|
+
* upload, and fix it up with a protocol tree if needed
|
|
59
|
+
* @param forceEnableSummarizeProtocolTree - Enforce uploading a protocol summary regardless of the service's policy
|
|
60
|
+
*/
|
|
61
|
+
public constructor(
|
|
62
|
+
detachedBlobStorage: IDetachedBlobStorage | undefined,
|
|
63
|
+
private readonly logger: ITelemetryLogger,
|
|
64
|
+
/**
|
|
65
|
+
* ArrayBufferLikes or utf8 encoded strings, containing blobs from a snapshot
|
|
66
|
+
*/
|
|
67
|
+
private readonly blobContents: { [id: string]: ArrayBufferLike | string } = {},
|
|
68
|
+
private readonly addProtocolSummaryIfMissing: (summaryTree: ISummaryTree) => ISummaryTree,
|
|
69
|
+
forceEnableSummarizeProtocolTree: boolean | undefined,
|
|
70
|
+
) {
|
|
71
|
+
this._storageService = new BlobOnlyStorage(detachedBlobStorage, logger);
|
|
72
|
+
this._summarizeProtocolTree = forceEnableSummarizeProtocolTree;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
disposed: boolean = false;
|
|
76
|
+
dispose(error?: Error): void {
|
|
77
|
+
this._storageService?.dispose?.(error);
|
|
78
|
+
this.disposed = true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public async connectToService(service: IDocumentService): Promise<void> {
|
|
82
|
+
if (!(this._storageService instanceof BlobOnlyStorage)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const storageService = await service.connectToStorage();
|
|
87
|
+
const retriableStorage = (this._storageService = new RetriableDocumentStorageService(
|
|
88
|
+
storageService,
|
|
89
|
+
this.logger,
|
|
90
|
+
));
|
|
91
|
+
|
|
92
|
+
this._summarizeProtocolTree =
|
|
93
|
+
this._summarizeProtocolTree ?? service.policies?.summarizeProtocolTree;
|
|
94
|
+
if (this.summarizeProtocolTree) {
|
|
95
|
+
this.logger.sendTelemetryEvent({ eventName: "summarizeProtocolTreeEnabled" });
|
|
96
|
+
this._storageService = new ProtocolTreeStorageService(
|
|
97
|
+
retriableStorage,
|
|
98
|
+
this.addProtocolSummaryIfMissing,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ensure we did not lose that policy in the process of wrapping
|
|
103
|
+
assert(
|
|
104
|
+
storageService.policies?.minBlobSize === this._storageService.policies?.minBlobSize,
|
|
105
|
+
0x0e0 /* "lost minBlobSize policy" */,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public loadSnapshotForRehydratingContainer(snapshotTree: ISnapshotTreeWithBlobContents) {
|
|
110
|
+
this.getBlobContents(snapshotTree);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private getBlobContents(snapshotTree: ISnapshotTreeWithBlobContents) {
|
|
114
|
+
for (const [id, value] of Object.entries(snapshotTree.blobsContents)) {
|
|
115
|
+
this.blobContents[id] = value;
|
|
116
|
+
}
|
|
117
|
+
for (const [_, tree] of Object.entries(snapshotTree.trees)) {
|
|
118
|
+
this.getBlobContents(tree);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public get policies(): IDocumentStorageServicePolicies | undefined {
|
|
123
|
+
// back-compat 0.40 containerRuntime requests policies even in detached container if storage is present
|
|
124
|
+
// and storage is always present in >=0.41.
|
|
125
|
+
try {
|
|
126
|
+
return this._storageService.policies;
|
|
127
|
+
} catch (e) {}
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public get repositoryUrl(): string {
|
|
132
|
+
return this._storageService.repositoryUrl;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public async getSnapshotTree(
|
|
136
|
+
version?: IVersion,
|
|
137
|
+
scenarioName?: string,
|
|
138
|
+
): Promise<ISnapshotTree | null> {
|
|
139
|
+
return this._storageService.getSnapshotTree(version, scenarioName);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public async readBlob(id: string): Promise<ArrayBufferLike> {
|
|
143
|
+
const maybeBlob = this.blobContents[id];
|
|
144
|
+
if (maybeBlob !== undefined) {
|
|
145
|
+
if (typeof maybeBlob === "string") {
|
|
146
|
+
const blob = stringToBuffer(maybeBlob, "utf8");
|
|
147
|
+
return blob;
|
|
148
|
+
}
|
|
149
|
+
return maybeBlob;
|
|
150
|
+
}
|
|
151
|
+
return this._storageService.readBlob(id);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public async getVersions(
|
|
155
|
+
versionId: string | null,
|
|
156
|
+
count: number,
|
|
157
|
+
scenarioName?: string,
|
|
158
|
+
fetchSource?: FetchSource,
|
|
159
|
+
): Promise<IVersion[]> {
|
|
160
|
+
return this._storageService.getVersions(versionId, count, scenarioName, fetchSource);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public async uploadSummaryWithContext(
|
|
164
|
+
summary: ISummaryTree,
|
|
165
|
+
context: ISummaryContext,
|
|
166
|
+
): Promise<string> {
|
|
167
|
+
return this._storageService.uploadSummaryWithContext(summary, context);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {
|
|
171
|
+
return this._storageService.downloadSummary(handle);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {
|
|
175
|
+
return this._storageService.createBlob(file);
|
|
176
|
+
}
|
|
130
177
|
}
|
|
131
178
|
|
|
132
179
|
/**
|
|
@@ -134,50 +181,117 @@ export class ContainerStorageAdapter implements IDocumentStorageService, IDispos
|
|
|
134
181
|
* blobs in detached containers.
|
|
135
182
|
*/
|
|
136
183
|
class BlobOnlyStorage implements IDocumentStorageService {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
constructor(
|
|
185
|
+
private readonly detachedStorage: IDetachedBlobStorage | undefined,
|
|
186
|
+
private readonly logger: ITelemetryLogger,
|
|
187
|
+
) {}
|
|
188
|
+
|
|
189
|
+
public async createBlob(content: ArrayBufferLike): Promise<ICreateBlobResponse> {
|
|
190
|
+
return this.verifyStorage().createBlob(content);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
public async readBlob(blobId: string): Promise<ArrayBufferLike> {
|
|
194
|
+
return this.verifyStorage().readBlob(blobId);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private verifyStorage(): IDetachedBlobStorage {
|
|
198
|
+
if (this.detachedStorage === undefined) {
|
|
199
|
+
throw new UsageError("Real storage calls not allowed in Unattached container");
|
|
200
|
+
}
|
|
201
|
+
return this.detachedStorage;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
public get policies(): IDocumentStorageServicePolicies | undefined {
|
|
205
|
+
return this.notCalled();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public get repositoryUrl(): string {
|
|
209
|
+
return this.notCalled();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
213
|
+
public getSnapshotTree: () => Promise<ISnapshotTree | null> = this.notCalled;
|
|
214
|
+
public getVersions: () => Promise<IVersion[]> = this.notCalled;
|
|
215
|
+
public write: () => Promise<IVersion> = this.notCalled;
|
|
216
|
+
public uploadSummaryWithContext: () => Promise<string> = this.notCalled;
|
|
217
|
+
public downloadSummary: () => Promise<ISummaryTree> = this.notCalled;
|
|
218
|
+
/* eslint-enable @typescript-eslint/unbound-method */
|
|
219
|
+
|
|
220
|
+
private notCalled(): never {
|
|
221
|
+
this.verifyStorage();
|
|
222
|
+
try {
|
|
223
|
+
// some browsers may not populate stack unless exception is thrown
|
|
224
|
+
throw new Error("BlobOnlyStorage not implemented method used");
|
|
225
|
+
} catch (err) {
|
|
226
|
+
this.logger.sendTelemetryEvent({ eventName: "BlobOnlyStorageWrongCall" }, err);
|
|
227
|
+
throw err;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// runtime will write a tree to the summary containing only "attachment" type entries
|
|
233
|
+
// which reference attachment blobs by ID. However, some drivers do not support this type
|
|
234
|
+
// and will convert them to "blob" type entries. We want to avoid saving these to reduce
|
|
235
|
+
// the size of stashed change blobs.
|
|
236
|
+
const blobsTreeName = ".blobs";
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Get blob contents of a snapshot tree from storage (or, ideally, cache)
|
|
240
|
+
*/
|
|
241
|
+
export async function getBlobContentsFromTree(
|
|
242
|
+
snapshot: ISnapshotTree,
|
|
243
|
+
storage: IDocumentStorageService,
|
|
244
|
+
): Promise<ISerializableBlobContents> {
|
|
245
|
+
const blobs = {};
|
|
246
|
+
await getBlobContentsFromTreeCore(snapshot, blobs, storage);
|
|
247
|
+
return blobs;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async function getBlobContentsFromTreeCore(
|
|
251
|
+
tree: ISnapshotTree,
|
|
252
|
+
blobs: ISerializableBlobContents,
|
|
253
|
+
storage: IDocumentStorageService,
|
|
254
|
+
root = true,
|
|
255
|
+
) {
|
|
256
|
+
const treePs: Promise<any>[] = [];
|
|
257
|
+
for (const [key, subTree] of Object.entries(tree.trees)) {
|
|
258
|
+
if (!root || key !== blobsTreeName) {
|
|
259
|
+
treePs.push(getBlobContentsFromTreeCore(subTree, blobs, storage, false));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
for (const id of Object.values(tree.blobs)) {
|
|
263
|
+
const blob = await storage.readBlob(id);
|
|
264
|
+
// ArrayBufferLike will not survive JSON.stringify()
|
|
265
|
+
blobs[id] = bufferToString(blob, "utf8");
|
|
266
|
+
}
|
|
267
|
+
return Promise.all(treePs);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Extract blob contents from a snapshot tree with blob contents
|
|
272
|
+
*/
|
|
273
|
+
export function getBlobContentsFromTreeWithBlobContents(
|
|
274
|
+
snapshot: ISnapshotTreeWithBlobContents,
|
|
275
|
+
): ISerializableBlobContents {
|
|
276
|
+
const blobs = {};
|
|
277
|
+
getBlobContentsFromTreeWithBlobContentsCore(snapshot, blobs);
|
|
278
|
+
return blobs;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function getBlobContentsFromTreeWithBlobContentsCore(
|
|
282
|
+
tree: ISnapshotTreeWithBlobContents,
|
|
283
|
+
blobs: ISerializableBlobContents,
|
|
284
|
+
root = true,
|
|
285
|
+
) {
|
|
286
|
+
for (const [key, subTree] of Object.entries(tree.trees)) {
|
|
287
|
+
if (!root || key !== blobsTreeName) {
|
|
288
|
+
getBlobContentsFromTreeWithBlobContentsCore(subTree, blobs, false);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
for (const id of Object.values(tree.blobs)) {
|
|
292
|
+
const blob = tree.blobsContents[id];
|
|
293
|
+
assert(blob !== undefined, 0x2ec /* "Blob must be present in blobsContents" */);
|
|
294
|
+
// ArrayBufferLike will not survive JSON.stringify()
|
|
295
|
+
blobs[id] = bufferToString(blob, "utf8");
|
|
296
|
+
}
|
|
183
297
|
}
|