@fluidframework/container-loader 2.0.0-internal.5.1.1 → 2.0.0-internal.5.3.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 +27 -0
- 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 +1 -1
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +4 -1
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +10 -8
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +30 -31
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +182 -109
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +23 -66
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +28 -213
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +1 -1
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +38 -6
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +1 -3
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts +2 -1
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.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/loader.d.ts +1 -2
- package/dist/loader.d.ts.map +1 -1
- 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 +1 -1
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.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 +1 -1
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +4 -1
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +10 -8
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +30 -31
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +186 -113
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +23 -66
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +28 -213
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +1 -1
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +38 -6
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +1 -3
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts +2 -1
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.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/loader.d.ts +1 -2
- package/lib/loader.d.ts.map +1 -1
- 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 +1 -1
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/package.json +18 -14
- package/src/catchUpMonitor.ts +1 -1
- package/src/connectionManager.ts +1 -1
- package/src/connectionStateHandler.ts +15 -10
- package/src/container.ts +284 -139
- package/src/containerContext.ts +33 -335
- package/src/containerStorageAdapter.ts +47 -5
- package/src/contracts.ts +1 -3
- package/src/deltaManager.ts +15 -8
- package/src/disposal.ts +25 -0
- package/src/loader.ts +1 -1
- 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 +2 -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/lib/container.js
CHANGED
|
@@ -5,30 +5,30 @@
|
|
|
5
5
|
// eslint-disable-next-line import/no-internal-modules
|
|
6
6
|
import merge from "lodash/merge";
|
|
7
7
|
import { v4 as uuid } from "uuid";
|
|
8
|
-
import { assert, performance, unreachableCase } from "@fluidframework/common-utils";
|
|
8
|
+
import { TypedEventEmitter, assert, performance, unreachableCase, } from "@fluidframework/common-utils";
|
|
9
9
|
import { AttachState, isFluidCodeDetails, } from "@fluidframework/container-definitions";
|
|
10
10
|
import { GenericError, UsageError } from "@fluidframework/container-utils";
|
|
11
|
-
import { readAndParse, OnlineStatus, isOnline, combineAppAndProtocolSummary, runWithRetry, isCombinedAppAndProtocolSummary, } from "@fluidframework/driver-utils";
|
|
11
|
+
import { readAndParse, OnlineStatus, isOnline, combineAppAndProtocolSummary, runWithRetry, isCombinedAppAndProtocolSummary, MessageType2, canBeCoalescedByService, } from "@fluidframework/driver-utils";
|
|
12
12
|
import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
|
|
13
13
|
import { ChildLogger, EventEmitterWithErrorHandling, PerformanceEvent, raiseConnectedEvent, TelemetryLogger, connectedEventName, normalizeError, loggerToMonitoringContext, wrapError, } from "@fluidframework/telemetry-utils";
|
|
14
14
|
import { Audience } from "./audience";
|
|
15
15
|
import { ContainerContext } from "./containerContext";
|
|
16
16
|
import { ReconnectMode, getPackageName } from "./contracts";
|
|
17
17
|
import { DeltaManager } from "./deltaManager";
|
|
18
|
-
import { DeltaManagerProxy } from "./deltaManagerProxy";
|
|
19
18
|
import { RelativeLoader } from "./loader";
|
|
20
19
|
import { pkgVersion } from "./packageVersion";
|
|
21
20
|
import { ContainerStorageAdapter, getBlobContentsFromTree, getBlobContentsFromTreeWithBlobContents, } from "./containerStorageAdapter";
|
|
22
21
|
import { createConnectionStateHandler } from "./connectionStateHandler";
|
|
23
22
|
import { getProtocolSnapshotTree, getSnapshotTreeFromSerializedContainer } from "./utils";
|
|
24
|
-
import { initQuorumValuesFromCodeDetails, getCodeDetailsFromQuorumValues
|
|
25
|
-
import {
|
|
23
|
+
import { initQuorumValuesFromCodeDetails, getCodeDetailsFromQuorumValues } from "./quorum";
|
|
24
|
+
import { NoopHeuristic } from "./noopHeuristic";
|
|
26
25
|
import { ConnectionManager } from "./connectionManager";
|
|
27
26
|
import { ConnectionState } from "./connectionState";
|
|
28
|
-
import { OnlyValidTermValue, ProtocolHandler, } from "./protocol";
|
|
27
|
+
import { OnlyValidTermValue, ProtocolHandler, protocolHandlerShouldProcessSignal, } from "./protocol";
|
|
29
28
|
const detachedContainerRefSeqNumber = 0;
|
|
30
29
|
const dirtyContainerEvent = "dirty";
|
|
31
30
|
const savedContainerEvent = "saved";
|
|
31
|
+
const packageNotFactoryError = "Code package does not implement IRuntimeFactory";
|
|
32
32
|
/**
|
|
33
33
|
* Waits until container connects to delta storage and gets up-to-date.
|
|
34
34
|
*
|
|
@@ -156,8 +156,23 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
156
156
|
this.attachStarted = false;
|
|
157
157
|
this._dirtyContainer = false;
|
|
158
158
|
this.savedOps = [];
|
|
159
|
+
this.clientsWhoShouldHaveLeft = new Set();
|
|
159
160
|
this.setAutoReconnectTime = performance.now();
|
|
161
|
+
this._lifecycleEvents = new TypedEventEmitter();
|
|
160
162
|
this._disposed = false;
|
|
163
|
+
this.getAbsoluteUrl = async (relativeUrl) => {
|
|
164
|
+
if (this.resolvedUrl === undefined) {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, getPackageName(this._loadedCodeDetails));
|
|
168
|
+
};
|
|
169
|
+
this.updateDirtyContainerState = (dirty) => {
|
|
170
|
+
if (this._dirtyContainer === dirty) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
this._dirtyContainer = dirty;
|
|
174
|
+
this.emit(dirty ? dirtyContainerEvent : savedContainerEvent);
|
|
175
|
+
};
|
|
161
176
|
const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, detachedBlobStorage, protocolHandlerBuilder, } = createProps;
|
|
162
177
|
this.connectionTransitionTimes[ConnectionState.Disconnected] = performance.now();
|
|
163
178
|
const pendingLocalState = loadProps === null || loadProps === void 0 ? void 0 : loadProps.pendingLocalState;
|
|
@@ -202,13 +217,18 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
202
217
|
dmInitialSeqNumber: () => { var _a; return (_a = this._deltaManager) === null || _a === void 0 ? void 0 : _a.initialSequenceNumber; },
|
|
203
218
|
dmLastProcessedSeqNumber: () => { var _a; return (_a = this._deltaManager) === null || _a === void 0 ? void 0 : _a.lastSequenceNumber; },
|
|
204
219
|
dmLastKnownSeqNumber: () => { var _a; return (_a = this._deltaManager) === null || _a === void 0 ? void 0 : _a.lastKnownSeqNumber; },
|
|
205
|
-
containerLoadedFromVersionId: () => { var _a; return (_a = this.
|
|
206
|
-
containerLoadedFromVersionDate: () => { var _a; return (_a = this.
|
|
220
|
+
containerLoadedFromVersionId: () => { var _a; return (_a = this._loadedFromVersion) === null || _a === void 0 ? void 0 : _a.id; },
|
|
221
|
+
containerLoadedFromVersionDate: () => { var _a; return (_a = this._loadedFromVersion) === null || _a === void 0 ? void 0 : _a.date; },
|
|
207
222
|
// message information to associate errors with the specific execution state
|
|
208
223
|
// dmLastMsqSeqNumber: if present, same as dmLastProcessedSeqNumber
|
|
209
224
|
dmLastMsqSeqNumber: () => { var _a, _b; return (_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.sequenceNumber; },
|
|
210
225
|
dmLastMsqSeqTimestamp: () => { var _a, _b; return (_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.timestamp; },
|
|
211
|
-
dmLastMsqSeqClientId: () => {
|
|
226
|
+
dmLastMsqSeqClientId: () => {
|
|
227
|
+
var _a, _b, _c, _d;
|
|
228
|
+
return ((_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.clientId) === null
|
|
229
|
+
? "null"
|
|
230
|
+
: (_d = (_c = this.deltaManager) === null || _c === void 0 ? void 0 : _c.lastMessage) === null || _d === void 0 ? void 0 : _d.clientId;
|
|
231
|
+
},
|
|
212
232
|
dmLastMsgClientSeq: () => { var _a, _b; return (_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.clientSequenceNumber; },
|
|
213
233
|
connectionStateDuration: () => performance.now() - this.connectionTransitionTimes[this.connectionState],
|
|
214
234
|
},
|
|
@@ -254,6 +274,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
254
274
|
this.connect();
|
|
255
275
|
}
|
|
256
276
|
},
|
|
277
|
+
clientShouldHaveLeft: (clientId) => {
|
|
278
|
+
this.clientsWhoShouldHaveLeft.add(clientId);
|
|
279
|
+
},
|
|
257
280
|
}, this.deltaManager, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.clientId);
|
|
258
281
|
this.on(savedContainerEvent, () => {
|
|
259
282
|
this.connectionStateHandler.containerSaved();
|
|
@@ -296,6 +319,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
296
319
|
static async load(loadProps, createProps) {
|
|
297
320
|
const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
|
|
298
321
|
const container = new Container(createProps, loadProps);
|
|
322
|
+
const disableRecordHeapSize = container.mc.config.getBoolean("Fluid.Loader.DisableRecordHeapSize");
|
|
299
323
|
return PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "Load" }, async (event) => new Promise((resolve, reject) => {
|
|
300
324
|
const defaultMode = { opsBeforeReturn: "cached" };
|
|
301
325
|
// if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
|
|
@@ -323,7 +347,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
323
347
|
container.close(err);
|
|
324
348
|
onClosed(err);
|
|
325
349
|
});
|
|
326
|
-
}), { start: true, end: true, cancel: "generic" });
|
|
350
|
+
}), { start: true, end: true, cancel: "generic" }, disableRecordHeapSize !== true /* recordHeapSize */);
|
|
327
351
|
}
|
|
328
352
|
/**
|
|
329
353
|
* Create a new container in a detached state.
|
|
@@ -362,14 +386,11 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
362
386
|
this._lifecycleState === "disposing" ||
|
|
363
387
|
this._lifecycleState === "disposed");
|
|
364
388
|
}
|
|
365
|
-
get
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
get context() {
|
|
369
|
-
if (this._context === undefined) {
|
|
370
|
-
throw new GenericError("Attempted to access context before it was defined");
|
|
389
|
+
get runtime() {
|
|
390
|
+
if (this._runtime === undefined) {
|
|
391
|
+
throw new Error("Attempted to access runtime before it was defined");
|
|
371
392
|
}
|
|
372
|
-
return this.
|
|
393
|
+
return this._runtime;
|
|
373
394
|
}
|
|
374
395
|
get protocolHandler() {
|
|
375
396
|
if (this._protocolHandler === undefined) {
|
|
@@ -398,15 +419,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
398
419
|
*/
|
|
399
420
|
return (_a = this.service) === null || _a === void 0 ? void 0 : _a.resolvedUrl;
|
|
400
421
|
}
|
|
401
|
-
get loadedFromVersion() {
|
|
402
|
-
return this._loadedFromVersion;
|
|
403
|
-
}
|
|
404
422
|
get readOnlyInfo() {
|
|
405
423
|
return this._deltaManager.readOnlyInfo;
|
|
406
424
|
}
|
|
407
|
-
get closeSignal() {
|
|
408
|
-
return this._deltaManager.closeAbortController.signal;
|
|
409
|
-
}
|
|
410
425
|
/**
|
|
411
426
|
* Tracks host requiring read-only mode.
|
|
412
427
|
*/
|
|
@@ -422,13 +437,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
422
437
|
get connected() {
|
|
423
438
|
return this.connectionStateHandler.connectionState === ConnectionState.Connected;
|
|
424
439
|
}
|
|
425
|
-
/**
|
|
426
|
-
* Service configuration details. If running in offline mode will be undefined otherwise will contain service
|
|
427
|
-
* configuration details returned as part of the initial connection.
|
|
428
|
-
*/
|
|
429
|
-
get serviceConfiguration() {
|
|
430
|
-
return this._deltaManager.serviceConfiguration;
|
|
431
|
-
}
|
|
432
440
|
/**
|
|
433
441
|
* The server provided id of the client.
|
|
434
442
|
* Set once this.connected is true, otherwise undefined
|
|
@@ -436,21 +444,11 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
436
444
|
get clientId() {
|
|
437
445
|
return this._clientId;
|
|
438
446
|
}
|
|
439
|
-
/**
|
|
440
|
-
* The server provided claims of the client.
|
|
441
|
-
* Set once this.connected is true, otherwise undefined
|
|
442
|
-
*/
|
|
443
|
-
get scopes() {
|
|
444
|
-
return this._deltaManager.connectionManager.scopes;
|
|
445
|
-
}
|
|
446
|
-
get clientDetails() {
|
|
447
|
-
return this._deltaManager.clientDetails;
|
|
448
|
-
}
|
|
449
447
|
get offlineLoadEnabled() {
|
|
450
448
|
var _a, _b;
|
|
451
449
|
const enabled = (_a = this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad")) !== null && _a !== void 0 ? _a : ((_b = this.options) === null || _b === void 0 ? void 0 : _b.enableOfflineLoad) === true;
|
|
452
450
|
// summarizer will not have any pending state we want to save
|
|
453
|
-
return enabled && this.clientDetails.capabilities.interactive;
|
|
451
|
+
return enabled && this.deltaManager.clientDetails.capabilities.interactive;
|
|
454
452
|
}
|
|
455
453
|
/**
|
|
456
454
|
* Get the code details that are currently specified for the container.
|
|
@@ -465,8 +463,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
465
463
|
* loaded.
|
|
466
464
|
*/
|
|
467
465
|
getLoadedCodeDetails() {
|
|
468
|
-
|
|
469
|
-
return (_a = this._context) === null || _a === void 0 ? void 0 : _a.codeDetails;
|
|
466
|
+
return this._loadedCodeDetails;
|
|
470
467
|
}
|
|
471
468
|
/**
|
|
472
469
|
* Retrieves the audience associated with the document
|
|
@@ -487,32 +484,26 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
487
484
|
*/
|
|
488
485
|
async getEntryPoint() {
|
|
489
486
|
var _a, _b;
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
if (this.
|
|
494
|
-
|
|
495
|
-
}
|
|
496
|
-
while (this._context === undefined) {
|
|
497
|
-
await new Promise((resolve, reject) => {
|
|
498
|
-
const contextChangedHandler = () => {
|
|
499
|
-
resolve();
|
|
500
|
-
this.off("disposed", disposedHandler);
|
|
501
|
-
};
|
|
502
|
-
const disposedHandler = (error) => {
|
|
503
|
-
reject(error !== null && error !== void 0 ? error : "The Container is disposed");
|
|
504
|
-
this.off("contextChanged", contextChangedHandler);
|
|
505
|
-
};
|
|
506
|
-
this.once("contextChanged", contextChangedHandler);
|
|
507
|
-
this.once("disposed", disposedHandler);
|
|
508
|
-
});
|
|
509
|
-
// The Promise above should only resolve (vs reject) if the 'contextChanged' event was emitted and that
|
|
510
|
-
// should have set this._context; making sure.
|
|
511
|
-
assert(this._context !== undefined, 0x5a2 /* Context still not defined after contextChanged event */);
|
|
487
|
+
if (this._disposed) {
|
|
488
|
+
throw new UsageError("The context is already disposed");
|
|
489
|
+
}
|
|
490
|
+
if (this._runtime !== undefined) {
|
|
491
|
+
return (_b = (_a = this._runtime).getEntryPoint) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
512
492
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
493
|
+
return new Promise((resolve, reject) => {
|
|
494
|
+
const runtimeInstantiatedHandler = () => {
|
|
495
|
+
var _a, _b;
|
|
496
|
+
assert(this._runtime !== undefined, 0x5a3 /* runtimeInstantiated fired but runtime is still undefined */);
|
|
497
|
+
resolve((_b = (_a = this._runtime).getEntryPoint) === null || _b === void 0 ? void 0 : _b.call(_a));
|
|
498
|
+
this._lifecycleEvents.off("disposed", disposedHandler);
|
|
499
|
+
};
|
|
500
|
+
const disposedHandler = () => {
|
|
501
|
+
reject(new Error("ContainerContext was disposed"));
|
|
502
|
+
this._lifecycleEvents.off("runtimeInstantiated", runtimeInstantiatedHandler);
|
|
503
|
+
};
|
|
504
|
+
this._lifecycleEvents.once("runtimeInstantiated", runtimeInstantiatedHandler);
|
|
505
|
+
this._lifecycleEvents.once("disposed", disposedHandler);
|
|
506
|
+
});
|
|
516
507
|
}
|
|
517
508
|
/**
|
|
518
509
|
* Retrieves the quorum associated with the document
|
|
@@ -566,6 +557,10 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
566
557
|
}
|
|
567
558
|
finally {
|
|
568
559
|
this._lifecycleState = "closed";
|
|
560
|
+
// There is no user for summarizer, so we need to ensure dispose is called
|
|
561
|
+
if (this.client.details.type === summarizerClientType) {
|
|
562
|
+
this.dispose(error);
|
|
563
|
+
}
|
|
569
564
|
}
|
|
570
565
|
}
|
|
571
566
|
disposeCore(error) {
|
|
@@ -579,7 +574,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
579
574
|
// This gives us a chance to know what errors happened on open vs. on fully loaded container.
|
|
580
575
|
this.mc.logger.sendTelemetryEvent({
|
|
581
576
|
eventName: "ContainerDispose",
|
|
582
|
-
|
|
577
|
+
// Only log error if container isn't closed
|
|
578
|
+
category: !this.closed && error !== undefined ? "error" : "generic",
|
|
583
579
|
}, error);
|
|
584
580
|
// ! Progressing from "closed" to "disposing" is not allowed
|
|
585
581
|
if (this._lifecycleState !== "closed") {
|
|
@@ -587,7 +583,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
587
583
|
}
|
|
588
584
|
(_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.close();
|
|
589
585
|
this.connectionStateHandler.dispose();
|
|
590
|
-
|
|
586
|
+
const maybeError = error !== undefined ? new Error(error.message) : undefined;
|
|
587
|
+
(_b = this._runtime) === null || _b === void 0 ? void 0 : _b.dispose(maybeError);
|
|
591
588
|
this.storageAdapter.dispose();
|
|
592
589
|
// Notify storage about critical errors. They may be due to disconnect between client & server knowledge
|
|
593
590
|
// about file, like file being overwritten in storage, but client having stale local cache.
|
|
@@ -605,6 +602,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
605
602
|
}
|
|
606
603
|
finally {
|
|
607
604
|
this._lifecycleState = "disposed";
|
|
605
|
+
this._lifecycleEvents.emit("disposed");
|
|
608
606
|
}
|
|
609
607
|
}
|
|
610
608
|
closeAndGetPendingLocalState() {
|
|
@@ -619,12 +617,15 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
619
617
|
if (!this.offlineLoadEnabled) {
|
|
620
618
|
throw new UsageError("Can't get pending local state unless offline load is enabled");
|
|
621
619
|
}
|
|
620
|
+
if (this.closed || this._disposed) {
|
|
621
|
+
throw new UsageError("Pending state cannot be retried if the container is closed or disposed");
|
|
622
|
+
}
|
|
622
623
|
assert(this.attachState === AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
|
|
623
624
|
assert(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
|
|
624
625
|
assert(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
|
|
625
626
|
assert(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
|
|
626
627
|
const pendingState = {
|
|
627
|
-
pendingRuntimeState: this.
|
|
628
|
+
pendingRuntimeState: this.runtime.getPendingLocalState(),
|
|
628
629
|
baseSnapshot: this.baseSnapshot,
|
|
629
630
|
snapshotBlobs: this.baseSnapshotBlobs,
|
|
630
631
|
savedOps: this.savedOps,
|
|
@@ -640,7 +641,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
640
641
|
}
|
|
641
642
|
serialize() {
|
|
642
643
|
assert(this.attachState === AttachState.Detached, 0x0d3 /* "Should only be called in detached container" */);
|
|
643
|
-
const appSummary = this.
|
|
644
|
+
const appSummary = this.runtime.createSummary();
|
|
644
645
|
const protocolSummary = this.captureProtocolSummary();
|
|
645
646
|
const combinedSummary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
646
647
|
if (this.detachedBlobStorage && this.detachedBlobStorage.size > 0) {
|
|
@@ -669,7 +670,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
669
670
|
if (!hasAttachmentBlobs) {
|
|
670
671
|
// Get the document state post attach - possibly can just call attach but we need to change the
|
|
671
672
|
// semantics around what the attach means as far as async code goes.
|
|
672
|
-
const appSummary = this.
|
|
673
|
+
const appSummary = this.runtime.createSummary();
|
|
673
674
|
const protocolSummary = this.captureProtocolSummary();
|
|
674
675
|
summary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
675
676
|
// Set the state as attaching as we are starting the process of attaching container.
|
|
@@ -677,6 +678,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
677
678
|
// starting to attach the container to storage.
|
|
678
679
|
// Also, this should only be fired in detached container.
|
|
679
680
|
this._attachState = AttachState.Attaching;
|
|
681
|
+
this.runtime.setAttachState(AttachState.Attaching);
|
|
680
682
|
this.emit("attaching");
|
|
681
683
|
if (this.offlineLoadEnabled) {
|
|
682
684
|
const snapshot = getSnapshotTreeFromSerializedContainer(summary);
|
|
@@ -691,7 +693,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
691
693
|
assert(this.client.details.type !== summarizerClientType &&
|
|
692
694
|
createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
|
|
693
695
|
this.service = await runWithRetry(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
|
|
694
|
-
cancel: this.
|
|
696
|
+
cancel: this._deltaManager.closeAbortController.signal,
|
|
695
697
|
});
|
|
696
698
|
}
|
|
697
699
|
await this.storageAdapter.connectToService(this.service);
|
|
@@ -713,10 +715,11 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
713
715
|
}
|
|
714
716
|
}
|
|
715
717
|
// take summary and upload
|
|
716
|
-
const appSummary = this.
|
|
718
|
+
const appSummary = this.runtime.createSummary(redirectTable);
|
|
717
719
|
const protocolSummary = this.captureProtocolSummary();
|
|
718
720
|
summary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
719
721
|
this._attachState = AttachState.Attaching;
|
|
722
|
+
this.runtime.setAttachState(AttachState.Attaching);
|
|
720
723
|
this.emit("attaching");
|
|
721
724
|
if (this.offlineLoadEnabled) {
|
|
722
725
|
const snapshot = getSnapshotTreeFromSerializedContainer(summary);
|
|
@@ -731,6 +734,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
731
734
|
});
|
|
732
735
|
}
|
|
733
736
|
this._attachState = AttachState.Attached;
|
|
737
|
+
this.runtime.setAttachState(AttachState.Attached);
|
|
734
738
|
this.emit("attached");
|
|
735
739
|
if (!this.closed) {
|
|
736
740
|
this.resumeInternal({
|
|
@@ -749,7 +753,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
749
753
|
}, { start: true, end: true, cancel: "generic" });
|
|
750
754
|
}
|
|
751
755
|
async request(path) {
|
|
752
|
-
return PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Request" }, async () => this.
|
|
756
|
+
return PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Request" }, async () => this.runtime.request(path), { end: true, cancel: "error" });
|
|
753
757
|
}
|
|
754
758
|
setAutoReconnectInternal(mode) {
|
|
755
759
|
const currentMode = this._deltaManager.connectionManager.reconnectMode;
|
|
@@ -815,13 +819,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
815
819
|
// Ensure connection to web socket
|
|
816
820
|
this.connectToDeltaStream(args);
|
|
817
821
|
}
|
|
818
|
-
async getAbsoluteUrl(relativeUrl) {
|
|
819
|
-
var _a;
|
|
820
|
-
if (this.resolvedUrl === undefined) {
|
|
821
|
-
return undefined;
|
|
822
|
-
}
|
|
823
|
-
return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, getPackageName((_a = this._context) === null || _a === void 0 ? void 0 : _a.codeDetails));
|
|
824
|
-
}
|
|
825
822
|
async proposeCodeDetails(codeDetails) {
|
|
826
823
|
if (!isFluidCodeDetails(codeDetails)) {
|
|
827
824
|
throw new Error("Provided codeDetails are not IFluidCodeDetails");
|
|
@@ -843,7 +840,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
843
840
|
this.deltaManager.inbound.pause(),
|
|
844
841
|
this.deltaManager.inboundSignal.pause(),
|
|
845
842
|
]);
|
|
846
|
-
if ((await this.
|
|
843
|
+
if ((await this.satisfies(codeDetails)) === true) {
|
|
847
844
|
this.deltaManager.inbound.resume();
|
|
848
845
|
this.deltaManager.inboundSignal.resume();
|
|
849
846
|
return;
|
|
@@ -852,6 +849,38 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
852
849
|
const error = new GenericError("Existing context does not satisfy incoming proposal");
|
|
853
850
|
this.close(error);
|
|
854
851
|
}
|
|
852
|
+
/**
|
|
853
|
+
* Determines if the currently loaded module satisfies the incoming constraint code details
|
|
854
|
+
*/
|
|
855
|
+
async satisfies(constraintCodeDetails) {
|
|
856
|
+
var _a, _b;
|
|
857
|
+
// If we have no module, it can't satisfy anything.
|
|
858
|
+
if (this._loadedModule === undefined) {
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
const comparers = [];
|
|
862
|
+
const maybeCompareCodeLoader = this.codeLoader;
|
|
863
|
+
if (maybeCompareCodeLoader.IFluidCodeDetailsComparer !== undefined) {
|
|
864
|
+
comparers.push(maybeCompareCodeLoader.IFluidCodeDetailsComparer);
|
|
865
|
+
}
|
|
866
|
+
const maybeCompareExport = (_a = this._loadedModule) === null || _a === void 0 ? void 0 : _a.module.fluidExport;
|
|
867
|
+
if ((maybeCompareExport === null || maybeCompareExport === void 0 ? void 0 : maybeCompareExport.IFluidCodeDetailsComparer) !== undefined) {
|
|
868
|
+
comparers.push(maybeCompareExport.IFluidCodeDetailsComparer);
|
|
869
|
+
}
|
|
870
|
+
// If there are no comparers, then it's impossible to know if the currently loaded package satisfies
|
|
871
|
+
// the incoming constraint, so we return false. Assuming it does not satisfy is safer, to force a reload
|
|
872
|
+
// rather than potentially running with incompatible code.
|
|
873
|
+
if (comparers.length === 0) {
|
|
874
|
+
return false;
|
|
875
|
+
}
|
|
876
|
+
for (const comparer of comparers) {
|
|
877
|
+
const satisfies = await comparer.satisfies((_b = this._loadedModule) === null || _b === void 0 ? void 0 : _b.details, constraintCodeDetails);
|
|
878
|
+
if (satisfies === false) {
|
|
879
|
+
return false;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
return true;
|
|
883
|
+
}
|
|
855
884
|
async getVersion(version) {
|
|
856
885
|
const versions = await this.storageAdapter.getVersions(version, 1);
|
|
857
886
|
return versions[0];
|
|
@@ -869,7 +898,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
869
898
|
* @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
|
|
870
899
|
*/
|
|
871
900
|
async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState) {
|
|
872
|
-
var _a;
|
|
901
|
+
var _a, _b, _c;
|
|
873
902
|
this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
|
|
874
903
|
// Ideally we always connect as "read" by default.
|
|
875
904
|
// Currently that works with SPO & r11s, because we get "write" connection when connecting to non-existing file.
|
|
@@ -913,7 +942,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
913
942
|
if (this.offlineLoadEnabled) {
|
|
914
943
|
this.baseSnapshot = snapshot;
|
|
915
944
|
// Save contents of snapshot now, otherwise closeAndGetPendingLocalState() must be async
|
|
916
|
-
this.baseSnapshotBlobs = await getBlobContentsFromTree(snapshot, this.
|
|
945
|
+
this.baseSnapshotBlobs = await getBlobContentsFromTree(snapshot, this.storageAdapter);
|
|
917
946
|
}
|
|
918
947
|
}
|
|
919
948
|
const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshot);
|
|
@@ -949,7 +978,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
949
978
|
for (const message of pendingLocalState.savedOps) {
|
|
950
979
|
this.processRemoteMessage(message);
|
|
951
980
|
// allow runtime to apply stashed ops at this op's sequence number
|
|
952
|
-
await this.
|
|
981
|
+
await ((_c = (_b = this.runtime).notifyOpReplay) === null || _c === void 0 ? void 0 : _c.call(_b, message));
|
|
953
982
|
}
|
|
954
983
|
pendingLocalState.savedOps = [];
|
|
955
984
|
// now set clientId to stashed clientId so live ops are correctly processed as local
|
|
@@ -1188,7 +1217,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1188
1217
|
});
|
|
1189
1218
|
deltaManager.on("disconnect", (reason, error) => {
|
|
1190
1219
|
var _a;
|
|
1191
|
-
(_a = this.
|
|
1220
|
+
(_a = this.noopHeuristic) === null || _a === void 0 ? void 0 : _a.notifyDisconnect();
|
|
1192
1221
|
if (!this.closed) {
|
|
1193
1222
|
this.connectionStateHandler.receivedDisconnectEvent(reason, error);
|
|
1194
1223
|
}
|
|
@@ -1245,7 +1274,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1245
1274
|
else if (value === ConnectionState.CatchingUp) {
|
|
1246
1275
|
// This info is of most interesting while Catching Up.
|
|
1247
1276
|
checkpointSequenceNumber = this.deltaManager.lastKnownSeqNumber;
|
|
1248
|
-
|
|
1277
|
+
// Need to check that we have already loaded and fetched the snapshot.
|
|
1278
|
+
if (this.deltaManager.hasCheckpointSequenceNumber &&
|
|
1279
|
+
this._lifecycleState === "loaded") {
|
|
1249
1280
|
opsBehind = checkpointSequenceNumber - this.deltaManager.lastSequenceNumber;
|
|
1250
1281
|
}
|
|
1251
1282
|
}
|
|
@@ -1332,7 +1363,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1332
1363
|
return -1;
|
|
1333
1364
|
}
|
|
1334
1365
|
this.messageCountAfterDisconnection += 1;
|
|
1335
|
-
(_a = this.
|
|
1366
|
+
(_a = this.noopHeuristic) === null || _a === void 0 ? void 0 : _a.notifyMessageSent();
|
|
1336
1367
|
return this._deltaManager.submit(type, contents, batch, metadata, compression, referenceSequenceNumber);
|
|
1337
1368
|
}
|
|
1338
1369
|
processRemoteMessage(message) {
|
|
@@ -1340,24 +1371,51 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1340
1371
|
this.savedOps.push(message);
|
|
1341
1372
|
}
|
|
1342
1373
|
const local = this.clientId === message.clientId;
|
|
1374
|
+
// Check and report if we're getting messages from a clientId that we previously
|
|
1375
|
+
// flagged should have left, or from a client that's not in the quorum but should be
|
|
1376
|
+
if (message.clientId != null) {
|
|
1377
|
+
const client = this.protocolHandler.quorum.getMember(message.clientId);
|
|
1378
|
+
if (client === undefined && message.type !== MessageType.ClientJoin) {
|
|
1379
|
+
// pre-0.58 error message: messageClientIdMissingFromQuorum
|
|
1380
|
+
throw new Error("Remote message's clientId is missing from the quorum");
|
|
1381
|
+
}
|
|
1382
|
+
// Here checking canBeCoalescedByService is used as an approximation of "is benign to process despite being unexpected".
|
|
1383
|
+
// It's still not good to see these messages from unexpected clientIds, but since they don't harm the integrity of the
|
|
1384
|
+
// document we don't need to blow up aggressively.
|
|
1385
|
+
if (this.clientsWhoShouldHaveLeft.has(message.clientId) &&
|
|
1386
|
+
!canBeCoalescedByService(message)) {
|
|
1387
|
+
// pre-0.58 error message: messageClientIdShouldHaveLeft
|
|
1388
|
+
throw new Error("Remote message's clientId already should have left");
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1343
1391
|
// Allow the protocol handler to process the message
|
|
1344
1392
|
const result = this.protocolHandler.processMessage(message, local);
|
|
1345
1393
|
// Forward messages to the loaded runtime for processing
|
|
1346
|
-
this.
|
|
1394
|
+
this.runtime.process(message, local);
|
|
1347
1395
|
// Inactive (not in quorum or not writers) clients don't take part in the minimum sequence number calculation.
|
|
1348
1396
|
if (this.activeConnection()) {
|
|
1349
|
-
if (this.
|
|
1397
|
+
if (this.noopHeuristic === undefined) {
|
|
1398
|
+
const serviceConfiguration = this.deltaManager.serviceConfiguration;
|
|
1350
1399
|
// Note that config from first connection will be used for this container's lifetime.
|
|
1351
1400
|
// That means that if relay service changes settings, such changes will impact only newly booted
|
|
1352
1401
|
// clients.
|
|
1353
1402
|
// All existing will continue to use settings they got earlier.
|
|
1354
|
-
assert(
|
|
1355
|
-
this.
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1403
|
+
assert(serviceConfiguration !== undefined, 0x2e4 /* "there should be service config for active connection" */);
|
|
1404
|
+
this.noopHeuristic = new NoopHeuristic(serviceConfiguration.noopTimeFrequency, serviceConfiguration.noopCountFrequency);
|
|
1405
|
+
this.noopHeuristic.on("wantsNoop", () => {
|
|
1406
|
+
// On disconnect we notify the heuristic which should prevent it from wanting a noop.
|
|
1407
|
+
// Hitting this assert would imply we lost activeConnection between notifying the heuristic of a processed message and
|
|
1408
|
+
// running the microtask that the heuristic queued in response.
|
|
1409
|
+
assert(this.activeConnection(), 0x241 /* "Trying to send noop without active connection" */);
|
|
1410
|
+
this.submitMessage(MessageType.NoOp);
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
this.noopHeuristic.notifyMessageProcessed(message);
|
|
1414
|
+
// The contract with the protocolHandler is that returning "immediateNoOp" is equivalent to "please immediately accept the proposal I just processed".
|
|
1415
|
+
if (result.immediateNoOp === true) {
|
|
1416
|
+
// ADO:1385: Remove cast and use MessageType once definition changes propagate
|
|
1417
|
+
this.submitMessage(MessageType2.Accept);
|
|
1359
1418
|
}
|
|
1360
|
-
this.collabWindowTracker.scheduleSequenceNumberUpdate(message, result.immediateNoOp === true);
|
|
1361
1419
|
}
|
|
1362
1420
|
this.emit("op", message);
|
|
1363
1421
|
}
|
|
@@ -1366,12 +1424,12 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1366
1424
|
}
|
|
1367
1425
|
processSignal(message) {
|
|
1368
1426
|
// No clientId indicates a system signal message.
|
|
1369
|
-
if (message
|
|
1427
|
+
if (protocolHandlerShouldProcessSignal(message)) {
|
|
1370
1428
|
this.protocolHandler.processSignal(message);
|
|
1371
1429
|
}
|
|
1372
1430
|
else {
|
|
1373
1431
|
const local = this.clientId === message.clientId;
|
|
1374
|
-
this.
|
|
1432
|
+
this.runtime.processSignal(message, local);
|
|
1375
1433
|
}
|
|
1376
1434
|
}
|
|
1377
1435
|
/**
|
|
@@ -1404,21 +1462,37 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1404
1462
|
await this.instantiateContext(existing, codeDetails, snapshot);
|
|
1405
1463
|
}
|
|
1406
1464
|
async instantiateContext(existing, codeDetails, snapshot, pendingLocalState) {
|
|
1407
|
-
var _a;
|
|
1408
|
-
assert(((_a = this.
|
|
1465
|
+
var _a, _b;
|
|
1466
|
+
assert(((_a = this._runtime) === null || _a === void 0 ? void 0 : _a.disposed) !== false, 0x0dd /* "Existing runtime not disposed" */);
|
|
1409
1467
|
// The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
|
|
1410
1468
|
// are set. Global requests will still go directly to the loader
|
|
1411
1469
|
const maybeLoader = this.scope;
|
|
1412
1470
|
const loader = new RelativeLoader(this, maybeLoader.ILoader);
|
|
1413
|
-
|
|
1414
|
-
this.
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1471
|
+
const loadCodeResult = await PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "CodeLoad" }, async () => this.codeLoader.load(codeDetails));
|
|
1472
|
+
this._loadedModule = {
|
|
1473
|
+
module: loadCodeResult.module,
|
|
1474
|
+
// An older interface ICodeLoader could return an IFluidModule which didn't have details.
|
|
1475
|
+
// If we're using one of those older ICodeLoaders, then we fix up the module with the specified details here.
|
|
1476
|
+
// TODO: Determine if this is still a realistic scenario or if this fixup could be removed.
|
|
1477
|
+
details: (_b = loadCodeResult.details) !== null && _b !== void 0 ? _b : codeDetails,
|
|
1478
|
+
};
|
|
1479
|
+
const fluidExport = this._loadedModule.module.fluidExport;
|
|
1480
|
+
const runtimeFactory = fluidExport === null || fluidExport === void 0 ? void 0 : fluidExport.IRuntimeFactory;
|
|
1481
|
+
if (runtimeFactory === undefined) {
|
|
1482
|
+
throw new Error(packageNotFactoryError);
|
|
1419
1483
|
}
|
|
1420
|
-
|
|
1421
|
-
|
|
1484
|
+
const getSpecifiedCodeDetails = () => {
|
|
1485
|
+
var _a;
|
|
1486
|
+
return ((_a = this.protocolHandler.quorum.get("code")) !== null && _a !== void 0 ? _a : this.protocolHandler.quorum.get("code2"));
|
|
1487
|
+
};
|
|
1488
|
+
const context = new ContainerContext(this.options, this.scope, snapshot, this._loadedFromVersion, this._deltaManager, this.storageAdapter, this.protocolHandler.quorum, this.protocolHandler.audience, loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber), (batch, referenceSequenceNumber) => this.submitBatch(batch, referenceSequenceNumber), (message) => this.submitSignal(message), (error) => this.dispose(error), (error) => this.close(error), this.updateDirtyContainerState, this.getAbsoluteUrl, () => { var _a; return (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.id; }, () => this.clientId, () => this._deltaManager.serviceConfiguration, () => this.attachState, () => this.connected, getSpecifiedCodeDetails, this._deltaManager.clientDetails, existing, this.subLogger, pendingLocalState);
|
|
1489
|
+
this._lifecycleEvents.once("disposed", () => {
|
|
1490
|
+
context.dispose();
|
|
1491
|
+
});
|
|
1492
|
+
this._runtime = await PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "InstantiateRuntime" }, async () => runtimeFactory.instantiateRuntime(context, existing));
|
|
1493
|
+
this._lifecycleEvents.emit("runtimeInstantiated");
|
|
1494
|
+
this._loadedCodeDetails = codeDetails;
|
|
1495
|
+
this.emit("contextChanged", codeDetails);
|
|
1422
1496
|
}
|
|
1423
1497
|
/**
|
|
1424
1498
|
* Set the connected state of the ContainerContext
|
|
@@ -1428,16 +1502,15 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1428
1502
|
*/
|
|
1429
1503
|
setContextConnectedState(state, readonly) {
|
|
1430
1504
|
var _a;
|
|
1431
|
-
if (((_a = this.
|
|
1505
|
+
if (((_a = this._runtime) === null || _a === void 0 ? void 0 : _a.disposed) === false) {
|
|
1432
1506
|
/**
|
|
1433
1507
|
* We want to lie to the ContainerRuntime when we are in readonly mode to prevent issues with pending
|
|
1434
1508
|
* ops getting through to the DeltaManager.
|
|
1435
1509
|
* The ContainerRuntime's "connected" state simply means it is ok to send ops
|
|
1436
1510
|
* See https://dev.azure.com/fluidframework/internal/_workitems/edit/1246
|
|
1437
1511
|
*/
|
|
1438
|
-
this.
|
|
1512
|
+
this.runtime.setConnectionState(state && !readonly, this.clientId);
|
|
1439
1513
|
}
|
|
1440
1514
|
}
|
|
1441
1515
|
}
|
|
1442
|
-
Container.version = "^0.1.0";
|
|
1443
1516
|
//# sourceMappingURL=container.js.map
|