@fluidframework/container-loader 2.0.0-dev.4.4.0.162253 → 2.0.0-dev.5.2.0.169897
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/CHANGELOG.md +28 -0
- package/README.md +27 -3
- package/dist/connectionManager.d.ts +3 -2
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +32 -13
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +15 -3
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +24 -1
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +74 -44
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +81 -111
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +2 -2
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +3 -7
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +3 -3
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +6 -15
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +8 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts +21 -9
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +42 -31
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.d.ts +2 -3
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js +2 -3
- package/dist/deltaQueue.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +9 -7
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +47 -61
- 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/retriableDocumentStorageService.d.ts +3 -2
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/tsdoc-metadata.json +11 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +8 -1
- package/dist/utils.js.map +1 -1
- package/lib/connectionManager.d.ts +3 -2
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +33 -14
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +15 -3
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +25 -2
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +74 -44
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +82 -112
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +2 -2
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +3 -7
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +3 -3
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +6 -15
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +8 -0
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts +21 -9
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +44 -33
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.d.ts +2 -3
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js +2 -3
- package/lib/deltaQueue.js.map +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/loader.d.ts +9 -7
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +47 -61
- 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/retriableDocumentStorageService.d.ts +3 -2
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/lib/utils.d.ts +2 -0
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +7 -1
- package/lib/utils.js.map +1 -1
- package/package.json +16 -18
- package/src/connectionManager.ts +40 -22
- package/src/connectionStateHandler.ts +52 -8
- package/src/container.ts +191 -159
- package/src/containerContext.ts +3 -9
- package/src/containerStorageAdapter.ts +8 -20
- package/src/contracts.ts +10 -0
- package/src/deltaManager.ts +59 -37
- package/src/deltaQueue.ts +2 -3
- package/src/index.ts +1 -8
- package/src/loader.ts +85 -83
- package/src/packageVersion.ts +1 -1
- package/src/retriableDocumentStorageService.ts +3 -2
- package/src/utils.ts +15 -1
package/src/containerContext.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { ITelemetryLoggerExt, PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
7
7
|
import { assert, LazyPromise, TypedEventEmitter } from "@fluidframework/common-utils";
|
|
8
8
|
import {
|
|
9
9
|
IAudience,
|
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
} from "@fluidframework/container-definitions";
|
|
26
26
|
import { IRequest, IResponse, FluidObject } from "@fluidframework/core-interfaces";
|
|
27
27
|
import { IDocumentStorageService } from "@fluidframework/driver-definitions";
|
|
28
|
-
import { isFluidResolvedUrl } from "@fluidframework/driver-utils";
|
|
29
28
|
import {
|
|
30
29
|
IClientConfiguration,
|
|
31
30
|
IClientDetails,
|
|
@@ -40,7 +39,6 @@ import {
|
|
|
40
39
|
MessageType,
|
|
41
40
|
ISummaryContent,
|
|
42
41
|
} from "@fluidframework/protocol-definitions";
|
|
43
|
-
import { PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
44
42
|
import { UsageError } from "@fluidframework/container-utils";
|
|
45
43
|
import { Container } from "./container";
|
|
46
44
|
|
|
@@ -101,7 +99,7 @@ export class ContainerContext implements IContainerContext {
|
|
|
101
99
|
return context;
|
|
102
100
|
}
|
|
103
101
|
|
|
104
|
-
public readonly taggedLogger:
|
|
102
|
+
public readonly taggedLogger: ITelemetryLoggerExt;
|
|
105
103
|
public readonly supportedFeatures: ReadonlyMap<string, unknown>;
|
|
106
104
|
|
|
107
105
|
public get clientId(): string | undefined {
|
|
@@ -112,11 +110,7 @@ export class ContainerContext implements IContainerContext {
|
|
|
112
110
|
* DISCLAIMER: this id is only for telemetry purposes. Not suitable for any other usages.
|
|
113
111
|
*/
|
|
114
112
|
public get id(): string {
|
|
115
|
-
|
|
116
|
-
if (isFluidResolvedUrl(resolvedUrl)) {
|
|
117
|
-
return resolvedUrl.id;
|
|
118
|
-
}
|
|
119
|
-
return "";
|
|
113
|
+
return this.container.resolvedUrl?.id ?? "";
|
|
120
114
|
}
|
|
121
115
|
|
|
122
116
|
public get clientDetails(): IClientDetails {
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { IDisposable
|
|
6
|
+
import { IDisposable } from "@fluidframework/common-definitions";
|
|
7
|
+
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
|
|
7
8
|
import { assert, bufferToString, stringToBuffer } from "@fluidframework/common-utils";
|
|
8
9
|
import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions";
|
|
9
10
|
import {
|
|
@@ -27,7 +28,6 @@ import { RetriableDocumentStorageService } from "./retriableDocumentStorageServi
|
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Stringified blobs from a summary/snapshot tree.
|
|
30
|
-
* @deprecated this is an internal interface and will not longer be exported in future versions
|
|
31
31
|
* @internal
|
|
32
32
|
*/
|
|
33
33
|
export interface ISerializableBlobContents {
|
|
@@ -60,7 +60,7 @@ export class ContainerStorageAdapter implements IDocumentStorageService, IDispos
|
|
|
60
60
|
*/
|
|
61
61
|
public constructor(
|
|
62
62
|
detachedBlobStorage: IDetachedBlobStorage | undefined,
|
|
63
|
-
private readonly logger:
|
|
63
|
+
private readonly logger: ITelemetryLoggerExt,
|
|
64
64
|
/**
|
|
65
65
|
* ArrayBufferLikes or utf8 encoded strings, containing blobs from a snapshot
|
|
66
66
|
*/
|
|
@@ -183,7 +183,7 @@ export class ContainerStorageAdapter implements IDocumentStorageService, IDispos
|
|
|
183
183
|
class BlobOnlyStorage implements IDocumentStorageService {
|
|
184
184
|
constructor(
|
|
185
185
|
private readonly detachedStorage: IDetachedBlobStorage | undefined,
|
|
186
|
-
private readonly logger:
|
|
186
|
+
private readonly logger: ITelemetryLoggerExt,
|
|
187
187
|
) {}
|
|
188
188
|
|
|
189
189
|
public async createBlob(content: ArrayBufferLike): Promise<ICreateBlobResponse> {
|
|
@@ -229,12 +229,6 @@ class BlobOnlyStorage implements IDocumentStorageService {
|
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
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
232
|
/**
|
|
239
233
|
* Get blob contents of a snapshot tree from storage (or, ideally, cache)
|
|
240
234
|
*/
|
|
@@ -251,13 +245,10 @@ async function getBlobContentsFromTreeCore(
|
|
|
251
245
|
tree: ISnapshotTree,
|
|
252
246
|
blobs: ISerializableBlobContents,
|
|
253
247
|
storage: IDocumentStorageService,
|
|
254
|
-
root = true,
|
|
255
248
|
) {
|
|
256
249
|
const treePs: Promise<any>[] = [];
|
|
257
|
-
for (const
|
|
258
|
-
|
|
259
|
-
treePs.push(getBlobContentsFromTreeCore(subTree, blobs, storage, false));
|
|
260
|
-
}
|
|
250
|
+
for (const subTree of Object.values(tree.trees)) {
|
|
251
|
+
treePs.push(getBlobContentsFromTreeCore(subTree, blobs, storage));
|
|
261
252
|
}
|
|
262
253
|
for (const id of Object.values(tree.blobs)) {
|
|
263
254
|
const blob = await storage.readBlob(id);
|
|
@@ -281,12 +272,9 @@ export function getBlobContentsFromTreeWithBlobContents(
|
|
|
281
272
|
function getBlobContentsFromTreeWithBlobContentsCore(
|
|
282
273
|
tree: ISnapshotTreeWithBlobContents,
|
|
283
274
|
blobs: ISerializableBlobContents,
|
|
284
|
-
root = true,
|
|
285
275
|
) {
|
|
286
|
-
for (const
|
|
287
|
-
|
|
288
|
-
getBlobContentsFromTreeWithBlobContentsCore(subTree, blobs, false);
|
|
289
|
-
}
|
|
276
|
+
for (const subTree of Object.values(tree.trees)) {
|
|
277
|
+
getBlobContentsFromTreeWithBlobContentsCore(subTree, blobs);
|
|
290
278
|
}
|
|
291
279
|
for (const id of Object.values(tree.blobs)) {
|
|
292
280
|
const blob = tree.blobsContents[id];
|
package/src/contracts.ts
CHANGED
|
@@ -167,6 +167,16 @@ export interface IConnectionManagerFactoryArgs {
|
|
|
167
167
|
* `undefined` indicates that user permissions are not yet known.
|
|
168
168
|
*/
|
|
169
169
|
readonly readonlyChangeHandler: (readonly?: boolean) => void;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Called whenever we try to start establishing a new connection.
|
|
173
|
+
*/
|
|
174
|
+
readonly establishConnectionHandler: (reason: string) => void;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Called whenever we cancel the connection in progress.
|
|
178
|
+
*/
|
|
179
|
+
readonly cancelConnectionHandler: (reason: string) => void;
|
|
170
180
|
}
|
|
171
181
|
|
|
172
182
|
/**
|
package/src/deltaManager.ts
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import { default as AbortController } from "abort-controller";
|
|
7
7
|
import { v4 as uuid } from "uuid";
|
|
8
8
|
import {
|
|
9
|
-
ITelemetryLogger,
|
|
10
9
|
IEventProvider,
|
|
11
10
|
ITelemetryProperties,
|
|
12
11
|
ITelemetryErrorEvent,
|
|
@@ -21,7 +20,13 @@ import {
|
|
|
21
20
|
IConnectionDetailsInternal,
|
|
22
21
|
} from "@fluidframework/container-definitions";
|
|
23
22
|
import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
|
|
24
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
normalizeError,
|
|
25
|
+
logIfFalse,
|
|
26
|
+
safeRaiseEvent,
|
|
27
|
+
isFluidError,
|
|
28
|
+
ITelemetryLoggerExt,
|
|
29
|
+
} from "@fluidframework/telemetry-utils";
|
|
25
30
|
import {
|
|
26
31
|
IDocumentDeltaStorageService,
|
|
27
32
|
IDocumentService,
|
|
@@ -41,6 +46,7 @@ import {
|
|
|
41
46
|
DataCorruptionError,
|
|
42
47
|
extractSafePropertiesFromMessage,
|
|
43
48
|
DataProcessingError,
|
|
49
|
+
UsageError,
|
|
44
50
|
} from "@fluidframework/container-utils";
|
|
45
51
|
import { IConnectionManagerFactoryArgs, IConnectionManager } from "./contracts";
|
|
46
52
|
import { DeltaQueue } from "./deltaQueue";
|
|
@@ -60,6 +66,8 @@ export interface IDeltaManagerInternalEvents extends IDeltaManagerEvents {
|
|
|
60
66
|
(event: "throttled", listener: (error: IThrottlingWarning) => void);
|
|
61
67
|
(event: "closed" | "disposed", listener: (error?: ICriticalContainerError) => void);
|
|
62
68
|
(event: "connect", listener: (details: IConnectionDetailsInternal, opsBehind?: number) => void);
|
|
69
|
+
(event: "establishingConnection", listener: (reason: string) => void);
|
|
70
|
+
(event: "cancelEstablishingConnection", listener: (reason: string) => void);
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
/**
|
|
@@ -340,7 +348,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
340
348
|
|
|
341
349
|
constructor(
|
|
342
350
|
private readonly serviceProvider: () => IDocumentService | undefined,
|
|
343
|
-
private readonly logger:
|
|
351
|
+
private readonly logger: ITelemetryLoggerExt,
|
|
344
352
|
private readonly _active: () => boolean,
|
|
345
353
|
createConnectionManager: (props: IConnectionManagerFactoryArgs) => TConnectionManager,
|
|
346
354
|
) {
|
|
@@ -365,6 +373,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
365
373
|
pongHandler: (latency: number) => this.emit("pong", latency),
|
|
366
374
|
readonlyChangeHandler: (readonly?: boolean) =>
|
|
367
375
|
safeRaiseEvent(this, this.logger, "readonly", readonly),
|
|
376
|
+
establishConnectionHandler: (reason: string) => this.establishingConnection(reason),
|
|
377
|
+
cancelConnectionHandler: (reason: string) => this.cancelEstablishingConnection(reason),
|
|
368
378
|
};
|
|
369
379
|
|
|
370
380
|
this.connectionManager = createConnectionManager(props);
|
|
@@ -404,6 +414,14 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
404
414
|
// - inbound & inboundSignal are resumed in attachOpHandler() when we have handler setup
|
|
405
415
|
}
|
|
406
416
|
|
|
417
|
+
private cancelEstablishingConnection(reason: string) {
|
|
418
|
+
this.emit("cancelEstablishingConnection", reason);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private establishingConnection(reason: string) {
|
|
422
|
+
this.emit("establishingConnection", reason);
|
|
423
|
+
}
|
|
424
|
+
|
|
407
425
|
private connectHandler(connection: IConnectionDetailsInternal) {
|
|
408
426
|
this.refreshDelayInfo(this.deltaStreamDelayId);
|
|
409
427
|
|
|
@@ -453,10 +471,6 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
453
471
|
}
|
|
454
472
|
}
|
|
455
473
|
|
|
456
|
-
public dispose() {
|
|
457
|
-
throw new Error("Not implemented.");
|
|
458
|
-
}
|
|
459
|
-
|
|
460
474
|
/**
|
|
461
475
|
* Sets the sequence number from which inbound messages should be returned
|
|
462
476
|
*/
|
|
@@ -644,23 +658,51 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
644
658
|
/**
|
|
645
659
|
* Closes the connection and clears inbound & outbound queues.
|
|
646
660
|
*
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
* -
|
|
650
|
-
* -
|
|
651
|
-
* - dispose can be called after closure, but not vis versa
|
|
661
|
+
* Differences from dispose:
|
|
662
|
+
* - close will trigger readonly notification
|
|
663
|
+
* - close emits "closed"
|
|
664
|
+
* - close cannot be called after dispose
|
|
652
665
|
*/
|
|
653
|
-
public close(error?: ICriticalContainerError
|
|
666
|
+
public close(error?: ICriticalContainerError): void {
|
|
654
667
|
if (this._closed) {
|
|
655
|
-
if (doDispose === true) {
|
|
656
|
-
this.disposeInternal(error);
|
|
657
|
-
}
|
|
658
668
|
return;
|
|
659
669
|
}
|
|
660
670
|
this._closed = true;
|
|
661
671
|
|
|
662
|
-
this.connectionManager.dispose(error,
|
|
672
|
+
this.connectionManager.dispose(error, true /* switchToReadonly */);
|
|
673
|
+
this.clearQueues();
|
|
674
|
+
this.emit("closed", error);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Disposes the connection and clears the inbound & outbound queues.
|
|
679
|
+
*
|
|
680
|
+
* Differences from close:
|
|
681
|
+
* - dispose will emit "disposed"
|
|
682
|
+
* - dispose will remove all listeners
|
|
683
|
+
* - dispose can be called after closure
|
|
684
|
+
*/
|
|
685
|
+
public dispose(error?: Error | ICriticalContainerError): void {
|
|
686
|
+
if (this._disposed) {
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
if (error !== undefined && !isFluidError(error)) {
|
|
690
|
+
throw new UsageError("Error must be a Fluid error");
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
this._disposed = true;
|
|
694
|
+
this._closed = true; // We consider "disposed" as a further state than "closed"
|
|
695
|
+
|
|
696
|
+
this.connectionManager.dispose(error, false /* switchToReadonly */);
|
|
697
|
+
this.clearQueues();
|
|
698
|
+
|
|
699
|
+
// This needs to be the last thing we do (before removing listeners), as it causes
|
|
700
|
+
// Container to dispose context and break ability of data stores / runtime to "hear" from delta manager.
|
|
701
|
+
this.emit("disposed", error);
|
|
702
|
+
this.removeAllListeners();
|
|
703
|
+
}
|
|
663
704
|
|
|
705
|
+
private clearQueues() {
|
|
664
706
|
this.closeAbortController.abort();
|
|
665
707
|
|
|
666
708
|
this._inbound.clear();
|
|
@@ -673,26 +715,6 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
673
715
|
|
|
674
716
|
// Drop pending messages - this will ensure catchUp() does not go into infinite loop
|
|
675
717
|
this.pending = [];
|
|
676
|
-
|
|
677
|
-
if (doDispose === true) {
|
|
678
|
-
this.disposeInternal(error);
|
|
679
|
-
} else {
|
|
680
|
-
this.emit("closed", error);
|
|
681
|
-
this.disposeInternal(error); // ! TODO: remove this call when Container close no longer disposes
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
private disposeInternal(error?: ICriticalContainerError): void {
|
|
686
|
-
if (this._disposed) {
|
|
687
|
-
return;
|
|
688
|
-
}
|
|
689
|
-
this._disposed = true;
|
|
690
|
-
|
|
691
|
-
// This needs to be the last thing we do (before removing listeners), as it causes
|
|
692
|
-
// Container to dispose context and break ability of data stores / runtime to "hear"
|
|
693
|
-
// from delta manager, including notification (above) about readonly state.
|
|
694
|
-
this.emit("disposed", error);
|
|
695
|
-
this.removeAllListeners();
|
|
696
718
|
}
|
|
697
719
|
|
|
698
720
|
public refreshDelayInfo(id: string) {
|
package/src/deltaQueue.ts
CHANGED
|
@@ -20,8 +20,8 @@ export class DeltaQueue<T>
|
|
|
20
20
|
private readonly q = new Deque<T>();
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* Tracks the number of pause requests for the queue
|
|
24
|
-
* The DeltaQueue is
|
|
23
|
+
* Tracks the number of pause requests for the queue.
|
|
24
|
+
* The DeltaQueue is created initially paused.
|
|
25
25
|
*/
|
|
26
26
|
private pauseCount = 1;
|
|
27
27
|
|
|
@@ -58,7 +58,6 @@ export class DeltaQueue<T>
|
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* @param worker - A callback to process a delta.
|
|
61
|
-
* @param logger - For logging telemetry.
|
|
62
61
|
*/
|
|
63
62
|
constructor(private readonly worker: (delta: T) => void) {
|
|
64
63
|
super();
|
package/src/index.ts
CHANGED
|
@@ -4,14 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export { ConnectionState } from "./connectionState";
|
|
7
|
-
export {
|
|
8
|
-
IContainerConfig,
|
|
9
|
-
IContainerExperimental,
|
|
10
|
-
IContainerLoadOptions,
|
|
11
|
-
IPendingContainerState,
|
|
12
|
-
waitContainerToCatchUp,
|
|
13
|
-
} from "./container";
|
|
14
|
-
export { ISerializableBlobContents } from "./containerStorageAdapter";
|
|
7
|
+
export { IContainerExperimental, waitContainerToCatchUp } from "./container";
|
|
15
8
|
export {
|
|
16
9
|
ICodeDetailsLoader,
|
|
17
10
|
IDetachedBlobStorage,
|
package/src/loader.ts
CHANGED
|
@@ -4,7 +4,18 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { v4 as uuid } from "uuid";
|
|
7
|
-
import { ITelemetryBaseLogger
|
|
7
|
+
import { ITelemetryBaseLogger } from "@fluidframework/common-definitions";
|
|
8
|
+
import {
|
|
9
|
+
ITelemetryLoggerExt,
|
|
10
|
+
ChildLogger,
|
|
11
|
+
DebugLogger,
|
|
12
|
+
IConfigProviderBase,
|
|
13
|
+
loggerToMonitoringContext,
|
|
14
|
+
mixinMonitoringContext,
|
|
15
|
+
MonitoringContext,
|
|
16
|
+
PerformanceEvent,
|
|
17
|
+
sessionStorageConfigProvider,
|
|
18
|
+
} from "@fluidframework/telemetry-utils";
|
|
8
19
|
import {
|
|
9
20
|
FluidObject,
|
|
10
21
|
IFluidRouter,
|
|
@@ -22,24 +33,13 @@ import {
|
|
|
22
33
|
IProvideFluidCodeDetailsComparer,
|
|
23
34
|
IFluidCodeDetails,
|
|
24
35
|
} from "@fluidframework/container-definitions";
|
|
25
|
-
import {
|
|
26
|
-
ChildLogger,
|
|
27
|
-
DebugLogger,
|
|
28
|
-
IConfigProviderBase,
|
|
29
|
-
loggerToMonitoringContext,
|
|
30
|
-
mixinMonitoringContext,
|
|
31
|
-
MonitoringContext,
|
|
32
|
-
PerformanceEvent,
|
|
33
|
-
sessionStorageConfigProvider,
|
|
34
|
-
} from "@fluidframework/telemetry-utils";
|
|
35
36
|
import {
|
|
36
37
|
IDocumentServiceFactory,
|
|
37
38
|
IDocumentStorageService,
|
|
38
|
-
|
|
39
|
+
IResolvedUrl,
|
|
39
40
|
IUrlResolver,
|
|
40
41
|
} from "@fluidframework/driver-definitions";
|
|
41
42
|
import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
|
42
|
-
import { ensureFluidResolvedUrl } from "@fluidframework/driver-utils";
|
|
43
43
|
import { Container, IPendingContainerState } from "./container";
|
|
44
44
|
import { IParsedUrl, parseUrl } from "./utils";
|
|
45
45
|
import { pkgVersion } from "./packageVersion";
|
|
@@ -53,8 +53,15 @@ function canUseCache(request: IRequest): boolean {
|
|
|
53
53
|
return request.headers[LoaderHeader.cache] !== false;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
function ensureResolvedUrlDefined(
|
|
57
|
+
resolved: IResolvedUrl | undefined,
|
|
58
|
+
): asserts resolved is IResolvedUrl {
|
|
59
|
+
if (resolved === undefined) {
|
|
60
|
+
throw new Error(`Object is not a IResolveUrl.`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
56
63
|
/**
|
|
57
|
-
* @
|
|
64
|
+
* @internal
|
|
58
65
|
*/
|
|
59
66
|
export class RelativeLoader implements ILoader {
|
|
60
67
|
constructor(
|
|
@@ -71,15 +78,18 @@ export class RelativeLoader implements ILoader {
|
|
|
71
78
|
if (canUseCache(request)) {
|
|
72
79
|
return this.container;
|
|
73
80
|
} else {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
ensureResolvedUrlDefined(this.container.resolvedUrl);
|
|
82
|
+
const container = await this.container.clone(
|
|
83
|
+
{
|
|
84
|
+
resolvedUrl: { ...this.container.resolvedUrl },
|
|
85
|
+
version: request.headers?.[LoaderHeader.version] ?? undefined,
|
|
86
|
+
loadMode: request.headers?.[LoaderHeader.loadMode],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
canReconnect: request.headers?.[LoaderHeader.reconnect],
|
|
90
|
+
clientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],
|
|
91
|
+
},
|
|
92
|
+
);
|
|
83
93
|
return container;
|
|
84
94
|
}
|
|
85
95
|
}
|
|
@@ -237,12 +247,18 @@ export interface ILoaderServices {
|
|
|
237
247
|
/**
|
|
238
248
|
* The logger downstream consumers should construct their loggers from
|
|
239
249
|
*/
|
|
240
|
-
readonly subLogger:
|
|
250
|
+
readonly subLogger: ITelemetryLoggerExt;
|
|
241
251
|
|
|
242
252
|
/**
|
|
243
253
|
* Blobs storage for detached containers.
|
|
244
254
|
*/
|
|
245
255
|
readonly detachedBlobStorage?: IDetachedBlobStorage;
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Optional property for allowing the container to use a custom
|
|
259
|
+
* protocol implementation for handling the quorum and/or the audience.
|
|
260
|
+
*/
|
|
261
|
+
readonly protocolHandlerBuilder?: ProtocolHandlerBuilder;
|
|
246
262
|
}
|
|
247
263
|
|
|
248
264
|
/**
|
|
@@ -266,7 +282,7 @@ export async function requestResolvedObjectFromContainer(
|
|
|
266
282
|
container: IContainer,
|
|
267
283
|
headers?: IRequestHeader,
|
|
268
284
|
): Promise<IResponse> {
|
|
269
|
-
|
|
285
|
+
ensureResolvedUrlDefined(container.resolvedUrl);
|
|
270
286
|
const parsedUrl = parseUrl(container.resolvedUrl.url);
|
|
271
287
|
|
|
272
288
|
if (parsedUrl === undefined) {
|
|
@@ -289,37 +305,45 @@ export class Loader implements IHostLoader {
|
|
|
289
305
|
private readonly containers = new Map<string, Promise<Container>>();
|
|
290
306
|
public readonly services: ILoaderServices;
|
|
291
307
|
private readonly mc: MonitoringContext;
|
|
292
|
-
private readonly protocolHandlerBuilder: ProtocolHandlerBuilder | undefined;
|
|
293
308
|
|
|
294
309
|
constructor(loaderProps: ILoaderProps) {
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
310
|
+
const {
|
|
311
|
+
urlResolver,
|
|
312
|
+
documentServiceFactory,
|
|
313
|
+
codeLoader,
|
|
314
|
+
options,
|
|
315
|
+
scope,
|
|
316
|
+
logger,
|
|
317
|
+
detachedBlobStorage,
|
|
318
|
+
configProvider,
|
|
319
|
+
protocolHandlerBuilder,
|
|
320
|
+
} = loaderProps;
|
|
321
|
+
|
|
299
322
|
const telemetryProps = {
|
|
300
323
|
loaderId: uuid(),
|
|
301
324
|
loaderVersion: pkgVersion,
|
|
302
325
|
};
|
|
303
326
|
|
|
304
327
|
const subMc = mixinMonitoringContext(
|
|
305
|
-
DebugLogger.mixinDebugLogger("fluid:telemetry",
|
|
328
|
+
DebugLogger.mixinDebugLogger("fluid:telemetry", logger, {
|
|
306
329
|
all: telemetryProps,
|
|
307
330
|
}),
|
|
308
331
|
sessionStorageConfigProvider.value,
|
|
309
|
-
|
|
332
|
+
configProvider,
|
|
310
333
|
);
|
|
311
334
|
|
|
312
335
|
this.services = {
|
|
313
|
-
urlResolver
|
|
314
|
-
documentServiceFactory
|
|
315
|
-
codeLoader
|
|
316
|
-
options:
|
|
317
|
-
scope
|
|
336
|
+
urlResolver,
|
|
337
|
+
documentServiceFactory,
|
|
338
|
+
codeLoader,
|
|
339
|
+
options: options ?? {},
|
|
340
|
+
scope:
|
|
341
|
+
options?.provideScopeLoader !== false ? { ...scope, ILoader: this } : { ...scope },
|
|
342
|
+
detachedBlobStorage,
|
|
343
|
+
protocolHandlerBuilder,
|
|
318
344
|
subLogger: subMc.logger,
|
|
319
|
-
detachedBlobStorage: loaderProps.detachedBlobStorage,
|
|
320
345
|
};
|
|
321
346
|
this.mc = loggerToMonitoringContext(ChildLogger.create(this.services.subLogger, "Loader"));
|
|
322
|
-
this.protocolHandlerBuilder = loaderProps.protocolHandlerBuilder;
|
|
323
347
|
}
|
|
324
348
|
|
|
325
349
|
public get IFluidRouter(): IFluidRouter {
|
|
@@ -327,15 +351,11 @@ export class Loader implements IHostLoader {
|
|
|
327
351
|
}
|
|
328
352
|
|
|
329
353
|
public async createDetachedContainer(codeDetails: IFluidCodeDetails): Promise<IContainer> {
|
|
330
|
-
const container = await Container.createDetached(
|
|
331
|
-
this,
|
|
332
|
-
codeDetails,
|
|
333
|
-
this.protocolHandlerBuilder,
|
|
334
|
-
);
|
|
354
|
+
const container = await Container.createDetached(this.services, codeDetails);
|
|
335
355
|
|
|
336
356
|
if (this.cachingEnabled) {
|
|
337
357
|
container.once("attached", () => {
|
|
338
|
-
|
|
358
|
+
ensureResolvedUrlDefined(container.resolvedUrl);
|
|
339
359
|
const parsedUrl = parseUrl(container.resolvedUrl.url);
|
|
340
360
|
if (parsedUrl !== undefined) {
|
|
341
361
|
this.addToContainerCache(parsedUrl.id, Promise.resolve(container));
|
|
@@ -347,7 +367,7 @@ export class Loader implements IHostLoader {
|
|
|
347
367
|
}
|
|
348
368
|
|
|
349
369
|
public async rehydrateDetachedContainerFromSnapshot(snapshot: string): Promise<IContainer> {
|
|
350
|
-
return Container.rehydrateDetachedFromSnapshot(this, snapshot
|
|
370
|
+
return Container.rehydrateDetachedFromSnapshot(this.services, snapshot);
|
|
351
371
|
}
|
|
352
372
|
|
|
353
373
|
public async resolve(request: IRequest, pendingLocalState?: string): Promise<IContainer> {
|
|
@@ -404,7 +424,7 @@ export class Loader implements IHostLoader {
|
|
|
404
424
|
pendingLocalState?: IPendingContainerState,
|
|
405
425
|
): Promise<{ container: Container; parsed: IParsedUrl }> {
|
|
406
426
|
const resolvedAsFluid = await this.services.urlResolver.resolve(request);
|
|
407
|
-
|
|
427
|
+
ensureResolvedUrlDefined(resolvedAsFluid);
|
|
408
428
|
|
|
409
429
|
// Parse URL into data stores
|
|
410
430
|
const parsed = parseUrl(resolvedAsFluid.url);
|
|
@@ -423,11 +443,18 @@ export class Loader implements IHostLoader {
|
|
|
423
443
|
}
|
|
424
444
|
}
|
|
425
445
|
|
|
426
|
-
|
|
427
|
-
|
|
446
|
+
request.headers ??= {};
|
|
447
|
+
// If set in both query string and headers, use query string. Also write the value from the query string into the header either way.
|
|
448
|
+
request.headers[LoaderHeader.version] =
|
|
449
|
+
parsed.version ?? request.headers[LoaderHeader.version];
|
|
450
|
+
const canCache =
|
|
451
|
+
this.cachingEnabled &&
|
|
452
|
+
request.headers[LoaderHeader.cache] !== false &&
|
|
453
|
+
pendingLocalState === undefined;
|
|
454
|
+
const fromSequenceNumber = request.headers[LoaderHeader.sequenceNumber] ?? -1;
|
|
428
455
|
|
|
429
456
|
let container: Container;
|
|
430
|
-
if (
|
|
457
|
+
if (canCache) {
|
|
431
458
|
const key = this.getKeyForContainerCache(request, parsed);
|
|
432
459
|
const maybeContainer = await this.containers.get(key);
|
|
433
460
|
if (maybeContainer !== undefined) {
|
|
@@ -461,48 +488,23 @@ export class Loader implements IHostLoader {
|
|
|
461
488
|
return this.services.options.cache !== false;
|
|
462
489
|
}
|
|
463
490
|
|
|
464
|
-
private canCacheForRequest(headers: IRequestHeader): boolean {
|
|
465
|
-
return this.cachingEnabled && headers[LoaderHeader.cache] !== false;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
private parseHeader(parsed: IParsedUrl, request: IRequest) {
|
|
469
|
-
let fromSequenceNumber = -1;
|
|
470
|
-
|
|
471
|
-
request.headers = request.headers ?? {};
|
|
472
|
-
|
|
473
|
-
const headerSeqNum = request.headers[LoaderHeader.sequenceNumber];
|
|
474
|
-
if (headerSeqNum !== undefined) {
|
|
475
|
-
fromSequenceNumber = headerSeqNum;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// If set in both query string and headers, use query string
|
|
479
|
-
request.headers[LoaderHeader.version] =
|
|
480
|
-
parsed.version ?? request.headers[LoaderHeader.version];
|
|
481
|
-
|
|
482
|
-
const canCache = this.canCacheForRequest(request.headers);
|
|
483
|
-
|
|
484
|
-
return {
|
|
485
|
-
canCache,
|
|
486
|
-
fromSequenceNumber,
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
|
|
490
491
|
private async loadContainer(
|
|
491
492
|
request: IRequest,
|
|
492
|
-
|
|
493
|
+
resolvedUrl: IResolvedUrl,
|
|
493
494
|
pendingLocalState?: IPendingContainerState,
|
|
494
495
|
): Promise<Container> {
|
|
495
496
|
return Container.load(
|
|
496
|
-
this,
|
|
497
497
|
{
|
|
498
|
-
|
|
499
|
-
clientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],
|
|
500
|
-
resolvedUrl: resolved,
|
|
498
|
+
resolvedUrl,
|
|
501
499
|
version: request.headers?.[LoaderHeader.version] ?? undefined,
|
|
502
500
|
loadMode: request.headers?.[LoaderHeader.loadMode],
|
|
501
|
+
pendingLocalState,
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
canReconnect: request.headers?.[LoaderHeader.reconnect],
|
|
505
|
+
clientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],
|
|
506
|
+
...this.services,
|
|
503
507
|
},
|
|
504
|
-
pendingLocalState,
|
|
505
|
-
this.protocolHandlerBuilder,
|
|
506
508
|
);
|
|
507
509
|
}
|
|
508
510
|
}
|
package/src/packageVersion.ts
CHANGED
|
@@ -18,14 +18,15 @@ import {
|
|
|
18
18
|
ISummaryTree,
|
|
19
19
|
IVersion,
|
|
20
20
|
} from "@fluidframework/protocol-definitions";
|
|
21
|
-
import { IDisposable
|
|
21
|
+
import { IDisposable } from "@fluidframework/common-definitions";
|
|
22
|
+
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
|
|
22
23
|
import { runWithRetry } from "@fluidframework/driver-utils";
|
|
23
24
|
|
|
24
25
|
export class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {
|
|
25
26
|
private _disposed = false;
|
|
26
27
|
constructor(
|
|
27
28
|
private readonly internalStorageService: IDocumentStorageService,
|
|
28
|
-
private readonly logger:
|
|
29
|
+
private readonly logger: ITelemetryLoggerExt,
|
|
29
30
|
) {}
|
|
30
31
|
|
|
31
32
|
public get policies(): IDocumentStorageServicePolicies | undefined {
|