@fluidframework/container-loader 2.0.0-dev.4.4.0.162574 → 2.0.0-dev.5.3.2.178189
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 +59 -0
- package/README.md +27 -3
- package/dist/catchUpMonitor.d.ts +1 -1
- package/dist/catchUpMonitor.d.ts.map +1 -1
- package/dist/catchUpMonitor.js.map +1 -1
- 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 +18 -3
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +34 -9
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +99 -70
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +260 -218
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +24 -67
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +28 -217
- 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 +29 -6
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +9 -3
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts +22 -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/disposal.d.ts +13 -0
- package/dist/disposal.d.ts.map +1 -0
- package/dist/disposal.js +25 -0
- package/dist/disposal.js.map +1 -0
- 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 -8
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +47 -61
- package/dist/loader.js.map +1 -1
- package/dist/noopHeuristic.d.ts +23 -0
- package/dist/noopHeuristic.d.ts.map +1 -0
- package/dist/{collabWindowTracker.js → noopHeuristic.js} +30 -42
- package/dist/noopHeuristic.js.map +1 -0
- 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 +7 -12
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +17 -19
- package/dist/protocol.js.map +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/dist/protocolTreeDocumentStorageService.js.map +1 -1
- package/dist/quorum.d.ts +1 -17
- package/dist/quorum.d.ts.map +1 -1
- package/dist/quorum.js +1 -17
- package/dist/quorum.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/catchUpMonitor.d.ts +1 -1
- package/lib/catchUpMonitor.d.ts.map +1 -1
- package/lib/catchUpMonitor.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 +18 -3
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +35 -10
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +99 -70
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +264 -222
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +24 -67
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +28 -217
- 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 +29 -6
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +9 -3
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts +22 -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/disposal.d.ts +13 -0
- package/lib/disposal.d.ts.map +1 -0
- package/lib/disposal.js +21 -0
- package/lib/disposal.js.map +1 -0
- 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 -8
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +47 -61
- package/lib/loader.js.map +1 -1
- package/lib/noopHeuristic.d.ts +23 -0
- package/lib/noopHeuristic.d.ts.map +1 -0
- package/lib/{collabWindowTracker.js → noopHeuristic.js} +30 -42
- package/lib/noopHeuristic.js.map +1 -0
- 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 +7 -12
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +15 -18
- package/lib/protocol.js.map +1 -1
- package/lib/protocolTreeDocumentStorageService.d.ts +1 -1
- package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/lib/protocolTreeDocumentStorageService.js.map +1 -1
- package/lib/quorum.d.ts +1 -17
- package/lib/quorum.d.ts.map +1 -1
- package/lib/quorum.js +1 -16
- package/lib/quorum.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 +22 -20
- package/src/catchUpMonitor.ts +1 -1
- package/src/connectionManager.ts +40 -22
- package/src/connectionStateHandler.ts +66 -17
- package/src/container.ts +464 -292
- package/src/containerContext.ts +33 -341
- package/src/containerStorageAdapter.ts +40 -10
- package/src/contracts.ts +11 -3
- package/src/deltaManager.ts +74 -45
- package/src/deltaQueue.ts +2 -3
- package/src/disposal.ts +25 -0
- package/src/index.ts +1 -8
- package/src/loader.ts +85 -83
- package/src/{collabWindowTracker.ts → noopHeuristic.ts} +37 -47
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +18 -39
- package/src/protocolTreeDocumentStorageService.ts +1 -1
- package/src/quorum.ts +2 -31
- package/src/retriableDocumentStorageService.ts +4 -2
- package/src/utils.ts +15 -1
- package/dist/collabWindowTracker.d.ts +0 -19
- package/dist/collabWindowTracker.d.ts.map +0 -1
- package/dist/collabWindowTracker.js.map +0 -1
- package/dist/deltaManagerProxy.d.ts +0 -42
- package/dist/deltaManagerProxy.d.ts.map +0 -1
- package/dist/deltaManagerProxy.js +0 -79
- package/dist/deltaManagerProxy.js.map +0 -1
- package/lib/collabWindowTracker.d.ts +0 -19
- package/lib/collabWindowTracker.d.ts.map +0 -1
- package/lib/collabWindowTracker.js.map +0 -1
- package/lib/deltaManagerProxy.d.ts +0 -42
- package/lib/deltaManagerProxy.d.ts.map +0 -1
- package/lib/deltaManagerProxy.js +0 -74
- package/lib/deltaManagerProxy.js.map +0 -1
- package/src/deltaManagerProxy.ts +0 -109
package/src/deltaManager.ts
CHANGED
|
@@ -5,12 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import { default as AbortController } from "abort-controller";
|
|
7
7
|
import { v4 as uuid } from "uuid";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
IEventProvider,
|
|
11
|
-
ITelemetryProperties,
|
|
12
|
-
ITelemetryErrorEvent,
|
|
13
|
-
} from "@fluidframework/common-definitions";
|
|
8
|
+
import { IEventProvider } from "@fluidframework/common-definitions";
|
|
9
|
+
import { ITelemetryProperties, ITelemetryErrorEvent } from "@fluidframework/core-interfaces";
|
|
14
10
|
import {
|
|
15
11
|
IDeltaHandlerStrategy,
|
|
16
12
|
IDeltaManager,
|
|
@@ -21,7 +17,13 @@ import {
|
|
|
21
17
|
IConnectionDetailsInternal,
|
|
22
18
|
} from "@fluidframework/container-definitions";
|
|
23
19
|
import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
|
|
24
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
normalizeError,
|
|
22
|
+
logIfFalse,
|
|
23
|
+
safeRaiseEvent,
|
|
24
|
+
isFluidError,
|
|
25
|
+
ITelemetryLoggerExt,
|
|
26
|
+
} from "@fluidframework/telemetry-utils";
|
|
25
27
|
import {
|
|
26
28
|
IDocumentDeltaStorageService,
|
|
27
29
|
IDocumentService,
|
|
@@ -41,6 +43,7 @@ import {
|
|
|
41
43
|
DataCorruptionError,
|
|
42
44
|
extractSafePropertiesFromMessage,
|
|
43
45
|
DataProcessingError,
|
|
46
|
+
UsageError,
|
|
44
47
|
} from "@fluidframework/container-utils";
|
|
45
48
|
import { IConnectionManagerFactoryArgs, IConnectionManager } from "./contracts";
|
|
46
49
|
import { DeltaQueue } from "./deltaQueue";
|
|
@@ -60,6 +63,15 @@ export interface IDeltaManagerInternalEvents extends IDeltaManagerEvents {
|
|
|
60
63
|
(event: "throttled", listener: (error: IThrottlingWarning) => void);
|
|
61
64
|
(event: "closed" | "disposed", listener: (error?: ICriticalContainerError) => void);
|
|
62
65
|
(event: "connect", listener: (details: IConnectionDetailsInternal, opsBehind?: number) => void);
|
|
66
|
+
(event: "establishingConnection", listener: (reason: string) => void);
|
|
67
|
+
(event: "cancelEstablishingConnection", listener: (reason: string) => void);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Batching makes assumptions about what might be on the metadata. This interface codifies those assumptions, but does not validate them.
|
|
72
|
+
*/
|
|
73
|
+
interface IBatchMetadata {
|
|
74
|
+
batch?: boolean;
|
|
63
75
|
}
|
|
64
76
|
|
|
65
77
|
/**
|
|
@@ -285,13 +297,16 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
285
297
|
|
|
286
298
|
if (batch.length === 1) {
|
|
287
299
|
assert(
|
|
288
|
-
batch[0].metadata?.batch === undefined,
|
|
300
|
+
(batch[0].metadata as IBatchMetadata)?.batch === undefined,
|
|
289
301
|
0x3c9 /* no batch markup on single message */,
|
|
290
302
|
);
|
|
291
303
|
} else {
|
|
292
|
-
assert(batch[0].metadata?.batch === true, 0x3ca /* no start batch markup */);
|
|
293
304
|
assert(
|
|
294
|
-
batch[
|
|
305
|
+
(batch[0].metadata as IBatchMetadata)?.batch === true,
|
|
306
|
+
0x3ca /* no start batch markup */,
|
|
307
|
+
);
|
|
308
|
+
assert(
|
|
309
|
+
(batch[batch.length - 1].metadata as IBatchMetadata)?.batch === false,
|
|
295
310
|
0x3cb /* no end batch markup */,
|
|
296
311
|
);
|
|
297
312
|
}
|
|
@@ -340,7 +355,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
340
355
|
|
|
341
356
|
constructor(
|
|
342
357
|
private readonly serviceProvider: () => IDocumentService | undefined,
|
|
343
|
-
private readonly logger:
|
|
358
|
+
private readonly logger: ITelemetryLoggerExt,
|
|
344
359
|
private readonly _active: () => boolean,
|
|
345
360
|
createConnectionManager: (props: IConnectionManagerFactoryArgs) => TConnectionManager,
|
|
346
361
|
) {
|
|
@@ -365,6 +380,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
365
380
|
pongHandler: (latency: number) => this.emit("pong", latency),
|
|
366
381
|
readonlyChangeHandler: (readonly?: boolean) =>
|
|
367
382
|
safeRaiseEvent(this, this.logger, "readonly", readonly),
|
|
383
|
+
establishConnectionHandler: (reason: string) => this.establishingConnection(reason),
|
|
384
|
+
cancelConnectionHandler: (reason: string) => this.cancelEstablishingConnection(reason),
|
|
368
385
|
};
|
|
369
386
|
|
|
370
387
|
this.connectionManager = createConnectionManager(props);
|
|
@@ -404,6 +421,14 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
404
421
|
// - inbound & inboundSignal are resumed in attachOpHandler() when we have handler setup
|
|
405
422
|
}
|
|
406
423
|
|
|
424
|
+
private cancelEstablishingConnection(reason: string) {
|
|
425
|
+
this.emit("cancelEstablishingConnection", reason);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
private establishingConnection(reason: string) {
|
|
429
|
+
this.emit("establishingConnection", reason);
|
|
430
|
+
}
|
|
431
|
+
|
|
407
432
|
private connectHandler(connection: IConnectionDetailsInternal) {
|
|
408
433
|
this.refreshDelayInfo(this.deltaStreamDelayId);
|
|
409
434
|
|
|
@@ -453,10 +478,6 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
453
478
|
}
|
|
454
479
|
}
|
|
455
480
|
|
|
456
|
-
public dispose() {
|
|
457
|
-
throw new Error("Not implemented.");
|
|
458
|
-
}
|
|
459
|
-
|
|
460
481
|
/**
|
|
461
482
|
* Sets the sequence number from which inbound messages should be returned
|
|
462
483
|
*/
|
|
@@ -644,23 +665,51 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
644
665
|
/**
|
|
645
666
|
* Closes the connection and clears inbound & outbound queues.
|
|
646
667
|
*
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
* -
|
|
650
|
-
* -
|
|
651
|
-
* - dispose can be called after closure, but not vis versa
|
|
668
|
+
* Differences from dispose:
|
|
669
|
+
* - close will trigger readonly notification
|
|
670
|
+
* - close emits "closed"
|
|
671
|
+
* - close cannot be called after dispose
|
|
652
672
|
*/
|
|
653
|
-
public close(error?: ICriticalContainerError
|
|
673
|
+
public close(error?: ICriticalContainerError): void {
|
|
654
674
|
if (this._closed) {
|
|
655
|
-
if (doDispose === true) {
|
|
656
|
-
this.disposeInternal(error);
|
|
657
|
-
}
|
|
658
675
|
return;
|
|
659
676
|
}
|
|
660
677
|
this._closed = true;
|
|
661
678
|
|
|
662
|
-
this.connectionManager.dispose(error,
|
|
679
|
+
this.connectionManager.dispose(error, true /* switchToReadonly */);
|
|
680
|
+
this.clearQueues();
|
|
681
|
+
this.emit("closed", error);
|
|
682
|
+
}
|
|
663
683
|
|
|
684
|
+
/**
|
|
685
|
+
* Disposes the connection and clears the inbound & outbound queues.
|
|
686
|
+
*
|
|
687
|
+
* Differences from close:
|
|
688
|
+
* - dispose will emit "disposed"
|
|
689
|
+
* - dispose will remove all listeners
|
|
690
|
+
* - dispose can be called after closure
|
|
691
|
+
*/
|
|
692
|
+
public dispose(error?: Error | ICriticalContainerError): void {
|
|
693
|
+
if (this._disposed) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
if (error !== undefined && !isFluidError(error)) {
|
|
697
|
+
throw new UsageError("Error must be a Fluid error");
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
this._disposed = true;
|
|
701
|
+
this._closed = true; // We consider "disposed" as a further state than "closed"
|
|
702
|
+
|
|
703
|
+
this.connectionManager.dispose(error, false /* switchToReadonly */);
|
|
704
|
+
this.clearQueues();
|
|
705
|
+
|
|
706
|
+
// This needs to be the last thing we do (before removing listeners), as it causes
|
|
707
|
+
// Container to dispose context and break ability of data stores / runtime to "hear" from delta manager.
|
|
708
|
+
this.emit("disposed", error);
|
|
709
|
+
this.removeAllListeners();
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
private clearQueues() {
|
|
664
713
|
this.closeAbortController.abort();
|
|
665
714
|
|
|
666
715
|
this._inbound.clear();
|
|
@@ -673,26 +722,6 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
673
722
|
|
|
674
723
|
// Drop pending messages - this will ensure catchUp() does not go into infinite loop
|
|
675
724
|
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
725
|
}
|
|
697
726
|
|
|
698
727
|
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/disposal.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { IDisposable } from "@fluidframework/common-definitions";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns a wrapper around the provided function, which will only invoke the inner function if the provided
|
|
10
|
+
* {@link @fluidframework/common-definitions#IDisposable | disposable} object has not yet been disposed.
|
|
11
|
+
*
|
|
12
|
+
* @throws Will throw an error if the item has already been disposed.
|
|
13
|
+
*/
|
|
14
|
+
export function doIfNotDisposed<T>(
|
|
15
|
+
disposable: IDisposable,
|
|
16
|
+
f: (...args: any[]) => T,
|
|
17
|
+
): (...args: any[]) => T {
|
|
18
|
+
return (...args: any[]): T => {
|
|
19
|
+
if (disposable.disposed) {
|
|
20
|
+
throw new Error("Already disposed");
|
|
21
|
+
} else {
|
|
22
|
+
return f(...args);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
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,8 +4,19 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { v4 as uuid } from "uuid";
|
|
7
|
-
import { ITelemetryBaseLogger, ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
8
7
|
import {
|
|
8
|
+
ITelemetryLoggerExt,
|
|
9
|
+
ChildLogger,
|
|
10
|
+
DebugLogger,
|
|
11
|
+
IConfigProviderBase,
|
|
12
|
+
loggerToMonitoringContext,
|
|
13
|
+
mixinMonitoringContext,
|
|
14
|
+
MonitoringContext,
|
|
15
|
+
PerformanceEvent,
|
|
16
|
+
sessionStorageConfigProvider,
|
|
17
|
+
} from "@fluidframework/telemetry-utils";
|
|
18
|
+
import {
|
|
19
|
+
ITelemetryBaseLogger,
|
|
9
20
|
FluidObject,
|
|
10
21
|
IFluidRouter,
|
|
11
22
|
IRequest,
|
|
@@ -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
|
}
|