@fluidframework/driver-base 0.56.5 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,8 @@
4
4
  */
5
5
  /// <reference types="@types/socket.io-client" />
6
6
  import { BatchManager, TypedEventEmitter } from "@fluidframework/common-utils";
7
- import { IDocumentDeltaConnection, IDocumentDeltaConnectionEvents, DriverError } from "@fluidframework/driver-definitions";
7
+ import { IDocumentDeltaConnection, IDocumentDeltaConnectionEvents } from "@fluidframework/driver-definitions";
8
+ import { IAnyDriverError } from "@fluidframework/driver-utils";
8
9
  import { ConnectionMode, IClientConfiguration, IConnect, IConnected, IDocumentMessage, ISequencedDocumentMessage, ISignalClient, ISignalMessage, ITokenClaims } from "@fluidframework/protocol-definitions";
9
10
  import { IDisposable, ITelemetryLogger } from "@fluidframework/common-definitions";
10
11
  /**
@@ -13,6 +14,7 @@ import { IDisposable, ITelemetryLogger } from "@fluidframework/common-definition
13
14
  export declare class DocumentDeltaConnection extends TypedEventEmitter<IDocumentDeltaConnectionEvents> implements IDocumentDeltaConnection, IDisposable {
14
15
  protected readonly socket: SocketIOClient.Socket;
15
16
  documentId: string;
17
+ private readonly enableLongPollingDowngrades;
16
18
  static readonly eventsToForward: string[];
17
19
  static readonly eventsAlwaysForwarded: string[];
18
20
  /**
@@ -33,6 +35,7 @@ export declare class DocumentDeltaConnection extends TypedEventEmitter<IDocument
33
35
  private socketConnectionTimeout;
34
36
  protected readonly submitManager: BatchManager<IDocumentMessage[]>;
35
37
  private _details;
38
+ private reconnectAttempts;
36
39
  private readonly connectionListeners;
37
40
  private readonly trackedListeners;
38
41
  protected get hasDetails(): boolean;
@@ -52,8 +55,10 @@ export declare class DocumentDeltaConnection extends TypedEventEmitter<IDocument
52
55
  /**
53
56
  * @param socket - websocket to be used
54
57
  * @param documentId - ID of the document
58
+ * @param logger - for reporting telemetry events
59
+ * @param enableLongPollingDowngrades - allow connection to be downgraded to long-polling on websocket failure
55
60
  */
56
- protected constructor(socket: SocketIOClient.Socket, documentId: string, logger: ITelemetryLogger);
61
+ protected constructor(socket: SocketIOClient.Socket, documentId: string, logger: ITelemetryLogger, enableLongPollingDowngrades?: boolean);
57
62
  /**
58
63
  * Get the ID of the client who is sending the message
59
64
  *
@@ -129,14 +134,14 @@ export declare class DocumentDeltaConnection extends TypedEventEmitter<IDocument
129
134
  * Disconnect from the websocket, and permanently disable this DocumentDeltaConnection.
130
135
  */
131
136
  dispose(): void;
132
- protected disposeCore(socketProtocolError: boolean, err: any): void;
137
+ protected disposeCore(socketProtocolError: boolean, err: IAnyDriverError): void;
133
138
  /**
134
139
  * Disconnect from the websocket.
135
140
  * @param socketProtocolError - true if error happened on socket / socket.io protocol level
136
141
  * (not on Fluid protocol level)
137
142
  * @param reason - reason for disconnect
138
143
  */
139
- protected disconnect(socketProtocolError: boolean, reason: any): void;
144
+ protected disconnect(socketProtocolError: boolean, reason: IAnyDriverError): void;
140
145
  protected initialize(connectMessage: IConnect, timeout: number): Promise<void>;
141
146
  protected earlyOpHandler: (documentId: string, msgs: ISequencedDocumentMessage[]) => void;
142
147
  protected earlySignalHandler: (msg: ISignalMessage) => void;
@@ -149,6 +154,6 @@ export declare class DocumentDeltaConnection extends TypedEventEmitter<IDocument
149
154
  /**
150
155
  * Error raising for socket.io issues
151
156
  */
152
- protected createErrorObject(handler: string, error?: any, canRetry?: boolean): DriverError;
157
+ protected createErrorObject(handler: string, error?: any, canRetry?: boolean): IAnyDriverError;
153
158
  }
154
159
  //# sourceMappingURL=documentDeltaConnection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"documentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/documentDeltaConnection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"documentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/documentDeltaConnection.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,8 @@ const common_utils_1 = require("@fluidframework/common-utils");
9
9
  const driver_utils_1 = require("@fluidframework/driver-utils");
10
10
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
11
11
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
12
+ // For now, this package is versioned and released in unison with the specific drivers
13
+ const packageVersion_1 = require("./packageVersion");
12
14
  // Local storage key to disable the BatchManager
13
15
  const batchManagerDisabledKey = "Fluid.Driver.BaseDocumentDeltaConnection.DisableBatchManager";
14
16
  /**
@@ -18,11 +20,14 @@ class DocumentDeltaConnection extends common_utils_1.TypedEventEmitter {
18
20
  /**
19
21
  * @param socket - websocket to be used
20
22
  * @param documentId - ID of the document
23
+ * @param logger - for reporting telemetry events
24
+ * @param enableLongPollingDowngrades - allow connection to be downgraded to long-polling on websocket failure
21
25
  */
22
- constructor(socket, documentId, logger) {
26
+ constructor(socket, documentId, logger, enableLongPollingDowngrades = false) {
23
27
  super();
24
28
  this.socket = socket;
25
29
  this.documentId = documentId;
30
+ this.enableLongPollingDowngrades = enableLongPollingDowngrades;
26
31
  // Listen for ops sent before we receive a response to connect_document
27
32
  this.queuedMessages = [];
28
33
  this.queuedSignals = [];
@@ -31,6 +36,7 @@ class DocumentDeltaConnection extends common_utils_1.TypedEventEmitter {
31
36
  * to later be retrieved via initialMessages.
32
37
  */
33
38
  this.earlyOpHandlerAttached = false;
39
+ this.reconnectAttempts = 0;
34
40
  // Listeners only needed while the connection is in progress
35
41
  this.connectionListeners = new Map();
36
42
  // Listeners used throughout the lifetime of the DocumentDeltaConnection
@@ -234,7 +240,7 @@ class DocumentDeltaConnection extends common_utils_1.TypedEventEmitter {
234
240
  */
235
241
  dispose() {
236
242
  this.disposeCore(false, // socketProtocolError
237
- driver_utils_1.createGenericNetworkError("clientClosingConnection", undefined, true /* canRetry */));
243
+ driver_utils_1.createGenericNetworkError("clientClosingConnection", undefined, { canRetry: true }, { driverVersion: packageVersion_1.pkgVersion }));
238
244
  }
239
245
  disposeCore(socketProtocolError, err) {
240
246
  // Can't check this.disposed here, as we get here on socket closure,
@@ -272,16 +278,43 @@ class DocumentDeltaConnection extends common_utils_1.TypedEventEmitter {
272
278
  };
273
279
  // Listen for connection issues
274
280
  this.addConnectionListener("connect_error", (error) => {
281
+ var _a;
282
+ let isWebSocketTransportError = false;
275
283
  try {
276
284
  const description = error === null || error === void 0 ? void 0 : error.description;
277
285
  if (description && typeof description === "object") {
286
+ if (error.type === "TransportError") {
287
+ isWebSocketTransportError = true;
288
+ }
278
289
  // That's a WebSocket. Clear it as we can't log it.
279
290
  description.target = undefined;
280
291
  }
281
292
  }
282
293
  catch (_e) { }
294
+ // Handle socket transport downgrading.
295
+ if (isWebSocketTransportError &&
296
+ this.enableLongPollingDowngrades &&
297
+ ((_a = this.socket.io.opts.transports) === null || _a === void 0 ? void 0 : _a[0]) !== "polling") {
298
+ // Downgrade transports to polling upgrade mechanism.
299
+ this.socket.io.opts.transports = ["polling", "websocket"];
300
+ // Don't alter reconnection behavior if already enabled.
301
+ if (!this.socket.io.reconnection()) {
302
+ // Allow single reconnection attempt using polling upgrade mechanism.
303
+ this.socket.io.reconnection(true);
304
+ this.socket.io.reconnectionAttempts(1);
305
+ }
306
+ }
307
+ // Allow built-in socket.io reconnection handling.
308
+ if (this.socket.io.reconnection() &&
309
+ this.reconnectAttempts < this.socket.io.reconnectionAttempts()) {
310
+ // Reconnection is enabled and maximum reconnect attempts have not been reached.
311
+ return;
312
+ }
283
313
  fail(true, this.createErrorObject("connectError", error));
284
314
  });
315
+ this.addConnectionListener("reconnect_attempt", () => {
316
+ this.reconnectAttempts++;
317
+ });
285
318
  // Listen for timeouts
286
319
  this.addConnectionListener("connect_timeout", () => {
287
320
  fail(true, this.createErrorObject("connectTimeout"));
@@ -411,7 +444,7 @@ class DocumentDeltaConnection extends common_utils_1.TypedEventEmitter {
411
444
  else {
412
445
  message = `${message}: [object omitted]`;
413
446
  }
414
- const errorObj = driver_utils_1.createGenericNetworkError(`socketError [${handler}]`, message, canRetry);
447
+ const errorObj = driver_utils_1.createGenericNetworkError(`socketError [${handler}]`, message, { canRetry }, { driverVersion: packageVersion_1.pkgVersion });
415
448
  return errorObj;
416
449
  }
417
450
  }
@@ -1 +1 @@
1
- {"version":3,"file":"documentDeltaConnection.js","sourceRoot":"","sources":["../src/documentDeltaConnection.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert, BatchManager, TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport {\n IDocumentDeltaConnection,\n IDocumentDeltaConnectionEvents,\n DriverError,\n} from \"@fluidframework/driver-definitions\";\nimport { createGenericNetworkError } from \"@fluidframework/driver-utils\";\nimport {\n ConnectionMode,\n IClientConfiguration,\n IConnect,\n IConnected,\n IDocumentMessage,\n ISequencedDocumentMessage,\n ISignalClient,\n ISignalMessage,\n ITokenClaims,\n ScopeType,\n} from \"@fluidframework/protocol-definitions\";\nimport { IDisposable, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport {\n ChildLogger,\n getCircularReplacer,\n loggerToMonitoringContext,\n MonitoringContext,\n} from \"@fluidframework/telemetry-utils\";\n\n// Local storage key to disable the BatchManager\nconst batchManagerDisabledKey = \"Fluid.Driver.BaseDocumentDeltaConnection.DisableBatchManager\";\n\n/**\n * Represents a connection to a stream of delta updates\n */\nexport class DocumentDeltaConnection\n extends TypedEventEmitter<IDocumentDeltaConnectionEvents>\n implements IDocumentDeltaConnection, IDisposable {\n static readonly eventsToForward = [\"nack\", \"op\", \"signal\", \"pong\"];\n\n // WARNING: These are critical events that we can't miss, so registration for them has to be in place at all times!\n // Including before handshake is over, and after that (but before DeltaManager had a chance to put its own handlers)\n static readonly eventsAlwaysForwarded = [\"disconnect\", \"error\"];\n\n /**\n * Last known sequence number to ordering service at the time of connection\n * It may lap actual last sequence number (quite a bit, if container is very active).\n * But it's best information for client to figure out how far it is behind, at least\n * for \"read\" connections. \"write\" connections may use own \"join\" op to similar information,\n * that is likely to be more up-to-date.\n */\n public checkpointSequenceNumber: number | undefined;\n\n // Listen for ops sent before we receive a response to connect_document\n protected readonly queuedMessages: ISequencedDocumentMessage[] = [];\n protected readonly queuedSignals: ISignalMessage[] = [];\n /**\n * A flag to indicate whether we have our handler attached. If it's attached, we're queueing incoming ops\n * to later be retrieved via initialMessages.\n */\n private earlyOpHandlerAttached: boolean = false;\n\n private socketConnectionTimeout: ReturnType<typeof setTimeout> | undefined;\n\n protected readonly submitManager: BatchManager<IDocumentMessage[]>;\n\n private _details: IConnected | undefined;\n\n // Listeners only needed while the connection is in progress\n private readonly connectionListeners: Map<string, (...args: any[]) => void> = new Map();\n // Listeners used throughout the lifetime of the DocumentDeltaConnection\n private readonly trackedListeners: Map<string, (...args: any[]) => void> = new Map();\n\n protected get hasDetails(): boolean {\n return !!this._details;\n }\n\n public get disposed() {\n assert(this._disposed || this.socket.connected, 0x244 /* \"Socket is closed, but connection is not!\" */);\n return this._disposed;\n }\n /**\n * Flag to indicate whether the DocumentDeltaConnection is expected to still be capable of sending messages.\n * After disconnection, we flip this to prevent any stale messages from being emitted.\n */\n protected _disposed: boolean = false;\n private readonly mc: MonitoringContext;\n protected readonly isBatchManagerDisabled: boolean = false;\n /**\n * @deprecated - Implementors should manage their own logger or monitoring context\n */\n protected get logger(): ITelemetryLogger {\n return this.mc.logger;\n }\n\n public get details(): IConnected {\n if (!this._details) {\n throw new Error(\"Internal error: calling method before _details is initialized!\");\n }\n return this._details;\n }\n\n /**\n * @param socket - websocket to be used\n * @param documentId - ID of the document\n */\n protected constructor(\n protected readonly socket: SocketIOClient.Socket,\n public documentId: string,\n logger: ITelemetryLogger,\n ) {\n super();\n\n this.mc = loggerToMonitoringContext(\n ChildLogger.create(logger, \"DeltaConnection\"));\n\n this.submitManager = new BatchManager<IDocumentMessage[]>(\n (submitType, work) => this.emitMessages(submitType, work));\n\n this.on(\"newListener\", (event, listener) => {\n assert(!this.disposed, 0x20a /* \"register for event on disposed object\" */);\n\n // Some events are already forwarded - see this.addTrackedListener() calls in initialize().\n if (DocumentDeltaConnection.eventsAlwaysForwarded.includes(event)) {\n assert(this.trackedListeners.has(event), 0x245 /* \"tracked listener\" */);\n return;\n }\n\n if (!DocumentDeltaConnection.eventsToForward.includes(event)) {\n throw new Error(`DocumentDeltaConnection: Registering for unknown event: ${event}`);\n }\n\n // Whenever listener is added, we should subscribe on same event on socket, so these two things\n // should be in sync. This currently assumes that nobody unregisters and registers back listeners,\n // and that there are no \"internal\" listeners installed (like \"error\" case we skip above)\n // Better flow might be to always unconditionally register all handlers on successful connection,\n // though some logic (naming assert in initialMessages getter) might need to be adjusted (it becomes noop)\n assert((this.listeners(event).length !== 0) === this.trackedListeners.has(event), 0x20b /* \"mismatch\" */);\n if (!this.trackedListeners.has(event)) {\n this.addTrackedListener(\n event,\n (...args: any[]) => {\n this.emit(event, ...args);\n });\n }\n });\n\n this.isBatchManagerDisabled = this.mc.config.getBoolean(batchManagerDisabledKey) === true;\n }\n\n /**\n * Get the ID of the client who is sending the message\n *\n * @returns the client ID\n */\n public get clientId(): string {\n return this.details.clientId;\n }\n\n /**\n * Get the mode of the client\n *\n * @returns the client mode\n */\n public get mode(): ConnectionMode {\n return this.details.mode;\n }\n\n /**\n * Get the claims of the client who is sending the message\n *\n * @returns client claims\n */\n public get claims(): ITokenClaims {\n return this.details.claims;\n }\n\n /**\n * Get whether or not this is an existing document\n *\n * @returns true if the document exists\n */\n public get existing(): boolean {\n return this.details.existing;\n }\n\n /**\n * Get the maximum size of a message before chunking is required\n *\n * @returns the maximum size of a message before chunking is required\n */\n public get maxMessageSize(): number {\n return this.details.serviceConfiguration.maxMessageSize;\n }\n\n /**\n * Semver of protocol being used with the service\n */\n public get version(): string {\n return this.details.version;\n }\n\n /**\n * Configuration details provided by the service\n */\n public get serviceConfiguration(): IClientConfiguration {\n return this.details.serviceConfiguration;\n }\n\n private checkNotClosed() {\n assert(!this.disposed, 0x20c /* \"connection disposed\" */);\n }\n\n /**\n * Get messages sent during the connection\n *\n * @returns messages sent during the connection\n */\n public get initialMessages(): ISequencedDocumentMessage[] {\n this.checkNotClosed();\n\n // If we call this when the earlyOpHandler is not attached, then the queuedMessages may not include the\n // latest ops. This could possibly indicate that initialMessages was called twice.\n assert(this.earlyOpHandlerAttached, 0x08e /* \"Potentially missed initial messages\" */);\n // We will lose ops and perf will tank as we need to go to storage to become current!\n assert(this.listeners(\"op\").length !== 0, 0x08f /* \"No op handler is setup!\" */);\n\n this.removeEarlyOpHandler();\n\n if (this.queuedMessages.length > 0) {\n // Some messages were queued.\n // add them to the list of initialMessages to be processed\n this.details.initialMessages.push(...this.queuedMessages);\n this.details.initialMessages.sort((a, b) => a.sequenceNumber - b.sequenceNumber);\n this.queuedMessages.length = 0;\n }\n return this.details.initialMessages;\n }\n\n /**\n * Get signals sent during the connection\n *\n * @returns signals sent during the connection\n */\n public get initialSignals(): ISignalMessage[] {\n this.checkNotClosed();\n assert(this.listeners(\"signal\").length !== 0, 0x090 /* \"No signal handler is setup!\" */);\n\n this.removeEarlySignalHandler();\n\n if (this.queuedSignals.length > 0) {\n // Some signals were queued.\n // add them to the list of initialSignals to be processed\n this.details.initialSignals.push(...this.queuedSignals);\n this.queuedSignals.length = 0;\n }\n return this.details.initialSignals;\n }\n\n /**\n * Get initial client list\n *\n * @returns initial client list sent during the connection\n */\n public get initialClients(): ISignalClient[] {\n this.checkNotClosed();\n return this.details.initialClients;\n }\n\n protected emitMessages(type: string, messages: IDocumentMessage[][]) {\n // Although the implementation here disconnects the socket and does not reuse it, other subclasses\n // (e.g. OdspDocumentDeltaConnection) may reuse the socket. In these cases, we need to avoid emitting\n // on the still-live socket.\n if (!this.disposed) {\n this.socket.emit(type, this.clientId, messages);\n }\n }\n\n protected submitCore(type: string, messages: IDocumentMessage[]) {\n if (this.isBatchManagerDisabled) {\n this.emitMessages(type, [messages]);\n } else {\n this.submitManager.add(type, messages);\n }\n }\n\n /**\n * Submits a new delta operation to the server\n *\n * @param message - delta operation to submit\n */\n public submit(messages: IDocumentMessage[]): void {\n this.checkNotClosed();\n this.submitCore(\"submitOp\", messages);\n }\n\n /**\n * Submits a new signal to the server\n *\n * @param message - signal to submit\n */\n public submitSignal(message: IDocumentMessage): void {\n this.checkNotClosed();\n this.submitCore(\"submitSignal\", [message]);\n }\n\n /**\n * Disconnect from the websocket, and permanently disable this DocumentDeltaConnection.\n */\n public dispose() {\n this.disposeCore(\n false, // socketProtocolError\n createGenericNetworkError(\"clientClosingConnection\", undefined, true /* canRetry */));\n }\n\n protected disposeCore(socketProtocolError: boolean, err: any) {\n // Can't check this.disposed here, as we get here on socket closure,\n // so _disposed & socket.connected might be not in sync while processing\n // \"dispose\" event.\n if (this._disposed) {\n return;\n }\n\n // We set the disposed flag as a part of the contract for overriding the disconnect method. This is used by\n // DocumentDeltaConnection to determine if emitting messages (ops) on the socket is allowed, which is\n // important since OdspDocumentDeltaConnection reuses the socket rather than truly disconnecting it. Note that\n // OdspDocumentDeltaConnection may still send disconnect_document which is allowed; this is only intended\n // to prevent normal messages from being emitted.\n this._disposed = true;\n\n this.removeTrackedListeners();\n this.disconnect(socketProtocolError, err);\n }\n\n /**\n * Disconnect from the websocket.\n * @param socketProtocolError - true if error happened on socket / socket.io protocol level\n * (not on Fluid protocol level)\n * @param reason - reason for disconnect\n */\n protected disconnect(socketProtocolError: boolean, reason: any) {\n this.socket.disconnect();\n }\n\n protected async initialize(connectMessage: IConnect, timeout: number) {\n this.socket.on(\"op\", this.earlyOpHandler);\n this.socket.on(\"signal\", this.earlySignalHandler);\n this.earlyOpHandlerAttached = true;\n\n this._details = await new Promise<IConnected>((resolve, reject) => {\n const fail = (socketProtocolError: boolean, err: DriverError) => {\n this.disposeCore(socketProtocolError, err);\n reject(err);\n };\n\n // Listen for connection issues\n this.addConnectionListener(\"connect_error\", (error) => {\n try {\n const description = error?.description;\n if (description && typeof description === \"object\") {\n // That's a WebSocket. Clear it as we can't log it.\n description.target = undefined;\n }\n } catch(_e) {}\n fail(true, this.createErrorObject(\"connectError\", error));\n });\n\n // Listen for timeouts\n this.addConnectionListener(\"connect_timeout\", () => {\n fail(true, this.createErrorObject(\"connectTimeout\"));\n });\n\n this.addConnectionListener(\"connect_document_success\", (response: IConnected) => {\n // If we sent a nonce and the server supports nonces, check that the nonces match\n if (connectMessage.nonce !== undefined &&\n response.nonce !== undefined &&\n response.nonce !== connectMessage.nonce) {\n return;\n }\n\n const requestedMode = connectMessage.mode;\n const actualMode = response.mode;\n const writingPermitted = response.claims.scopes.includes(ScopeType.DocWrite);\n\n if (writingPermitted) {\n // The only time we expect a mismatch in requested/actual is if we lack write permissions\n // In this case we will get \"read\", even if we requested \"write\"\n if (actualMode !== requestedMode) {\n fail(false, this.createErrorObject(\n \"connectDocumentSuccess\",\n \"Connected in a different mode than was requested\",\n false,\n ));\n return;\n }\n } else {\n if (actualMode === \"write\") {\n fail(false, this.createErrorObject(\n \"connectDocumentSuccess\",\n \"Connected in write mode without write permissions\",\n false,\n ));\n return;\n }\n }\n\n this.checkpointSequenceNumber = response.checkpointSequenceNumber;\n\n this.removeConnectionListeners();\n resolve(response);\n });\n\n // Socket can be disconnected while waiting for Fluid protocol messages\n // (connect_document_error / connect_document_success), as well as before DeltaManager\n // had a chance to register its handlers.\n this.addTrackedListener(\"disconnect\", (reason) => {\n const err = this.createErrorObject(\"disconnect\", reason);\n this.emit(\"disconnect\", err);\n fail(true, err);\n });\n\n this.addTrackedListener(\"error\", ((error) => {\n // First, raise an error event, to give clients a chance to observe error contents\n // This includes \"Invalid namespace\" error, which we consider critical (reconnecting will not help)\n const err = this.createErrorObject(\"error\", error, error !== \"Invalid namespace\");\n this.emit(\"error\", err);\n // Disconnect socket - required if happened before initial handshake\n fail(true, err);\n }));\n\n this.addConnectionListener(\"connect_document_error\", ((error) => {\n // If we sent a nonce and the server supports nonces, check that the nonces match\n if (connectMessage.nonce !== undefined &&\n error.nonce !== undefined &&\n error.nonce !== connectMessage.nonce) {\n return;\n }\n\n // This is not an socket.io error - it's Fluid protocol error.\n // In this case fail connection and indicate that we were unable to create connection\n fail(false, this.createErrorObject(\"connectDocumentError\", error));\n }));\n\n this.socket.emit(\"connect_document\", connectMessage);\n\n // Give extra 2 seconds for handshake on top of socket connection timeout\n this.socketConnectionTimeout = setTimeout(() => {\n fail(false, this.createErrorObject(\"orderingServiceHandshakeTimeout\"));\n }, timeout + 2000);\n });\n\n assert(!this.disposed, 0x246 /* \"checking consistency of socket & _disposed flags\" */);\n }\n\n protected earlyOpHandler = (documentId: string, msgs: ISequencedDocumentMessage[]) => {\n this.queuedMessages.push(...msgs);\n };\n\n protected earlySignalHandler = (msg: ISignalMessage) => {\n this.queuedSignals.push(msg);\n };\n\n private removeEarlyOpHandler() {\n this.socket.removeListener(\"op\", this.earlyOpHandler);\n this.earlyOpHandlerAttached = false;\n }\n\n private removeEarlySignalHandler() {\n this.socket.removeListener(\"signal\", this.earlySignalHandler);\n }\n\n private addConnectionListener(event: string, listener: (...args: any[]) => void) {\n assert(!DocumentDeltaConnection.eventsAlwaysForwarded.includes(event),\n 0x247 /* \"Use addTrackedListener instead\" */);\n assert(!DocumentDeltaConnection.eventsToForward.includes(event),\n 0x248 /* \"should not subscribe to forwarded events\" */);\n this.socket.on(event, listener);\n assert(!this.connectionListeners.has(event), 0x20d /* \"double connection listener\" */);\n this.connectionListeners.set(event, listener);\n }\n\n protected addTrackedListener(event: string, listener: (...args: any[]) => void) {\n this.socket.on(event, listener);\n assert(!this.trackedListeners.has(event), 0x20e /* \"double tracked listener\" */);\n this.trackedListeners.set(event, listener);\n }\n\n private removeTrackedListeners() {\n for (const [event, listener] of this.trackedListeners.entries()) {\n this.socket.off(event, listener);\n }\n // removeTrackedListeners removes all listeners, including connection listeners\n this.removeConnectionListeners();\n\n this.removeEarlyOpHandler();\n this.removeEarlySignalHandler();\n\n this.trackedListeners.clear();\n }\n\n private removeConnectionListeners() {\n if (this.socketConnectionTimeout !== undefined) {\n clearTimeout(this.socketConnectionTimeout);\n }\n\n for (const [event, listener] of this.connectionListeners.entries()) {\n this.socket.off(event, listener);\n }\n this.connectionListeners.clear();\n }\n\n /**\n * Error raising for socket.io issues\n */\n protected createErrorObject(handler: string, error?: any, canRetry = true): DriverError {\n // Note: we suspect the incoming error object is either:\n // - a string: log it in the message (if not a string, it may contain PII but will print as [object Object])\n // - an Error object thrown by socket.io engine. Be careful with not recording PII!\n let message = `socket.io (${handler})`;\n if (typeof error !== \"object\") {\n message = `${message}: ${error}`;\n } else if (error?.type === \"TransportError\") {\n // JSON.stringify drops Error.message\n if (error?.message !== undefined) {\n message = `${message}: ${error.message}`;\n }\n // Websocket errors reported by engine.io-client.\n // They are Error objects with description containing WS error and description = \"TransportError\"\n // Please see https://github.com/socketio/engine.io-client/blob/7245b80/lib/transport.ts#L44,\n message = `${message}: ${JSON.stringify(error, getCircularReplacer())}`;\n } else {\n message = `${message}: [object omitted]`;\n }\n const errorObj = createGenericNetworkError(\n `socketError [${handler}]`,\n message,\n canRetry,\n );\n\n return errorObj;\n }\n}\n"]}
1
+ {"version":3,"file":"documentDeltaConnection.js","sourceRoot":"","sources":["../src/documentDeltaConnection.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert, BatchManager, TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport {\n IDocumentDeltaConnection,\n IDocumentDeltaConnectionEvents,\n} from \"@fluidframework/driver-definitions\";\nimport { createGenericNetworkError, IAnyDriverError } from \"@fluidframework/driver-utils\";\nimport {\n ConnectionMode,\n IClientConfiguration,\n IConnect,\n IConnected,\n IDocumentMessage,\n ISequencedDocumentMessage,\n ISignalClient,\n ISignalMessage,\n ITokenClaims,\n ScopeType,\n} from \"@fluidframework/protocol-definitions\";\nimport { IDisposable, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport {\n ChildLogger,\n getCircularReplacer,\n loggerToMonitoringContext,\n MonitoringContext,\n} from \"@fluidframework/telemetry-utils\";\n// For now, this package is versioned and released in unison with the specific drivers\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\n\n// Local storage key to disable the BatchManager\nconst batchManagerDisabledKey = \"Fluid.Driver.BaseDocumentDeltaConnection.DisableBatchManager\";\n\n/**\n * Represents a connection to a stream of delta updates\n */\nexport class DocumentDeltaConnection\n extends TypedEventEmitter<IDocumentDeltaConnectionEvents>\n implements IDocumentDeltaConnection, IDisposable {\n static readonly eventsToForward = [\"nack\", \"op\", \"signal\", \"pong\"];\n\n // WARNING: These are critical events that we can't miss, so registration for them has to be in place at all times!\n // Including before handshake is over, and after that (but before DeltaManager had a chance to put its own handlers)\n static readonly eventsAlwaysForwarded = [\"disconnect\", \"error\"];\n\n /**\n * Last known sequence number to ordering service at the time of connection\n * It may lap actual last sequence number (quite a bit, if container is very active).\n * But it's best information for client to figure out how far it is behind, at least\n * for \"read\" connections. \"write\" connections may use own \"join\" op to similar information,\n * that is likely to be more up-to-date.\n */\n public checkpointSequenceNumber: number | undefined;\n\n // Listen for ops sent before we receive a response to connect_document\n protected readonly queuedMessages: ISequencedDocumentMessage[] = [];\n protected readonly queuedSignals: ISignalMessage[] = [];\n /**\n * A flag to indicate whether we have our handler attached. If it's attached, we're queueing incoming ops\n * to later be retrieved via initialMessages.\n */\n private earlyOpHandlerAttached: boolean = false;\n\n private socketConnectionTimeout: ReturnType<typeof setTimeout> | undefined;\n\n protected readonly submitManager: BatchManager<IDocumentMessage[]>;\n\n private _details: IConnected | undefined;\n\n private reconnectAttempts: number = 0;\n\n // Listeners only needed while the connection is in progress\n private readonly connectionListeners: Map<string, (...args: any[]) => void> = new Map();\n // Listeners used throughout the lifetime of the DocumentDeltaConnection\n private readonly trackedListeners: Map<string, (...args: any[]) => void> = new Map();\n\n protected get hasDetails(): boolean {\n return !!this._details;\n }\n\n public get disposed() {\n assert(this._disposed || this.socket.connected, 0x244 /* \"Socket is closed, but connection is not!\" */);\n return this._disposed;\n }\n /**\n * Flag to indicate whether the DocumentDeltaConnection is expected to still be capable of sending messages.\n * After disconnection, we flip this to prevent any stale messages from being emitted.\n */\n protected _disposed: boolean = false;\n private readonly mc: MonitoringContext;\n protected readonly isBatchManagerDisabled: boolean = false;\n /**\n * @deprecated - Implementors should manage their own logger or monitoring context\n */\n protected get logger(): ITelemetryLogger {\n return this.mc.logger;\n }\n\n public get details(): IConnected {\n if (!this._details) {\n throw new Error(\"Internal error: calling method before _details is initialized!\");\n }\n return this._details;\n }\n\n /**\n * @param socket - websocket to be used\n * @param documentId - ID of the document\n * @param logger - for reporting telemetry events\n * @param enableLongPollingDowngrades - allow connection to be downgraded to long-polling on websocket failure\n */\n protected constructor(\n protected readonly socket: SocketIOClient.Socket,\n public documentId: string,\n logger: ITelemetryLogger,\n private readonly enableLongPollingDowngrades: boolean = false,\n ) {\n super();\n\n this.mc = loggerToMonitoringContext(\n ChildLogger.create(logger, \"DeltaConnection\"));\n\n this.submitManager = new BatchManager<IDocumentMessage[]>(\n (submitType, work) => this.emitMessages(submitType, work));\n\n this.on(\"newListener\", (event, listener) => {\n assert(!this.disposed, 0x20a /* \"register for event on disposed object\" */);\n\n // Some events are already forwarded - see this.addTrackedListener() calls in initialize().\n if (DocumentDeltaConnection.eventsAlwaysForwarded.includes(event)) {\n assert(this.trackedListeners.has(event), 0x245 /* \"tracked listener\" */);\n return;\n }\n\n if (!DocumentDeltaConnection.eventsToForward.includes(event)) {\n throw new Error(`DocumentDeltaConnection: Registering for unknown event: ${event}`);\n }\n\n // Whenever listener is added, we should subscribe on same event on socket, so these two things\n // should be in sync. This currently assumes that nobody unregisters and registers back listeners,\n // and that there are no \"internal\" listeners installed (like \"error\" case we skip above)\n // Better flow might be to always unconditionally register all handlers on successful connection,\n // though some logic (naming assert in initialMessages getter) might need to be adjusted (it becomes noop)\n assert((this.listeners(event).length !== 0) === this.trackedListeners.has(event), 0x20b /* \"mismatch\" */);\n if (!this.trackedListeners.has(event)) {\n this.addTrackedListener(\n event,\n (...args: any[]) => {\n this.emit(event, ...args);\n });\n }\n });\n\n this.isBatchManagerDisabled = this.mc.config.getBoolean(batchManagerDisabledKey) === true;\n }\n\n /**\n * Get the ID of the client who is sending the message\n *\n * @returns the client ID\n */\n public get clientId(): string {\n return this.details.clientId;\n }\n\n /**\n * Get the mode of the client\n *\n * @returns the client mode\n */\n public get mode(): ConnectionMode {\n return this.details.mode;\n }\n\n /**\n * Get the claims of the client who is sending the message\n *\n * @returns client claims\n */\n public get claims(): ITokenClaims {\n return this.details.claims;\n }\n\n /**\n * Get whether or not this is an existing document\n *\n * @returns true if the document exists\n */\n public get existing(): boolean {\n return this.details.existing;\n }\n\n /**\n * Get the maximum size of a message before chunking is required\n *\n * @returns the maximum size of a message before chunking is required\n */\n public get maxMessageSize(): number {\n return this.details.serviceConfiguration.maxMessageSize;\n }\n\n /**\n * Semver of protocol being used with the service\n */\n public get version(): string {\n return this.details.version;\n }\n\n /**\n * Configuration details provided by the service\n */\n public get serviceConfiguration(): IClientConfiguration {\n return this.details.serviceConfiguration;\n }\n\n private checkNotClosed() {\n assert(!this.disposed, 0x20c /* \"connection disposed\" */);\n }\n\n /**\n * Get messages sent during the connection\n *\n * @returns messages sent during the connection\n */\n public get initialMessages(): ISequencedDocumentMessage[] {\n this.checkNotClosed();\n\n // If we call this when the earlyOpHandler is not attached, then the queuedMessages may not include the\n // latest ops. This could possibly indicate that initialMessages was called twice.\n assert(this.earlyOpHandlerAttached, 0x08e /* \"Potentially missed initial messages\" */);\n // We will lose ops and perf will tank as we need to go to storage to become current!\n assert(this.listeners(\"op\").length !== 0, 0x08f /* \"No op handler is setup!\" */);\n\n this.removeEarlyOpHandler();\n\n if (this.queuedMessages.length > 0) {\n // Some messages were queued.\n // add them to the list of initialMessages to be processed\n this.details.initialMessages.push(...this.queuedMessages);\n this.details.initialMessages.sort((a, b) => a.sequenceNumber - b.sequenceNumber);\n this.queuedMessages.length = 0;\n }\n return this.details.initialMessages;\n }\n\n /**\n * Get signals sent during the connection\n *\n * @returns signals sent during the connection\n */\n public get initialSignals(): ISignalMessage[] {\n this.checkNotClosed();\n assert(this.listeners(\"signal\").length !== 0, 0x090 /* \"No signal handler is setup!\" */);\n\n this.removeEarlySignalHandler();\n\n if (this.queuedSignals.length > 0) {\n // Some signals were queued.\n // add them to the list of initialSignals to be processed\n this.details.initialSignals.push(...this.queuedSignals);\n this.queuedSignals.length = 0;\n }\n return this.details.initialSignals;\n }\n\n /**\n * Get initial client list\n *\n * @returns initial client list sent during the connection\n */\n public get initialClients(): ISignalClient[] {\n this.checkNotClosed();\n return this.details.initialClients;\n }\n\n protected emitMessages(type: string, messages: IDocumentMessage[][]) {\n // Although the implementation here disconnects the socket and does not reuse it, other subclasses\n // (e.g. OdspDocumentDeltaConnection) may reuse the socket. In these cases, we need to avoid emitting\n // on the still-live socket.\n if (!this.disposed) {\n this.socket.emit(type, this.clientId, messages);\n }\n }\n\n protected submitCore(type: string, messages: IDocumentMessage[]) {\n if (this.isBatchManagerDisabled) {\n this.emitMessages(type, [messages]);\n } else {\n this.submitManager.add(type, messages);\n }\n }\n\n /**\n * Submits a new delta operation to the server\n *\n * @param message - delta operation to submit\n */\n public submit(messages: IDocumentMessage[]): void {\n this.checkNotClosed();\n this.submitCore(\"submitOp\", messages);\n }\n\n /**\n * Submits a new signal to the server\n *\n * @param message - signal to submit\n */\n public submitSignal(message: IDocumentMessage): void {\n this.checkNotClosed();\n this.submitCore(\"submitSignal\", [message]);\n }\n\n /**\n * Disconnect from the websocket, and permanently disable this DocumentDeltaConnection.\n */\n public dispose() {\n this.disposeCore(\n false, // socketProtocolError\n createGenericNetworkError(\n \"clientClosingConnection\", undefined, { canRetry: true }, { driverVersion }));\n }\n\n protected disposeCore(socketProtocolError: boolean, err: IAnyDriverError) {\n // Can't check this.disposed here, as we get here on socket closure,\n // so _disposed & socket.connected might be not in sync while processing\n // \"dispose\" event.\n if (this._disposed) {\n return;\n }\n\n // We set the disposed flag as a part of the contract for overriding the disconnect method. This is used by\n // DocumentDeltaConnection to determine if emitting messages (ops) on the socket is allowed, which is\n // important since OdspDocumentDeltaConnection reuses the socket rather than truly disconnecting it. Note that\n // OdspDocumentDeltaConnection may still send disconnect_document which is allowed; this is only intended\n // to prevent normal messages from being emitted.\n this._disposed = true;\n\n this.removeTrackedListeners();\n this.disconnect(socketProtocolError, err);\n }\n\n /**\n * Disconnect from the websocket.\n * @param socketProtocolError - true if error happened on socket / socket.io protocol level\n * (not on Fluid protocol level)\n * @param reason - reason for disconnect\n */\n protected disconnect(socketProtocolError: boolean, reason: IAnyDriverError) {\n this.socket.disconnect();\n }\n\n protected async initialize(connectMessage: IConnect, timeout: number) {\n this.socket.on(\"op\", this.earlyOpHandler);\n this.socket.on(\"signal\", this.earlySignalHandler);\n this.earlyOpHandlerAttached = true;\n\n this._details = await new Promise<IConnected>((resolve, reject) => {\n const fail = (socketProtocolError: boolean, err: IAnyDriverError) => {\n this.disposeCore(socketProtocolError, err);\n reject(err);\n };\n\n // Listen for connection issues\n this.addConnectionListener(\"connect_error\", (error) => {\n let isWebSocketTransportError = false;\n try {\n const description = error?.description;\n if (description && typeof description === \"object\") {\n if (error.type === \"TransportError\") {\n isWebSocketTransportError = true;\n }\n // That's a WebSocket. Clear it as we can't log it.\n description.target = undefined;\n }\n } catch(_e) {}\n\n // Handle socket transport downgrading.\n if (isWebSocketTransportError &&\n this.enableLongPollingDowngrades &&\n this.socket.io.opts.transports?.[0] !== \"polling\") {\n // Downgrade transports to polling upgrade mechanism.\n this.socket.io.opts.transports = [\"polling\", \"websocket\"];\n // Don't alter reconnection behavior if already enabled.\n if (!this.socket.io.reconnection()) {\n // Allow single reconnection attempt using polling upgrade mechanism.\n this.socket.io.reconnection(true);\n this.socket.io.reconnectionAttempts(1);\n }\n }\n\n // Allow built-in socket.io reconnection handling.\n if (this.socket.io.reconnection() &&\n this.reconnectAttempts < this.socket.io.reconnectionAttempts()) {\n // Reconnection is enabled and maximum reconnect attempts have not been reached.\n return;\n }\n\n fail(true, this.createErrorObject(\"connectError\", error));\n });\n\n this.addConnectionListener(\"reconnect_attempt\", () => {\n this.reconnectAttempts++;\n });\n\n // Listen for timeouts\n this.addConnectionListener(\"connect_timeout\", () => {\n fail(true, this.createErrorObject(\"connectTimeout\"));\n });\n\n this.addConnectionListener(\"connect_document_success\", (response: IConnected) => {\n // If we sent a nonce and the server supports nonces, check that the nonces match\n if (connectMessage.nonce !== undefined &&\n response.nonce !== undefined &&\n response.nonce !== connectMessage.nonce) {\n return;\n }\n\n const requestedMode = connectMessage.mode;\n const actualMode = response.mode;\n const writingPermitted = response.claims.scopes.includes(ScopeType.DocWrite);\n\n if (writingPermitted) {\n // The only time we expect a mismatch in requested/actual is if we lack write permissions\n // In this case we will get \"read\", even if we requested \"write\"\n if (actualMode !== requestedMode) {\n fail(false, this.createErrorObject(\n \"connectDocumentSuccess\",\n \"Connected in a different mode than was requested\",\n false,\n ));\n return;\n }\n } else {\n if (actualMode === \"write\") {\n fail(false, this.createErrorObject(\n \"connectDocumentSuccess\",\n \"Connected in write mode without write permissions\",\n false,\n ));\n return;\n }\n }\n\n this.checkpointSequenceNumber = response.checkpointSequenceNumber;\n\n this.removeConnectionListeners();\n resolve(response);\n });\n\n // Socket can be disconnected while waiting for Fluid protocol messages\n // (connect_document_error / connect_document_success), as well as before DeltaManager\n // had a chance to register its handlers.\n this.addTrackedListener(\"disconnect\", (reason) => {\n const err = this.createErrorObject(\"disconnect\", reason);\n this.emit(\"disconnect\", err);\n fail(true, err);\n });\n\n this.addTrackedListener(\"error\", ((error) => {\n // First, raise an error event, to give clients a chance to observe error contents\n // This includes \"Invalid namespace\" error, which we consider critical (reconnecting will not help)\n const err = this.createErrorObject(\"error\", error, error !== \"Invalid namespace\");\n this.emit(\"error\", err);\n // Disconnect socket - required if happened before initial handshake\n fail(true, err);\n }));\n\n this.addConnectionListener(\"connect_document_error\", ((error) => {\n // If we sent a nonce and the server supports nonces, check that the nonces match\n if (connectMessage.nonce !== undefined &&\n error.nonce !== undefined &&\n error.nonce !== connectMessage.nonce) {\n return;\n }\n\n // This is not an socket.io error - it's Fluid protocol error.\n // In this case fail connection and indicate that we were unable to create connection\n fail(false, this.createErrorObject(\"connectDocumentError\", error));\n }));\n\n this.socket.emit(\"connect_document\", connectMessage);\n\n // Give extra 2 seconds for handshake on top of socket connection timeout\n this.socketConnectionTimeout = setTimeout(() => {\n fail(false, this.createErrorObject(\"orderingServiceHandshakeTimeout\"));\n }, timeout + 2000);\n });\n\n assert(!this.disposed, 0x246 /* \"checking consistency of socket & _disposed flags\" */);\n }\n\n protected earlyOpHandler = (documentId: string, msgs: ISequencedDocumentMessage[]) => {\n this.queuedMessages.push(...msgs);\n };\n\n protected earlySignalHandler = (msg: ISignalMessage) => {\n this.queuedSignals.push(msg);\n };\n\n private removeEarlyOpHandler() {\n this.socket.removeListener(\"op\", this.earlyOpHandler);\n this.earlyOpHandlerAttached = false;\n }\n\n private removeEarlySignalHandler() {\n this.socket.removeListener(\"signal\", this.earlySignalHandler);\n }\n\n private addConnectionListener(event: string, listener: (...args: any[]) => void) {\n assert(!DocumentDeltaConnection.eventsAlwaysForwarded.includes(event),\n 0x247 /* \"Use addTrackedListener instead\" */);\n assert(!DocumentDeltaConnection.eventsToForward.includes(event),\n 0x248 /* \"should not subscribe to forwarded events\" */);\n this.socket.on(event, listener);\n assert(!this.connectionListeners.has(event), 0x20d /* \"double connection listener\" */);\n this.connectionListeners.set(event, listener);\n }\n\n protected addTrackedListener(event: string, listener: (...args: any[]) => void) {\n this.socket.on(event, listener);\n assert(!this.trackedListeners.has(event), 0x20e /* \"double tracked listener\" */);\n this.trackedListeners.set(event, listener);\n }\n\n private removeTrackedListeners() {\n for (const [event, listener] of this.trackedListeners.entries()) {\n this.socket.off(event, listener);\n }\n // removeTrackedListeners removes all listeners, including connection listeners\n this.removeConnectionListeners();\n\n this.removeEarlyOpHandler();\n this.removeEarlySignalHandler();\n\n this.trackedListeners.clear();\n }\n\n private removeConnectionListeners() {\n if (this.socketConnectionTimeout !== undefined) {\n clearTimeout(this.socketConnectionTimeout);\n }\n\n for (const [event, listener] of this.connectionListeners.entries()) {\n this.socket.off(event, listener);\n }\n this.connectionListeners.clear();\n }\n\n /**\n * Error raising for socket.io issues\n */\n protected createErrorObject(handler: string, error?: any, canRetry = true): IAnyDriverError {\n // Note: we suspect the incoming error object is either:\n // - a string: log it in the message (if not a string, it may contain PII but will print as [object Object])\n // - an Error object thrown by socket.io engine. Be careful with not recording PII!\n let message = `socket.io (${handler})`;\n if (typeof error !== \"object\") {\n message = `${message}: ${error}`;\n } else if (error?.type === \"TransportError\") {\n // JSON.stringify drops Error.message\n if (error?.message !== undefined) {\n message = `${message}: ${error.message}`;\n }\n // Websocket errors reported by engine.io-client.\n // They are Error objects with description containing WS error and description = \"TransportError\"\n // Please see https://github.com/socketio/engine.io-client/blob/7245b80/lib/transport.ts#L44,\n message = `${message}: ${JSON.stringify(error, getCircularReplacer())}`;\n } else {\n message = `${message}: [object omitted]`;\n }\n const errorObj = createGenericNetworkError(\n `socketError [${handler}]`,\n message,\n { canRetry },\n { driverVersion },\n );\n\n return errorObj;\n }\n}\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/driver-base";
8
- export declare const pkgVersion = "0.56.5";
8
+ export declare const pkgVersion = "0.57.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -8,5 +8,5 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.pkgVersion = exports.pkgName = void 0;
10
10
  exports.pkgName = "@fluidframework/driver-base";
11
- exports.pkgVersion = "0.56.5";
11
+ exports.pkgVersion = "0.57.0";
12
12
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,6BAA6B,CAAC;AACxC,QAAA,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-base\";\nexport const pkgVersion = \"0.56.5\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,6BAA6B,CAAC;AACxC,QAAA,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-base\";\nexport const pkgVersion = \"0.57.0\";\n"]}
@@ -4,7 +4,8 @@
4
4
  */
5
5
  /// <reference types="@types/socket.io-client" />
6
6
  import { BatchManager, TypedEventEmitter } from "@fluidframework/common-utils";
7
- import { IDocumentDeltaConnection, IDocumentDeltaConnectionEvents, DriverError } from "@fluidframework/driver-definitions";
7
+ import { IDocumentDeltaConnection, IDocumentDeltaConnectionEvents } from "@fluidframework/driver-definitions";
8
+ import { IAnyDriverError } from "@fluidframework/driver-utils";
8
9
  import { ConnectionMode, IClientConfiguration, IConnect, IConnected, IDocumentMessage, ISequencedDocumentMessage, ISignalClient, ISignalMessage, ITokenClaims } from "@fluidframework/protocol-definitions";
9
10
  import { IDisposable, ITelemetryLogger } from "@fluidframework/common-definitions";
10
11
  /**
@@ -13,6 +14,7 @@ import { IDisposable, ITelemetryLogger } from "@fluidframework/common-definition
13
14
  export declare class DocumentDeltaConnection extends TypedEventEmitter<IDocumentDeltaConnectionEvents> implements IDocumentDeltaConnection, IDisposable {
14
15
  protected readonly socket: SocketIOClient.Socket;
15
16
  documentId: string;
17
+ private readonly enableLongPollingDowngrades;
16
18
  static readonly eventsToForward: string[];
17
19
  static readonly eventsAlwaysForwarded: string[];
18
20
  /**
@@ -33,6 +35,7 @@ export declare class DocumentDeltaConnection extends TypedEventEmitter<IDocument
33
35
  private socketConnectionTimeout;
34
36
  protected readonly submitManager: BatchManager<IDocumentMessage[]>;
35
37
  private _details;
38
+ private reconnectAttempts;
36
39
  private readonly connectionListeners;
37
40
  private readonly trackedListeners;
38
41
  protected get hasDetails(): boolean;
@@ -52,8 +55,10 @@ export declare class DocumentDeltaConnection extends TypedEventEmitter<IDocument
52
55
  /**
53
56
  * @param socket - websocket to be used
54
57
  * @param documentId - ID of the document
58
+ * @param logger - for reporting telemetry events
59
+ * @param enableLongPollingDowngrades - allow connection to be downgraded to long-polling on websocket failure
55
60
  */
56
- protected constructor(socket: SocketIOClient.Socket, documentId: string, logger: ITelemetryLogger);
61
+ protected constructor(socket: SocketIOClient.Socket, documentId: string, logger: ITelemetryLogger, enableLongPollingDowngrades?: boolean);
57
62
  /**
58
63
  * Get the ID of the client who is sending the message
59
64
  *
@@ -129,14 +134,14 @@ export declare class DocumentDeltaConnection extends TypedEventEmitter<IDocument
129
134
  * Disconnect from the websocket, and permanently disable this DocumentDeltaConnection.
130
135
  */
131
136
  dispose(): void;
132
- protected disposeCore(socketProtocolError: boolean, err: any): void;
137
+ protected disposeCore(socketProtocolError: boolean, err: IAnyDriverError): void;
133
138
  /**
134
139
  * Disconnect from the websocket.
135
140
  * @param socketProtocolError - true if error happened on socket / socket.io protocol level
136
141
  * (not on Fluid protocol level)
137
142
  * @param reason - reason for disconnect
138
143
  */
139
- protected disconnect(socketProtocolError: boolean, reason: any): void;
144
+ protected disconnect(socketProtocolError: boolean, reason: IAnyDriverError): void;
140
145
  protected initialize(connectMessage: IConnect, timeout: number): Promise<void>;
141
146
  protected earlyOpHandler: (documentId: string, msgs: ISequencedDocumentMessage[]) => void;
142
147
  protected earlySignalHandler: (msg: ISignalMessage) => void;
@@ -149,6 +154,6 @@ export declare class DocumentDeltaConnection extends TypedEventEmitter<IDocument
149
154
  /**
150
155
  * Error raising for socket.io issues
151
156
  */
152
- protected createErrorObject(handler: string, error?: any, canRetry?: boolean): DriverError;
157
+ protected createErrorObject(handler: string, error?: any, canRetry?: boolean): IAnyDriverError;
153
158
  }
154
159
  //# sourceMappingURL=documentDeltaConnection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"documentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/documentDeltaConnection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"documentDeltaConnection.d.ts","sourceRoot":"","sources":["../src/documentDeltaConnection.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,8 @@ import { assert, BatchManager, TypedEventEmitter } from "@fluidframework/common-
6
6
  import { createGenericNetworkError } from "@fluidframework/driver-utils";
7
7
  import { ScopeType, } from "@fluidframework/protocol-definitions";
8
8
  import { ChildLogger, getCircularReplacer, loggerToMonitoringContext, } from "@fluidframework/telemetry-utils";
9
+ // For now, this package is versioned and released in unison with the specific drivers
10
+ import { pkgVersion as driverVersion } from "./packageVersion";
9
11
  // Local storage key to disable the BatchManager
10
12
  const batchManagerDisabledKey = "Fluid.Driver.BaseDocumentDeltaConnection.DisableBatchManager";
11
13
  /**
@@ -15,11 +17,14 @@ export class DocumentDeltaConnection extends TypedEventEmitter {
15
17
  /**
16
18
  * @param socket - websocket to be used
17
19
  * @param documentId - ID of the document
20
+ * @param logger - for reporting telemetry events
21
+ * @param enableLongPollingDowngrades - allow connection to be downgraded to long-polling on websocket failure
18
22
  */
19
- constructor(socket, documentId, logger) {
23
+ constructor(socket, documentId, logger, enableLongPollingDowngrades = false) {
20
24
  super();
21
25
  this.socket = socket;
22
26
  this.documentId = documentId;
27
+ this.enableLongPollingDowngrades = enableLongPollingDowngrades;
23
28
  // Listen for ops sent before we receive a response to connect_document
24
29
  this.queuedMessages = [];
25
30
  this.queuedSignals = [];
@@ -28,6 +33,7 @@ export class DocumentDeltaConnection extends TypedEventEmitter {
28
33
  * to later be retrieved via initialMessages.
29
34
  */
30
35
  this.earlyOpHandlerAttached = false;
36
+ this.reconnectAttempts = 0;
31
37
  // Listeners only needed while the connection is in progress
32
38
  this.connectionListeners = new Map();
33
39
  // Listeners used throughout the lifetime of the DocumentDeltaConnection
@@ -231,7 +237,7 @@ export class DocumentDeltaConnection extends TypedEventEmitter {
231
237
  */
232
238
  dispose() {
233
239
  this.disposeCore(false, // socketProtocolError
234
- createGenericNetworkError("clientClosingConnection", undefined, true /* canRetry */));
240
+ createGenericNetworkError("clientClosingConnection", undefined, { canRetry: true }, { driverVersion }));
235
241
  }
236
242
  disposeCore(socketProtocolError, err) {
237
243
  // Can't check this.disposed here, as we get here on socket closure,
@@ -269,16 +275,43 @@ export class DocumentDeltaConnection extends TypedEventEmitter {
269
275
  };
270
276
  // Listen for connection issues
271
277
  this.addConnectionListener("connect_error", (error) => {
278
+ var _a;
279
+ let isWebSocketTransportError = false;
272
280
  try {
273
281
  const description = error === null || error === void 0 ? void 0 : error.description;
274
282
  if (description && typeof description === "object") {
283
+ if (error.type === "TransportError") {
284
+ isWebSocketTransportError = true;
285
+ }
275
286
  // That's a WebSocket. Clear it as we can't log it.
276
287
  description.target = undefined;
277
288
  }
278
289
  }
279
290
  catch (_e) { }
291
+ // Handle socket transport downgrading.
292
+ if (isWebSocketTransportError &&
293
+ this.enableLongPollingDowngrades &&
294
+ ((_a = this.socket.io.opts.transports) === null || _a === void 0 ? void 0 : _a[0]) !== "polling") {
295
+ // Downgrade transports to polling upgrade mechanism.
296
+ this.socket.io.opts.transports = ["polling", "websocket"];
297
+ // Don't alter reconnection behavior if already enabled.
298
+ if (!this.socket.io.reconnection()) {
299
+ // Allow single reconnection attempt using polling upgrade mechanism.
300
+ this.socket.io.reconnection(true);
301
+ this.socket.io.reconnectionAttempts(1);
302
+ }
303
+ }
304
+ // Allow built-in socket.io reconnection handling.
305
+ if (this.socket.io.reconnection() &&
306
+ this.reconnectAttempts < this.socket.io.reconnectionAttempts()) {
307
+ // Reconnection is enabled and maximum reconnect attempts have not been reached.
308
+ return;
309
+ }
280
310
  fail(true, this.createErrorObject("connectError", error));
281
311
  });
312
+ this.addConnectionListener("reconnect_attempt", () => {
313
+ this.reconnectAttempts++;
314
+ });
282
315
  // Listen for timeouts
283
316
  this.addConnectionListener("connect_timeout", () => {
284
317
  fail(true, this.createErrorObject("connectTimeout"));
@@ -408,7 +441,7 @@ export class DocumentDeltaConnection extends TypedEventEmitter {
408
441
  else {
409
442
  message = `${message}: [object omitted]`;
410
443
  }
411
- const errorObj = createGenericNetworkError(`socketError [${handler}]`, message, canRetry);
444
+ const errorObj = createGenericNetworkError(`socketError [${handler}]`, message, { canRetry }, { driverVersion });
412
445
  return errorObj;
413
446
  }
414
447
  }
@@ -1 +1 @@
1
- {"version":3,"file":"documentDeltaConnection.js","sourceRoot":"","sources":["../src/documentDeltaConnection.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert, BatchManager, TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport {\n IDocumentDeltaConnection,\n IDocumentDeltaConnectionEvents,\n DriverError,\n} from \"@fluidframework/driver-definitions\";\nimport { createGenericNetworkError } from \"@fluidframework/driver-utils\";\nimport {\n ConnectionMode,\n IClientConfiguration,\n IConnect,\n IConnected,\n IDocumentMessage,\n ISequencedDocumentMessage,\n ISignalClient,\n ISignalMessage,\n ITokenClaims,\n ScopeType,\n} from \"@fluidframework/protocol-definitions\";\nimport { IDisposable, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport {\n ChildLogger,\n getCircularReplacer,\n loggerToMonitoringContext,\n MonitoringContext,\n} from \"@fluidframework/telemetry-utils\";\n\n// Local storage key to disable the BatchManager\nconst batchManagerDisabledKey = \"Fluid.Driver.BaseDocumentDeltaConnection.DisableBatchManager\";\n\n/**\n * Represents a connection to a stream of delta updates\n */\nexport class DocumentDeltaConnection\n extends TypedEventEmitter<IDocumentDeltaConnectionEvents>\n implements IDocumentDeltaConnection, IDisposable {\n static readonly eventsToForward = [\"nack\", \"op\", \"signal\", \"pong\"];\n\n // WARNING: These are critical events that we can't miss, so registration for them has to be in place at all times!\n // Including before handshake is over, and after that (but before DeltaManager had a chance to put its own handlers)\n static readonly eventsAlwaysForwarded = [\"disconnect\", \"error\"];\n\n /**\n * Last known sequence number to ordering service at the time of connection\n * It may lap actual last sequence number (quite a bit, if container is very active).\n * But it's best information for client to figure out how far it is behind, at least\n * for \"read\" connections. \"write\" connections may use own \"join\" op to similar information,\n * that is likely to be more up-to-date.\n */\n public checkpointSequenceNumber: number | undefined;\n\n // Listen for ops sent before we receive a response to connect_document\n protected readonly queuedMessages: ISequencedDocumentMessage[] = [];\n protected readonly queuedSignals: ISignalMessage[] = [];\n /**\n * A flag to indicate whether we have our handler attached. If it's attached, we're queueing incoming ops\n * to later be retrieved via initialMessages.\n */\n private earlyOpHandlerAttached: boolean = false;\n\n private socketConnectionTimeout: ReturnType<typeof setTimeout> | undefined;\n\n protected readonly submitManager: BatchManager<IDocumentMessage[]>;\n\n private _details: IConnected | undefined;\n\n // Listeners only needed while the connection is in progress\n private readonly connectionListeners: Map<string, (...args: any[]) => void> = new Map();\n // Listeners used throughout the lifetime of the DocumentDeltaConnection\n private readonly trackedListeners: Map<string, (...args: any[]) => void> = new Map();\n\n protected get hasDetails(): boolean {\n return !!this._details;\n }\n\n public get disposed() {\n assert(this._disposed || this.socket.connected, 0x244 /* \"Socket is closed, but connection is not!\" */);\n return this._disposed;\n }\n /**\n * Flag to indicate whether the DocumentDeltaConnection is expected to still be capable of sending messages.\n * After disconnection, we flip this to prevent any stale messages from being emitted.\n */\n protected _disposed: boolean = false;\n private readonly mc: MonitoringContext;\n protected readonly isBatchManagerDisabled: boolean = false;\n /**\n * @deprecated - Implementors should manage their own logger or monitoring context\n */\n protected get logger(): ITelemetryLogger {\n return this.mc.logger;\n }\n\n public get details(): IConnected {\n if (!this._details) {\n throw new Error(\"Internal error: calling method before _details is initialized!\");\n }\n return this._details;\n }\n\n /**\n * @param socket - websocket to be used\n * @param documentId - ID of the document\n */\n protected constructor(\n protected readonly socket: SocketIOClient.Socket,\n public documentId: string,\n logger: ITelemetryLogger,\n ) {\n super();\n\n this.mc = loggerToMonitoringContext(\n ChildLogger.create(logger, \"DeltaConnection\"));\n\n this.submitManager = new BatchManager<IDocumentMessage[]>(\n (submitType, work) => this.emitMessages(submitType, work));\n\n this.on(\"newListener\", (event, listener) => {\n assert(!this.disposed, 0x20a /* \"register for event on disposed object\" */);\n\n // Some events are already forwarded - see this.addTrackedListener() calls in initialize().\n if (DocumentDeltaConnection.eventsAlwaysForwarded.includes(event)) {\n assert(this.trackedListeners.has(event), 0x245 /* \"tracked listener\" */);\n return;\n }\n\n if (!DocumentDeltaConnection.eventsToForward.includes(event)) {\n throw new Error(`DocumentDeltaConnection: Registering for unknown event: ${event}`);\n }\n\n // Whenever listener is added, we should subscribe on same event on socket, so these two things\n // should be in sync. This currently assumes that nobody unregisters and registers back listeners,\n // and that there are no \"internal\" listeners installed (like \"error\" case we skip above)\n // Better flow might be to always unconditionally register all handlers on successful connection,\n // though some logic (naming assert in initialMessages getter) might need to be adjusted (it becomes noop)\n assert((this.listeners(event).length !== 0) === this.trackedListeners.has(event), 0x20b /* \"mismatch\" */);\n if (!this.trackedListeners.has(event)) {\n this.addTrackedListener(\n event,\n (...args: any[]) => {\n this.emit(event, ...args);\n });\n }\n });\n\n this.isBatchManagerDisabled = this.mc.config.getBoolean(batchManagerDisabledKey) === true;\n }\n\n /**\n * Get the ID of the client who is sending the message\n *\n * @returns the client ID\n */\n public get clientId(): string {\n return this.details.clientId;\n }\n\n /**\n * Get the mode of the client\n *\n * @returns the client mode\n */\n public get mode(): ConnectionMode {\n return this.details.mode;\n }\n\n /**\n * Get the claims of the client who is sending the message\n *\n * @returns client claims\n */\n public get claims(): ITokenClaims {\n return this.details.claims;\n }\n\n /**\n * Get whether or not this is an existing document\n *\n * @returns true if the document exists\n */\n public get existing(): boolean {\n return this.details.existing;\n }\n\n /**\n * Get the maximum size of a message before chunking is required\n *\n * @returns the maximum size of a message before chunking is required\n */\n public get maxMessageSize(): number {\n return this.details.serviceConfiguration.maxMessageSize;\n }\n\n /**\n * Semver of protocol being used with the service\n */\n public get version(): string {\n return this.details.version;\n }\n\n /**\n * Configuration details provided by the service\n */\n public get serviceConfiguration(): IClientConfiguration {\n return this.details.serviceConfiguration;\n }\n\n private checkNotClosed() {\n assert(!this.disposed, 0x20c /* \"connection disposed\" */);\n }\n\n /**\n * Get messages sent during the connection\n *\n * @returns messages sent during the connection\n */\n public get initialMessages(): ISequencedDocumentMessage[] {\n this.checkNotClosed();\n\n // If we call this when the earlyOpHandler is not attached, then the queuedMessages may not include the\n // latest ops. This could possibly indicate that initialMessages was called twice.\n assert(this.earlyOpHandlerAttached, 0x08e /* \"Potentially missed initial messages\" */);\n // We will lose ops and perf will tank as we need to go to storage to become current!\n assert(this.listeners(\"op\").length !== 0, 0x08f /* \"No op handler is setup!\" */);\n\n this.removeEarlyOpHandler();\n\n if (this.queuedMessages.length > 0) {\n // Some messages were queued.\n // add them to the list of initialMessages to be processed\n this.details.initialMessages.push(...this.queuedMessages);\n this.details.initialMessages.sort((a, b) => a.sequenceNumber - b.sequenceNumber);\n this.queuedMessages.length = 0;\n }\n return this.details.initialMessages;\n }\n\n /**\n * Get signals sent during the connection\n *\n * @returns signals sent during the connection\n */\n public get initialSignals(): ISignalMessage[] {\n this.checkNotClosed();\n assert(this.listeners(\"signal\").length !== 0, 0x090 /* \"No signal handler is setup!\" */);\n\n this.removeEarlySignalHandler();\n\n if (this.queuedSignals.length > 0) {\n // Some signals were queued.\n // add them to the list of initialSignals to be processed\n this.details.initialSignals.push(...this.queuedSignals);\n this.queuedSignals.length = 0;\n }\n return this.details.initialSignals;\n }\n\n /**\n * Get initial client list\n *\n * @returns initial client list sent during the connection\n */\n public get initialClients(): ISignalClient[] {\n this.checkNotClosed();\n return this.details.initialClients;\n }\n\n protected emitMessages(type: string, messages: IDocumentMessage[][]) {\n // Although the implementation here disconnects the socket and does not reuse it, other subclasses\n // (e.g. OdspDocumentDeltaConnection) may reuse the socket. In these cases, we need to avoid emitting\n // on the still-live socket.\n if (!this.disposed) {\n this.socket.emit(type, this.clientId, messages);\n }\n }\n\n protected submitCore(type: string, messages: IDocumentMessage[]) {\n if (this.isBatchManagerDisabled) {\n this.emitMessages(type, [messages]);\n } else {\n this.submitManager.add(type, messages);\n }\n }\n\n /**\n * Submits a new delta operation to the server\n *\n * @param message - delta operation to submit\n */\n public submit(messages: IDocumentMessage[]): void {\n this.checkNotClosed();\n this.submitCore(\"submitOp\", messages);\n }\n\n /**\n * Submits a new signal to the server\n *\n * @param message - signal to submit\n */\n public submitSignal(message: IDocumentMessage): void {\n this.checkNotClosed();\n this.submitCore(\"submitSignal\", [message]);\n }\n\n /**\n * Disconnect from the websocket, and permanently disable this DocumentDeltaConnection.\n */\n public dispose() {\n this.disposeCore(\n false, // socketProtocolError\n createGenericNetworkError(\"clientClosingConnection\", undefined, true /* canRetry */));\n }\n\n protected disposeCore(socketProtocolError: boolean, err: any) {\n // Can't check this.disposed here, as we get here on socket closure,\n // so _disposed & socket.connected might be not in sync while processing\n // \"dispose\" event.\n if (this._disposed) {\n return;\n }\n\n // We set the disposed flag as a part of the contract for overriding the disconnect method. This is used by\n // DocumentDeltaConnection to determine if emitting messages (ops) on the socket is allowed, which is\n // important since OdspDocumentDeltaConnection reuses the socket rather than truly disconnecting it. Note that\n // OdspDocumentDeltaConnection may still send disconnect_document which is allowed; this is only intended\n // to prevent normal messages from being emitted.\n this._disposed = true;\n\n this.removeTrackedListeners();\n this.disconnect(socketProtocolError, err);\n }\n\n /**\n * Disconnect from the websocket.\n * @param socketProtocolError - true if error happened on socket / socket.io protocol level\n * (not on Fluid protocol level)\n * @param reason - reason for disconnect\n */\n protected disconnect(socketProtocolError: boolean, reason: any) {\n this.socket.disconnect();\n }\n\n protected async initialize(connectMessage: IConnect, timeout: number) {\n this.socket.on(\"op\", this.earlyOpHandler);\n this.socket.on(\"signal\", this.earlySignalHandler);\n this.earlyOpHandlerAttached = true;\n\n this._details = await new Promise<IConnected>((resolve, reject) => {\n const fail = (socketProtocolError: boolean, err: DriverError) => {\n this.disposeCore(socketProtocolError, err);\n reject(err);\n };\n\n // Listen for connection issues\n this.addConnectionListener(\"connect_error\", (error) => {\n try {\n const description = error?.description;\n if (description && typeof description === \"object\") {\n // That's a WebSocket. Clear it as we can't log it.\n description.target = undefined;\n }\n } catch(_e) {}\n fail(true, this.createErrorObject(\"connectError\", error));\n });\n\n // Listen for timeouts\n this.addConnectionListener(\"connect_timeout\", () => {\n fail(true, this.createErrorObject(\"connectTimeout\"));\n });\n\n this.addConnectionListener(\"connect_document_success\", (response: IConnected) => {\n // If we sent a nonce and the server supports nonces, check that the nonces match\n if (connectMessage.nonce !== undefined &&\n response.nonce !== undefined &&\n response.nonce !== connectMessage.nonce) {\n return;\n }\n\n const requestedMode = connectMessage.mode;\n const actualMode = response.mode;\n const writingPermitted = response.claims.scopes.includes(ScopeType.DocWrite);\n\n if (writingPermitted) {\n // The only time we expect a mismatch in requested/actual is if we lack write permissions\n // In this case we will get \"read\", even if we requested \"write\"\n if (actualMode !== requestedMode) {\n fail(false, this.createErrorObject(\n \"connectDocumentSuccess\",\n \"Connected in a different mode than was requested\",\n false,\n ));\n return;\n }\n } else {\n if (actualMode === \"write\") {\n fail(false, this.createErrorObject(\n \"connectDocumentSuccess\",\n \"Connected in write mode without write permissions\",\n false,\n ));\n return;\n }\n }\n\n this.checkpointSequenceNumber = response.checkpointSequenceNumber;\n\n this.removeConnectionListeners();\n resolve(response);\n });\n\n // Socket can be disconnected while waiting for Fluid protocol messages\n // (connect_document_error / connect_document_success), as well as before DeltaManager\n // had a chance to register its handlers.\n this.addTrackedListener(\"disconnect\", (reason) => {\n const err = this.createErrorObject(\"disconnect\", reason);\n this.emit(\"disconnect\", err);\n fail(true, err);\n });\n\n this.addTrackedListener(\"error\", ((error) => {\n // First, raise an error event, to give clients a chance to observe error contents\n // This includes \"Invalid namespace\" error, which we consider critical (reconnecting will not help)\n const err = this.createErrorObject(\"error\", error, error !== \"Invalid namespace\");\n this.emit(\"error\", err);\n // Disconnect socket - required if happened before initial handshake\n fail(true, err);\n }));\n\n this.addConnectionListener(\"connect_document_error\", ((error) => {\n // If we sent a nonce and the server supports nonces, check that the nonces match\n if (connectMessage.nonce !== undefined &&\n error.nonce !== undefined &&\n error.nonce !== connectMessage.nonce) {\n return;\n }\n\n // This is not an socket.io error - it's Fluid protocol error.\n // In this case fail connection and indicate that we were unable to create connection\n fail(false, this.createErrorObject(\"connectDocumentError\", error));\n }));\n\n this.socket.emit(\"connect_document\", connectMessage);\n\n // Give extra 2 seconds for handshake on top of socket connection timeout\n this.socketConnectionTimeout = setTimeout(() => {\n fail(false, this.createErrorObject(\"orderingServiceHandshakeTimeout\"));\n }, timeout + 2000);\n });\n\n assert(!this.disposed, 0x246 /* \"checking consistency of socket & _disposed flags\" */);\n }\n\n protected earlyOpHandler = (documentId: string, msgs: ISequencedDocumentMessage[]) => {\n this.queuedMessages.push(...msgs);\n };\n\n protected earlySignalHandler = (msg: ISignalMessage) => {\n this.queuedSignals.push(msg);\n };\n\n private removeEarlyOpHandler() {\n this.socket.removeListener(\"op\", this.earlyOpHandler);\n this.earlyOpHandlerAttached = false;\n }\n\n private removeEarlySignalHandler() {\n this.socket.removeListener(\"signal\", this.earlySignalHandler);\n }\n\n private addConnectionListener(event: string, listener: (...args: any[]) => void) {\n assert(!DocumentDeltaConnection.eventsAlwaysForwarded.includes(event),\n 0x247 /* \"Use addTrackedListener instead\" */);\n assert(!DocumentDeltaConnection.eventsToForward.includes(event),\n 0x248 /* \"should not subscribe to forwarded events\" */);\n this.socket.on(event, listener);\n assert(!this.connectionListeners.has(event), 0x20d /* \"double connection listener\" */);\n this.connectionListeners.set(event, listener);\n }\n\n protected addTrackedListener(event: string, listener: (...args: any[]) => void) {\n this.socket.on(event, listener);\n assert(!this.trackedListeners.has(event), 0x20e /* \"double tracked listener\" */);\n this.trackedListeners.set(event, listener);\n }\n\n private removeTrackedListeners() {\n for (const [event, listener] of this.trackedListeners.entries()) {\n this.socket.off(event, listener);\n }\n // removeTrackedListeners removes all listeners, including connection listeners\n this.removeConnectionListeners();\n\n this.removeEarlyOpHandler();\n this.removeEarlySignalHandler();\n\n this.trackedListeners.clear();\n }\n\n private removeConnectionListeners() {\n if (this.socketConnectionTimeout !== undefined) {\n clearTimeout(this.socketConnectionTimeout);\n }\n\n for (const [event, listener] of this.connectionListeners.entries()) {\n this.socket.off(event, listener);\n }\n this.connectionListeners.clear();\n }\n\n /**\n * Error raising for socket.io issues\n */\n protected createErrorObject(handler: string, error?: any, canRetry = true): DriverError {\n // Note: we suspect the incoming error object is either:\n // - a string: log it in the message (if not a string, it may contain PII but will print as [object Object])\n // - an Error object thrown by socket.io engine. Be careful with not recording PII!\n let message = `socket.io (${handler})`;\n if (typeof error !== \"object\") {\n message = `${message}: ${error}`;\n } else if (error?.type === \"TransportError\") {\n // JSON.stringify drops Error.message\n if (error?.message !== undefined) {\n message = `${message}: ${error.message}`;\n }\n // Websocket errors reported by engine.io-client.\n // They are Error objects with description containing WS error and description = \"TransportError\"\n // Please see https://github.com/socketio/engine.io-client/blob/7245b80/lib/transport.ts#L44,\n message = `${message}: ${JSON.stringify(error, getCircularReplacer())}`;\n } else {\n message = `${message}: [object omitted]`;\n }\n const errorObj = createGenericNetworkError(\n `socketError [${handler}]`,\n message,\n canRetry,\n );\n\n return errorObj;\n }\n}\n"]}
1
+ {"version":3,"file":"documentDeltaConnection.js","sourceRoot":"","sources":["../src/documentDeltaConnection.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert, BatchManager, TypedEventEmitter } from \"@fluidframework/common-utils\";\nimport {\n IDocumentDeltaConnection,\n IDocumentDeltaConnectionEvents,\n} from \"@fluidframework/driver-definitions\";\nimport { createGenericNetworkError, IAnyDriverError } from \"@fluidframework/driver-utils\";\nimport {\n ConnectionMode,\n IClientConfiguration,\n IConnect,\n IConnected,\n IDocumentMessage,\n ISequencedDocumentMessage,\n ISignalClient,\n ISignalMessage,\n ITokenClaims,\n ScopeType,\n} from \"@fluidframework/protocol-definitions\";\nimport { IDisposable, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport {\n ChildLogger,\n getCircularReplacer,\n loggerToMonitoringContext,\n MonitoringContext,\n} from \"@fluidframework/telemetry-utils\";\n// For now, this package is versioned and released in unison with the specific drivers\nimport { pkgVersion as driverVersion } from \"./packageVersion\";\n\n// Local storage key to disable the BatchManager\nconst batchManagerDisabledKey = \"Fluid.Driver.BaseDocumentDeltaConnection.DisableBatchManager\";\n\n/**\n * Represents a connection to a stream of delta updates\n */\nexport class DocumentDeltaConnection\n extends TypedEventEmitter<IDocumentDeltaConnectionEvents>\n implements IDocumentDeltaConnection, IDisposable {\n static readonly eventsToForward = [\"nack\", \"op\", \"signal\", \"pong\"];\n\n // WARNING: These are critical events that we can't miss, so registration for them has to be in place at all times!\n // Including before handshake is over, and after that (but before DeltaManager had a chance to put its own handlers)\n static readonly eventsAlwaysForwarded = [\"disconnect\", \"error\"];\n\n /**\n * Last known sequence number to ordering service at the time of connection\n * It may lap actual last sequence number (quite a bit, if container is very active).\n * But it's best information for client to figure out how far it is behind, at least\n * for \"read\" connections. \"write\" connections may use own \"join\" op to similar information,\n * that is likely to be more up-to-date.\n */\n public checkpointSequenceNumber: number | undefined;\n\n // Listen for ops sent before we receive a response to connect_document\n protected readonly queuedMessages: ISequencedDocumentMessage[] = [];\n protected readonly queuedSignals: ISignalMessage[] = [];\n /**\n * A flag to indicate whether we have our handler attached. If it's attached, we're queueing incoming ops\n * to later be retrieved via initialMessages.\n */\n private earlyOpHandlerAttached: boolean = false;\n\n private socketConnectionTimeout: ReturnType<typeof setTimeout> | undefined;\n\n protected readonly submitManager: BatchManager<IDocumentMessage[]>;\n\n private _details: IConnected | undefined;\n\n private reconnectAttempts: number = 0;\n\n // Listeners only needed while the connection is in progress\n private readonly connectionListeners: Map<string, (...args: any[]) => void> = new Map();\n // Listeners used throughout the lifetime of the DocumentDeltaConnection\n private readonly trackedListeners: Map<string, (...args: any[]) => void> = new Map();\n\n protected get hasDetails(): boolean {\n return !!this._details;\n }\n\n public get disposed() {\n assert(this._disposed || this.socket.connected, 0x244 /* \"Socket is closed, but connection is not!\" */);\n return this._disposed;\n }\n /**\n * Flag to indicate whether the DocumentDeltaConnection is expected to still be capable of sending messages.\n * After disconnection, we flip this to prevent any stale messages from being emitted.\n */\n protected _disposed: boolean = false;\n private readonly mc: MonitoringContext;\n protected readonly isBatchManagerDisabled: boolean = false;\n /**\n * @deprecated - Implementors should manage their own logger or monitoring context\n */\n protected get logger(): ITelemetryLogger {\n return this.mc.logger;\n }\n\n public get details(): IConnected {\n if (!this._details) {\n throw new Error(\"Internal error: calling method before _details is initialized!\");\n }\n return this._details;\n }\n\n /**\n * @param socket - websocket to be used\n * @param documentId - ID of the document\n * @param logger - for reporting telemetry events\n * @param enableLongPollingDowngrades - allow connection to be downgraded to long-polling on websocket failure\n */\n protected constructor(\n protected readonly socket: SocketIOClient.Socket,\n public documentId: string,\n logger: ITelemetryLogger,\n private readonly enableLongPollingDowngrades: boolean = false,\n ) {\n super();\n\n this.mc = loggerToMonitoringContext(\n ChildLogger.create(logger, \"DeltaConnection\"));\n\n this.submitManager = new BatchManager<IDocumentMessage[]>(\n (submitType, work) => this.emitMessages(submitType, work));\n\n this.on(\"newListener\", (event, listener) => {\n assert(!this.disposed, 0x20a /* \"register for event on disposed object\" */);\n\n // Some events are already forwarded - see this.addTrackedListener() calls in initialize().\n if (DocumentDeltaConnection.eventsAlwaysForwarded.includes(event)) {\n assert(this.trackedListeners.has(event), 0x245 /* \"tracked listener\" */);\n return;\n }\n\n if (!DocumentDeltaConnection.eventsToForward.includes(event)) {\n throw new Error(`DocumentDeltaConnection: Registering for unknown event: ${event}`);\n }\n\n // Whenever listener is added, we should subscribe on same event on socket, so these two things\n // should be in sync. This currently assumes that nobody unregisters and registers back listeners,\n // and that there are no \"internal\" listeners installed (like \"error\" case we skip above)\n // Better flow might be to always unconditionally register all handlers on successful connection,\n // though some logic (naming assert in initialMessages getter) might need to be adjusted (it becomes noop)\n assert((this.listeners(event).length !== 0) === this.trackedListeners.has(event), 0x20b /* \"mismatch\" */);\n if (!this.trackedListeners.has(event)) {\n this.addTrackedListener(\n event,\n (...args: any[]) => {\n this.emit(event, ...args);\n });\n }\n });\n\n this.isBatchManagerDisabled = this.mc.config.getBoolean(batchManagerDisabledKey) === true;\n }\n\n /**\n * Get the ID of the client who is sending the message\n *\n * @returns the client ID\n */\n public get clientId(): string {\n return this.details.clientId;\n }\n\n /**\n * Get the mode of the client\n *\n * @returns the client mode\n */\n public get mode(): ConnectionMode {\n return this.details.mode;\n }\n\n /**\n * Get the claims of the client who is sending the message\n *\n * @returns client claims\n */\n public get claims(): ITokenClaims {\n return this.details.claims;\n }\n\n /**\n * Get whether or not this is an existing document\n *\n * @returns true if the document exists\n */\n public get existing(): boolean {\n return this.details.existing;\n }\n\n /**\n * Get the maximum size of a message before chunking is required\n *\n * @returns the maximum size of a message before chunking is required\n */\n public get maxMessageSize(): number {\n return this.details.serviceConfiguration.maxMessageSize;\n }\n\n /**\n * Semver of protocol being used with the service\n */\n public get version(): string {\n return this.details.version;\n }\n\n /**\n * Configuration details provided by the service\n */\n public get serviceConfiguration(): IClientConfiguration {\n return this.details.serviceConfiguration;\n }\n\n private checkNotClosed() {\n assert(!this.disposed, 0x20c /* \"connection disposed\" */);\n }\n\n /**\n * Get messages sent during the connection\n *\n * @returns messages sent during the connection\n */\n public get initialMessages(): ISequencedDocumentMessage[] {\n this.checkNotClosed();\n\n // If we call this when the earlyOpHandler is not attached, then the queuedMessages may not include the\n // latest ops. This could possibly indicate that initialMessages was called twice.\n assert(this.earlyOpHandlerAttached, 0x08e /* \"Potentially missed initial messages\" */);\n // We will lose ops and perf will tank as we need to go to storage to become current!\n assert(this.listeners(\"op\").length !== 0, 0x08f /* \"No op handler is setup!\" */);\n\n this.removeEarlyOpHandler();\n\n if (this.queuedMessages.length > 0) {\n // Some messages were queued.\n // add them to the list of initialMessages to be processed\n this.details.initialMessages.push(...this.queuedMessages);\n this.details.initialMessages.sort((a, b) => a.sequenceNumber - b.sequenceNumber);\n this.queuedMessages.length = 0;\n }\n return this.details.initialMessages;\n }\n\n /**\n * Get signals sent during the connection\n *\n * @returns signals sent during the connection\n */\n public get initialSignals(): ISignalMessage[] {\n this.checkNotClosed();\n assert(this.listeners(\"signal\").length !== 0, 0x090 /* \"No signal handler is setup!\" */);\n\n this.removeEarlySignalHandler();\n\n if (this.queuedSignals.length > 0) {\n // Some signals were queued.\n // add them to the list of initialSignals to be processed\n this.details.initialSignals.push(...this.queuedSignals);\n this.queuedSignals.length = 0;\n }\n return this.details.initialSignals;\n }\n\n /**\n * Get initial client list\n *\n * @returns initial client list sent during the connection\n */\n public get initialClients(): ISignalClient[] {\n this.checkNotClosed();\n return this.details.initialClients;\n }\n\n protected emitMessages(type: string, messages: IDocumentMessage[][]) {\n // Although the implementation here disconnects the socket and does not reuse it, other subclasses\n // (e.g. OdspDocumentDeltaConnection) may reuse the socket. In these cases, we need to avoid emitting\n // on the still-live socket.\n if (!this.disposed) {\n this.socket.emit(type, this.clientId, messages);\n }\n }\n\n protected submitCore(type: string, messages: IDocumentMessage[]) {\n if (this.isBatchManagerDisabled) {\n this.emitMessages(type, [messages]);\n } else {\n this.submitManager.add(type, messages);\n }\n }\n\n /**\n * Submits a new delta operation to the server\n *\n * @param message - delta operation to submit\n */\n public submit(messages: IDocumentMessage[]): void {\n this.checkNotClosed();\n this.submitCore(\"submitOp\", messages);\n }\n\n /**\n * Submits a new signal to the server\n *\n * @param message - signal to submit\n */\n public submitSignal(message: IDocumentMessage): void {\n this.checkNotClosed();\n this.submitCore(\"submitSignal\", [message]);\n }\n\n /**\n * Disconnect from the websocket, and permanently disable this DocumentDeltaConnection.\n */\n public dispose() {\n this.disposeCore(\n false, // socketProtocolError\n createGenericNetworkError(\n \"clientClosingConnection\", undefined, { canRetry: true }, { driverVersion }));\n }\n\n protected disposeCore(socketProtocolError: boolean, err: IAnyDriverError) {\n // Can't check this.disposed here, as we get here on socket closure,\n // so _disposed & socket.connected might be not in sync while processing\n // \"dispose\" event.\n if (this._disposed) {\n return;\n }\n\n // We set the disposed flag as a part of the contract for overriding the disconnect method. This is used by\n // DocumentDeltaConnection to determine if emitting messages (ops) on the socket is allowed, which is\n // important since OdspDocumentDeltaConnection reuses the socket rather than truly disconnecting it. Note that\n // OdspDocumentDeltaConnection may still send disconnect_document which is allowed; this is only intended\n // to prevent normal messages from being emitted.\n this._disposed = true;\n\n this.removeTrackedListeners();\n this.disconnect(socketProtocolError, err);\n }\n\n /**\n * Disconnect from the websocket.\n * @param socketProtocolError - true if error happened on socket / socket.io protocol level\n * (not on Fluid protocol level)\n * @param reason - reason for disconnect\n */\n protected disconnect(socketProtocolError: boolean, reason: IAnyDriverError) {\n this.socket.disconnect();\n }\n\n protected async initialize(connectMessage: IConnect, timeout: number) {\n this.socket.on(\"op\", this.earlyOpHandler);\n this.socket.on(\"signal\", this.earlySignalHandler);\n this.earlyOpHandlerAttached = true;\n\n this._details = await new Promise<IConnected>((resolve, reject) => {\n const fail = (socketProtocolError: boolean, err: IAnyDriverError) => {\n this.disposeCore(socketProtocolError, err);\n reject(err);\n };\n\n // Listen for connection issues\n this.addConnectionListener(\"connect_error\", (error) => {\n let isWebSocketTransportError = false;\n try {\n const description = error?.description;\n if (description && typeof description === \"object\") {\n if (error.type === \"TransportError\") {\n isWebSocketTransportError = true;\n }\n // That's a WebSocket. Clear it as we can't log it.\n description.target = undefined;\n }\n } catch(_e) {}\n\n // Handle socket transport downgrading.\n if (isWebSocketTransportError &&\n this.enableLongPollingDowngrades &&\n this.socket.io.opts.transports?.[0] !== \"polling\") {\n // Downgrade transports to polling upgrade mechanism.\n this.socket.io.opts.transports = [\"polling\", \"websocket\"];\n // Don't alter reconnection behavior if already enabled.\n if (!this.socket.io.reconnection()) {\n // Allow single reconnection attempt using polling upgrade mechanism.\n this.socket.io.reconnection(true);\n this.socket.io.reconnectionAttempts(1);\n }\n }\n\n // Allow built-in socket.io reconnection handling.\n if (this.socket.io.reconnection() &&\n this.reconnectAttempts < this.socket.io.reconnectionAttempts()) {\n // Reconnection is enabled and maximum reconnect attempts have not been reached.\n return;\n }\n\n fail(true, this.createErrorObject(\"connectError\", error));\n });\n\n this.addConnectionListener(\"reconnect_attempt\", () => {\n this.reconnectAttempts++;\n });\n\n // Listen for timeouts\n this.addConnectionListener(\"connect_timeout\", () => {\n fail(true, this.createErrorObject(\"connectTimeout\"));\n });\n\n this.addConnectionListener(\"connect_document_success\", (response: IConnected) => {\n // If we sent a nonce and the server supports nonces, check that the nonces match\n if (connectMessage.nonce !== undefined &&\n response.nonce !== undefined &&\n response.nonce !== connectMessage.nonce) {\n return;\n }\n\n const requestedMode = connectMessage.mode;\n const actualMode = response.mode;\n const writingPermitted = response.claims.scopes.includes(ScopeType.DocWrite);\n\n if (writingPermitted) {\n // The only time we expect a mismatch in requested/actual is if we lack write permissions\n // In this case we will get \"read\", even if we requested \"write\"\n if (actualMode !== requestedMode) {\n fail(false, this.createErrorObject(\n \"connectDocumentSuccess\",\n \"Connected in a different mode than was requested\",\n false,\n ));\n return;\n }\n } else {\n if (actualMode === \"write\") {\n fail(false, this.createErrorObject(\n \"connectDocumentSuccess\",\n \"Connected in write mode without write permissions\",\n false,\n ));\n return;\n }\n }\n\n this.checkpointSequenceNumber = response.checkpointSequenceNumber;\n\n this.removeConnectionListeners();\n resolve(response);\n });\n\n // Socket can be disconnected while waiting for Fluid protocol messages\n // (connect_document_error / connect_document_success), as well as before DeltaManager\n // had a chance to register its handlers.\n this.addTrackedListener(\"disconnect\", (reason) => {\n const err = this.createErrorObject(\"disconnect\", reason);\n this.emit(\"disconnect\", err);\n fail(true, err);\n });\n\n this.addTrackedListener(\"error\", ((error) => {\n // First, raise an error event, to give clients a chance to observe error contents\n // This includes \"Invalid namespace\" error, which we consider critical (reconnecting will not help)\n const err = this.createErrorObject(\"error\", error, error !== \"Invalid namespace\");\n this.emit(\"error\", err);\n // Disconnect socket - required if happened before initial handshake\n fail(true, err);\n }));\n\n this.addConnectionListener(\"connect_document_error\", ((error) => {\n // If we sent a nonce and the server supports nonces, check that the nonces match\n if (connectMessage.nonce !== undefined &&\n error.nonce !== undefined &&\n error.nonce !== connectMessage.nonce) {\n return;\n }\n\n // This is not an socket.io error - it's Fluid protocol error.\n // In this case fail connection and indicate that we were unable to create connection\n fail(false, this.createErrorObject(\"connectDocumentError\", error));\n }));\n\n this.socket.emit(\"connect_document\", connectMessage);\n\n // Give extra 2 seconds for handshake on top of socket connection timeout\n this.socketConnectionTimeout = setTimeout(() => {\n fail(false, this.createErrorObject(\"orderingServiceHandshakeTimeout\"));\n }, timeout + 2000);\n });\n\n assert(!this.disposed, 0x246 /* \"checking consistency of socket & _disposed flags\" */);\n }\n\n protected earlyOpHandler = (documentId: string, msgs: ISequencedDocumentMessage[]) => {\n this.queuedMessages.push(...msgs);\n };\n\n protected earlySignalHandler = (msg: ISignalMessage) => {\n this.queuedSignals.push(msg);\n };\n\n private removeEarlyOpHandler() {\n this.socket.removeListener(\"op\", this.earlyOpHandler);\n this.earlyOpHandlerAttached = false;\n }\n\n private removeEarlySignalHandler() {\n this.socket.removeListener(\"signal\", this.earlySignalHandler);\n }\n\n private addConnectionListener(event: string, listener: (...args: any[]) => void) {\n assert(!DocumentDeltaConnection.eventsAlwaysForwarded.includes(event),\n 0x247 /* \"Use addTrackedListener instead\" */);\n assert(!DocumentDeltaConnection.eventsToForward.includes(event),\n 0x248 /* \"should not subscribe to forwarded events\" */);\n this.socket.on(event, listener);\n assert(!this.connectionListeners.has(event), 0x20d /* \"double connection listener\" */);\n this.connectionListeners.set(event, listener);\n }\n\n protected addTrackedListener(event: string, listener: (...args: any[]) => void) {\n this.socket.on(event, listener);\n assert(!this.trackedListeners.has(event), 0x20e /* \"double tracked listener\" */);\n this.trackedListeners.set(event, listener);\n }\n\n private removeTrackedListeners() {\n for (const [event, listener] of this.trackedListeners.entries()) {\n this.socket.off(event, listener);\n }\n // removeTrackedListeners removes all listeners, including connection listeners\n this.removeConnectionListeners();\n\n this.removeEarlyOpHandler();\n this.removeEarlySignalHandler();\n\n this.trackedListeners.clear();\n }\n\n private removeConnectionListeners() {\n if (this.socketConnectionTimeout !== undefined) {\n clearTimeout(this.socketConnectionTimeout);\n }\n\n for (const [event, listener] of this.connectionListeners.entries()) {\n this.socket.off(event, listener);\n }\n this.connectionListeners.clear();\n }\n\n /**\n * Error raising for socket.io issues\n */\n protected createErrorObject(handler: string, error?: any, canRetry = true): IAnyDriverError {\n // Note: we suspect the incoming error object is either:\n // - a string: log it in the message (if not a string, it may contain PII but will print as [object Object])\n // - an Error object thrown by socket.io engine. Be careful with not recording PII!\n let message = `socket.io (${handler})`;\n if (typeof error !== \"object\") {\n message = `${message}: ${error}`;\n } else if (error?.type === \"TransportError\") {\n // JSON.stringify drops Error.message\n if (error?.message !== undefined) {\n message = `${message}: ${error.message}`;\n }\n // Websocket errors reported by engine.io-client.\n // They are Error objects with description containing WS error and description = \"TransportError\"\n // Please see https://github.com/socketio/engine.io-client/blob/7245b80/lib/transport.ts#L44,\n message = `${message}: ${JSON.stringify(error, getCircularReplacer())}`;\n } else {\n message = `${message}: [object omitted]`;\n }\n const errorObj = createGenericNetworkError(\n `socketError [${handler}]`,\n message,\n { canRetry },\n { driverVersion },\n );\n\n return errorObj;\n }\n}\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/driver-base";
8
- export declare const pkgVersion = "0.56.5";
8
+ export declare const pkgVersion = "0.57.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/driver-base";
8
- export const pkgVersion = "0.56.5";
8
+ export const pkgVersion = "0.57.0";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,6BAA6B,CAAC;AACrD,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-base\";\nexport const pkgVersion = \"0.56.5\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,6BAA6B,CAAC;AACrD,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/driver-base\";\nexport const pkgVersion = \"0.57.0\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/driver-base",
3
- "version": "0.56.5",
3
+ "version": "0.57.0",
4
4
  "description": "Shared driver code for Fluid driver implementations",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": "https://github.com/microsoft/FluidFramework",
@@ -32,13 +32,13 @@
32
32
  "@fluidframework/common-definitions": "^0.20.1",
33
33
  "@fluidframework/common-utils": "^0.32.1",
34
34
  "@fluidframework/driver-definitions": "^0.44.0",
35
- "@fluidframework/driver-utils": "^0.56.5",
35
+ "@fluidframework/driver-utils": "^0.57.0",
36
36
  "@fluidframework/protocol-definitions": "^0.1026.0",
37
- "@fluidframework/telemetry-utils": "^0.56.5"
37
+ "@fluidframework/telemetry-utils": "^0.57.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@fluidframework/build-common": "^0.23.0",
41
- "@fluidframework/eslint-config-fluid": "^0.25.0",
41
+ "@fluidframework/eslint-config-fluid": "^0.26.0",
42
42
  "@microsoft/api-extractor": "^7.16.1",
43
43
  "@rushstack/eslint-config": "^2.5.1",
44
44
  "@types/node": "^14.18.0",
@@ -7,9 +7,8 @@ import { assert, BatchManager, TypedEventEmitter } from "@fluidframework/common-
7
7
  import {
8
8
  IDocumentDeltaConnection,
9
9
  IDocumentDeltaConnectionEvents,
10
- DriverError,
11
10
  } from "@fluidframework/driver-definitions";
12
- import { createGenericNetworkError } from "@fluidframework/driver-utils";
11
+ import { createGenericNetworkError, IAnyDriverError } from "@fluidframework/driver-utils";
13
12
  import {
14
13
  ConnectionMode,
15
14
  IClientConfiguration,
@@ -29,6 +28,8 @@ import {
29
28
  loggerToMonitoringContext,
30
29
  MonitoringContext,
31
30
  } from "@fluidframework/telemetry-utils";
31
+ // For now, this package is versioned and released in unison with the specific drivers
32
+ import { pkgVersion as driverVersion } from "./packageVersion";
32
33
 
33
34
  // Local storage key to disable the BatchManager
34
35
  const batchManagerDisabledKey = "Fluid.Driver.BaseDocumentDeltaConnection.DisableBatchManager";
@@ -69,6 +70,8 @@ export class DocumentDeltaConnection
69
70
 
70
71
  private _details: IConnected | undefined;
71
72
 
73
+ private reconnectAttempts: number = 0;
74
+
72
75
  // Listeners only needed while the connection is in progress
73
76
  private readonly connectionListeners: Map<string, (...args: any[]) => void> = new Map();
74
77
  // Listeners used throughout the lifetime of the DocumentDeltaConnection
@@ -106,11 +109,14 @@ export class DocumentDeltaConnection
106
109
  /**
107
110
  * @param socket - websocket to be used
108
111
  * @param documentId - ID of the document
112
+ * @param logger - for reporting telemetry events
113
+ * @param enableLongPollingDowngrades - allow connection to be downgraded to long-polling on websocket failure
109
114
  */
110
115
  protected constructor(
111
116
  protected readonly socket: SocketIOClient.Socket,
112
117
  public documentId: string,
113
118
  logger: ITelemetryLogger,
119
+ private readonly enableLongPollingDowngrades: boolean = false,
114
120
  ) {
115
121
  super();
116
122
 
@@ -313,10 +319,11 @@ export class DocumentDeltaConnection
313
319
  public dispose() {
314
320
  this.disposeCore(
315
321
  false, // socketProtocolError
316
- createGenericNetworkError("clientClosingConnection", undefined, true /* canRetry */));
322
+ createGenericNetworkError(
323
+ "clientClosingConnection", undefined, { canRetry: true }, { driverVersion }));
317
324
  }
318
325
 
319
- protected disposeCore(socketProtocolError: boolean, err: any) {
326
+ protected disposeCore(socketProtocolError: boolean, err: IAnyDriverError) {
320
327
  // Can't check this.disposed here, as we get here on socket closure,
321
328
  // so _disposed & socket.connected might be not in sync while processing
322
329
  // "dispose" event.
@@ -341,7 +348,7 @@ export class DocumentDeltaConnection
341
348
  * (not on Fluid protocol level)
342
349
  * @param reason - reason for disconnect
343
350
  */
344
- protected disconnect(socketProtocolError: boolean, reason: any) {
351
+ protected disconnect(socketProtocolError: boolean, reason: IAnyDriverError) {
345
352
  this.socket.disconnect();
346
353
  }
347
354
 
@@ -351,23 +358,53 @@ export class DocumentDeltaConnection
351
358
  this.earlyOpHandlerAttached = true;
352
359
 
353
360
  this._details = await new Promise<IConnected>((resolve, reject) => {
354
- const fail = (socketProtocolError: boolean, err: DriverError) => {
361
+ const fail = (socketProtocolError: boolean, err: IAnyDriverError) => {
355
362
  this.disposeCore(socketProtocolError, err);
356
363
  reject(err);
357
364
  };
358
365
 
359
366
  // Listen for connection issues
360
367
  this.addConnectionListener("connect_error", (error) => {
368
+ let isWebSocketTransportError = false;
361
369
  try {
362
370
  const description = error?.description;
363
371
  if (description && typeof description === "object") {
372
+ if (error.type === "TransportError") {
373
+ isWebSocketTransportError = true;
374
+ }
364
375
  // That's a WebSocket. Clear it as we can't log it.
365
376
  description.target = undefined;
366
377
  }
367
378
  } catch(_e) {}
379
+
380
+ // Handle socket transport downgrading.
381
+ if (isWebSocketTransportError &&
382
+ this.enableLongPollingDowngrades &&
383
+ this.socket.io.opts.transports?.[0] !== "polling") {
384
+ // Downgrade transports to polling upgrade mechanism.
385
+ this.socket.io.opts.transports = ["polling", "websocket"];
386
+ // Don't alter reconnection behavior if already enabled.
387
+ if (!this.socket.io.reconnection()) {
388
+ // Allow single reconnection attempt using polling upgrade mechanism.
389
+ this.socket.io.reconnection(true);
390
+ this.socket.io.reconnectionAttempts(1);
391
+ }
392
+ }
393
+
394
+ // Allow built-in socket.io reconnection handling.
395
+ if (this.socket.io.reconnection() &&
396
+ this.reconnectAttempts < this.socket.io.reconnectionAttempts()) {
397
+ // Reconnection is enabled and maximum reconnect attempts have not been reached.
398
+ return;
399
+ }
400
+
368
401
  fail(true, this.createErrorObject("connectError", error));
369
402
  });
370
403
 
404
+ this.addConnectionListener("reconnect_attempt", () => {
405
+ this.reconnectAttempts++;
406
+ });
407
+
371
408
  // Listen for timeouts
372
409
  this.addConnectionListener("connect_timeout", () => {
373
410
  fail(true, this.createErrorObject("connectTimeout"));
@@ -515,7 +552,7 @@ export class DocumentDeltaConnection
515
552
  /**
516
553
  * Error raising for socket.io issues
517
554
  */
518
- protected createErrorObject(handler: string, error?: any, canRetry = true): DriverError {
555
+ protected createErrorObject(handler: string, error?: any, canRetry = true): IAnyDriverError {
519
556
  // Note: we suspect the incoming error object is either:
520
557
  // - a string: log it in the message (if not a string, it may contain PII but will print as [object Object])
521
558
  // - an Error object thrown by socket.io engine. Be careful with not recording PII!
@@ -537,7 +574,8 @@ export class DocumentDeltaConnection
537
574
  const errorObj = createGenericNetworkError(
538
575
  `socketError [${handler}]`,
539
576
  message,
540
- canRetry,
577
+ { canRetry },
578
+ { driverVersion },
541
579
  );
542
580
 
543
581
  return errorObj;
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/driver-base";
9
- export const pkgVersion = "0.56.5";
9
+ export const pkgVersion = "0.57.0";