@fluidframework/container-loader 2.0.0-dev.6.4.0.192049 → 2.0.0-dev.7.2.0.203917
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 +110 -98
- 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 +113 -99
- 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 +58 -31
- 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
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { assert } from "@fluidframework/core-utils";
|
|
6
6
|
import { performance, TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
7
|
+
import {
|
|
8
|
+
// eslint-disable-next-line import/no-deprecated
|
|
9
|
+
DriverErrorType, } from "@fluidframework/driver-definitions";
|
|
7
10
|
import { canRetryOnError, createWriteError, createGenericNetworkError, getRetryDelayFromError, logNetworkFailure, isRuntimeMessage, calculateMaxWaitTime, } from "@fluidframework/driver-utils";
|
|
8
11
|
import { MessageType, ScopeType, } from "@fluidframework/protocol-definitions";
|
|
9
|
-
import { formatTick, GenericError, normalizeError, UsageError, } from "@fluidframework/telemetry-utils";
|
|
12
|
+
import { formatTick, GenericError, isFluidError, normalizeError, UsageError, } from "@fluidframework/telemetry-utils";
|
|
10
13
|
import { ReconnectMode, } from "./contracts";
|
|
11
14
|
import { DeltaQueue } from "./deltaQueue";
|
|
12
15
|
import { SignalType } from "./protocol";
|
|
@@ -33,9 +36,15 @@ const clientNoDeltaStream = {
|
|
|
33
36
|
};
|
|
34
37
|
const clientIdNoDeltaStream = "storage-only client";
|
|
35
38
|
class NoDeltaStream extends TypedEventEmitter {
|
|
36
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Connection which is not connected to socket.
|
|
41
|
+
* @param storageOnlyReason - Reason on why the connection to delta stream is not allowed.
|
|
42
|
+
* @param readonlyConnectionReason - reason/error if any which lead to using NoDeltaStream.
|
|
43
|
+
*/
|
|
44
|
+
constructor(storageOnlyReason, readonlyConnectionReason) {
|
|
37
45
|
super();
|
|
38
46
|
this.storageOnlyReason = storageOnlyReason;
|
|
47
|
+
this.readonlyConnectionReason = readonlyConnectionReason;
|
|
39
48
|
this.clientId = clientIdNoDeltaStream;
|
|
40
49
|
this.claims = {
|
|
41
50
|
scopes: [ScopeType.DocRead],
|
|
@@ -98,67 +107,6 @@ const waitForOnline = async () => {
|
|
|
98
107
|
* Exposes various controls to influence this process, including manual reconnects, forced read-only mode, etc.
|
|
99
108
|
*/
|
|
100
109
|
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
110
|
get connectionVerboseProps() {
|
|
163
111
|
return this._connectionVerboseProps;
|
|
164
112
|
}
|
|
@@ -272,6 +220,71 @@ export class ConnectionManager {
|
|
|
272
220
|
reason,
|
|
273
221
|
};
|
|
274
222
|
}
|
|
223
|
+
constructor(serviceProvider, containerDirty, client, reconnectAllowed, logger, props) {
|
|
224
|
+
this.serviceProvider = serviceProvider;
|
|
225
|
+
this.containerDirty = containerDirty;
|
|
226
|
+
this.client = client;
|
|
227
|
+
this.logger = logger;
|
|
228
|
+
this.props = props;
|
|
229
|
+
/** tracks host requiring read-only mode. */
|
|
230
|
+
this._forceReadonly = false;
|
|
231
|
+
/** True if there is pending (async) reconnection from "read" to "write" */
|
|
232
|
+
this.pendingReconnect = false;
|
|
233
|
+
this.clientSequenceNumber = 0;
|
|
234
|
+
this.clientSequenceNumberObserved = 0;
|
|
235
|
+
/** Counts the number of non-runtime ops sent by the client which may not be acked. */
|
|
236
|
+
this.localOpsToIgnore = 0;
|
|
237
|
+
this.connectFirstConnection = true;
|
|
238
|
+
this._connectionVerboseProps = {};
|
|
239
|
+
this._connectionProps = {};
|
|
240
|
+
this._disposed = false;
|
|
241
|
+
this.opHandler = (documentId, messagesArg) => {
|
|
242
|
+
const messages = Array.isArray(messagesArg) ? messagesArg : [messagesArg];
|
|
243
|
+
this.props.incomingOpHandler(messages, "opHandler");
|
|
244
|
+
};
|
|
245
|
+
this.signalHandler = (signalsArg) => {
|
|
246
|
+
const signals = Array.isArray(signalsArg) ? signalsArg : [signalsArg];
|
|
247
|
+
this.props.signalHandler(signals);
|
|
248
|
+
};
|
|
249
|
+
// Always connect in write mode after getting nacked.
|
|
250
|
+
this.nackHandler = (documentId, messages) => {
|
|
251
|
+
const message = messages[0];
|
|
252
|
+
if (this._readonlyPermissions === true) {
|
|
253
|
+
this.props.closeHandler(createWriteError("writeOnReadOnlyDocument", { driverVersion: undefined }));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const reconnectInfo = getNackReconnectInfo(message.content);
|
|
257
|
+
// If the nack indicates we cannot retry, then close the container outright
|
|
258
|
+
if (!reconnectInfo.canRetry) {
|
|
259
|
+
this.props.closeHandler(reconnectInfo);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
this.reconnectOnError("write", reconnectInfo);
|
|
263
|
+
};
|
|
264
|
+
// Connection mode is always read on disconnect/error unless the system mode was write.
|
|
265
|
+
this.disconnectHandlerInternal = (disconnectReason) => {
|
|
266
|
+
// Note: we might get multiple disconnect calls on same socket, as early disconnect notification
|
|
267
|
+
// ("server_disconnect", ODSP-specific) is mapped to "disconnect"
|
|
268
|
+
this.reconnectOnError(this.defaultReconnectionMode, disconnectReason);
|
|
269
|
+
};
|
|
270
|
+
this.errorHandler = (error) => {
|
|
271
|
+
this.reconnectOnError(this.defaultReconnectionMode, error);
|
|
272
|
+
};
|
|
273
|
+
this.clientDetails = this.client.details;
|
|
274
|
+
this.defaultReconnectionMode = this.client.mode;
|
|
275
|
+
this._reconnectMode = reconnectAllowed ? ReconnectMode.Enabled : ReconnectMode.Never;
|
|
276
|
+
// Outbound message queue. The outbound queue is represented as a queue of an array of ops. Ops contained
|
|
277
|
+
// within an array *must* fit within the maxMessageSize and are guaranteed to be ordered sequentially.
|
|
278
|
+
this._outbound = new DeltaQueue((messages) => {
|
|
279
|
+
if (this.connection === undefined) {
|
|
280
|
+
throw new Error("Attempted to submit an outbound message without connection");
|
|
281
|
+
}
|
|
282
|
+
this.connection.submit(messages);
|
|
283
|
+
});
|
|
284
|
+
this._outbound.on("error", (error) => {
|
|
285
|
+
this.props.closeHandler(normalizeError(error));
|
|
286
|
+
});
|
|
287
|
+
}
|
|
275
288
|
dispose(error, switchToReadonly = true) {
|
|
276
289
|
if (this._disposed) {
|
|
277
290
|
return;
|
|
@@ -291,7 +304,7 @@ export class ConnectionManager {
|
|
|
291
304
|
// Notify everyone we are in read-only state.
|
|
292
305
|
// Useful for data stores in case we hit some critical error,
|
|
293
306
|
// to switch to a mode where user edits are not accepted
|
|
294
|
-
this.set_readonlyPermissions(true, oldReadonlyValue);
|
|
307
|
+
this.set_readonlyPermissions(true, oldReadonlyValue, disconnectReason);
|
|
295
308
|
}
|
|
296
309
|
}
|
|
297
310
|
/**
|
|
@@ -307,21 +320,7 @@ export class ConnectionManager {
|
|
|
307
320
|
}
|
|
308
321
|
}
|
|
309
322
|
/**
|
|
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.
|
|
323
|
+
* {@inheritDoc Container.forceReadonly}
|
|
325
324
|
*/
|
|
326
325
|
forceReadonly(readonly) {
|
|
327
326
|
if (readonly !== this._forceReadonly) {
|
|
@@ -355,10 +354,10 @@ export class ConnectionManager {
|
|
|
355
354
|
}
|
|
356
355
|
}
|
|
357
356
|
}
|
|
358
|
-
set_readonlyPermissions(newReadonlyValue, oldReadonlyValue) {
|
|
357
|
+
set_readonlyPermissions(newReadonlyValue, oldReadonlyValue, readonlyConnectionReason) {
|
|
359
358
|
this._readonlyPermissions = newReadonlyValue;
|
|
360
359
|
if (oldReadonlyValue !== this.readonly) {
|
|
361
|
-
this.props.readonlyChangeHandler(this.readonly);
|
|
360
|
+
this.props.readonlyChangeHandler(this.readonly, readonlyConnectionReason);
|
|
362
361
|
}
|
|
363
362
|
}
|
|
364
363
|
connect(reason, connectionMode) {
|
|
@@ -439,7 +438,22 @@ export class ConnectionManager {
|
|
|
439
438
|
}
|
|
440
439
|
catch (origError) {
|
|
441
440
|
if (isDeltaStreamConnectionForbiddenError(origError)) {
|
|
442
|
-
connection = new NoDeltaStream(origError.storageOnlyReason
|
|
441
|
+
connection = new NoDeltaStream(origError.storageOnlyReason, {
|
|
442
|
+
text: origError.message,
|
|
443
|
+
error: origError,
|
|
444
|
+
});
|
|
445
|
+
requestedMode = "read";
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
else if (isFluidError(origError) &&
|
|
449
|
+
// eslint-disable-next-line import/no-deprecated
|
|
450
|
+
origError.errorType === DriverErrorType.outOfStorageError) {
|
|
451
|
+
// If we get out of storage error from calling joinsession, then use the NoDeltaStream object so
|
|
452
|
+
// that user can at least load the container.
|
|
453
|
+
connection = new NoDeltaStream(undefined, {
|
|
454
|
+
text: origError.message,
|
|
455
|
+
error: origError,
|
|
456
|
+
});
|
|
443
457
|
requestedMode = "read";
|
|
444
458
|
break;
|
|
445
459
|
}
|
|
@@ -547,7 +561,7 @@ export class ConnectionManager {
|
|
|
547
561
|
this.connection = undefined;
|
|
548
562
|
// Remove listeners first so we don't try to retrigger this flow accidentally through reconnectOnError
|
|
549
563
|
connection.off("op", this.opHandler);
|
|
550
|
-
connection.off("signal", this.
|
|
564
|
+
connection.off("signal", this.signalHandler);
|
|
551
565
|
connection.off("nack", this.nackHandler);
|
|
552
566
|
connection.off("disconnect", this.disconnectHandlerInternal);
|
|
553
567
|
connection.off("error", this.errorHandler);
|
|
@@ -600,7 +614,7 @@ export class ConnectionManager {
|
|
|
600
614
|
// removed after those packages have released and become ubiquitous.
|
|
601
615
|
assert(requestedMode === "read" || readonly === (this.connectionMode === "read"), 0x0e7 /* "claims/connectionMode mismatch" */);
|
|
602
616
|
assert(!readonly || this.connectionMode === "read", 0x0e8 /* "readonly perf with write connection" */);
|
|
603
|
-
this.set_readonlyPermissions(readonly, oldReadonlyValue);
|
|
617
|
+
this.set_readonlyPermissions(readonly, oldReadonlyValue, isNoDeltaStreamConnection(connection) ? connection.readonlyConnectionReason : undefined);
|
|
604
618
|
if (this._disposed) {
|
|
605
619
|
// Raise proper events, Log telemetry event and close connection.
|
|
606
620
|
this.disconnectFromDeltaStream({ text: "ConnectionManager already closed" });
|
|
@@ -608,7 +622,7 @@ export class ConnectionManager {
|
|
|
608
622
|
}
|
|
609
623
|
this._outbound.resume();
|
|
610
624
|
connection.on("op", this.opHandler);
|
|
611
|
-
connection.on("signal", this.
|
|
625
|
+
connection.on("signal", this.signalHandler);
|
|
612
626
|
connection.on("nack", this.nackHandler);
|
|
613
627
|
connection.on("disconnect", this.disconnectHandlerInternal);
|
|
614
628
|
connection.on("error", this.errorHandler);
|
|
@@ -659,26 +673,26 @@ export class ConnectionManager {
|
|
|
659
673
|
type: SignalType.Clear,
|
|
660
674
|
}),
|
|
661
675
|
};
|
|
662
|
-
this
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
676
|
+
// list of signals to process due to this new connection
|
|
677
|
+
let signalsToProcess = [clearSignal];
|
|
678
|
+
const clientJoinSignals = (connection.initialClients ?? []).map((priorClient) => ({
|
|
679
|
+
clientId: null,
|
|
680
|
+
content: JSON.stringify({
|
|
681
|
+
type: SignalType.ClientJoin,
|
|
682
|
+
content: priorClient, // ISignalClient
|
|
683
|
+
}),
|
|
684
|
+
}));
|
|
685
|
+
if (clientJoinSignals.length > 0) {
|
|
686
|
+
signalsToProcess = signalsToProcess.concat(clientJoinSignals);
|
|
672
687
|
}
|
|
673
688
|
// Unfortunately, there is no defined order between initialSignals (including join & leave signals)
|
|
674
689
|
// and connection.initialClients. In practice, connection.initialSignals quite often contains join signal
|
|
675
690
|
// for "self" and connection.initialClients does not contain "self", so we have to process them after
|
|
676
691
|
// "clear" signal above.
|
|
677
|
-
if (connection.initialSignals !== undefined) {
|
|
678
|
-
|
|
679
|
-
this.props.signalHandler(signal);
|
|
680
|
-
}
|
|
692
|
+
if (connection.initialSignals !== undefined && connection.initialSignals.length > 0) {
|
|
693
|
+
signalsToProcess = signalsToProcess.concat(connection.initialSignals);
|
|
681
694
|
}
|
|
695
|
+
this.props.signalHandler(signalsToProcess);
|
|
682
696
|
}
|
|
683
697
|
/**
|
|
684
698
|
* Disconnect the current connection and reconnect. Closes the container if it fails.
|