@fluidframework/container-loader 2.0.0-dev.6.4.0.192049 → 2.0.0-dev.7.2.0.204906
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 +122 -0
- package/api-extractor.json +9 -1
- package/api-report/container-loader.api.md +153 -0
- package/dist/catchUpMonitor.d.ts +2 -2
- package/dist/catchUpMonitor.d.ts.map +1 -1
- package/dist/connectionManager.d.ts +2 -15
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +117 -100
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionState.js +1 -1
- package/dist/connectionState.js.map +1 -1
- package/dist/connectionStateHandler.js +9 -9
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container-loader-alpha.d.ts +333 -0
- package/dist/container-loader-beta.d.ts +333 -0
- package/dist/container-loader-public.d.ts +333 -0
- package/dist/container-loader-untrimmed.d.ts +333 -0
- package/dist/container.d.ts +22 -2
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +235 -222
- package/dist/container.js.map +1 -1
- package/dist/containerContext.js +16 -16
- 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 +9 -11
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +5 -4
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/debugLogger.d.ts.map +1 -1
- package/dist/debugLogger.js +5 -4
- package/dist/debugLogger.js.map +1 -1
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +92 -96
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.js +14 -14
- package/dist/deltaQueue.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +6 -9
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +26 -91
- package/dist/loader.js.map +1 -1
- package/dist/location-redirection-utilities/index.d.ts +6 -0
- package/dist/location-redirection-utilities/index.d.ts.map +1 -0
- package/dist/location-redirection-utilities/index.js +11 -0
- package/dist/location-redirection-utilities/index.js.map +1 -0
- package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts +22 -0
- package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -0
- package/dist/location-redirection-utilities/resolveWithLocationRedirection.js +51 -0
- package/dist/location-redirection-utilities/resolveWithLocationRedirection.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 +1 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +3 -5
- package/dist/protocol.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts +3 -2
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +18 -11
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/utils.d.ts +23 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +11 -3
- package/dist/utils.js.map +1 -1
- package/lib/catchUpMonitor.d.ts +2 -2
- package/lib/catchUpMonitor.d.ts.map +1 -1
- package/lib/connectionManager.d.ts +2 -15
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +120 -101
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.js +9 -9
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +22 -2
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +236 -223
- package/lib/container.js.map +1 -1
- package/lib/containerContext.js +16 -16
- 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 +9 -11
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +5 -4
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/debugLogger.d.ts.map +1 -1
- package/lib/debugLogger.js +5 -4
- package/lib/debugLogger.js.map +1 -1
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +92 -96
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.js +14 -14
- package/lib/deltaQueue.js.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/loader.d.ts +6 -9
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +27 -92
- package/lib/loader.js.map +1 -1
- package/lib/location-redirection-utilities/index.d.ts +6 -0
- package/lib/location-redirection-utilities/index.d.ts.map +1 -0
- package/lib/location-redirection-utilities/index.js +6 -0
- package/lib/location-redirection-utilities/index.js.map +1 -0
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts +22 -0
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -0
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.js +46 -0
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.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 +1 -2
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +1 -3
- package/lib/protocol.js.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts +3 -2
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js +18 -11
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/lib/utils.d.ts +23 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +9 -1
- package/lib/utils.js.map +1 -1
- package/package.json +24 -26
- package/src/connectionManager.ts +69 -34
- package/src/container.ts +48 -30
- package/src/containerStorageAdapter.ts +3 -9
- package/src/contracts.ts +8 -4
- package/src/debugLogger.ts +5 -1
- package/src/deltaManager.ts +16 -31
- package/src/index.ts +5 -0
- package/src/loader.ts +31 -99
- package/src/location-redirection-utilities/index.ts +9 -0
- package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +59 -0
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +2 -6
- package/src/retriableDocumentStorageService.ts +29 -15
- package/src/utils.ts +23 -1
package/lib/connectionManager.js
CHANGED
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
+
import { LogLevel } from "@fluidframework/core-interfaces";
|
|
5
6
|
import { assert } from "@fluidframework/core-utils";
|
|
6
7
|
import { performance, TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
8
|
+
import {
|
|
9
|
+
// eslint-disable-next-line import/no-deprecated
|
|
10
|
+
DriverErrorType, } from "@fluidframework/driver-definitions";
|
|
7
11
|
import { canRetryOnError, createWriteError, createGenericNetworkError, getRetryDelayFromError, logNetworkFailure, isRuntimeMessage, calculateMaxWaitTime, } from "@fluidframework/driver-utils";
|
|
8
12
|
import { MessageType, ScopeType, } from "@fluidframework/protocol-definitions";
|
|
9
|
-
import { formatTick, GenericError, normalizeError, UsageError, } from "@fluidframework/telemetry-utils";
|
|
13
|
+
import { formatTick, GenericError, isFluidError, normalizeError, UsageError, } from "@fluidframework/telemetry-utils";
|
|
10
14
|
import { ReconnectMode, } from "./contracts";
|
|
11
15
|
import { DeltaQueue } from "./deltaQueue";
|
|
12
16
|
import { SignalType } from "./protocol";
|
|
@@ -33,9 +37,15 @@ const clientNoDeltaStream = {
|
|
|
33
37
|
};
|
|
34
38
|
const clientIdNoDeltaStream = "storage-only client";
|
|
35
39
|
class NoDeltaStream extends TypedEventEmitter {
|
|
36
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Connection which is not connected to socket.
|
|
42
|
+
* @param storageOnlyReason - Reason on why the connection to delta stream is not allowed.
|
|
43
|
+
* @param readonlyConnectionReason - reason/error if any which lead to using NoDeltaStream.
|
|
44
|
+
*/
|
|
45
|
+
constructor(storageOnlyReason, readonlyConnectionReason) {
|
|
37
46
|
super();
|
|
38
47
|
this.storageOnlyReason = storageOnlyReason;
|
|
48
|
+
this.readonlyConnectionReason = readonlyConnectionReason;
|
|
39
49
|
this.clientId = clientIdNoDeltaStream;
|
|
40
50
|
this.claims = {
|
|
41
51
|
scopes: [ScopeType.DocRead],
|
|
@@ -98,67 +108,6 @@ const waitForOnline = async () => {
|
|
|
98
108
|
* Exposes various controls to influence this process, including manual reconnects, forced read-only mode, etc.
|
|
99
109
|
*/
|
|
100
110
|
export class ConnectionManager {
|
|
101
|
-
constructor(serviceProvider, containerDirty, client, reconnectAllowed, logger, props) {
|
|
102
|
-
this.serviceProvider = serviceProvider;
|
|
103
|
-
this.containerDirty = containerDirty;
|
|
104
|
-
this.client = client;
|
|
105
|
-
this.logger = logger;
|
|
106
|
-
this.props = props;
|
|
107
|
-
/** tracks host requiring read-only mode. */
|
|
108
|
-
this._forceReadonly = false;
|
|
109
|
-
/** True if there is pending (async) reconnection from "read" to "write" */
|
|
110
|
-
this.pendingReconnect = false;
|
|
111
|
-
this.clientSequenceNumber = 0;
|
|
112
|
-
this.clientSequenceNumberObserved = 0;
|
|
113
|
-
/** Counts the number of non-runtime ops sent by the client which may not be acked. */
|
|
114
|
-
this.localOpsToIgnore = 0;
|
|
115
|
-
this.connectFirstConnection = true;
|
|
116
|
-
this._connectionVerboseProps = {};
|
|
117
|
-
this._connectionProps = {};
|
|
118
|
-
this._disposed = false;
|
|
119
|
-
this.opHandler = (documentId, messagesArg) => {
|
|
120
|
-
const messages = Array.isArray(messagesArg) ? messagesArg : [messagesArg];
|
|
121
|
-
this.props.incomingOpHandler(messages, "opHandler");
|
|
122
|
-
};
|
|
123
|
-
// Always connect in write mode after getting nacked.
|
|
124
|
-
this.nackHandler = (documentId, messages) => {
|
|
125
|
-
const message = messages[0];
|
|
126
|
-
if (this._readonlyPermissions === true) {
|
|
127
|
-
this.props.closeHandler(createWriteError("writeOnReadOnlyDocument", { driverVersion: undefined }));
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
const reconnectInfo = getNackReconnectInfo(message.content);
|
|
131
|
-
// If the nack indicates we cannot retry, then close the container outright
|
|
132
|
-
if (!reconnectInfo.canRetry) {
|
|
133
|
-
this.props.closeHandler(reconnectInfo);
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
this.reconnectOnError("write", reconnectInfo);
|
|
137
|
-
};
|
|
138
|
-
// Connection mode is always read on disconnect/error unless the system mode was write.
|
|
139
|
-
this.disconnectHandlerInternal = (disconnectReason) => {
|
|
140
|
-
// Note: we might get multiple disconnect calls on same socket, as early disconnect notification
|
|
141
|
-
// ("server_disconnect", ODSP-specific) is mapped to "disconnect"
|
|
142
|
-
this.reconnectOnError(this.defaultReconnectionMode, disconnectReason);
|
|
143
|
-
};
|
|
144
|
-
this.errorHandler = (error) => {
|
|
145
|
-
this.reconnectOnError(this.defaultReconnectionMode, error);
|
|
146
|
-
};
|
|
147
|
-
this.clientDetails = this.client.details;
|
|
148
|
-
this.defaultReconnectionMode = this.client.mode;
|
|
149
|
-
this._reconnectMode = reconnectAllowed ? ReconnectMode.Enabled : ReconnectMode.Never;
|
|
150
|
-
// Outbound message queue. The outbound queue is represented as a queue of an array of ops. Ops contained
|
|
151
|
-
// within an array *must* fit within the maxMessageSize and are guaranteed to be ordered sequentially.
|
|
152
|
-
this._outbound = new DeltaQueue((messages) => {
|
|
153
|
-
if (this.connection === undefined) {
|
|
154
|
-
throw new Error("Attempted to submit an outbound message without connection");
|
|
155
|
-
}
|
|
156
|
-
this.connection.submit(messages);
|
|
157
|
-
});
|
|
158
|
-
this._outbound.on("error", (error) => {
|
|
159
|
-
this.props.closeHandler(normalizeError(error));
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
111
|
get connectionVerboseProps() {
|
|
163
112
|
return this._connectionVerboseProps;
|
|
164
113
|
}
|
|
@@ -272,6 +221,71 @@ export class ConnectionManager {
|
|
|
272
221
|
reason,
|
|
273
222
|
};
|
|
274
223
|
}
|
|
224
|
+
constructor(serviceProvider, containerDirty, client, reconnectAllowed, logger, props) {
|
|
225
|
+
this.serviceProvider = serviceProvider;
|
|
226
|
+
this.containerDirty = containerDirty;
|
|
227
|
+
this.client = client;
|
|
228
|
+
this.logger = logger;
|
|
229
|
+
this.props = props;
|
|
230
|
+
/** tracks host requiring read-only mode. */
|
|
231
|
+
this._forceReadonly = false;
|
|
232
|
+
/** True if there is pending (async) reconnection from "read" to "write" */
|
|
233
|
+
this.pendingReconnect = false;
|
|
234
|
+
this.clientSequenceNumber = 0;
|
|
235
|
+
this.clientSequenceNumberObserved = 0;
|
|
236
|
+
/** Counts the number of non-runtime ops sent by the client which may not be acked. */
|
|
237
|
+
this.localOpsToIgnore = 0;
|
|
238
|
+
this.connectFirstConnection = true;
|
|
239
|
+
this._connectionVerboseProps = {};
|
|
240
|
+
this._connectionProps = {};
|
|
241
|
+
this._disposed = false;
|
|
242
|
+
this.opHandler = (documentId, messagesArg) => {
|
|
243
|
+
const messages = Array.isArray(messagesArg) ? messagesArg : [messagesArg];
|
|
244
|
+
this.props.incomingOpHandler(messages, "opHandler");
|
|
245
|
+
};
|
|
246
|
+
this.signalHandler = (signalsArg) => {
|
|
247
|
+
const signals = Array.isArray(signalsArg) ? signalsArg : [signalsArg];
|
|
248
|
+
this.props.signalHandler(signals);
|
|
249
|
+
};
|
|
250
|
+
// Always connect in write mode after getting nacked.
|
|
251
|
+
this.nackHandler = (documentId, messages) => {
|
|
252
|
+
const message = messages[0];
|
|
253
|
+
if (this._readonlyPermissions === true) {
|
|
254
|
+
this.props.closeHandler(createWriteError("writeOnReadOnlyDocument", { driverVersion: undefined }));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const reconnectInfo = getNackReconnectInfo(message.content);
|
|
258
|
+
// If the nack indicates we cannot retry, then close the container outright
|
|
259
|
+
if (!reconnectInfo.canRetry) {
|
|
260
|
+
this.props.closeHandler(reconnectInfo);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
this.reconnectOnError("write", reconnectInfo);
|
|
264
|
+
};
|
|
265
|
+
// Connection mode is always read on disconnect/error unless the system mode was write.
|
|
266
|
+
this.disconnectHandlerInternal = (disconnectReason) => {
|
|
267
|
+
// Note: we might get multiple disconnect calls on same socket, as early disconnect notification
|
|
268
|
+
// ("server_disconnect", ODSP-specific) is mapped to "disconnect"
|
|
269
|
+
this.reconnectOnError(this.defaultReconnectionMode, disconnectReason);
|
|
270
|
+
};
|
|
271
|
+
this.errorHandler = (error) => {
|
|
272
|
+
this.reconnectOnError(this.defaultReconnectionMode, error);
|
|
273
|
+
};
|
|
274
|
+
this.clientDetails = this.client.details;
|
|
275
|
+
this.defaultReconnectionMode = this.client.mode;
|
|
276
|
+
this._reconnectMode = reconnectAllowed ? ReconnectMode.Enabled : ReconnectMode.Never;
|
|
277
|
+
// Outbound message queue. The outbound queue is represented as a queue of an array of ops. Ops contained
|
|
278
|
+
// within an array *must* fit within the maxMessageSize and are guaranteed to be ordered sequentially.
|
|
279
|
+
this._outbound = new DeltaQueue((messages) => {
|
|
280
|
+
if (this.connection === undefined) {
|
|
281
|
+
throw new Error("Attempted to submit an outbound message without connection");
|
|
282
|
+
}
|
|
283
|
+
this.connection.submit(messages);
|
|
284
|
+
});
|
|
285
|
+
this._outbound.on("error", (error) => {
|
|
286
|
+
this.props.closeHandler(normalizeError(error));
|
|
287
|
+
});
|
|
288
|
+
}
|
|
275
289
|
dispose(error, switchToReadonly = true) {
|
|
276
290
|
if (this._disposed) {
|
|
277
291
|
return;
|
|
@@ -291,7 +305,7 @@ export class ConnectionManager {
|
|
|
291
305
|
// Notify everyone we are in read-only state.
|
|
292
306
|
// Useful for data stores in case we hit some critical error,
|
|
293
307
|
// to switch to a mode where user edits are not accepted
|
|
294
|
-
this.set_readonlyPermissions(true, oldReadonlyValue);
|
|
308
|
+
this.set_readonlyPermissions(true, oldReadonlyValue, disconnectReason);
|
|
295
309
|
}
|
|
296
310
|
}
|
|
297
311
|
/**
|
|
@@ -307,21 +321,7 @@ export class ConnectionManager {
|
|
|
307
321
|
}
|
|
308
322
|
}
|
|
309
323
|
/**
|
|
310
|
-
*
|
|
311
|
-
* Hosts may have read only views, indicating to data stores that no edits are allowed.
|
|
312
|
-
* This is independent from this._readonlyPermissions (permissions) and this.connectionMode
|
|
313
|
-
* (server can return "write" mode even when asked for "read")
|
|
314
|
-
* Leveraging same "readonly" event as runtime & data stores should behave the same in such case
|
|
315
|
-
* as in read-only permissions.
|
|
316
|
-
* But this.active can be used by some DDSes to figure out if ops can be sent
|
|
317
|
-
* (for example, read-only view still participates in code proposals / upgrades decisions)
|
|
318
|
-
*
|
|
319
|
-
* Forcing Readonly does not prevent DDS from generating ops. It is up to user code to honour
|
|
320
|
-
* the readonly flag. If ops are generated, they will accumulate locally and not be sent. If
|
|
321
|
-
* there are pending in the outbound queue, it will stop sending until force readonly is
|
|
322
|
-
* cleared.
|
|
323
|
-
*
|
|
324
|
-
* @param readonly - set or clear force readonly.
|
|
324
|
+
* {@inheritDoc Container.forceReadonly}
|
|
325
325
|
*/
|
|
326
326
|
forceReadonly(readonly) {
|
|
327
327
|
if (readonly !== this._forceReadonly) {
|
|
@@ -355,10 +355,10 @@ export class ConnectionManager {
|
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
357
|
}
|
|
358
|
-
set_readonlyPermissions(newReadonlyValue, oldReadonlyValue) {
|
|
358
|
+
set_readonlyPermissions(newReadonlyValue, oldReadonlyValue, readonlyConnectionReason) {
|
|
359
359
|
this._readonlyPermissions = newReadonlyValue;
|
|
360
360
|
if (oldReadonlyValue !== this.readonly) {
|
|
361
|
-
this.props.readonlyChangeHandler(this.readonly);
|
|
361
|
+
this.props.readonlyChangeHandler(this.readonly, readonlyConnectionReason);
|
|
362
362
|
}
|
|
363
363
|
}
|
|
364
364
|
connect(reason, connectionMode) {
|
|
@@ -436,10 +436,29 @@ export class ConnectionManager {
|
|
|
436
436
|
this.logger.sendTelemetryEvent({ eventName: "ReceivedClosedConnection" });
|
|
437
437
|
connection = undefined;
|
|
438
438
|
}
|
|
439
|
+
this.logger.sendTelemetryEvent({
|
|
440
|
+
eventName: "ConnectionReceived",
|
|
441
|
+
connected: connection !== undefined && connection.disposed === false,
|
|
442
|
+
}, undefined, LogLevel.verbose);
|
|
439
443
|
}
|
|
440
444
|
catch (origError) {
|
|
441
445
|
if (isDeltaStreamConnectionForbiddenError(origError)) {
|
|
442
|
-
connection = new NoDeltaStream(origError.storageOnlyReason
|
|
446
|
+
connection = new NoDeltaStream(origError.storageOnlyReason, {
|
|
447
|
+
text: origError.message,
|
|
448
|
+
error: origError,
|
|
449
|
+
});
|
|
450
|
+
requestedMode = "read";
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
else if (isFluidError(origError) &&
|
|
454
|
+
// eslint-disable-next-line import/no-deprecated
|
|
455
|
+
origError.errorType === DriverErrorType.outOfStorageError) {
|
|
456
|
+
// If we get out of storage error from calling joinsession, then use the NoDeltaStream object so
|
|
457
|
+
// that user can at least load the container.
|
|
458
|
+
connection = new NoDeltaStream(undefined, {
|
|
459
|
+
text: origError.message,
|
|
460
|
+
error: origError,
|
|
461
|
+
});
|
|
443
462
|
requestedMode = "read";
|
|
444
463
|
break;
|
|
445
464
|
}
|
|
@@ -496,8 +515,8 @@ export class ConnectionManager {
|
|
|
496
515
|
duration: formatTick(performance.now() - connectStartTime),
|
|
497
516
|
}, lastError);
|
|
498
517
|
}
|
|
499
|
-
// Check for abort signal after while loop as well
|
|
500
|
-
if (abortSignal.aborted === true) {
|
|
518
|
+
// Check for abort signal after while loop as well or we've been disposed
|
|
519
|
+
if (abortSignal.aborted === true || this._disposed) {
|
|
501
520
|
connection.dispose();
|
|
502
521
|
this.logger.sendTelemetryEvent({
|
|
503
522
|
eventName: "ConnectionAttemptCancelled",
|
|
@@ -547,7 +566,7 @@ export class ConnectionManager {
|
|
|
547
566
|
this.connection = undefined;
|
|
548
567
|
// Remove listeners first so we don't try to retrigger this flow accidentally through reconnectOnError
|
|
549
568
|
connection.off("op", this.opHandler);
|
|
550
|
-
connection.off("signal", this.
|
|
569
|
+
connection.off("signal", this.signalHandler);
|
|
551
570
|
connection.off("nack", this.nackHandler);
|
|
552
571
|
connection.off("disconnect", this.disconnectHandlerInternal);
|
|
553
572
|
connection.off("error", this.errorHandler);
|
|
@@ -600,7 +619,7 @@ export class ConnectionManager {
|
|
|
600
619
|
// removed after those packages have released and become ubiquitous.
|
|
601
620
|
assert(requestedMode === "read" || readonly === (this.connectionMode === "read"), 0x0e7 /* "claims/connectionMode mismatch" */);
|
|
602
621
|
assert(!readonly || this.connectionMode === "read", 0x0e8 /* "readonly perf with write connection" */);
|
|
603
|
-
this.set_readonlyPermissions(readonly, oldReadonlyValue);
|
|
622
|
+
this.set_readonlyPermissions(readonly, oldReadonlyValue, isNoDeltaStreamConnection(connection) ? connection.readonlyConnectionReason : undefined);
|
|
604
623
|
if (this._disposed) {
|
|
605
624
|
// Raise proper events, Log telemetry event and close connection.
|
|
606
625
|
this.disconnectFromDeltaStream({ text: "ConnectionManager already closed" });
|
|
@@ -608,7 +627,7 @@ export class ConnectionManager {
|
|
|
608
627
|
}
|
|
609
628
|
this._outbound.resume();
|
|
610
629
|
connection.on("op", this.opHandler);
|
|
611
|
-
connection.on("signal", this.
|
|
630
|
+
connection.on("signal", this.signalHandler);
|
|
612
631
|
connection.on("nack", this.nackHandler);
|
|
613
632
|
connection.on("disconnect", this.disconnectHandlerInternal);
|
|
614
633
|
connection.on("error", this.errorHandler);
|
|
@@ -659,26 +678,26 @@ export class ConnectionManager {
|
|
|
659
678
|
type: SignalType.Clear,
|
|
660
679
|
}),
|
|
661
680
|
};
|
|
662
|
-
this
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
681
|
+
// list of signals to process due to this new connection
|
|
682
|
+
let signalsToProcess = [clearSignal];
|
|
683
|
+
const clientJoinSignals = (connection.initialClients ?? []).map((priorClient) => ({
|
|
684
|
+
clientId: null,
|
|
685
|
+
content: JSON.stringify({
|
|
686
|
+
type: SignalType.ClientJoin,
|
|
687
|
+
content: priorClient, // ISignalClient
|
|
688
|
+
}),
|
|
689
|
+
}));
|
|
690
|
+
if (clientJoinSignals.length > 0) {
|
|
691
|
+
signalsToProcess = signalsToProcess.concat(clientJoinSignals);
|
|
672
692
|
}
|
|
673
693
|
// Unfortunately, there is no defined order between initialSignals (including join & leave signals)
|
|
674
694
|
// and connection.initialClients. In practice, connection.initialSignals quite often contains join signal
|
|
675
695
|
// for "self" and connection.initialClients does not contain "self", so we have to process them after
|
|
676
696
|
// "clear" signal above.
|
|
677
|
-
if (connection.initialSignals !== undefined) {
|
|
678
|
-
|
|
679
|
-
this.props.signalHandler(signal);
|
|
680
|
-
}
|
|
697
|
+
if (connection.initialSignals !== undefined && connection.initialSignals.length > 0) {
|
|
698
|
+
signalsToProcess = signalsToProcess.concat(connection.initialSignals);
|
|
681
699
|
}
|
|
700
|
+
this.props.signalHandler(signalsToProcess);
|
|
682
701
|
}
|
|
683
702
|
/**
|
|
684
703
|
* Disconnect the current connection and reconnect. Closes the container if it fails.
|