@fluidframework/container-loader 1.3.0 → 2.0.0-dev.1.4.5.105745
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/.eslintrc.js +8 -21
- package/.mocharc.js +12 -0
- package/dist/audience.d.ts +2 -2
- package/dist/audience.d.ts.map +1 -1
- package/dist/audience.js.map +1 -1
- package/dist/catchUpMonitor.d.ts +29 -0
- package/dist/catchUpMonitor.d.ts.map +1 -0
- package/dist/catchUpMonitor.js +43 -0
- package/dist/catchUpMonitor.js.map +1 -0
- package/dist/collabWindowTracker.d.ts +1 -1
- package/dist/collabWindowTracker.d.ts.map +1 -1
- package/dist/collabWindowTracker.js +12 -4
- package/dist/collabWindowTracker.js.map +1 -1
- package/dist/connectionManager.d.ts +5 -5
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +13 -18
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionState.d.ts +0 -5
- package/dist/connectionState.d.ts.map +1 -1
- package/dist/connectionState.js +0 -5
- package/dist/connectionState.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +84 -22
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +172 -59
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +30 -17
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +173 -165
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +18 -7
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +18 -8
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +11 -25
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +51 -17
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +5 -5
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts +4 -1
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +33 -6
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.js +3 -3
- package/dist/deltaQueue.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +8 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +4 -3
- package/dist/loader.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocol.d.ts +22 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +53 -0
- package/dist/protocol.js.map +1 -0
- package/dist/protocolTreeDocumentStorageService.d.ts +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts +2 -2
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +2 -2
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/lib/audience.d.ts +2 -2
- package/lib/audience.d.ts.map +1 -1
- package/lib/audience.js.map +1 -1
- package/lib/catchUpMonitor.d.ts +29 -0
- package/lib/catchUpMonitor.d.ts.map +1 -0
- package/lib/catchUpMonitor.js +39 -0
- package/lib/catchUpMonitor.js.map +1 -0
- package/lib/collabWindowTracker.d.ts +1 -1
- package/lib/collabWindowTracker.d.ts.map +1 -1
- package/lib/collabWindowTracker.js +13 -5
- package/lib/collabWindowTracker.js.map +1 -1
- package/lib/connectionManager.d.ts +5 -5
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +14 -21
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionState.d.ts +0 -5
- package/lib/connectionState.d.ts.map +1 -1
- package/lib/connectionState.js +0 -5
- package/lib/connectionState.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +84 -22
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +171 -59
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +30 -17
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +176 -168
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +18 -7
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +19 -9
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +11 -25
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +51 -16
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +5 -5
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts +4 -1
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +35 -8
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.js +3 -3
- package/lib/deltaQueue.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/loader.d.ts +8 -1
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +4 -3
- package/lib/loader.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocol.d.ts +22 -0
- package/lib/protocol.d.ts.map +1 -0
- package/lib/protocol.js +49 -0
- package/lib/protocol.js.map +1 -0
- package/lib/protocolTreeDocumentStorageService.d.ts +1 -1
- package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts +2 -2
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js +2 -2
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/package.json +26 -20
- package/src/audience.ts +2 -2
- package/src/catchUpMonitor.ts +59 -0
- package/src/collabWindowTracker.ts +15 -6
- package/src/connectionManager.ts +23 -27
- package/src/connectionState.ts +0 -6
- package/src/connectionStateHandler.ts +235 -70
- package/src/container.ts +223 -209
- package/src/containerContext.ts +22 -8
- package/src/containerStorageAdapter.ts +71 -16
- package/src/contracts.ts +7 -7
- package/src/deltaManager.ts +42 -11
- package/src/deltaQueue.ts +3 -3
- package/src/index.ts +4 -0
- package/src/loader.ts +14 -3
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +97 -0
- package/src/retriableDocumentStorageService.ts +8 -2
package/dist/container.js
CHANGED
|
@@ -15,7 +15,6 @@ const common_utils_1 = require("@fluidframework/common-utils");
|
|
|
15
15
|
const container_definitions_1 = require("@fluidframework/container-definitions");
|
|
16
16
|
const container_utils_1 = require("@fluidframework/container-utils");
|
|
17
17
|
const driver_utils_1 = require("@fluidframework/driver-utils");
|
|
18
|
-
const protocol_base_1 = require("@fluidframework/protocol-base");
|
|
19
18
|
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
20
19
|
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
21
20
|
const audience_1 = require("./audience");
|
|
@@ -25,27 +24,31 @@ const deltaManager_1 = require("./deltaManager");
|
|
|
25
24
|
const deltaManagerProxy_1 = require("./deltaManagerProxy");
|
|
26
25
|
const loader_1 = require("./loader");
|
|
27
26
|
const packageVersion_1 = require("./packageVersion");
|
|
28
|
-
const connectionStateHandler_1 = require("./connectionStateHandler");
|
|
29
|
-
const retriableDocumentStorageService_1 = require("./retriableDocumentStorageService");
|
|
30
|
-
const protocolTreeDocumentStorageService_1 = require("./protocolTreeDocumentStorageService");
|
|
31
27
|
const containerStorageAdapter_1 = require("./containerStorageAdapter");
|
|
28
|
+
const connectionStateHandler_1 = require("./connectionStateHandler");
|
|
32
29
|
const utils_1 = require("./utils");
|
|
33
30
|
const quorum_1 = require("./quorum");
|
|
34
31
|
const collabWindowTracker_1 = require("./collabWindowTracker");
|
|
35
32
|
const connectionManager_1 = require("./connectionManager");
|
|
36
33
|
const connectionState_1 = require("./connectionState");
|
|
34
|
+
const protocol_1 = require("./protocol");
|
|
37
35
|
const detachedContainerRefSeqNumber = 0;
|
|
38
36
|
const dirtyContainerEvent = "dirty";
|
|
39
37
|
const savedContainerEvent = "saved";
|
|
40
38
|
/**
|
|
41
|
-
* Waits until container connects to delta storage and gets up-to-date
|
|
39
|
+
* Waits until container connects to delta storage and gets up-to-date.
|
|
40
|
+
*
|
|
42
41
|
* Useful when resolving URIs and hitting 404, due to container being loaded from (stale) snapshot and not being
|
|
43
42
|
* up to date. Host may chose to wait in such case and retry resolving URI.
|
|
43
|
+
*
|
|
44
44
|
* Warning: Will wait infinitely for connection to establish if there is no connection.
|
|
45
45
|
* May result in deadlock if Container.disconnect() is called and never followed by a call to Container.connect().
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
46
|
+
*
|
|
47
|
+
* @returns `true`: container is up to date, it processed all the ops that were know at the time of first connection.
|
|
48
|
+
*
|
|
49
|
+
* `false`: storage does not provide indication of how far the client is. Container processed all the ops known to it,
|
|
50
|
+
* but it maybe still behind.
|
|
51
|
+
*
|
|
49
52
|
* @throws an error beginning with `"Container closed"` if the container is closed before it catches up.
|
|
50
53
|
*/
|
|
51
54
|
async function waitContainerToCatchUp(container) {
|
|
@@ -63,6 +66,10 @@ async function waitContainerToCatchUp(container) {
|
|
|
63
66
|
: new container_utils_1.GenericError(baseMessage));
|
|
64
67
|
};
|
|
65
68
|
container.on("closed", closedCallback);
|
|
69
|
+
// Depending on config, transition to "connected" state may include the guarantee
|
|
70
|
+
// that all known ops have been processed. If so, we may introduce additional wait here.
|
|
71
|
+
// Waiting for "connected" state in either case gets us at least to our own Join op
|
|
72
|
+
// which is a reasonable approximation of "caught up"
|
|
66
73
|
const waitForOps = () => {
|
|
67
74
|
(0, common_utils_1.assert)(container.connectionState === connectionState_1.ConnectionState.CatchingUp
|
|
68
75
|
|| container.connectionState === connectionState_1.ConnectionState.Connected, 0x0cd /* "Container disconnected while waiting for ops!" */);
|
|
@@ -120,7 +127,7 @@ async function ReportIfTooLong(logger, eventName, action) {
|
|
|
120
127
|
}
|
|
121
128
|
const summarizerClientType = "summarizer";
|
|
122
129
|
class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
123
|
-
constructor(loader, config) {
|
|
130
|
+
constructor(loader, config, protocolHandlerBuilder) {
|
|
124
131
|
var _a, _b;
|
|
125
132
|
super((name, error) => {
|
|
126
133
|
this.mc.logger.sendErrorEvent({
|
|
@@ -129,6 +136,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
129
136
|
}, error);
|
|
130
137
|
});
|
|
131
138
|
this.loader = loader;
|
|
139
|
+
this.protocolHandlerBuilder = protocolHandlerBuilder;
|
|
132
140
|
// Tells if container can reconnect on losing fist connection
|
|
133
141
|
// If false, container gets closed on loss of connection.
|
|
134
142
|
this._canReconnect = true;
|
|
@@ -142,7 +150,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
142
150
|
this.attachStarted = false;
|
|
143
151
|
this._dirtyContainer = false;
|
|
144
152
|
this.setAutoReconnectTime = common_utils_1.performance.now();
|
|
145
|
-
this._audience = new audience_1.Audience();
|
|
146
153
|
this.clientDetailsOverride = config.clientDetailsOverride;
|
|
147
154
|
this._resolvedUrl = config.resolvedUrl;
|
|
148
155
|
if (config.canReconnect !== undefined) {
|
|
@@ -186,9 +193,19 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
186
193
|
this.mc = (0, telemetry_utils_1.loggerToMonitoringContext)(telemetry_utils_1.ChildLogger.create(this.subLogger, "Container"));
|
|
187
194
|
const summarizeProtocolTree = (_a = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree")) !== null && _a !== void 0 ? _a : this.loader.services.options.summarizeProtocolTree;
|
|
188
195
|
this.options = Object.assign(Object.assign({}, this.loader.services.options), { summarizeProtocolTree });
|
|
189
|
-
this.
|
|
190
|
-
|
|
191
|
-
|
|
196
|
+
this._deltaManager = this.createDeltaManager();
|
|
197
|
+
this._clientId = (_b = config.serializedContainerState) === null || _b === void 0 ? void 0 : _b.clientId;
|
|
198
|
+
this.connectionStateHandler = (0, connectionStateHandler_1.createConnectionStateHandler)({
|
|
199
|
+
logger: this.mc.logger,
|
|
200
|
+
connectionStateChanged: (value, oldState, reason) => {
|
|
201
|
+
if (value === connectionState_1.ConnectionState.Connected) {
|
|
202
|
+
this._clientId = this.connectionStateHandler.pendingClientId;
|
|
203
|
+
}
|
|
204
|
+
this.logConnectionStateChangeTelemetry(value, oldState, reason);
|
|
205
|
+
if (this._lifecycleState === "loaded") {
|
|
206
|
+
this.propagateConnectionState(false /* initial transition */);
|
|
207
|
+
}
|
|
208
|
+
},
|
|
192
209
|
shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
|
|
193
210
|
maxClientLeaveWaitTime: this.loader.services.options.maxClientLeaveWaitTime,
|
|
194
211
|
logConnectionIssue: (eventName, details) => {
|
|
@@ -196,29 +213,13 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
196
213
|
// its own join op. Attempt recovery option.
|
|
197
214
|
this._deltaManager.logConnectionIssue(Object.assign({ eventName, duration: common_utils_1.performance.now() - this.connectionTransitionTimes[connectionState_1.ConnectionState.CatchingUp] }, (details === undefined ? {} : { details: JSON.stringify(details) })));
|
|
198
215
|
},
|
|
199
|
-
|
|
200
|
-
// Fire events only if container is fully loaded and not closed
|
|
201
|
-
if (this._lifecycleState === "loaded") {
|
|
202
|
-
this.propagateConnectionState();
|
|
203
|
-
}
|
|
204
|
-
},
|
|
205
|
-
}, this.mc.logger, (_b = config.serializedContainerState) === null || _b === void 0 ? void 0 : _b.clientId);
|
|
216
|
+
}, this.deltaManager, this._clientId);
|
|
206
217
|
this.on(savedContainerEvent, () => {
|
|
207
218
|
this.connectionStateHandler.containerSaved();
|
|
208
219
|
});
|
|
209
|
-
this.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (this.loader.services.detachedBlobStorage !== undefined) {
|
|
213
|
-
return new containerStorageAdapter_1.BlobOnlyStorage(this.loader.services.detachedBlobStorage, this.mc.logger);
|
|
214
|
-
}
|
|
215
|
-
this.mc.logger.sendErrorEvent({
|
|
216
|
-
eventName: "NoRealStorageInDetachedContainer",
|
|
217
|
-
});
|
|
218
|
-
throw new Error("Real storage calls not allowed in Unattached container");
|
|
219
|
-
}
|
|
220
|
-
return this.storageService;
|
|
221
|
-
});
|
|
220
|
+
this.storageService = new containerStorageAdapter_1.ContainerStorageAdapter(this.loader.services.detachedBlobStorage, this.mc.logger, this.options.summarizeProtocolTree === true
|
|
221
|
+
? () => this.captureProtocolSummary()
|
|
222
|
+
: undefined);
|
|
222
223
|
const isDomAvailable = typeof document === "object" &&
|
|
223
224
|
document !== null &&
|
|
224
225
|
typeof document.addEventListener === "function" &&
|
|
@@ -275,13 +276,13 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
275
276
|
/**
|
|
276
277
|
* Load an existing container.
|
|
277
278
|
*/
|
|
278
|
-
static async load(loader, loadOptions, pendingLocalState) {
|
|
279
|
+
static async load(loader, loadOptions, pendingLocalState, protocolHandlerBuilder) {
|
|
279
280
|
const container = new Container(loader, {
|
|
280
281
|
clientDetailsOverride: loadOptions.clientDetailsOverride,
|
|
281
282
|
resolvedUrl: loadOptions.resolvedUrl,
|
|
282
283
|
canReconnect: loadOptions.canReconnect,
|
|
283
284
|
serializedContainerState: pendingLocalState,
|
|
284
|
-
});
|
|
285
|
+
}, protocolHandlerBuilder);
|
|
285
286
|
return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "Load" }, async (event) => new Promise((resolve, reject) => {
|
|
286
287
|
var _a, _b;
|
|
287
288
|
const version = loadOptions.version;
|
|
@@ -315,8 +316,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
315
316
|
/**
|
|
316
317
|
* Create a new container in a detached state.
|
|
317
318
|
*/
|
|
318
|
-
static async createDetached(loader, codeDetails) {
|
|
319
|
-
const container = new Container(loader, {});
|
|
319
|
+
static async createDetached(loader, codeDetails, protocolHandlerBuilder) {
|
|
320
|
+
const container = new Container(loader, {}, protocolHandlerBuilder);
|
|
320
321
|
return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "CreateDetached" }, async (_event) => {
|
|
321
322
|
await container.createDetached(codeDetails);
|
|
322
323
|
return container;
|
|
@@ -326,8 +327,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
326
327
|
* Create a new container in a detached state that is initialized with a
|
|
327
328
|
* snapshot from a previous detached container.
|
|
328
329
|
*/
|
|
329
|
-
static async rehydrateDetachedFromSnapshot(loader, snapshot) {
|
|
330
|
-
const container = new Container(loader, {});
|
|
330
|
+
static async rehydrateDetachedFromSnapshot(loader, snapshot, protocolHandlerBuilder) {
|
|
331
|
+
const container = new Container(loader, {}, protocolHandlerBuilder);
|
|
331
332
|
return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "RehydrateDetachedFromSnapshot" }, async (_event) => {
|
|
332
333
|
const deserializedSummary = JSON.parse(snapshot);
|
|
333
334
|
await container.rehydrateDetachedFromSnapshot(deserializedSummary);
|
|
@@ -339,7 +340,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
339
340
|
// Only transition states if currently loading
|
|
340
341
|
if (this._lifecycleState === "loading") {
|
|
341
342
|
// Propagate current connection state through the system.
|
|
342
|
-
this.propagateConnectionState();
|
|
343
|
+
this.propagateConnectionState(true /* initial transition */);
|
|
343
344
|
this._lifecycleState = "loaded";
|
|
344
345
|
}
|
|
345
346
|
}
|
|
@@ -347,13 +348,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
347
348
|
return (this._lifecycleState === "closing" || this._lifecycleState === "closed");
|
|
348
349
|
}
|
|
349
350
|
get storage() {
|
|
350
|
-
return this.
|
|
351
|
-
}
|
|
352
|
-
get storageService() {
|
|
353
|
-
if (this._storageService === undefined) {
|
|
354
|
-
throw new Error("Attempted to access storageService before it was defined");
|
|
355
|
-
}
|
|
356
|
-
return this._storageService;
|
|
351
|
+
return this.storageService;
|
|
357
352
|
}
|
|
358
353
|
get context() {
|
|
359
354
|
if (this._context === undefined) {
|
|
@@ -394,7 +389,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
394
389
|
return this.connectionStateHandler.connectionState;
|
|
395
390
|
}
|
|
396
391
|
get connected() {
|
|
397
|
-
return this.connectionStateHandler.
|
|
392
|
+
return this.connectionStateHandler.connectionState === connectionState_1.ConnectionState.Connected;
|
|
398
393
|
}
|
|
399
394
|
/**
|
|
400
395
|
* Service configuration details. If running in offline mode will be undefined otherwise will contain service
|
|
@@ -408,7 +403,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
408
403
|
* Set once this.connected is true, otherwise undefined
|
|
409
404
|
*/
|
|
410
405
|
get clientId() {
|
|
411
|
-
return this.
|
|
406
|
+
return this._clientId;
|
|
412
407
|
}
|
|
413
408
|
/**
|
|
414
409
|
* The server provided claims of the client.
|
|
@@ -440,12 +435,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
440
435
|
* Retrieves the audience associated with the document
|
|
441
436
|
*/
|
|
442
437
|
get audience() {
|
|
443
|
-
return this.
|
|
438
|
+
return this.protocolHandler.audience;
|
|
444
439
|
}
|
|
445
440
|
/**
|
|
446
441
|
* Returns true if container is dirty.
|
|
447
442
|
* Which means data loss if container is closed at that same moment
|
|
448
|
-
* Most likely that happens when there is no network connection to
|
|
443
|
+
* Most likely that happens when there is no network connection to Relay Service
|
|
449
444
|
*/
|
|
450
445
|
get isDirty() {
|
|
451
446
|
return this._dirtyContainer;
|
|
@@ -470,7 +465,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
470
465
|
(0, common_utils_1.assert)(this._lifecycleState === "closed", 0x314 /* Container properly closed */);
|
|
471
466
|
}
|
|
472
467
|
closeCore(error) {
|
|
473
|
-
var _a, _b, _c
|
|
468
|
+
var _a, _b, _c;
|
|
474
469
|
(0, common_utils_1.assert)(!this.closed, 0x315 /* re-entrancy */);
|
|
475
470
|
try {
|
|
476
471
|
// Ensure that we raise all key events even if one of these throws
|
|
@@ -485,11 +480,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
485
480
|
(_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.close();
|
|
486
481
|
this.connectionStateHandler.dispose();
|
|
487
482
|
(_b = this._context) === null || _b === void 0 ? void 0 : _b.dispose(error !== undefined ? new Error(error.message) : undefined);
|
|
488
|
-
|
|
483
|
+
this.storageService.dispose();
|
|
489
484
|
// Notify storage about critical errors. They may be due to disconnect between client & server knowledge
|
|
490
485
|
// about file, like file being overwritten in storage, but client having stale local cache.
|
|
491
486
|
// Driver need to ensure all caches are cleared on critical errors
|
|
492
|
-
(
|
|
487
|
+
(_c = this.service) === null || _c === void 0 ? void 0 : _c.dispose(error);
|
|
493
488
|
}
|
|
494
489
|
catch (exception) {
|
|
495
490
|
this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
|
|
@@ -511,7 +506,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
511
506
|
(0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
|
|
512
507
|
(0, common_utils_1.assert)(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
|
|
513
508
|
(0, common_utils_1.assert)(!!this._protocolHandler, 0x2e3 /* "Must have a valid protocol handler instance" */);
|
|
514
|
-
(0, common_utils_1.assert)(this._protocolHandler.attributes.term !== undefined,
|
|
509
|
+
(0, common_utils_1.assert)(this._protocolHandler.attributes.term !== undefined, 0x37e /* Must have a valid protocol handler instance */);
|
|
515
510
|
const pendingState = {
|
|
516
511
|
pendingRuntimeState: this.context.getPendingLocalState(),
|
|
517
512
|
url: this.resolvedUrl.url,
|
|
@@ -519,6 +514,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
519
514
|
term: this._protocolHandler.attributes.term,
|
|
520
515
|
clientId: this.clientId,
|
|
521
516
|
};
|
|
517
|
+
this.mc.logger.sendTelemetryEvent({ eventName: "CloseAndGetPendingLocalState" });
|
|
522
518
|
this.close();
|
|
523
519
|
return JSON.stringify(pendingState);
|
|
524
520
|
}
|
|
@@ -575,7 +571,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
575
571
|
const resolvedUrl = this.service.resolvedUrl;
|
|
576
572
|
(0, driver_utils_1.ensureFluidResolvedUrl)(resolvedUrl);
|
|
577
573
|
this._resolvedUrl = resolvedUrl;
|
|
578
|
-
await this.
|
|
574
|
+
await this.storageService.connectToService(this.service);
|
|
579
575
|
if (hasAttachmentBlobs) {
|
|
580
576
|
// upload blobs to storage
|
|
581
577
|
(0, common_utils_1.assert)(!!this.loader.services.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
|
|
@@ -605,8 +601,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
605
601
|
}
|
|
606
602
|
this._attachState = container_definitions_1.AttachState.Attached;
|
|
607
603
|
this.emit("attached");
|
|
608
|
-
// Propagate current connection state through the system.
|
|
609
|
-
this.propagateConnectionState();
|
|
610
604
|
if (!this.closed) {
|
|
611
605
|
this.resumeInternal({ fetchOpsFromStorage: false, reason: "createDetached" });
|
|
612
606
|
}
|
|
@@ -745,9 +739,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
745
739
|
/**
|
|
746
740
|
* Load container.
|
|
747
741
|
*
|
|
748
|
-
* @param specifiedVersion -
|
|
749
|
-
* - undefined - fetch latest snapshot
|
|
750
|
-
* - otherwise, version sha to load snapshot
|
|
742
|
+
* @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
|
|
751
743
|
*/
|
|
752
744
|
async load(specifiedVersion, loadMode, pendingLocalState) {
|
|
753
745
|
if (this._resolvedUrl === undefined) {
|
|
@@ -770,11 +762,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
770
762
|
this.connectToDeltaStream(connectionArgs);
|
|
771
763
|
}
|
|
772
764
|
if (!pendingLocalState) {
|
|
773
|
-
await this.
|
|
765
|
+
await this.storageService.connectToService(this.service);
|
|
774
766
|
}
|
|
775
767
|
else {
|
|
776
768
|
// if we have pendingLocalState we can load without storage; don't wait for connection
|
|
777
|
-
this.
|
|
769
|
+
this.storageService.connectToService(this.service).catch((error) => this.close(error));
|
|
778
770
|
}
|
|
779
771
|
this._attachState = container_definitions_1.AttachState.Attached;
|
|
780
772
|
// Fetch specified snapshot.
|
|
@@ -809,9 +801,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
809
801
|
}
|
|
810
802
|
// ...load in the existing quorum
|
|
811
803
|
// Initialize the protocol handler
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
804
|
+
if (pendingLocalState === undefined) {
|
|
805
|
+
await this.initializeProtocolStateFromSnapshot(attributes, this.storageService, snapshot);
|
|
806
|
+
}
|
|
807
|
+
else {
|
|
808
|
+
this.initializeProtocolState(attributes, {
|
|
809
|
+
members: pendingLocalState.protocol.members,
|
|
810
|
+
proposals: pendingLocalState.protocol.proposals,
|
|
811
|
+
values: pendingLocalState.protocol.values,
|
|
812
|
+
});
|
|
813
|
+
}
|
|
815
814
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
816
815
|
await this.instantiateContext(true, // existing
|
|
817
816
|
codeDetails, snapshot, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.pendingRuntimeState);
|
|
@@ -865,9 +864,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
865
864
|
await this.attachDeltaManagerOpHandler(attributes);
|
|
866
865
|
// Need to just seed the source data in the code quorum. Quorum itself is empty
|
|
867
866
|
const qValues = (0, quorum_1.initQuorumValuesFromCodeDetails)(source);
|
|
868
|
-
this.
|
|
869
|
-
|
|
870
|
-
|
|
867
|
+
this.initializeProtocolState(attributes, {
|
|
868
|
+
members: [],
|
|
869
|
+
proposals: [],
|
|
870
|
+
values: qValues,
|
|
871
|
+
});
|
|
871
872
|
// The load context - given we seeded the quorum - will be great
|
|
872
873
|
await this.instantiateContextDetached(false);
|
|
873
874
|
this.setLoaded();
|
|
@@ -878,38 +879,22 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
878
879
|
delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
|
|
879
880
|
}
|
|
880
881
|
const snapshotTree = (0, utils_1.getSnapshotTreeFromSerializedContainer)(detachedContainerSnapshot);
|
|
881
|
-
this.
|
|
882
|
-
const attributes = await this.getDocumentAttributes(this.
|
|
882
|
+
this.storageService.loadSnapshotForRehydratingContainer(snapshotTree);
|
|
883
|
+
const attributes = await this.getDocumentAttributes(this.storageService, snapshotTree);
|
|
883
884
|
await this.attachDeltaManagerOpHandler(attributes);
|
|
884
885
|
// Initialize the protocol handler
|
|
885
886
|
const baseTree = (0, utils_1.getProtocolSnapshotTree)(snapshotTree);
|
|
886
|
-
const qValues = await (0, driver_utils_1.readAndParse)(this.
|
|
887
|
+
const qValues = await (0, driver_utils_1.readAndParse)(this.storageService, baseTree.blobs.quorumValues);
|
|
887
888
|
const codeDetails = (0, quorum_1.getCodeDetailsFromQuorumValues)(qValues);
|
|
888
|
-
this.
|
|
889
|
-
|
|
890
|
-
[],
|
|
891
|
-
codeDetails !== undefined ? (0, quorum_1.initQuorumValuesFromCodeDetails)(codeDetails) : []
|
|
889
|
+
this.initializeProtocolState(attributes, {
|
|
890
|
+
members: [],
|
|
891
|
+
proposals: [],
|
|
892
|
+
values: codeDetails !== undefined ? (0, quorum_1.initQuorumValuesFromCodeDetails)(codeDetails) : [],
|
|
893
|
+
});
|
|
892
894
|
await this.instantiateContextDetached(true, // existing
|
|
893
895
|
snapshotTree);
|
|
894
896
|
this.setLoaded();
|
|
895
897
|
}
|
|
896
|
-
async connectStorageService() {
|
|
897
|
-
var _a, _b;
|
|
898
|
-
if (this._storageService !== undefined) {
|
|
899
|
-
return;
|
|
900
|
-
}
|
|
901
|
-
(0, common_utils_1.assert)(this.service !== undefined, 0x1ef /* "services must be defined" */);
|
|
902
|
-
const storageService = await this.service.connectToStorage();
|
|
903
|
-
this._storageService =
|
|
904
|
-
new retriableDocumentStorageService_1.RetriableDocumentStorageService(storageService, this.mc.logger);
|
|
905
|
-
if (this.options.summarizeProtocolTree === true) {
|
|
906
|
-
this.mc.logger.sendTelemetryEvent({ eventName: "summarizeProtocolTreeEnabled" });
|
|
907
|
-
this._storageService =
|
|
908
|
-
new protocolTreeDocumentStorageService_1.ProtocolTreeStorageService(this._storageService, () => this.captureProtocolSummary());
|
|
909
|
-
}
|
|
910
|
-
// ensure we did not lose that policy in the process of wrapping
|
|
911
|
-
(0, common_utils_1.assert)(((_a = storageService.policies) === null || _a === void 0 ? void 0 : _a.minBlobSize) === ((_b = this.storageService.policies) === null || _b === void 0 ? void 0 : _b.minBlobSize), 0x0e0 /* "lost minBlobSize policy" */);
|
|
912
|
-
}
|
|
913
898
|
async getDocumentAttributes(storage, tree) {
|
|
914
899
|
if (tree === undefined) {
|
|
915
900
|
return {
|
|
@@ -930,22 +915,26 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
930
915
|
return attributes;
|
|
931
916
|
}
|
|
932
917
|
async initializeProtocolStateFromSnapshot(attributes, storage, snapshot) {
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
918
|
+
const quorumSnapshot = {
|
|
919
|
+
members: [],
|
|
920
|
+
proposals: [],
|
|
921
|
+
values: [],
|
|
922
|
+
};
|
|
936
923
|
if (snapshot !== undefined) {
|
|
937
924
|
const baseTree = (0, utils_1.getProtocolSnapshotTree)(snapshot);
|
|
938
|
-
[members, proposals, values] = await Promise.all([
|
|
925
|
+
[quorumSnapshot.members, quorumSnapshot.proposals, quorumSnapshot.values] = await Promise.all([
|
|
939
926
|
(0, driver_utils_1.readAndParse)(storage, baseTree.blobs.quorumMembers),
|
|
940
927
|
(0, driver_utils_1.readAndParse)(storage, baseTree.blobs.quorumProposals),
|
|
941
928
|
(0, driver_utils_1.readAndParse)(storage, baseTree.blobs.quorumValues),
|
|
942
929
|
]);
|
|
943
930
|
}
|
|
944
|
-
|
|
945
|
-
return protocolHandler;
|
|
931
|
+
this.initializeProtocolState(attributes, quorumSnapshot);
|
|
946
932
|
}
|
|
947
|
-
|
|
948
|
-
|
|
933
|
+
initializeProtocolState(attributes, quorumSnapshot) {
|
|
934
|
+
var _a, _b;
|
|
935
|
+
const protocolHandlerBuilder = (_a = this.protocolHandlerBuilder) !== null && _a !== void 0 ? _a : ((...args) => new protocol_1.ProtocolHandler(...args, new audience_1.Audience()));
|
|
936
|
+
const protocol = protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) => this.submitMessage(protocol_definitions_1.MessageType.Propose, JSON.stringify({ key, value })), (_b = this._initialClients) !== null && _b !== void 0 ? _b : []);
|
|
937
|
+
this._initialClients = undefined;
|
|
949
938
|
const protocolLogger = telemetry_utils_1.ChildLogger.create(this.subLogger, "ProtocolHandler");
|
|
950
939
|
protocol.quorum.on("error", (error) => {
|
|
951
940
|
protocolLogger.sendErrorEvent(error);
|
|
@@ -970,7 +959,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
970
959
|
});
|
|
971
960
|
}
|
|
972
961
|
});
|
|
973
|
-
|
|
962
|
+
// we need to make sure this member get set in a synchronous context,
|
|
963
|
+
// or other things can happen after the object that will be set is created, but not yet set
|
|
964
|
+
// this was breaking this._initialClients handling
|
|
965
|
+
//
|
|
966
|
+
this._protocolHandler = protocol;
|
|
974
967
|
}
|
|
975
968
|
captureProtocolSummary() {
|
|
976
969
|
const quorumSnapshot = this.protocolHandler.snapshot();
|
|
@@ -1039,12 +1032,20 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1039
1032
|
deltaManager.inbound.pause();
|
|
1040
1033
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1041
1034
|
deltaManager.inboundSignal.pause();
|
|
1042
|
-
deltaManager.on("connect", (details,
|
|
1035
|
+
deltaManager.on("connect", (details, _opsBehind) => {
|
|
1043
1036
|
var _a;
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
this.
|
|
1037
|
+
if (this._protocolHandler === undefined) {
|
|
1038
|
+
// Store the initial clients so that they can be submitted to the
|
|
1039
|
+
// protocol handler when it is created.
|
|
1040
|
+
this._initialClients = details.initialClients;
|
|
1041
|
+
}
|
|
1042
|
+
else {
|
|
1043
|
+
// When reconnecting, the protocol handler is already created,
|
|
1044
|
+
// so we can update the audience right now.
|
|
1045
|
+
this._protocolHandler.audience.clear();
|
|
1046
|
+
for (const priorClient of (_a = details.initialClients) !== null && _a !== void 0 ? _a : []) {
|
|
1047
|
+
this._protocolHandler.audience.addMember(priorClient.clientId, priorClient.client);
|
|
1048
|
+
}
|
|
1048
1049
|
}
|
|
1049
1050
|
this.connectionStateHandler.receivedConnectEvent(this.connectionMode, details);
|
|
1050
1051
|
});
|
|
@@ -1063,6 +1064,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1063
1064
|
this.emit("warning", warn);
|
|
1064
1065
|
});
|
|
1065
1066
|
deltaManager.on("readonly", (readonly) => {
|
|
1067
|
+
this.setContextConnectedState(this.connectionState === connectionState_1.ConnectionState.Connected, readonly);
|
|
1066
1068
|
this.emit("readonly", readonly);
|
|
1067
1069
|
});
|
|
1068
1070
|
deltaManager.on("closed", (error) => {
|
|
@@ -1105,12 +1107,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1105
1107
|
opsBehind = checkpointSequenceNumber - this.deltaManager.lastSequenceNumber;
|
|
1106
1108
|
}
|
|
1107
1109
|
}
|
|
1108
|
-
|
|
1109
|
-
connectionInitiationReason = "InitialConnect";
|
|
1110
|
-
}
|
|
1111
|
-
else {
|
|
1112
|
-
connectionInitiationReason = "AutoReconnect";
|
|
1113
|
-
}
|
|
1110
|
+
connectionInitiationReason = this.firstConnection ? "InitialConnect" : "AutoReconnect";
|
|
1114
1111
|
}
|
|
1115
1112
|
this.mc.logger.sendPerformanceEvent(Object.assign({ eventName: `ConnectionStateChange_${connectionState_1.ConnectionState[value]}`, from: connectionState_1.ConnectionState[oldState], duration,
|
|
1116
1113
|
durationFromDisconnected,
|
|
@@ -1121,49 +1118,64 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1121
1118
|
this.firstConnection = false;
|
|
1122
1119
|
}
|
|
1123
1120
|
}
|
|
1124
|
-
propagateConnectionState() {
|
|
1121
|
+
propagateConnectionState(initialTransition) {
|
|
1125
1122
|
var _a;
|
|
1123
|
+
// When container loaded, we want to propagate initial connection state.
|
|
1124
|
+
// After that, we communicate only transitions to Connected & Disconnected states, skipping all other states.
|
|
1125
|
+
// This can be changed in the future, for example we likely should add "CatchingUp" event on Container.
|
|
1126
|
+
if (!initialTransition &&
|
|
1127
|
+
this.connectionState !== connectionState_1.ConnectionState.Connected &&
|
|
1128
|
+
this.connectionState !== connectionState_1.ConnectionState.Disconnected) {
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
const state = this.connectionState === connectionState_1.ConnectionState.Connected;
|
|
1126
1132
|
const logOpsOnReconnect = this.connectionState === connectionState_1.ConnectionState.Connected &&
|
|
1127
1133
|
!this.firstConnection &&
|
|
1128
1134
|
this.connectionMode === "write";
|
|
1129
1135
|
if (logOpsOnReconnect) {
|
|
1130
1136
|
this.messageCountAfterDisconnection = 0;
|
|
1131
1137
|
}
|
|
1132
|
-
const state = this.connectionState === connectionState_1.ConnectionState.Connected;
|
|
1133
1138
|
// Both protocol and context should not be undefined if we got so far.
|
|
1134
|
-
|
|
1135
|
-
this.context.setConnectionState(state, this.clientId);
|
|
1136
|
-
}
|
|
1139
|
+
this.setContextConnectedState(state, (_a = this._deltaManager.connectionManager.readOnlyInfo.readonly) !== null && _a !== void 0 ? _a : false);
|
|
1137
1140
|
this.protocolHandler.setConnectionState(state, this.clientId);
|
|
1138
1141
|
(0, telemetry_utils_1.raiseConnectedEvent)(this.mc.logger, this, state, this.clientId);
|
|
1139
1142
|
if (logOpsOnReconnect) {
|
|
1140
1143
|
this.mc.logger.sendTelemetryEvent({ eventName: "OpsSentOnReconnect", count: this.messageCountAfterDisconnection });
|
|
1141
1144
|
}
|
|
1142
1145
|
}
|
|
1146
|
+
// back-compat: ADO #1385: Remove in the future, summary op should come through submitSummaryMessage()
|
|
1143
1147
|
submitContainerMessage(type, contents, batch, metadata) {
|
|
1144
|
-
|
|
1145
|
-
switch (outboundMessageType) {
|
|
1148
|
+
switch (type) {
|
|
1146
1149
|
case protocol_definitions_1.MessageType.Operation:
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
// github #6451: this is only needed for staging so the server
|
|
1151
|
-
// know when the protocol tree is included
|
|
1152
|
-
// this can be removed once all clients send
|
|
1153
|
-
// protocol tree by default
|
|
1154
|
-
const summary = contents;
|
|
1155
|
-
if (summary.details === undefined) {
|
|
1156
|
-
summary.details = {};
|
|
1157
|
-
}
|
|
1158
|
-
summary.details.includesProtocolTree =
|
|
1159
|
-
this.options.summarizeProtocolTree === true;
|
|
1160
|
-
break;
|
|
1161
|
-
}
|
|
1150
|
+
return this.submitMessage(type, JSON.stringify(contents), batch, metadata);
|
|
1151
|
+
case protocol_definitions_1.MessageType.Summarize:
|
|
1152
|
+
return this.submitSummaryMessage(contents);
|
|
1162
1153
|
default:
|
|
1163
1154
|
this.close(new container_utils_1.GenericError("invalidContainerSubmitOpType", undefined /* error */, { messageType: type }));
|
|
1164
1155
|
return -1;
|
|
1165
1156
|
}
|
|
1166
|
-
|
|
1157
|
+
}
|
|
1158
|
+
/** @returns clientSequenceNumber of last message in a batch */
|
|
1159
|
+
submitBatch(batch) {
|
|
1160
|
+
let clientSequenceNumber = -1;
|
|
1161
|
+
for (const message of batch) {
|
|
1162
|
+
clientSequenceNumber = this.submitMessage(protocol_definitions_1.MessageType.Operation, message.contents, true, // batch
|
|
1163
|
+
message.metadata);
|
|
1164
|
+
}
|
|
1165
|
+
this._deltaManager.flush();
|
|
1166
|
+
return clientSequenceNumber;
|
|
1167
|
+
}
|
|
1168
|
+
submitSummaryMessage(summary) {
|
|
1169
|
+
// github #6451: this is only needed for staging so the server
|
|
1170
|
+
// know when the protocol tree is included
|
|
1171
|
+
// this can be removed once all clients send
|
|
1172
|
+
// protocol tree by default
|
|
1173
|
+
if (summary.details === undefined) {
|
|
1174
|
+
summary.details = {};
|
|
1175
|
+
}
|
|
1176
|
+
summary.details.includesProtocolTree =
|
|
1177
|
+
this.options.summarizeProtocolTree === true;
|
|
1178
|
+
return this.submitMessage(protocol_definitions_1.MessageType.Summarize, JSON.stringify(summary), false /* batch */);
|
|
1167
1179
|
}
|
|
1168
1180
|
submitMessage(type, contents, batch, metadata) {
|
|
1169
1181
|
var _a;
|
|
@@ -1178,22 +1190,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1178
1190
|
processRemoteMessage(message) {
|
|
1179
1191
|
const local = this.clientId === message.clientId;
|
|
1180
1192
|
// Allow the protocol handler to process the message
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
}
|
|
1185
|
-
catch (error) {
|
|
1186
|
-
this.close((0, telemetry_utils_1.wrapError)(error, (errorMessage) => new container_utils_1.DataCorruptionError(errorMessage, (0, container_utils_1.extractSafePropertiesFromMessage)(message))));
|
|
1187
|
-
}
|
|
1188
|
-
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
1189
|
-
if ((0, driver_utils_1.isUnpackedRuntimeMessage)(message) && !(0, driver_utils_1.isRuntimeMessage)(message)) {
|
|
1190
|
-
this.mc.logger.sendTelemetryEvent({ eventName: "UnpackedRuntimeMessage", type: message.type });
|
|
1191
|
-
}
|
|
1192
|
-
// Forward non system messages to the loaded runtime for processing
|
|
1193
|
-
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
1194
|
-
if ((0, driver_utils_1.isRuntimeMessage)(message) || (0, driver_utils_1.isUnpackedRuntimeMessage)(message)) {
|
|
1195
|
-
this.context.process(message, local, undefined);
|
|
1196
|
-
}
|
|
1193
|
+
const result = this.protocolHandler.processMessage(message, local);
|
|
1194
|
+
// Forward messages to the loaded runtime for processing
|
|
1195
|
+
this.context.process(message, local, undefined);
|
|
1197
1196
|
// Inactive (not in quorum or not writers) clients don't take part in the minimum sequence number calculation.
|
|
1198
1197
|
if (this.activeConnection()) {
|
|
1199
1198
|
if (this.collabWindowTracker === undefined) {
|
|
@@ -1202,15 +1201,14 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1202
1201
|
// clients.
|
|
1203
1202
|
// All existing will continue to use settings they got earlier.
|
|
1204
1203
|
(0, common_utils_1.assert)(this.serviceConfiguration !== undefined, 0x2e4 /* "there should be service config for active connection" */);
|
|
1205
|
-
this.collabWindowTracker = new collabWindowTracker_1.CollabWindowTracker((type
|
|
1204
|
+
this.collabWindowTracker = new collabWindowTracker_1.CollabWindowTracker((type) => {
|
|
1206
1205
|
(0, common_utils_1.assert)(this.activeConnection(), 0x241 /* "disconnect should result in stopSequenceNumberUpdate() call" */);
|
|
1207
|
-
this.submitMessage(type
|
|
1206
|
+
this.submitMessage(type);
|
|
1208
1207
|
}, this.serviceConfiguration.noopTimeFrequency, this.serviceConfiguration.noopCountFrequency);
|
|
1209
1208
|
}
|
|
1210
1209
|
this.collabWindowTracker.scheduleSequenceNumberUpdate(message, result.immediateNoOp === true);
|
|
1211
1210
|
}
|
|
1212
1211
|
this.emit("op", message);
|
|
1213
|
-
return result;
|
|
1214
1212
|
}
|
|
1215
1213
|
submitSignal(message) {
|
|
1216
1214
|
this._deltaManager.submitSignal(JSON.stringify(message));
|
|
@@ -1218,15 +1216,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1218
1216
|
processSignal(message) {
|
|
1219
1217
|
// No clientId indicates a system signal message.
|
|
1220
1218
|
if (message.clientId === null) {
|
|
1221
|
-
|
|
1222
|
-
if (innerContent.type === protocol_definitions_1.MessageType.ClientJoin) {
|
|
1223
|
-
const newClient = innerContent.content;
|
|
1224
|
-
this._audience.addMember(newClient.clientId, newClient.client);
|
|
1225
|
-
}
|
|
1226
|
-
else if (innerContent.type === protocol_definitions_1.MessageType.ClientLeave) {
|
|
1227
|
-
const leftClientId = innerContent.content;
|
|
1228
|
-
this._audience.removeMember(leftClientId);
|
|
1229
|
-
}
|
|
1219
|
+
this.protocolHandler.processSignal(message);
|
|
1230
1220
|
}
|
|
1231
1221
|
else {
|
|
1232
1222
|
const local = this.clientId === message.clientId;
|
|
@@ -1265,7 +1255,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1265
1255
|
// The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
|
|
1266
1256
|
// are set. Global requests will still go directly to the loader
|
|
1267
1257
|
const loader = new loader_1.RelativeLoader(this, this.loader);
|
|
1268
|
-
this._context = await containerContext_1.ContainerContext.createOrLoad(this, this.scope, this.codeLoader, codeDetails, snapshot, new deltaManagerProxy_1.DeltaManagerProxy(this._deltaManager), new quorum_1.QuorumProxy(this.protocolHandler.quorum), loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (message) => this.submitSignal(message), (error) => this.close(error), Container.version, (dirty) => this.updateDirtyContainerState(dirty), existing, pendingLocalState);
|
|
1258
|
+
this._context = await containerContext_1.ContainerContext.createOrLoad(this, this.scope, this.codeLoader, codeDetails, snapshot, new deltaManagerProxy_1.DeltaManagerProxy(this._deltaManager), new quorum_1.QuorumProxy(this.protocolHandler.quorum), loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp) => this.submitSummaryMessage(summaryOp), (batch) => this.submitBatch(batch), (message) => this.submitSignal(message), (error) => this.close(error), Container.version, (dirty) => this.updateDirtyContainerState(dirty), existing, pendingLocalState);
|
|
1269
1259
|
this.emit("contextChanged", codeDetails);
|
|
1270
1260
|
}
|
|
1271
1261
|
updateDirtyContainerState(dirty) {
|
|
@@ -1278,6 +1268,24 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
|
|
|
1278
1268
|
logContainerError(warning) {
|
|
1279
1269
|
this.mc.logger.sendErrorEvent({ eventName: "ContainerWarning" }, warning);
|
|
1280
1270
|
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Set the connected state of the ContainerContext
|
|
1273
|
+
* This controls the "connected" state of the ContainerRuntime as well
|
|
1274
|
+
* @param state - Is the container currently connected?
|
|
1275
|
+
* @param readonly - Is the container in readonly mode?
|
|
1276
|
+
*/
|
|
1277
|
+
setContextConnectedState(state, readonly) {
|
|
1278
|
+
var _a;
|
|
1279
|
+
if (((_a = this._context) === null || _a === void 0 ? void 0 : _a.disposed) === false) {
|
|
1280
|
+
/**
|
|
1281
|
+
* We want to lie to the ContainerRuntime when we are in readonly mode to prevent issues with pending
|
|
1282
|
+
* ops getting through to the DeltaManager.
|
|
1283
|
+
* The ContainerRuntime's "connected" state simply means it is ok to send ops
|
|
1284
|
+
* See https://dev.azure.com/fluidframework/internal/_workitems/edit/1246
|
|
1285
|
+
*/
|
|
1286
|
+
this.context.setConnectionState(state && !readonly, this.clientId);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1281
1289
|
}
|
|
1282
1290
|
exports.Container = Container;
|
|
1283
1291
|
Container.version = "^0.1.0";
|