@fluidframework/container-loader 2.0.0-dev.5.2.0.169897 → 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 +31 -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 +180 -108
- 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 +184 -112
- 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 +279 -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();
|
|
@@ -363,14 +386,11 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
363
386
|
this._lifecycleState === "disposing" ||
|
|
364
387
|
this._lifecycleState === "disposed");
|
|
365
388
|
}
|
|
366
|
-
get
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
get context() {
|
|
370
|
-
if (this._context === undefined) {
|
|
371
|
-
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");
|
|
372
392
|
}
|
|
373
|
-
return this.
|
|
393
|
+
return this._runtime;
|
|
374
394
|
}
|
|
375
395
|
get protocolHandler() {
|
|
376
396
|
if (this._protocolHandler === undefined) {
|
|
@@ -399,15 +419,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
399
419
|
*/
|
|
400
420
|
return (_a = this.service) === null || _a === void 0 ? void 0 : _a.resolvedUrl;
|
|
401
421
|
}
|
|
402
|
-
get loadedFromVersion() {
|
|
403
|
-
return this._loadedFromVersion;
|
|
404
|
-
}
|
|
405
422
|
get readOnlyInfo() {
|
|
406
423
|
return this._deltaManager.readOnlyInfo;
|
|
407
424
|
}
|
|
408
|
-
get closeSignal() {
|
|
409
|
-
return this._deltaManager.closeAbortController.signal;
|
|
410
|
-
}
|
|
411
425
|
/**
|
|
412
426
|
* Tracks host requiring read-only mode.
|
|
413
427
|
*/
|
|
@@ -423,13 +437,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
423
437
|
get connected() {
|
|
424
438
|
return this.connectionStateHandler.connectionState === ConnectionState.Connected;
|
|
425
439
|
}
|
|
426
|
-
/**
|
|
427
|
-
* Service configuration details. If running in offline mode will be undefined otherwise will contain service
|
|
428
|
-
* configuration details returned as part of the initial connection.
|
|
429
|
-
*/
|
|
430
|
-
get serviceConfiguration() {
|
|
431
|
-
return this._deltaManager.serviceConfiguration;
|
|
432
|
-
}
|
|
433
440
|
/**
|
|
434
441
|
* The server provided id of the client.
|
|
435
442
|
* Set once this.connected is true, otherwise undefined
|
|
@@ -437,21 +444,11 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
437
444
|
get clientId() {
|
|
438
445
|
return this._clientId;
|
|
439
446
|
}
|
|
440
|
-
/**
|
|
441
|
-
* The server provided claims of the client.
|
|
442
|
-
* Set once this.connected is true, otherwise undefined
|
|
443
|
-
*/
|
|
444
|
-
get scopes() {
|
|
445
|
-
return this._deltaManager.connectionManager.scopes;
|
|
446
|
-
}
|
|
447
|
-
get clientDetails() {
|
|
448
|
-
return this._deltaManager.clientDetails;
|
|
449
|
-
}
|
|
450
447
|
get offlineLoadEnabled() {
|
|
451
448
|
var _a, _b;
|
|
452
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;
|
|
453
450
|
// summarizer will not have any pending state we want to save
|
|
454
|
-
return enabled && this.clientDetails.capabilities.interactive;
|
|
451
|
+
return enabled && this.deltaManager.clientDetails.capabilities.interactive;
|
|
455
452
|
}
|
|
456
453
|
/**
|
|
457
454
|
* Get the code details that are currently specified for the container.
|
|
@@ -466,8 +463,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
466
463
|
* loaded.
|
|
467
464
|
*/
|
|
468
465
|
getLoadedCodeDetails() {
|
|
469
|
-
|
|
470
|
-
return (_a = this._context) === null || _a === void 0 ? void 0 : _a.codeDetails;
|
|
466
|
+
return this._loadedCodeDetails;
|
|
471
467
|
}
|
|
472
468
|
/**
|
|
473
469
|
* Retrieves the audience associated with the document
|
|
@@ -488,32 +484,26 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
488
484
|
*/
|
|
489
485
|
async getEntryPoint() {
|
|
490
486
|
var _a, _b;
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
if (this.
|
|
495
|
-
|
|
496
|
-
}
|
|
497
|
-
while (this._context === undefined) {
|
|
498
|
-
await new Promise((resolve, reject) => {
|
|
499
|
-
const contextChangedHandler = () => {
|
|
500
|
-
resolve();
|
|
501
|
-
this.off("disposed", disposedHandler);
|
|
502
|
-
};
|
|
503
|
-
const disposedHandler = (error) => {
|
|
504
|
-
reject(error !== null && error !== void 0 ? error : "The Container is disposed");
|
|
505
|
-
this.off("contextChanged", contextChangedHandler);
|
|
506
|
-
};
|
|
507
|
-
this.once("contextChanged", contextChangedHandler);
|
|
508
|
-
this.once("disposed", disposedHandler);
|
|
509
|
-
});
|
|
510
|
-
// The Promise above should only resolve (vs reject) if the 'contextChanged' event was emitted and that
|
|
511
|
-
// should have set this._context; making sure.
|
|
512
|
-
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);
|
|
513
492
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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
|
+
});
|
|
517
507
|
}
|
|
518
508
|
/**
|
|
519
509
|
* Retrieves the quorum associated with the document
|
|
@@ -567,6 +557,10 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
567
557
|
}
|
|
568
558
|
finally {
|
|
569
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
|
+
}
|
|
570
564
|
}
|
|
571
565
|
}
|
|
572
566
|
disposeCore(error) {
|
|
@@ -580,7 +574,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
580
574
|
// This gives us a chance to know what errors happened on open vs. on fully loaded container.
|
|
581
575
|
this.mc.logger.sendTelemetryEvent({
|
|
582
576
|
eventName: "ContainerDispose",
|
|
583
|
-
|
|
577
|
+
// Only log error if container isn't closed
|
|
578
|
+
category: !this.closed && error !== undefined ? "error" : "generic",
|
|
584
579
|
}, error);
|
|
585
580
|
// ! Progressing from "closed" to "disposing" is not allowed
|
|
586
581
|
if (this._lifecycleState !== "closed") {
|
|
@@ -588,7 +583,8 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
588
583
|
}
|
|
589
584
|
(_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.close();
|
|
590
585
|
this.connectionStateHandler.dispose();
|
|
591
|
-
|
|
586
|
+
const maybeError = error !== undefined ? new Error(error.message) : undefined;
|
|
587
|
+
(_b = this._runtime) === null || _b === void 0 ? void 0 : _b.dispose(maybeError);
|
|
592
588
|
this.storageAdapter.dispose();
|
|
593
589
|
// Notify storage about critical errors. They may be due to disconnect between client & server knowledge
|
|
594
590
|
// about file, like file being overwritten in storage, but client having stale local cache.
|
|
@@ -606,6 +602,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
606
602
|
}
|
|
607
603
|
finally {
|
|
608
604
|
this._lifecycleState = "disposed";
|
|
605
|
+
this._lifecycleEvents.emit("disposed");
|
|
609
606
|
}
|
|
610
607
|
}
|
|
611
608
|
closeAndGetPendingLocalState() {
|
|
@@ -620,12 +617,15 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
620
617
|
if (!this.offlineLoadEnabled) {
|
|
621
618
|
throw new UsageError("Can't get pending local state unless offline load is enabled");
|
|
622
619
|
}
|
|
620
|
+
if (this.closed || this._disposed) {
|
|
621
|
+
throw new UsageError("Pending state cannot be retried if the container is closed or disposed");
|
|
622
|
+
}
|
|
623
623
|
assert(this.attachState === AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
|
|
624
624
|
assert(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
|
|
625
625
|
assert(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
|
|
626
626
|
assert(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
|
|
627
627
|
const pendingState = {
|
|
628
|
-
pendingRuntimeState: this.
|
|
628
|
+
pendingRuntimeState: this.runtime.getPendingLocalState(),
|
|
629
629
|
baseSnapshot: this.baseSnapshot,
|
|
630
630
|
snapshotBlobs: this.baseSnapshotBlobs,
|
|
631
631
|
savedOps: this.savedOps,
|
|
@@ -641,7 +641,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
641
641
|
}
|
|
642
642
|
serialize() {
|
|
643
643
|
assert(this.attachState === AttachState.Detached, 0x0d3 /* "Should only be called in detached container" */);
|
|
644
|
-
const appSummary = this.
|
|
644
|
+
const appSummary = this.runtime.createSummary();
|
|
645
645
|
const protocolSummary = this.captureProtocolSummary();
|
|
646
646
|
const combinedSummary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
647
647
|
if (this.detachedBlobStorage && this.detachedBlobStorage.size > 0) {
|
|
@@ -670,7 +670,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
670
670
|
if (!hasAttachmentBlobs) {
|
|
671
671
|
// Get the document state post attach - possibly can just call attach but we need to change the
|
|
672
672
|
// semantics around what the attach means as far as async code goes.
|
|
673
|
-
const appSummary = this.
|
|
673
|
+
const appSummary = this.runtime.createSummary();
|
|
674
674
|
const protocolSummary = this.captureProtocolSummary();
|
|
675
675
|
summary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
676
676
|
// Set the state as attaching as we are starting the process of attaching container.
|
|
@@ -678,6 +678,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
678
678
|
// starting to attach the container to storage.
|
|
679
679
|
// Also, this should only be fired in detached container.
|
|
680
680
|
this._attachState = AttachState.Attaching;
|
|
681
|
+
this.runtime.setAttachState(AttachState.Attaching);
|
|
681
682
|
this.emit("attaching");
|
|
682
683
|
if (this.offlineLoadEnabled) {
|
|
683
684
|
const snapshot = getSnapshotTreeFromSerializedContainer(summary);
|
|
@@ -692,7 +693,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
692
693
|
assert(this.client.details.type !== summarizerClientType &&
|
|
693
694
|
createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
|
|
694
695
|
this.service = await runWithRetry(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
|
|
695
|
-
cancel: this.
|
|
696
|
+
cancel: this._deltaManager.closeAbortController.signal,
|
|
696
697
|
});
|
|
697
698
|
}
|
|
698
699
|
await this.storageAdapter.connectToService(this.service);
|
|
@@ -714,10 +715,11 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
714
715
|
}
|
|
715
716
|
}
|
|
716
717
|
// take summary and upload
|
|
717
|
-
const appSummary = this.
|
|
718
|
+
const appSummary = this.runtime.createSummary(redirectTable);
|
|
718
719
|
const protocolSummary = this.captureProtocolSummary();
|
|
719
720
|
summary = combineAppAndProtocolSummary(appSummary, protocolSummary);
|
|
720
721
|
this._attachState = AttachState.Attaching;
|
|
722
|
+
this.runtime.setAttachState(AttachState.Attaching);
|
|
721
723
|
this.emit("attaching");
|
|
722
724
|
if (this.offlineLoadEnabled) {
|
|
723
725
|
const snapshot = getSnapshotTreeFromSerializedContainer(summary);
|
|
@@ -732,6 +734,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
732
734
|
});
|
|
733
735
|
}
|
|
734
736
|
this._attachState = AttachState.Attached;
|
|
737
|
+
this.runtime.setAttachState(AttachState.Attached);
|
|
735
738
|
this.emit("attached");
|
|
736
739
|
if (!this.closed) {
|
|
737
740
|
this.resumeInternal({
|
|
@@ -750,7 +753,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
750
753
|
}, { start: true, end: true, cancel: "generic" });
|
|
751
754
|
}
|
|
752
755
|
async request(path) {
|
|
753
|
-
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" });
|
|
754
757
|
}
|
|
755
758
|
setAutoReconnectInternal(mode) {
|
|
756
759
|
const currentMode = this._deltaManager.connectionManager.reconnectMode;
|
|
@@ -816,13 +819,6 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
816
819
|
// Ensure connection to web socket
|
|
817
820
|
this.connectToDeltaStream(args);
|
|
818
821
|
}
|
|
819
|
-
async getAbsoluteUrl(relativeUrl) {
|
|
820
|
-
var _a;
|
|
821
|
-
if (this.resolvedUrl === undefined) {
|
|
822
|
-
return undefined;
|
|
823
|
-
}
|
|
824
|
-
return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, getPackageName((_a = this._context) === null || _a === void 0 ? void 0 : _a.codeDetails));
|
|
825
|
-
}
|
|
826
822
|
async proposeCodeDetails(codeDetails) {
|
|
827
823
|
if (!isFluidCodeDetails(codeDetails)) {
|
|
828
824
|
throw new Error("Provided codeDetails are not IFluidCodeDetails");
|
|
@@ -844,7 +840,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
844
840
|
this.deltaManager.inbound.pause(),
|
|
845
841
|
this.deltaManager.inboundSignal.pause(),
|
|
846
842
|
]);
|
|
847
|
-
if ((await this.
|
|
843
|
+
if ((await this.satisfies(codeDetails)) === true) {
|
|
848
844
|
this.deltaManager.inbound.resume();
|
|
849
845
|
this.deltaManager.inboundSignal.resume();
|
|
850
846
|
return;
|
|
@@ -853,6 +849,38 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
853
849
|
const error = new GenericError("Existing context does not satisfy incoming proposal");
|
|
854
850
|
this.close(error);
|
|
855
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
|
+
}
|
|
856
884
|
async getVersion(version) {
|
|
857
885
|
const versions = await this.storageAdapter.getVersions(version, 1);
|
|
858
886
|
return versions[0];
|
|
@@ -870,7 +898,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
870
898
|
* @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
|
|
871
899
|
*/
|
|
872
900
|
async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState) {
|
|
873
|
-
var _a;
|
|
901
|
+
var _a, _b, _c;
|
|
874
902
|
this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
|
|
875
903
|
// Ideally we always connect as "read" by default.
|
|
876
904
|
// Currently that works with SPO & r11s, because we get "write" connection when connecting to non-existing file.
|
|
@@ -914,7 +942,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
914
942
|
if (this.offlineLoadEnabled) {
|
|
915
943
|
this.baseSnapshot = snapshot;
|
|
916
944
|
// Save contents of snapshot now, otherwise closeAndGetPendingLocalState() must be async
|
|
917
|
-
this.baseSnapshotBlobs = await getBlobContentsFromTree(snapshot, this.
|
|
945
|
+
this.baseSnapshotBlobs = await getBlobContentsFromTree(snapshot, this.storageAdapter);
|
|
918
946
|
}
|
|
919
947
|
}
|
|
920
948
|
const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshot);
|
|
@@ -950,7 +978,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
950
978
|
for (const message of pendingLocalState.savedOps) {
|
|
951
979
|
this.processRemoteMessage(message);
|
|
952
980
|
// allow runtime to apply stashed ops at this op's sequence number
|
|
953
|
-
await this.
|
|
981
|
+
await ((_c = (_b = this.runtime).notifyOpReplay) === null || _c === void 0 ? void 0 : _c.call(_b, message));
|
|
954
982
|
}
|
|
955
983
|
pendingLocalState.savedOps = [];
|
|
956
984
|
// now set clientId to stashed clientId so live ops are correctly processed as local
|
|
@@ -1189,7 +1217,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1189
1217
|
});
|
|
1190
1218
|
deltaManager.on("disconnect", (reason, error) => {
|
|
1191
1219
|
var _a;
|
|
1192
|
-
(_a = this.
|
|
1220
|
+
(_a = this.noopHeuristic) === null || _a === void 0 ? void 0 : _a.notifyDisconnect();
|
|
1193
1221
|
if (!this.closed) {
|
|
1194
1222
|
this.connectionStateHandler.receivedDisconnectEvent(reason, error);
|
|
1195
1223
|
}
|
|
@@ -1246,7 +1274,9 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1246
1274
|
else if (value === ConnectionState.CatchingUp) {
|
|
1247
1275
|
// This info is of most interesting while Catching Up.
|
|
1248
1276
|
checkpointSequenceNumber = this.deltaManager.lastKnownSeqNumber;
|
|
1249
|
-
|
|
1277
|
+
// Need to check that we have already loaded and fetched the snapshot.
|
|
1278
|
+
if (this.deltaManager.hasCheckpointSequenceNumber &&
|
|
1279
|
+
this._lifecycleState === "loaded") {
|
|
1250
1280
|
opsBehind = checkpointSequenceNumber - this.deltaManager.lastSequenceNumber;
|
|
1251
1281
|
}
|
|
1252
1282
|
}
|
|
@@ -1333,7 +1363,7 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1333
1363
|
return -1;
|
|
1334
1364
|
}
|
|
1335
1365
|
this.messageCountAfterDisconnection += 1;
|
|
1336
|
-
(_a = this.
|
|
1366
|
+
(_a = this.noopHeuristic) === null || _a === void 0 ? void 0 : _a.notifyMessageSent();
|
|
1337
1367
|
return this._deltaManager.submit(type, contents, batch, metadata, compression, referenceSequenceNumber);
|
|
1338
1368
|
}
|
|
1339
1369
|
processRemoteMessage(message) {
|
|
@@ -1341,24 +1371,51 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1341
1371
|
this.savedOps.push(message);
|
|
1342
1372
|
}
|
|
1343
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
|
+
}
|
|
1344
1391
|
// Allow the protocol handler to process the message
|
|
1345
1392
|
const result = this.protocolHandler.processMessage(message, local);
|
|
1346
1393
|
// Forward messages to the loaded runtime for processing
|
|
1347
|
-
this.
|
|
1394
|
+
this.runtime.process(message, local);
|
|
1348
1395
|
// Inactive (not in quorum or not writers) clients don't take part in the minimum sequence number calculation.
|
|
1349
1396
|
if (this.activeConnection()) {
|
|
1350
|
-
if (this.
|
|
1397
|
+
if (this.noopHeuristic === undefined) {
|
|
1398
|
+
const serviceConfiguration = this.deltaManager.serviceConfiguration;
|
|
1351
1399
|
// Note that config from first connection will be used for this container's lifetime.
|
|
1352
1400
|
// That means that if relay service changes settings, such changes will impact only newly booted
|
|
1353
1401
|
// clients.
|
|
1354
1402
|
// All existing will continue to use settings they got earlier.
|
|
1355
|
-
assert(
|
|
1356
|
-
this.
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
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);
|
|
1360
1418
|
}
|
|
1361
|
-
this.collabWindowTracker.scheduleSequenceNumberUpdate(message, result.immediateNoOp === true);
|
|
1362
1419
|
}
|
|
1363
1420
|
this.emit("op", message);
|
|
1364
1421
|
}
|
|
@@ -1367,12 +1424,12 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1367
1424
|
}
|
|
1368
1425
|
processSignal(message) {
|
|
1369
1426
|
// No clientId indicates a system signal message.
|
|
1370
|
-
if (message
|
|
1427
|
+
if (protocolHandlerShouldProcessSignal(message)) {
|
|
1371
1428
|
this.protocolHandler.processSignal(message);
|
|
1372
1429
|
}
|
|
1373
1430
|
else {
|
|
1374
1431
|
const local = this.clientId === message.clientId;
|
|
1375
|
-
this.
|
|
1432
|
+
this.runtime.processSignal(message, local);
|
|
1376
1433
|
}
|
|
1377
1434
|
}
|
|
1378
1435
|
/**
|
|
@@ -1405,21 +1462,37 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1405
1462
|
await this.instantiateContext(existing, codeDetails, snapshot);
|
|
1406
1463
|
}
|
|
1407
1464
|
async instantiateContext(existing, codeDetails, snapshot, pendingLocalState) {
|
|
1408
|
-
var _a;
|
|
1409
|
-
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" */);
|
|
1410
1467
|
// The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
|
|
1411
1468
|
// are set. Global requests will still go directly to the loader
|
|
1412
1469
|
const maybeLoader = this.scope;
|
|
1413
1470
|
const loader = new RelativeLoader(this, maybeLoader.ILoader);
|
|
1414
|
-
|
|
1415
|
-
this.
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
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);
|
|
1420
1483
|
}
|
|
1421
|
-
|
|
1422
|
-
|
|
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);
|
|
1423
1496
|
}
|
|
1424
1497
|
/**
|
|
1425
1498
|
* Set the connected state of the ContainerContext
|
|
@@ -1429,16 +1502,15 @@ export class Container extends EventEmitterWithErrorHandling {
|
|
|
1429
1502
|
*/
|
|
1430
1503
|
setContextConnectedState(state, readonly) {
|
|
1431
1504
|
var _a;
|
|
1432
|
-
if (((_a = this.
|
|
1505
|
+
if (((_a = this._runtime) === null || _a === void 0 ? void 0 : _a.disposed) === false) {
|
|
1433
1506
|
/**
|
|
1434
1507
|
* We want to lie to the ContainerRuntime when we are in readonly mode to prevent issues with pending
|
|
1435
1508
|
* ops getting through to the DeltaManager.
|
|
1436
1509
|
* The ContainerRuntime's "connected" state simply means it is ok to send ops
|
|
1437
1510
|
* See https://dev.azure.com/fluidframework/internal/_workitems/edit/1246
|
|
1438
1511
|
*/
|
|
1439
|
-
this.
|
|
1512
|
+
this.runtime.setConnectionState(state && !readonly, this.clientId);
|
|
1440
1513
|
}
|
|
1441
1514
|
}
|
|
1442
1515
|
}
|
|
1443
|
-
Container.version = "^0.1.0";
|
|
1444
1516
|
//# sourceMappingURL=container.js.map
|