@fluidframework/container-loader 2.0.0-internal.4.4.0 → 2.0.0-internal.5.0.0
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 +24 -0
- package/README.md +6 -3
- package/dist/connectionManager.d.ts +3 -2
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +4 -3
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +62 -36
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +63 -83
- 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.map +1 -1
- package/dist/deltaManager.d.ts +3 -2
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +0 -1
- package/dist/deltaManager.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 -5
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +28 -34
- 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/lib/connectionManager.d.ts +3 -2
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +1 -1
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +4 -3
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +1 -1
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +62 -36
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +64 -84
- 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.map +1 -1
- package/lib/deltaManager.d.ts +3 -2
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +1 -2
- package/lib/deltaManager.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 -5
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +28 -34
- 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/package.json +27 -10
- package/src/connectionManager.ts +7 -7
- package/src/connectionStateHandler.ts +7 -7
- package/src/container.ts +140 -125
- package/src/containerContext.ts +3 -9
- package/src/containerStorageAdapter.ts +4 -4
- package/src/deltaManager.ts +7 -4
- package/src/index.ts +1 -8
- package/src/loader.ts +56 -47
- package/src/packageVersion.ts +1 -1
- package/src/retriableDocumentStorageService.ts +3 -2
package/src/container.ts
CHANGED
|
@@ -7,11 +7,7 @@
|
|
|
7
7
|
import merge from "lodash/merge";
|
|
8
8
|
|
|
9
9
|
import { v4 as uuid } from "uuid";
|
|
10
|
-
import {
|
|
11
|
-
ITelemetryLogger,
|
|
12
|
-
ITelemetryProperties,
|
|
13
|
-
TelemetryEventCategory,
|
|
14
|
-
} from "@fluidframework/common-definitions";
|
|
10
|
+
import { ITelemetryProperties, TelemetryEventCategory } from "@fluidframework/common-definitions";
|
|
15
11
|
import { assert, performance, unreachableCase } from "@fluidframework/common-utils";
|
|
16
12
|
import { IRequest, IResponse, IFluidRouter, FluidObject } from "@fluidframework/core-interfaces";
|
|
17
13
|
import {
|
|
@@ -29,23 +25,24 @@ import {
|
|
|
29
25
|
IFluidCodeDetails,
|
|
30
26
|
isFluidCodeDetails,
|
|
31
27
|
IBatchMessage,
|
|
28
|
+
ICodeDetailsLoader,
|
|
29
|
+
IHostLoader,
|
|
32
30
|
} from "@fluidframework/container-definitions";
|
|
33
31
|
import { GenericError, UsageError } from "@fluidframework/container-utils";
|
|
34
32
|
import {
|
|
35
33
|
IAnyDriverError,
|
|
36
34
|
IDocumentService,
|
|
35
|
+
IDocumentServiceFactory,
|
|
37
36
|
IDocumentStorageService,
|
|
38
|
-
IFluidResolvedUrl,
|
|
39
37
|
IResolvedUrl,
|
|
38
|
+
IUrlResolver,
|
|
40
39
|
} from "@fluidframework/driver-definitions";
|
|
41
40
|
import {
|
|
42
41
|
readAndParse,
|
|
43
42
|
OnlineStatus,
|
|
44
43
|
isOnline,
|
|
45
|
-
ensureFluidResolvedUrl,
|
|
46
44
|
combineAppAndProtocolSummary,
|
|
47
45
|
runWithRetry,
|
|
48
|
-
isFluidResolvedUrl,
|
|
49
46
|
isCombinedAppAndProtocolSummary,
|
|
50
47
|
} from "@fluidframework/driver-utils";
|
|
51
48
|
import { IQuorumSnapshot } from "@fluidframework/protocol-base";
|
|
@@ -80,13 +77,14 @@ import {
|
|
|
80
77
|
MonitoringContext,
|
|
81
78
|
loggerToMonitoringContext,
|
|
82
79
|
wrapError,
|
|
80
|
+
ITelemetryLoggerExt,
|
|
83
81
|
} from "@fluidframework/telemetry-utils";
|
|
84
82
|
import { Audience } from "./audience";
|
|
85
83
|
import { ContainerContext } from "./containerContext";
|
|
86
84
|
import { ReconnectMode, IConnectionManagerFactoryArgs, getPackageName } from "./contracts";
|
|
87
85
|
import { DeltaManager, IConnectionArgs } from "./deltaManager";
|
|
88
86
|
import { DeltaManagerProxy } from "./deltaManagerProxy";
|
|
89
|
-
import {
|
|
87
|
+
import { IDetachedBlobStorage, ILoaderOptions, RelativeLoader } from "./loader";
|
|
90
88
|
import { pkgVersion } from "./packageVersion";
|
|
91
89
|
import {
|
|
92
90
|
ContainerStorageAdapter,
|
|
@@ -117,44 +115,82 @@ const dirtyContainerEvent = "dirty";
|
|
|
117
115
|
const savedContainerEvent = "saved";
|
|
118
116
|
|
|
119
117
|
/**
|
|
120
|
-
* @deprecated this is an internal interface and will not longer be exported in future versions
|
|
121
118
|
* @internal
|
|
122
119
|
*/
|
|
123
|
-
export interface
|
|
120
|
+
export interface IContainerLoadProps {
|
|
124
121
|
/**
|
|
125
|
-
*
|
|
122
|
+
* The resolved url of the container being loaded
|
|
126
123
|
*/
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Client details provided in the override will be merged over the default client.
|
|
130
|
-
*/
|
|
131
|
-
clientDetailsOverride?: IClientDetails;
|
|
132
|
-
resolvedUrl: IFluidResolvedUrl;
|
|
124
|
+
readonly resolvedUrl: IResolvedUrl;
|
|
133
125
|
/**
|
|
134
126
|
* Control which snapshot version to load from. See IParsedUrl for detailed information.
|
|
135
127
|
*/
|
|
136
|
-
version: string | undefined;
|
|
128
|
+
readonly version: string | undefined;
|
|
137
129
|
/**
|
|
138
130
|
* Loads the Container in paused state if true, unpaused otherwise.
|
|
139
131
|
*/
|
|
140
|
-
loadMode?: IContainerLoadMode;
|
|
132
|
+
readonly loadMode?: IContainerLoadMode;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The pending state serialized from a pervious container instance
|
|
136
|
+
*/
|
|
137
|
+
readonly pendingLocalState?: IPendingContainerState;
|
|
141
138
|
}
|
|
142
139
|
|
|
143
140
|
/**
|
|
144
|
-
* @deprecated this is an internal interface and will not longer be exported in future versions
|
|
145
141
|
* @internal
|
|
146
142
|
*/
|
|
147
|
-
export interface
|
|
148
|
-
|
|
149
|
-
|
|
143
|
+
export interface IContainerCreateProps {
|
|
144
|
+
/**
|
|
145
|
+
* Disables the Container from reconnecting if false, allows reconnect otherwise.
|
|
146
|
+
*/
|
|
147
|
+
readonly canReconnect?: boolean;
|
|
150
148
|
/**
|
|
151
149
|
* Client details provided in the override will be merged over the default client.
|
|
152
150
|
*/
|
|
153
|
-
clientDetailsOverride?: IClientDetails;
|
|
151
|
+
readonly clientDetailsOverride?: IClientDetails;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* The url resolver used by the loader for resolving external urls
|
|
155
|
+
* into Fluid urls such that the container specified by the
|
|
156
|
+
* external url can be loaded.
|
|
157
|
+
*/
|
|
158
|
+
readonly urlResolver: IUrlResolver;
|
|
159
|
+
/**
|
|
160
|
+
* The document service factory take the Fluid url provided
|
|
161
|
+
* by the resolved url and constructs all the necessary services
|
|
162
|
+
* for communication with the container's server.
|
|
163
|
+
*/
|
|
164
|
+
readonly documentServiceFactory: IDocumentServiceFactory;
|
|
165
|
+
/**
|
|
166
|
+
* The code loader handles loading the necessary code
|
|
167
|
+
* for running a container once it is loaded.
|
|
168
|
+
*/
|
|
169
|
+
readonly codeLoader: ICodeDetailsLoader;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* A property bag of options used by various layers
|
|
173
|
+
* to control features
|
|
174
|
+
*/
|
|
175
|
+
readonly options: ILoaderOptions;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Scope is provided to all container and is a set of shared
|
|
179
|
+
* services for container's to integrate with their host environment.
|
|
180
|
+
*/
|
|
181
|
+
readonly scope: FluidObject;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* The logger downstream consumers should construct their loggers from
|
|
185
|
+
*/
|
|
186
|
+
readonly subLogger: ITelemetryLoggerExt;
|
|
187
|
+
|
|
154
188
|
/**
|
|
155
|
-
*
|
|
189
|
+
* Blobs storage for detached containers.
|
|
156
190
|
*/
|
|
157
|
-
|
|
191
|
+
readonly detachedBlobStorage?: IDetachedBlobStorage;
|
|
192
|
+
|
|
193
|
+
readonly protocolHandlerBuilder?: ProtocolHandlerBuilder;
|
|
158
194
|
}
|
|
159
195
|
|
|
160
196
|
/**
|
|
@@ -260,7 +296,7 @@ const getCodeProposal =
|
|
|
260
296
|
* @param action - functor to call and measure
|
|
261
297
|
*/
|
|
262
298
|
export async function ReportIfTooLong(
|
|
263
|
-
logger:
|
|
299
|
+
logger: ITelemetryLoggerExt,
|
|
264
300
|
eventName: string,
|
|
265
301
|
action: () => Promise<ITelemetryProperties>,
|
|
266
302
|
) {
|
|
@@ -274,7 +310,6 @@ export async function ReportIfTooLong(
|
|
|
274
310
|
/**
|
|
275
311
|
* State saved by a container at close time, to be used to load a new instance
|
|
276
312
|
* of the container to the same state
|
|
277
|
-
* @deprecated this is an internal interface and will not longer be exported in future versions
|
|
278
313
|
* @internal
|
|
279
314
|
*/
|
|
280
315
|
export interface IPendingContainerState {
|
|
@@ -301,49 +336,46 @@ export interface IPendingContainerState {
|
|
|
301
336
|
|
|
302
337
|
const summarizerClientType = "summarizer";
|
|
303
338
|
|
|
304
|
-
/**
|
|
305
|
-
* @deprecated - In the next release Container will no longer be exported, IContainer should be used in its place.
|
|
306
|
-
*/
|
|
307
339
|
export class Container
|
|
308
340
|
extends EventEmitterWithErrorHandling<IContainerEvents>
|
|
309
341
|
implements IContainer, IContainerExperimental
|
|
310
342
|
{
|
|
311
343
|
public static version = "^0.1.0";
|
|
312
344
|
|
|
345
|
+
public static async clone(
|
|
346
|
+
container: Container,
|
|
347
|
+
loadProps: IContainerLoadProps,
|
|
348
|
+
createParamOverrides: Partial<IContainerCreateProps>,
|
|
349
|
+
) {
|
|
350
|
+
return this.load(loadProps, {
|
|
351
|
+
...container.createProps,
|
|
352
|
+
...createParamOverrides,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
313
356
|
/**
|
|
314
357
|
* Load an existing container.
|
|
315
358
|
* @internal
|
|
316
359
|
*/
|
|
317
360
|
public static async load(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
pendingLocalState?: IPendingContainerState,
|
|
321
|
-
protocolHandlerBuilder?: ProtocolHandlerBuilder,
|
|
361
|
+
loadProps: IContainerLoadProps,
|
|
362
|
+
createProps: IContainerCreateProps,
|
|
322
363
|
): Promise<Container> {
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
clientDetailsOverride: loadOptions.clientDetailsOverride,
|
|
327
|
-
resolvedUrl: loadOptions.resolvedUrl,
|
|
328
|
-
canReconnect: loadOptions.canReconnect,
|
|
329
|
-
serializedContainerState: pendingLocalState,
|
|
330
|
-
},
|
|
331
|
-
protocolHandlerBuilder,
|
|
332
|
-
);
|
|
364
|
+
const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
|
|
365
|
+
|
|
366
|
+
const container = new Container(createProps, loadProps);
|
|
333
367
|
|
|
334
368
|
return PerformanceEvent.timedExecAsync(
|
|
335
369
|
container.mc.logger,
|
|
336
370
|
{ eventName: "Load" },
|
|
337
371
|
async (event) =>
|
|
338
372
|
new Promise<Container>((resolve, reject) => {
|
|
339
|
-
const version = loadOptions.version;
|
|
340
|
-
|
|
341
373
|
const defaultMode: IContainerLoadMode = { opsBeforeReturn: "cached" };
|
|
342
374
|
// if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
|
|
343
375
|
// to return container, so ignore this value and use undefined for opsBeforeReturn
|
|
344
376
|
const mode: IContainerLoadMode = pendingLocalState
|
|
345
|
-
? { ...(
|
|
346
|
-
:
|
|
377
|
+
? { ...(loadMode ?? defaultMode), opsBeforeReturn: undefined }
|
|
378
|
+
: loadMode ?? defaultMode;
|
|
347
379
|
|
|
348
380
|
const onClosed = (err?: ICriticalContainerError) => {
|
|
349
381
|
// pre-0.58 error message: containerClosedWithoutErrorDuringLoad
|
|
@@ -354,13 +386,13 @@ export class Container
|
|
|
354
386
|
container.on("closed", onClosed);
|
|
355
387
|
|
|
356
388
|
container
|
|
357
|
-
.load(version, mode, pendingLocalState)
|
|
389
|
+
.load(version, mode, resolvedUrl, pendingLocalState)
|
|
358
390
|
.finally(() => {
|
|
359
391
|
container.removeListener("closed", onClosed);
|
|
360
392
|
})
|
|
361
393
|
.then(
|
|
362
394
|
(props) => {
|
|
363
|
-
event.end({ ...props, ...
|
|
395
|
+
event.end({ ...props, ...loadMode });
|
|
364
396
|
resolve(container);
|
|
365
397
|
},
|
|
366
398
|
(error) => {
|
|
@@ -381,11 +413,10 @@ export class Container
|
|
|
381
413
|
* Create a new container in a detached state.
|
|
382
414
|
*/
|
|
383
415
|
public static async createDetached(
|
|
384
|
-
|
|
416
|
+
createProps: IContainerCreateProps,
|
|
385
417
|
codeDetails: IFluidCodeDetails,
|
|
386
|
-
protocolHandlerBuilder?: ProtocolHandlerBuilder,
|
|
387
418
|
): Promise<Container> {
|
|
388
|
-
const container = new Container(
|
|
419
|
+
const container = new Container(createProps);
|
|
389
420
|
|
|
390
421
|
return PerformanceEvent.timedExecAsync(
|
|
391
422
|
container.mc.logger,
|
|
@@ -403,11 +434,10 @@ export class Container
|
|
|
403
434
|
* snapshot from a previous detached container.
|
|
404
435
|
*/
|
|
405
436
|
public static async rehydrateDetachedFromSnapshot(
|
|
406
|
-
|
|
437
|
+
createProps: IContainerCreateProps,
|
|
407
438
|
snapshot: string,
|
|
408
|
-
protocolHandlerBuilder?: ProtocolHandlerBuilder,
|
|
409
439
|
): Promise<Container> {
|
|
410
|
-
const container = new Container(
|
|
440
|
+
const container = new Container(createProps);
|
|
411
441
|
|
|
412
442
|
return PerformanceEvent.timedExecAsync(
|
|
413
443
|
container.mc.logger,
|
|
@@ -503,7 +533,6 @@ export class Container
|
|
|
503
533
|
private readonly connectionTransitionTimes: number[] = [];
|
|
504
534
|
private messageCountAfterDisconnection: number = 0;
|
|
505
535
|
private _loadedFromVersion: IVersion | undefined;
|
|
506
|
-
private _resolvedUrl: IFluidResolvedUrl | undefined;
|
|
507
536
|
private attachStarted = false;
|
|
508
537
|
private _dirtyContainer = false;
|
|
509
538
|
private readonly savedOps: ISequencedDocumentMessage[] = [];
|
|
@@ -527,7 +556,18 @@ export class Container
|
|
|
527
556
|
}
|
|
528
557
|
|
|
529
558
|
public get resolvedUrl(): IResolvedUrl | undefined {
|
|
530
|
-
|
|
559
|
+
/**
|
|
560
|
+
* All attached containers will have a document service,
|
|
561
|
+
* this is required, as attached containers are attached to
|
|
562
|
+
* a service. Detached containers will neither have a document
|
|
563
|
+
* service or a resolved url as they only exist locally.
|
|
564
|
+
* in order to create a document service a resolved url must
|
|
565
|
+
* first be obtained, this is how the container is identified.
|
|
566
|
+
* Because of this, the document service's resolved url
|
|
567
|
+
* is always the same as the containers, as we had to
|
|
568
|
+
* obtain the resolved url, and then create the service from it.
|
|
569
|
+
*/
|
|
570
|
+
return this.service?.resolvedUrl;
|
|
531
571
|
}
|
|
532
572
|
|
|
533
573
|
public get loadedFromVersion(): IVersion | undefined {
|
|
@@ -633,17 +673,17 @@ export class Container
|
|
|
633
673
|
}
|
|
634
674
|
|
|
635
675
|
private get serviceFactory() {
|
|
636
|
-
return this.
|
|
676
|
+
return this.createProps.documentServiceFactory;
|
|
637
677
|
}
|
|
638
678
|
private get urlResolver() {
|
|
639
|
-
return this.
|
|
679
|
+
return this.createProps.urlResolver;
|
|
640
680
|
}
|
|
641
681
|
public readonly options: ILoaderOptions;
|
|
642
682
|
private get scope() {
|
|
643
|
-
return this.
|
|
683
|
+
return this.createProps.scope;
|
|
644
684
|
}
|
|
645
685
|
private get codeLoader() {
|
|
646
|
-
return this.
|
|
686
|
+
return this.createProps.codeLoader;
|
|
647
687
|
}
|
|
648
688
|
|
|
649
689
|
/**
|
|
@@ -685,9 +725,8 @@ export class Container
|
|
|
685
725
|
* @internal
|
|
686
726
|
*/
|
|
687
727
|
constructor(
|
|
688
|
-
private readonly
|
|
689
|
-
|
|
690
|
-
private readonly protocolHandlerBuilder?: ProtocolHandlerBuilder,
|
|
728
|
+
private readonly createProps: IContainerCreateProps,
|
|
729
|
+
loadProps?: IContainerLoadProps,
|
|
691
730
|
) {
|
|
692
731
|
super((name, error) => {
|
|
693
732
|
this.mc.logger.sendErrorEvent(
|
|
@@ -699,10 +738,9 @@ export class Container
|
|
|
699
738
|
);
|
|
700
739
|
});
|
|
701
740
|
|
|
702
|
-
this.clientDetailsOverride =
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
this._canReconnect = config.canReconnect;
|
|
741
|
+
this.clientDetailsOverride = createProps.clientDetailsOverride;
|
|
742
|
+
if (createProps.canReconnect !== undefined) {
|
|
743
|
+
this._canReconnect = createProps.canReconnect;
|
|
706
744
|
}
|
|
707
745
|
|
|
708
746
|
// Create logger for data stores to use
|
|
@@ -713,15 +751,15 @@ export class Container
|
|
|
713
751
|
}`;
|
|
714
752
|
// Need to use the property getter for docId because for detached flow we don't have the docId initially.
|
|
715
753
|
// We assign the id later so property getter is used.
|
|
716
|
-
this.subLogger = ChildLogger.create(
|
|
754
|
+
this.subLogger = ChildLogger.create(createProps.subLogger, undefined, {
|
|
717
755
|
all: {
|
|
718
756
|
clientType, // Differentiating summarizer container from main container
|
|
719
757
|
containerId: uuid(),
|
|
720
|
-
docId: () => this.
|
|
758
|
+
docId: () => this.resolvedUrl?.id,
|
|
721
759
|
containerAttachState: () => this._attachState,
|
|
722
760
|
containerLifecycleState: () => this._lifecycleState,
|
|
723
761
|
containerConnectionState: () => ConnectionState[this.connectionState],
|
|
724
|
-
serializedContainer:
|
|
762
|
+
serializedContainer: loadProps?.pendingLocalState !== undefined,
|
|
725
763
|
},
|
|
726
764
|
// we need to be judicious with our logging here to avoid generating too much data
|
|
727
765
|
// all data logged here should be broadly applicable, and not specific to a
|
|
@@ -751,7 +789,7 @@ export class Container
|
|
|
751
789
|
// all clients that were loaded from the same loader (including summarizer clients).
|
|
752
790
|
// Tracking alternative ways to handle this in AB#4129.
|
|
753
791
|
this.options = {
|
|
754
|
-
...this.
|
|
792
|
+
...this.createProps.options,
|
|
755
793
|
};
|
|
756
794
|
|
|
757
795
|
this._deltaManager = this.createDeltaManager();
|
|
@@ -774,7 +812,7 @@ export class Container
|
|
|
774
812
|
}
|
|
775
813
|
},
|
|
776
814
|
shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
|
|
777
|
-
maxClientLeaveWaitTime: this.
|
|
815
|
+
maxClientLeaveWaitTime: this.createProps.options.maxClientLeaveWaitTime,
|
|
778
816
|
logConnectionIssue: (
|
|
779
817
|
eventName: string,
|
|
780
818
|
category: TelemetryEventCategory,
|
|
@@ -811,7 +849,7 @@ export class Container
|
|
|
811
849
|
},
|
|
812
850
|
},
|
|
813
851
|
this.deltaManager,
|
|
814
|
-
|
|
852
|
+
loadProps?.pendingLocalState?.clientId,
|
|
815
853
|
);
|
|
816
854
|
|
|
817
855
|
this.on(savedContainerEvent, () => {
|
|
@@ -830,12 +868,12 @@ export class Container
|
|
|
830
868
|
// Even if not forced on via this flag, combined summaries may still be enabled by service policy.
|
|
831
869
|
const forceEnableSummarizeProtocolTree =
|
|
832
870
|
this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
|
|
833
|
-
this.
|
|
871
|
+
this.createProps.options.summarizeProtocolTree;
|
|
834
872
|
|
|
835
873
|
this.storageAdapter = new ContainerStorageAdapter(
|
|
836
|
-
this.
|
|
874
|
+
this.createProps.detachedBlobStorage,
|
|
837
875
|
this.mc.logger,
|
|
838
|
-
|
|
876
|
+
loadProps?.pendingLocalState?.snapshotBlobs,
|
|
839
877
|
addProtocolSummaryIfMissing,
|
|
840
878
|
forceEnableSummarizeProtocolTree,
|
|
841
879
|
);
|
|
@@ -869,7 +907,7 @@ export class Container
|
|
|
869
907
|
return this.protocolHandler.quorum;
|
|
870
908
|
}
|
|
871
909
|
|
|
872
|
-
public dispose
|
|
910
|
+
public dispose(error?: ICriticalContainerError) {
|
|
873
911
|
this._deltaManager.close(error, true /* doDispose */);
|
|
874
912
|
this.verifyClosed();
|
|
875
913
|
}
|
|
@@ -921,15 +959,6 @@ export class Container
|
|
|
921
959
|
this._protocolHandler?.close();
|
|
922
960
|
|
|
923
961
|
this.connectionStateHandler.dispose();
|
|
924
|
-
|
|
925
|
-
this._context?.dispose(error !== undefined ? new Error(error.message) : undefined);
|
|
926
|
-
|
|
927
|
-
this.storageAdapter.dispose();
|
|
928
|
-
|
|
929
|
-
// Notify storage about critical errors. They may be due to disconnect between client & server knowledge
|
|
930
|
-
// about file, like file being overwritten in storage, but client having stale local cache.
|
|
931
|
-
// Driver need to ensure all caches are cleared on critical errors
|
|
932
|
-
this.service?.dispose(error);
|
|
933
962
|
} catch (exception) {
|
|
934
963
|
this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
|
|
935
964
|
}
|
|
@@ -1049,10 +1078,7 @@ export class Container
|
|
|
1049
1078
|
const protocolSummary = this.captureProtocolSummary();
|
|
1050
1079
|
const combinedSummary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
1051
1080
|
|
|
1052
|
-
if (
|
|
1053
|
-
this.loader.services.detachedBlobStorage &&
|
|
1054
|
-
this.loader.services.detachedBlobStorage.size > 0
|
|
1055
|
-
) {
|
|
1081
|
+
if (this.createProps.detachedBlobStorage && this.createProps.detachedBlobStorage.size > 0) {
|
|
1056
1082
|
combinedSummary.tree[".hasAttachmentBlobs"] = {
|
|
1057
1083
|
type: SummaryType.Blob,
|
|
1058
1084
|
content: "true",
|
|
@@ -1082,8 +1108,8 @@ export class Container
|
|
|
1082
1108
|
|
|
1083
1109
|
// If attachment blobs were uploaded in detached state we will go through a different attach flow
|
|
1084
1110
|
const hasAttachmentBlobs =
|
|
1085
|
-
this.
|
|
1086
|
-
this.
|
|
1111
|
+
this.createProps.detachedBlobStorage !== undefined &&
|
|
1112
|
+
this.createProps.detachedBlobStorage.size > 0;
|
|
1087
1113
|
|
|
1088
1114
|
try {
|
|
1089
1115
|
assert(
|
|
@@ -1114,11 +1140,11 @@ export class Container
|
|
|
1114
1140
|
}
|
|
1115
1141
|
|
|
1116
1142
|
// Actually go and create the resolved document
|
|
1117
|
-
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
1118
|
-
ensureFluidResolvedUrl(createNewResolvedUrl);
|
|
1119
1143
|
if (this.service === undefined) {
|
|
1144
|
+
const createNewResolvedUrl = await this.urlResolver.resolve(request);
|
|
1120
1145
|
assert(
|
|
1121
|
-
this.client.details.type !== summarizerClientType
|
|
1146
|
+
this.client.details.type !== summarizerClientType &&
|
|
1147
|
+
createNewResolvedUrl !== undefined,
|
|
1122
1148
|
0x2c4 /* "client should not be summarizer before container is created" */,
|
|
1123
1149
|
);
|
|
1124
1150
|
this.service = await runWithRetry(
|
|
@@ -1136,15 +1162,12 @@ export class Container
|
|
|
1136
1162
|
}, // progress
|
|
1137
1163
|
);
|
|
1138
1164
|
}
|
|
1139
|
-
const resolvedUrl = this.service.resolvedUrl;
|
|
1140
|
-
ensureFluidResolvedUrl(resolvedUrl);
|
|
1141
|
-
this._resolvedUrl = resolvedUrl;
|
|
1142
1165
|
await this.storageAdapter.connectToService(this.service);
|
|
1143
1166
|
|
|
1144
1167
|
if (hasAttachmentBlobs) {
|
|
1145
1168
|
// upload blobs to storage
|
|
1146
1169
|
assert(
|
|
1147
|
-
!!this.
|
|
1170
|
+
!!this.createProps.detachedBlobStorage,
|
|
1148
1171
|
0x24e /* "assertion for type narrowing" */,
|
|
1149
1172
|
);
|
|
1150
1173
|
|
|
@@ -1152,13 +1175,14 @@ export class Container
|
|
|
1152
1175
|
// support blob handles that only know about the local IDs
|
|
1153
1176
|
const redirectTable = new Map<string, string>();
|
|
1154
1177
|
// if new blobs are added while uploading, upload them too
|
|
1155
|
-
while (redirectTable.size < this.
|
|
1156
|
-
const newIds = this.
|
|
1178
|
+
while (redirectTable.size < this.createProps.detachedBlobStorage.size) {
|
|
1179
|
+
const newIds = this.createProps.detachedBlobStorage
|
|
1157
1180
|
.getBlobIds()
|
|
1158
1181
|
.filter((id) => !redirectTable.has(id));
|
|
1159
1182
|
for (const id of newIds) {
|
|
1160
|
-
const blob =
|
|
1161
|
-
|
|
1183
|
+
const blob = await this.createProps.detachedBlobStorage.readBlob(
|
|
1184
|
+
id,
|
|
1185
|
+
);
|
|
1162
1186
|
const response = await this.storageAdapter.createBlob(blob);
|
|
1163
1187
|
redirectTable.set(id, response.id);
|
|
1164
1188
|
}
|
|
@@ -1197,12 +1221,8 @@ export class Container
|
|
|
1197
1221
|
} catch (error) {
|
|
1198
1222
|
// add resolved URL on error object so that host has the ability to find this document and delete it
|
|
1199
1223
|
const newError = normalizeError(error);
|
|
1200
|
-
|
|
1201
|
-
if (isFluidResolvedUrl(resolvedUrl)) {
|
|
1202
|
-
newError.addTelemetryProperties({ resolvedUrl: resolvedUrl.url });
|
|
1203
|
-
}
|
|
1224
|
+
newError.addTelemetryProperties({ resolvedUrl: this.resolvedUrl?.url });
|
|
1204
1225
|
this.close(newError);
|
|
1205
|
-
this.dispose?.(newError);
|
|
1206
1226
|
throw newError;
|
|
1207
1227
|
}
|
|
1208
1228
|
},
|
|
@@ -1349,7 +1369,6 @@ export class Container
|
|
|
1349
1369
|
// pre-0.58 error message: existingContextDoesNotSatisfyIncomingProposal
|
|
1350
1370
|
const error = new GenericError("Existing context does not satisfy incoming proposal");
|
|
1351
1371
|
this.close(error);
|
|
1352
|
-
this.dispose?.(error);
|
|
1353
1372
|
}
|
|
1354
1373
|
|
|
1355
1374
|
private async getVersion(version: string | null): Promise<IVersion | undefined> {
|
|
@@ -1382,13 +1401,11 @@ export class Container
|
|
|
1382
1401
|
private async load(
|
|
1383
1402
|
specifiedVersion: string | undefined,
|
|
1384
1403
|
loadMode: IContainerLoadMode,
|
|
1404
|
+
resolvedUrl: IResolvedUrl,
|
|
1385
1405
|
pendingLocalState?: IPendingContainerState,
|
|
1386
1406
|
) {
|
|
1387
|
-
if (this._resolvedUrl === undefined) {
|
|
1388
|
-
throw new Error("Attempting to load without a resolved url");
|
|
1389
|
-
}
|
|
1390
1407
|
this.service = await this.serviceFactory.createDocumentService(
|
|
1391
|
-
|
|
1408
|
+
resolvedUrl,
|
|
1392
1409
|
this.subLogger,
|
|
1393
1410
|
this.client.details.type === summarizerClientType,
|
|
1394
1411
|
);
|
|
@@ -1420,7 +1437,6 @@ export class Container
|
|
|
1420
1437
|
// if we have pendingLocalState we can load without storage; don't wait for connection
|
|
1421
1438
|
this.storageAdapter.connectToService(this.service).catch((error) => {
|
|
1422
1439
|
this.close(error);
|
|
1423
|
-
this.dispose?.(error);
|
|
1424
1440
|
});
|
|
1425
1441
|
}
|
|
1426
1442
|
|
|
@@ -1603,8 +1619,8 @@ export class Container
|
|
|
1603
1619
|
private async rehydrateDetachedFromSnapshot(detachedContainerSnapshot: ISummaryTree) {
|
|
1604
1620
|
if (detachedContainerSnapshot.tree[".hasAttachmentBlobs"] !== undefined) {
|
|
1605
1621
|
assert(
|
|
1606
|
-
!!this.
|
|
1607
|
-
this.
|
|
1622
|
+
!!this.createProps.detachedBlobStorage &&
|
|
1623
|
+
this.createProps.detachedBlobStorage.size > 0,
|
|
1608
1624
|
0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */,
|
|
1609
1625
|
);
|
|
1610
1626
|
delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
|
|
@@ -1702,7 +1718,7 @@ export class Container
|
|
|
1702
1718
|
quorumSnapshot: IQuorumSnapshot,
|
|
1703
1719
|
): void {
|
|
1704
1720
|
const protocolHandlerBuilder =
|
|
1705
|
-
this.protocolHandlerBuilder ??
|
|
1721
|
+
this.createProps.protocolHandlerBuilder ??
|
|
1706
1722
|
((...args) => new ProtocolHandler(...args, new Audience()));
|
|
1707
1723
|
const protocol = protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) =>
|
|
1708
1724
|
this.submitMessage(MessageType.Propose, JSON.stringify({ key, value })),
|
|
@@ -1733,7 +1749,6 @@ export class Container
|
|
|
1733
1749
|
this.processCodeProposal().catch((error) => {
|
|
1734
1750
|
const normalizedError = normalizeError(error);
|
|
1735
1751
|
this.close(normalizedError);
|
|
1736
|
-
this.dispose?.(normalizedError);
|
|
1737
1752
|
throw error;
|
|
1738
1753
|
});
|
|
1739
1754
|
}
|
|
@@ -2013,7 +2028,6 @@ export class Container
|
|
|
2013
2028
|
{ messageType: type },
|
|
2014
2029
|
);
|
|
2015
2030
|
this.close(newError);
|
|
2016
|
-
this.dispose?.(newError);
|
|
2017
2031
|
return -1;
|
|
2018
2032
|
}
|
|
2019
2033
|
}
|
|
@@ -2183,7 +2197,8 @@ export class Container
|
|
|
2183
2197
|
|
|
2184
2198
|
// The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
|
|
2185
2199
|
// are set. Global requests will still go directly to the loader
|
|
2186
|
-
const
|
|
2200
|
+
const maybeLoader: FluidObject<IHostLoader> = this.scope;
|
|
2201
|
+
const loader = new RelativeLoader(this, maybeLoader.ILoader);
|
|
2187
2202
|
this._context = await ContainerContext.createOrLoad(
|
|
2188
2203
|
this,
|
|
2189
2204
|
this.scope,
|
|
@@ -2200,7 +2215,7 @@ export class Container
|
|
|
2200
2215
|
(batch: IBatchMessage[], referenceSequenceNumber?: number) =>
|
|
2201
2216
|
this.submitBatch(batch, referenceSequenceNumber),
|
|
2202
2217
|
(message) => this.submitSignal(message),
|
|
2203
|
-
(error?: ICriticalContainerError) => this.dispose
|
|
2218
|
+
(error?: ICriticalContainerError) => this.dispose(error),
|
|
2204
2219
|
(error?: ICriticalContainerError) => this.close(error),
|
|
2205
2220
|
Container.version,
|
|
2206
2221
|
(dirty: boolean) => this.updateDirtyContainerState(dirty),
|
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 {
|