@fluidframework/container-loader 2.0.0-internal.5.4.0 → 2.0.0-internal.6.1.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.
- package/CHANGELOG.md +85 -0
- package/dist/connectionManager.d.ts +4 -4
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +57 -49
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +15 -14
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +26 -28
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +10 -5
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +183 -134
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +2 -12
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +1 -20
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.js +3 -5
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +20 -7
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +3 -3
- package/dist/contracts.js.map +1 -1
- package/dist/debugLogger.js +2 -3
- package/dist/debugLogger.js.map +1 -1
- package/dist/deltaManager.d.ts +19 -6
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +67 -28
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.js +1 -2
- package/dist/deltaQueue.js.map +1 -1
- package/dist/loader.d.ts +12 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +57 -42
- package/dist/loader.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocol.d.ts +4 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +25 -4
- package/dist/protocol.js.map +1 -1
- package/dist/utils.d.ts +8 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +24 -6
- package/dist/utils.js.map +1 -1
- package/lib/connectionManager.d.ts +4 -4
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +58 -50
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +15 -14
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +26 -28
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +10 -5
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +182 -133
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +2 -12
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +1 -20
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.js +3 -5
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +20 -7
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js +3 -3
- package/lib/contracts.js.map +1 -1
- package/lib/debugLogger.js +2 -3
- package/lib/debugLogger.js.map +1 -1
- package/lib/deltaManager.d.ts +19 -6
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +67 -28
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.js +1 -2
- package/lib/deltaQueue.js.map +1 -1
- package/lib/loader.d.ts +12 -0
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +57 -42
- package/lib/loader.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocol.d.ts +4 -2
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +25 -4
- package/lib/protocol.js.map +1 -1
- package/lib/utils.d.ts +8 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +22 -5
- package/lib/utils.js.map +1 -1
- package/package.json +15 -19
- package/src/connectionManager.ts +53 -34
- package/src/connectionStateHandler.ts +30 -37
- package/src/container.ts +156 -76
- package/src/containerContext.ts +0 -24
- package/src/contracts.ts +27 -10
- package/src/deltaManager.ts +41 -18
- package/src/loader.ts +37 -23
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +33 -2
- package/src/utils.ts +29 -0
package/dist/utils.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.isDeltaStreamConnectionForbiddenError = exports.getProtocolSnapshotTree = exports.getSnapshotTreeFromSerializedContainer = exports.convertProtocolAndAppSummaryToSnapshotTree = exports.parseUrl = void 0;
|
|
7
|
+
exports.isDeltaStreamConnectionForbiddenError = exports.getProtocolSnapshotTree = exports.getSnapshotTreeFromSerializedContainer = exports.convertProtocolAndAppSummaryToSnapshotTree = exports.combineAppAndProtocolSummary = exports.parseUrl = void 0;
|
|
8
8
|
const url_1 = require("url");
|
|
9
9
|
const uuid_1 = require("uuid");
|
|
10
10
|
const common_utils_1 = require("@fluidframework/common-utils");
|
|
@@ -13,19 +13,37 @@ const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
|
13
13
|
const driver_utils_1 = require("@fluidframework/driver-utils");
|
|
14
14
|
const driver_definitions_1 = require("@fluidframework/driver-definitions");
|
|
15
15
|
function parseUrl(url) {
|
|
16
|
-
var _a;
|
|
17
16
|
const parsed = (0, url_1.parse)(url, true);
|
|
18
17
|
if (typeof parsed.pathname !== "string") {
|
|
19
18
|
throw new telemetry_utils_1.LoggingError("Failed to parse pathname");
|
|
20
19
|
}
|
|
21
|
-
const query =
|
|
20
|
+
const query = parsed.search ?? "";
|
|
22
21
|
const regex = /^\/([^/]*\/[^/]*)(\/?.*)$/;
|
|
23
22
|
const match = regex.exec(parsed.pathname);
|
|
24
|
-
return
|
|
23
|
+
return match?.length === 3
|
|
25
24
|
? { id: match[1], path: match[2], query, version: parsed.query.version }
|
|
26
25
|
: undefined;
|
|
27
26
|
}
|
|
28
27
|
exports.parseUrl = parseUrl;
|
|
28
|
+
/**
|
|
29
|
+
* Combine the app summary and protocol summary in 1 tree.
|
|
30
|
+
* @param appSummary - Summary of the app.
|
|
31
|
+
* @param protocolSummary - Summary of the protocol.
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
function combineAppAndProtocolSummary(appSummary, protocolSummary) {
|
|
35
|
+
(0, common_utils_1.assert)(!(0, driver_utils_1.isCombinedAppAndProtocolSummary)(appSummary), 0x5a8 /* app summary is already a combined tree! */);
|
|
36
|
+
(0, common_utils_1.assert)(!(0, driver_utils_1.isCombinedAppAndProtocolSummary)(protocolSummary), 0x5a9 /* protocol summary is already a combined tree! */);
|
|
37
|
+
const createNewSummary = {
|
|
38
|
+
type: protocol_definitions_1.SummaryType.Tree,
|
|
39
|
+
tree: {
|
|
40
|
+
".protocol": protocolSummary,
|
|
41
|
+
".app": appSummary,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
return createNewSummary;
|
|
45
|
+
}
|
|
46
|
+
exports.combineAppAndProtocolSummary = combineAppAndProtocolSummary;
|
|
29
47
|
/**
|
|
30
48
|
* Converts summary tree (for upload) to snapshot tree (for download).
|
|
31
49
|
* Summary tree blobs contain contents, but snapshot tree blobs normally
|
|
@@ -84,7 +102,7 @@ function convertProtocolAndAppSummaryToSnapshotTree(protocolSummaryTree, appSumm
|
|
|
84
102
|
// Shallow copy is fine, since we are doing a deep clone below.
|
|
85
103
|
const combinedSummary = {
|
|
86
104
|
type: protocol_definitions_1.SummaryType.Tree,
|
|
87
|
-
tree:
|
|
105
|
+
tree: { ...appSummaryTree.tree },
|
|
88
106
|
};
|
|
89
107
|
combinedSummary.tree[".protocol"] = protocolSummaryTree;
|
|
90
108
|
const snapshotTreeWithBlobContents = convertSummaryToSnapshotWithEmbeddedBlobContents(combinedSummary);
|
|
@@ -108,7 +126,7 @@ exports.getProtocolSnapshotTree = getProtocolSnapshotTree;
|
|
|
108
126
|
function isDeltaStreamConnectionForbiddenError(error) {
|
|
109
127
|
return (typeof error === "object" &&
|
|
110
128
|
error !== null &&
|
|
111
|
-
|
|
129
|
+
error?.errorType === driver_definitions_1.DriverErrorType.deltaStreamConnectionForbidden);
|
|
112
130
|
}
|
|
113
131
|
exports.isDeltaStreamConnectionForbiddenError = isDeltaStreamConnectionForbiddenError;
|
|
114
132
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.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 { parse } from \"url\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n\tassert,\n\tstringToBuffer,\n\tUint8ArrayToArrayBuffer,\n\tunreachableCase,\n} from \"@fluidframework/common-utils\";\nimport { ISummaryTree, ISnapshotTree, SummaryType } from \"@fluidframework/protocol-definitions\";\nimport { LoggingError } from \"@fluidframework/telemetry-utils\";\nimport {\n\tDeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n} from \"@fluidframework/driver-utils\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\n\n// This is used when we rehydrate a container from the snapshot. Here we put the blob contents\n// in separate property: blobContents.\nexport interface ISnapshotTreeWithBlobContents extends ISnapshotTree {\n\tblobsContents: { [path: string]: ArrayBufferLike };\n\ttrees: { [path: string]: ISnapshotTreeWithBlobContents };\n}\n\nexport interface IParsedUrl {\n\tid: string;\n\tpath: string;\n\tquery: string;\n\t/**\n\t * Null means do not use snapshots, undefined means load latest snapshot\n\t * otherwise it's version ID passed to IDocumentStorageService.getVersions() to figure out what snapshot to use.\n\t * If needed, can add undefined which is treated by Container.load() as load latest snapshot.\n\t */\n\tversion: string | null | undefined;\n}\n\nexport function parseUrl(url: string): IParsedUrl | undefined {\n\tconst parsed = parse(url, true);\n\tif (typeof parsed.pathname !== \"string\") {\n\t\tthrow new LoggingError(\"Failed to parse pathname\");\n\t}\n\tconst query = parsed.search ?? \"\";\n\tconst regex = /^\\/([^/]*\\/[^/]*)(\\/?.*)$/;\n\tconst match = regex.exec(parsed.pathname);\n\treturn match?.length === 3\n\t\t? { id: match[1], path: match[2], query, version: parsed.query.version as string }\n\t\t: undefined;\n}\n\n/**\n * Converts summary tree (for upload) to snapshot tree (for download).\n * Summary tree blobs contain contents, but snapshot tree blobs normally\n * contain IDs pointing to storage. This will create 2 blob entries in the\n * snapshot tree for each blob in the summary tree. One will be the regular\n * path pointing to a uniquely generated ID. Then there will be another\n * entry with the path as that uniquely generated ID, and value as the\n * blob contents as a base-64 string.\n * @param summary - summary to convert\n */\nfunction convertSummaryToSnapshotWithEmbeddedBlobContents(\n\tsummary: ISummaryTree,\n): ISnapshotTreeWithBlobContents {\n\tconst treeNode: ISnapshotTreeWithBlobContents = {\n\t\tblobs: {},\n\t\tblobsContents: {},\n\t\ttrees: {},\n\t\tid: uuid(),\n\t\tunreferenced: summary.unreferenced,\n\t};\n\tconst keys = Object.keys(summary.tree);\n\tfor (const key of keys) {\n\t\tconst summaryObject = summary.tree[key];\n\n\t\tswitch (summaryObject.type) {\n\t\t\tcase SummaryType.Tree: {\n\t\t\t\ttreeNode.trees[key] =\n\t\t\t\t\tconvertSummaryToSnapshotWithEmbeddedBlobContents(summaryObject);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Attachment:\n\t\t\t\ttreeNode.blobs[key] = summaryObject.id;\n\t\t\t\tbreak;\n\t\t\tcase SummaryType.Blob: {\n\t\t\t\tconst blobId = uuid();\n\t\t\t\ttreeNode.blobs[key] = blobId;\n\t\t\t\tconst contentBuffer =\n\t\t\t\t\ttypeof summaryObject.content === \"string\"\n\t\t\t\t\t\t? stringToBuffer(summaryObject.content, \"utf8\")\n\t\t\t\t\t\t: Uint8ArrayToArrayBuffer(summaryObject.content);\n\t\t\t\ttreeNode.blobsContents[blobId] = contentBuffer;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Handle:\n\t\t\t\tthrow new LoggingError(\n\t\t\t\t\t\"No handles should be there in summary in detached container!!\",\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn treeNode;\n}\n\n/**\n * Combine and convert protocol and app summary tree to format which is readable by container while rehydrating.\n * @param protocolSummaryTree - Protocol Summary Tree\n * @param appSummaryTree - App Summary Tree\n */\nexport function convertProtocolAndAppSummaryToSnapshotTree(\n\tprotocolSummaryTree: ISummaryTree,\n\tappSummaryTree: ISummaryTree,\n): ISnapshotTreeWithBlobContents {\n\t// Shallow copy is fine, since we are doing a deep clone below.\n\tconst combinedSummary: ISummaryTree = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: { ...appSummaryTree.tree },\n\t};\n\n\tcombinedSummary.tree[\".protocol\"] = protocolSummaryTree;\n\tconst snapshotTreeWithBlobContents =\n\t\tconvertSummaryToSnapshotWithEmbeddedBlobContents(combinedSummary);\n\treturn snapshotTreeWithBlobContents;\n}\n\n// This function converts the snapshot taken in detached container(by serialize api) to snapshotTree with which\n// a detached container can be rehydrated.\nexport const getSnapshotTreeFromSerializedContainer = (\n\tdetachedContainerSnapshot: ISummaryTree,\n): ISnapshotTreeWithBlobContents => {\n\tassert(\n\t\tisCombinedAppAndProtocolSummary(detachedContainerSnapshot),\n\t\t0x1e0 /* \"Protocol and App summary trees should be present\" */,\n\t);\n\tconst protocolSummaryTree = detachedContainerSnapshot.tree[\".protocol\"];\n\tconst appSummaryTree = detachedContainerSnapshot.tree[\".app\"];\n\tconst snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotTree(\n\t\tprotocolSummaryTree,\n\t\tappSummaryTree,\n\t);\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {\n\treturn \".protocol\" in snapshot.trees ? snapshot.trees[\".protocol\"] : snapshot;\n}\n\nexport function isDeltaStreamConnectionForbiddenError(\n\terror: any,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\terror?.errorType === DriverErrorType.deltaStreamConnectionForbidden\n\t);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.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 { parse } from \"url\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n\tassert,\n\tstringToBuffer,\n\tUint8ArrayToArrayBuffer,\n\tunreachableCase,\n} from \"@fluidframework/common-utils\";\nimport { ISummaryTree, ISnapshotTree, SummaryType } from \"@fluidframework/protocol-definitions\";\nimport { LoggingError } from \"@fluidframework/telemetry-utils\";\nimport {\n\tCombinedAppAndProtocolSummary,\n\tDeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n} from \"@fluidframework/driver-utils\";\nimport { DriverErrorType } from \"@fluidframework/driver-definitions\";\n\n// This is used when we rehydrate a container from the snapshot. Here we put the blob contents\n// in separate property: blobContents.\nexport interface ISnapshotTreeWithBlobContents extends ISnapshotTree {\n\tblobsContents: { [path: string]: ArrayBufferLike };\n\ttrees: { [path: string]: ISnapshotTreeWithBlobContents };\n}\n\nexport interface IParsedUrl {\n\tid: string;\n\tpath: string;\n\tquery: string;\n\t/**\n\t * Null means do not use snapshots, undefined means load latest snapshot\n\t * otherwise it's version ID passed to IDocumentStorageService.getVersions() to figure out what snapshot to use.\n\t * If needed, can add undefined which is treated by Container.load() as load latest snapshot.\n\t */\n\tversion: string | null | undefined;\n}\n\nexport function parseUrl(url: string): IParsedUrl | undefined {\n\tconst parsed = parse(url, true);\n\tif (typeof parsed.pathname !== \"string\") {\n\t\tthrow new LoggingError(\"Failed to parse pathname\");\n\t}\n\tconst query = parsed.search ?? \"\";\n\tconst regex = /^\\/([^/]*\\/[^/]*)(\\/?.*)$/;\n\tconst match = regex.exec(parsed.pathname);\n\treturn match?.length === 3\n\t\t? { id: match[1], path: match[2], query, version: parsed.query.version as string }\n\t\t: undefined;\n}\n\n/**\n * Combine the app summary and protocol summary in 1 tree.\n * @param appSummary - Summary of the app.\n * @param protocolSummary - Summary of the protocol.\n * @internal\n */\nexport function combineAppAndProtocolSummary(\n\tappSummary: ISummaryTree,\n\tprotocolSummary: ISummaryTree,\n): CombinedAppAndProtocolSummary {\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(appSummary),\n\t\t0x5a8 /* app summary is already a combined tree! */,\n\t);\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(protocolSummary),\n\t\t0x5a9 /* protocol summary is already a combined tree! */,\n\t);\n\tconst createNewSummary: CombinedAppAndProtocolSummary = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: {\n\t\t\t\".protocol\": protocolSummary,\n\t\t\t\".app\": appSummary,\n\t\t},\n\t};\n\treturn createNewSummary;\n}\n\n/**\n * Converts summary tree (for upload) to snapshot tree (for download).\n * Summary tree blobs contain contents, but snapshot tree blobs normally\n * contain IDs pointing to storage. This will create 2 blob entries in the\n * snapshot tree for each blob in the summary tree. One will be the regular\n * path pointing to a uniquely generated ID. Then there will be another\n * entry with the path as that uniquely generated ID, and value as the\n * blob contents as a base-64 string.\n * @param summary - summary to convert\n */\nfunction convertSummaryToSnapshotWithEmbeddedBlobContents(\n\tsummary: ISummaryTree,\n): ISnapshotTreeWithBlobContents {\n\tconst treeNode: ISnapshotTreeWithBlobContents = {\n\t\tblobs: {},\n\t\tblobsContents: {},\n\t\ttrees: {},\n\t\tid: uuid(),\n\t\tunreferenced: summary.unreferenced,\n\t};\n\tconst keys = Object.keys(summary.tree);\n\tfor (const key of keys) {\n\t\tconst summaryObject = summary.tree[key];\n\n\t\tswitch (summaryObject.type) {\n\t\t\tcase SummaryType.Tree: {\n\t\t\t\ttreeNode.trees[key] =\n\t\t\t\t\tconvertSummaryToSnapshotWithEmbeddedBlobContents(summaryObject);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Attachment:\n\t\t\t\ttreeNode.blobs[key] = summaryObject.id;\n\t\t\t\tbreak;\n\t\t\tcase SummaryType.Blob: {\n\t\t\t\tconst blobId = uuid();\n\t\t\t\ttreeNode.blobs[key] = blobId;\n\t\t\t\tconst contentBuffer =\n\t\t\t\t\ttypeof summaryObject.content === \"string\"\n\t\t\t\t\t\t? stringToBuffer(summaryObject.content, \"utf8\")\n\t\t\t\t\t\t: Uint8ArrayToArrayBuffer(summaryObject.content);\n\t\t\t\ttreeNode.blobsContents[blobId] = contentBuffer;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Handle:\n\t\t\t\tthrow new LoggingError(\n\t\t\t\t\t\"No handles should be there in summary in detached container!!\",\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn treeNode;\n}\n\n/**\n * Combine and convert protocol and app summary tree to format which is readable by container while rehydrating.\n * @param protocolSummaryTree - Protocol Summary Tree\n * @param appSummaryTree - App Summary Tree\n */\nexport function convertProtocolAndAppSummaryToSnapshotTree(\n\tprotocolSummaryTree: ISummaryTree,\n\tappSummaryTree: ISummaryTree,\n): ISnapshotTreeWithBlobContents {\n\t// Shallow copy is fine, since we are doing a deep clone below.\n\tconst combinedSummary: ISummaryTree = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: { ...appSummaryTree.tree },\n\t};\n\n\tcombinedSummary.tree[\".protocol\"] = protocolSummaryTree;\n\tconst snapshotTreeWithBlobContents =\n\t\tconvertSummaryToSnapshotWithEmbeddedBlobContents(combinedSummary);\n\treturn snapshotTreeWithBlobContents;\n}\n\n// This function converts the snapshot taken in detached container(by serialize api) to snapshotTree with which\n// a detached container can be rehydrated.\nexport const getSnapshotTreeFromSerializedContainer = (\n\tdetachedContainerSnapshot: ISummaryTree,\n): ISnapshotTreeWithBlobContents => {\n\tassert(\n\t\tisCombinedAppAndProtocolSummary(detachedContainerSnapshot),\n\t\t0x1e0 /* \"Protocol and App summary trees should be present\" */,\n\t);\n\tconst protocolSummaryTree = detachedContainerSnapshot.tree[\".protocol\"];\n\tconst appSummaryTree = detachedContainerSnapshot.tree[\".app\"];\n\tconst snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotTree(\n\t\tprotocolSummaryTree,\n\t\tappSummaryTree,\n\t);\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {\n\treturn \".protocol\" in snapshot.trees ? snapshot.trees[\".protocol\"] : snapshot;\n}\n\nexport function isDeltaStreamConnectionForbiddenError(\n\terror: any,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\terror?.errorType === DriverErrorType.deltaStreamConnectionForbidden\n\t);\n}\n"]}
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { ITelemetryProperties } from "@fluidframework/core-interfaces";
|
|
6
|
-
import { IDeltaQueue, ReadOnlyInfo
|
|
6
|
+
import { ICriticalContainerError, IDeltaQueue, ReadOnlyInfo } from "@fluidframework/container-definitions";
|
|
7
7
|
import { IDocumentService } from "@fluidframework/driver-definitions";
|
|
8
8
|
import { ConnectionMode, IClient, IClientConfiguration, IClientDetails, IDocumentMessage, ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
|
9
9
|
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
|
|
10
|
-
import { ReconnectMode, IConnectionManager, IConnectionManagerFactoryArgs } from "./contracts";
|
|
10
|
+
import { ReconnectMode, IConnectionManager, IConnectionManagerFactoryArgs, IConnectionStateChangeReason } from "./contracts";
|
|
11
11
|
/**
|
|
12
12
|
* Implementation of IConnectionManager, used by Container class
|
|
13
13
|
* Implements constant connectivity to relay service, by reconnecting in case of lost connection or error.
|
|
@@ -91,7 +91,7 @@ export declare class ConnectionManager implements IConnectionManager {
|
|
|
91
91
|
* Enables or disables automatic reconnecting.
|
|
92
92
|
* Will throw an error if reconnectMode set to Never.
|
|
93
93
|
*/
|
|
94
|
-
setAutoReconnect(mode: ReconnectMode): void;
|
|
94
|
+
setAutoReconnect(mode: ReconnectMode, reason: IConnectionStateChangeReason): void;
|
|
95
95
|
/**
|
|
96
96
|
* Sends signal to runtime (and data stores) to be read-only.
|
|
97
97
|
* Hosts may have read only views, indicating to data stores that no edits are allowed.
|
|
@@ -111,7 +111,7 @@ export declare class ConnectionManager implements IConnectionManager {
|
|
|
111
111
|
*/
|
|
112
112
|
forceReadonly(readonly: boolean): void;
|
|
113
113
|
private set_readonlyPermissions;
|
|
114
|
-
connect(reason:
|
|
114
|
+
connect(reason: IConnectionStateChangeReason, connectionMode?: ConnectionMode): void;
|
|
115
115
|
private connectCore;
|
|
116
116
|
/**
|
|
117
117
|
* Start the connection. Any error should result in container being closed.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connectionManager.d.ts","sourceRoot":"","sources":["../src/connectionManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAe,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEpF,OAAO,EACN,WAAW,EACX,YAAY,
|
|
1
|
+
{"version":3,"file":"connectionManager.d.ts","sourceRoot":"","sources":["../src/connectionManager.ts"],"names":[],"mappings":"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"}
|
package/lib/connectionManager.js
CHANGED
|
@@ -7,7 +7,7 @@ import { GenericError, UsageError } from "@fluidframework/container-utils";
|
|
|
7
7
|
import { canRetryOnError, createWriteError, createGenericNetworkError, getRetryDelayFromError, logNetworkFailure, isRuntimeMessage, calculateMaxWaitTime, } from "@fluidframework/driver-utils";
|
|
8
8
|
import { MessageType, ScopeType, } from "@fluidframework/protocol-definitions";
|
|
9
9
|
import { formatTick, normalizeError } from "@fluidframework/telemetry-utils";
|
|
10
|
-
import { ReconnectMode } from "./contracts";
|
|
10
|
+
import { ReconnectMode, } from "./contracts";
|
|
11
11
|
import { DeltaQueue } from "./deltaQueue";
|
|
12
12
|
import { SignalType } from "./protocol";
|
|
13
13
|
import { isDeltaStreamConnectionForbiddenError } from "./utils";
|
|
@@ -81,9 +81,8 @@ function isNoDeltaStreamConnection(connection) {
|
|
|
81
81
|
return connection instanceof NoDeltaStream;
|
|
82
82
|
}
|
|
83
83
|
const waitForOnline = async () => {
|
|
84
|
-
var _a;
|
|
85
84
|
// Only wait if we have a strong signal that we're offline - otherwise assume we're online.
|
|
86
|
-
if (
|
|
85
|
+
if (globalThis.navigator?.onLine === false && globalThis.addEventListener !== undefined) {
|
|
87
86
|
return new Promise((resolve) => {
|
|
88
87
|
const resolveAndRemoveListener = () => {
|
|
89
88
|
resolve();
|
|
@@ -167,15 +166,13 @@ export class ConnectionManager {
|
|
|
167
166
|
* The current connection mode, initially read.
|
|
168
167
|
*/
|
|
169
168
|
get connectionMode() {
|
|
170
|
-
|
|
171
|
-
return (_b = (_a = this.connection) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : "read";
|
|
169
|
+
return this.connection?.mode ?? "read";
|
|
172
170
|
}
|
|
173
171
|
get connected() {
|
|
174
172
|
return this.connection !== undefined;
|
|
175
173
|
}
|
|
176
174
|
get clientId() {
|
|
177
|
-
|
|
178
|
-
return (_a = this.connection) === null || _a === void 0 ? void 0 : _a.clientId;
|
|
175
|
+
return this.connection?.clientId;
|
|
179
176
|
}
|
|
180
177
|
/**
|
|
181
178
|
* Automatic reconnecting enabled or disabled.
|
|
@@ -185,8 +182,7 @@ export class ConnectionManager {
|
|
|
185
182
|
return this._reconnectMode;
|
|
186
183
|
}
|
|
187
184
|
get maxMessageSize() {
|
|
188
|
-
|
|
189
|
-
return (_c = (_b = (_a = this.connection) === null || _a === void 0 ? void 0 : _a.serviceConfiguration) === null || _b === void 0 ? void 0 : _b.maxMessageSize) !== null && _c !== void 0 ? _c : DefaultChunkSize;
|
|
185
|
+
return this.connection?.serviceConfiguration?.maxMessageSize ?? DefaultChunkSize;
|
|
190
186
|
}
|
|
191
187
|
get version() {
|
|
192
188
|
if (this.connection === undefined) {
|
|
@@ -195,12 +191,10 @@ export class ConnectionManager {
|
|
|
195
191
|
return this.connection.version;
|
|
196
192
|
}
|
|
197
193
|
get serviceConfiguration() {
|
|
198
|
-
|
|
199
|
-
return (_a = this.connection) === null || _a === void 0 ? void 0 : _a.serviceConfiguration;
|
|
194
|
+
return this.connection?.serviceConfiguration;
|
|
200
195
|
}
|
|
201
196
|
get scopes() {
|
|
202
|
-
|
|
203
|
-
return (_a = this.connection) === null || _a === void 0 ? void 0 : _a.claims.scopes;
|
|
197
|
+
return this.connection?.claims.scopes;
|
|
204
198
|
}
|
|
205
199
|
get outbound() {
|
|
206
200
|
return this._outbound;
|
|
@@ -212,9 +206,11 @@ export class ConnectionManager {
|
|
|
212
206
|
get connectionProps() {
|
|
213
207
|
return this.connection !== undefined
|
|
214
208
|
? this._connectionProps
|
|
215
|
-
:
|
|
209
|
+
: {
|
|
210
|
+
...this._connectionProps,
|
|
216
211
|
// Report how many ops this client sent in last disconnected session
|
|
217
|
-
sentOps: this.clientSequenceNumber
|
|
212
|
+
sentOps: this.clientSequenceNumber,
|
|
213
|
+
};
|
|
218
214
|
}
|
|
219
215
|
shouldJoinWrite() {
|
|
220
216
|
// We don't have to wait for ack for topmost NoOps. So subtract those.
|
|
@@ -284,7 +280,10 @@ export class ConnectionManager {
|
|
|
284
280
|
// Ensure that things like triggerConnect() will short circuit
|
|
285
281
|
this._reconnectMode = ReconnectMode.Never;
|
|
286
282
|
this._outbound.clear();
|
|
287
|
-
const disconnectReason =
|
|
283
|
+
const disconnectReason = {
|
|
284
|
+
text: "Closing DeltaManager",
|
|
285
|
+
error,
|
|
286
|
+
};
|
|
288
287
|
// This raises "disconnect" event if we have active connection.
|
|
289
288
|
this.disconnectFromDeltaStream(disconnectReason);
|
|
290
289
|
if (switchToReadonly) {
|
|
@@ -298,12 +297,12 @@ export class ConnectionManager {
|
|
|
298
297
|
* Enables or disables automatic reconnecting.
|
|
299
298
|
* Will throw an error if reconnectMode set to Never.
|
|
300
299
|
*/
|
|
301
|
-
setAutoReconnect(mode) {
|
|
300
|
+
setAutoReconnect(mode, reason) {
|
|
302
301
|
assert(mode !== ReconnectMode.Never && this._reconnectMode !== ReconnectMode.Never, 0x278 /* "API is not supported for non-connecting or closed container" */);
|
|
303
302
|
this._reconnectMode = mode;
|
|
304
303
|
if (mode !== ReconnectMode.Enabled) {
|
|
305
304
|
// immediately disconnect - do not rely on service eventually dropping connection.
|
|
306
|
-
this.disconnectFromDeltaStream(
|
|
305
|
+
this.disconnectFromDeltaStream(reason);
|
|
307
306
|
}
|
|
308
307
|
}
|
|
309
308
|
/**
|
|
@@ -346,12 +345,12 @@ export class ConnectionManager {
|
|
|
346
345
|
// host logic error.
|
|
347
346
|
this.logger.sendErrorEvent({ eventName: "ForceReadonlyPendingChanged" });
|
|
348
347
|
}
|
|
349
|
-
reconnect = this.disconnectFromDeltaStream("Force readonly");
|
|
348
|
+
reconnect = this.disconnectFromDeltaStream({ text: "Force readonly" });
|
|
350
349
|
}
|
|
351
350
|
this.props.readonlyChangeHandler(this.readonly);
|
|
352
351
|
if (reconnect) {
|
|
353
352
|
// reconnect if we disconnected from before.
|
|
354
|
-
this.triggerConnect("Force Readonly", "read");
|
|
353
|
+
this.triggerConnect({ text: "Force Readonly" }, "read");
|
|
355
354
|
}
|
|
356
355
|
}
|
|
357
356
|
}
|
|
@@ -363,13 +362,12 @@ export class ConnectionManager {
|
|
|
363
362
|
}
|
|
364
363
|
}
|
|
365
364
|
connect(reason, connectionMode) {
|
|
366
|
-
this.connectCore(reason, connectionMode).catch((
|
|
367
|
-
const normalizedError = normalizeError(
|
|
365
|
+
this.connectCore(reason, connectionMode).catch((e) => {
|
|
366
|
+
const normalizedError = normalizeError(e, { props: fatalConnectErrorProp });
|
|
368
367
|
this.props.closeHandler(normalizedError);
|
|
369
368
|
});
|
|
370
369
|
}
|
|
371
370
|
async connectCore(reason, connectionMode) {
|
|
372
|
-
var _a, _b, _c;
|
|
373
371
|
assert(!this._disposed, 0x26a /* "not closed" */);
|
|
374
372
|
if (this.connection !== undefined) {
|
|
375
373
|
return; // Connection attempt already completed successfully
|
|
@@ -381,7 +379,7 @@ export class ConnectionManager {
|
|
|
381
379
|
assert(this.pendingConnection === undefined, 0x344 /* this.pendingConnection should be undefined */);
|
|
382
380
|
}
|
|
383
381
|
// If there is no specified ConnectionMode, try the previous mode, if there is no previous mode use default
|
|
384
|
-
let requestedMode =
|
|
382
|
+
let requestedMode = connectionMode ?? pendingConnectionMode ?? this.defaultReconnectionMode;
|
|
385
383
|
// if we have any non-acked ops from last connection, reconnect as "write".
|
|
386
384
|
// without that we would connect in view-only mode, which will result in immediate
|
|
387
385
|
// firing of "connected" event from Container and switch of current clientId (as tracked
|
|
@@ -393,7 +391,7 @@ export class ConnectionManager {
|
|
|
393
391
|
const docService = this.serviceProvider();
|
|
394
392
|
assert(docService !== undefined, 0x2a7 /* "Container is not attached" */);
|
|
395
393
|
let connection;
|
|
396
|
-
if (
|
|
394
|
+
if (docService.policies?.storageOnly === true) {
|
|
397
395
|
connection = new NoDeltaStream();
|
|
398
396
|
this.setupNewSuccessfulConnection(connection, "read", reason);
|
|
399
397
|
assert(this.pendingConnection === undefined, 0x2b3 /* "logic error" */);
|
|
@@ -429,7 +427,10 @@ export class ConnectionManager {
|
|
|
429
427
|
connectRepeatCount++;
|
|
430
428
|
try {
|
|
431
429
|
this.client.mode = requestedMode;
|
|
432
|
-
connection = await docService.connectToDeltaStream(
|
|
430
|
+
connection = await docService.connectToDeltaStream({
|
|
431
|
+
...this.client,
|
|
432
|
+
mode: requestedMode,
|
|
433
|
+
});
|
|
433
434
|
if (connection.disposed) {
|
|
434
435
|
// Nobody observed this connection, so drop it on the floor and retry.
|
|
435
436
|
this.logger.sendTelemetryEvent({ eventName: "ReceivedClosedConnection" });
|
|
@@ -465,7 +466,7 @@ export class ConnectionManager {
|
|
|
465
466
|
setTimeout(resolve, retryDelayFromError);
|
|
466
467
|
});
|
|
467
468
|
}
|
|
468
|
-
else if (
|
|
469
|
+
else if (globalThis.navigator?.onLine !== false) {
|
|
469
470
|
// If the error didn't tell us to wait, let's still wait a little bit before retrying.
|
|
470
471
|
// We skip this delay if we're confident we're offline, because we probably just need to wait to come back online.
|
|
471
472
|
await new Promise((resolve) => {
|
|
@@ -531,7 +532,7 @@ export class ConnectionManager {
|
|
|
531
532
|
* @param error - Error causing the disconnect if any.
|
|
532
533
|
* @returns A boolean that indicates if there was an existing connection (or pending connection) to disconnect
|
|
533
534
|
*/
|
|
534
|
-
disconnectFromDeltaStream(reason
|
|
535
|
+
disconnectFromDeltaStream(reason) {
|
|
535
536
|
this.pendingReconnect = false;
|
|
536
537
|
if (this.connection === undefined) {
|
|
537
538
|
if (this.pendingConnection !== undefined) {
|
|
@@ -555,7 +556,7 @@ export class ConnectionManager {
|
|
|
555
556
|
this._outbound.pause();
|
|
556
557
|
this._outbound.clear();
|
|
557
558
|
connection.dispose();
|
|
558
|
-
this.props.disconnectHandler(reason
|
|
559
|
+
this.props.disconnectHandler(reason);
|
|
559
560
|
this._connectionVerboseProps = {};
|
|
560
561
|
return true;
|
|
561
562
|
}
|
|
@@ -567,7 +568,10 @@ export class ConnectionManager {
|
|
|
567
568
|
this.pendingConnection.abort();
|
|
568
569
|
this.pendingConnection = undefined;
|
|
569
570
|
this.logger.sendTelemetryEvent({ eventName: "ConnectionCancelReceived" });
|
|
570
|
-
this.props.cancelConnectionHandler(
|
|
571
|
+
this.props.cancelConnectionHandler({
|
|
572
|
+
text: `Cancel Pending Connection due to ${reason.text}`,
|
|
573
|
+
error: reason.error,
|
|
574
|
+
});
|
|
571
575
|
}
|
|
572
576
|
/**
|
|
573
577
|
* Once we've successfully gotten a connection, we need to set up state, attach event listeners, and process
|
|
@@ -575,7 +579,6 @@ export class ConnectionManager {
|
|
|
575
579
|
* @param connection - The newly established connection
|
|
576
580
|
*/
|
|
577
581
|
setupNewSuccessfulConnection(connection, requestedMode, reason) {
|
|
578
|
-
var _a;
|
|
579
582
|
// Old connection should have been cleaned up before establishing a new one
|
|
580
583
|
assert(this.connection === undefined, 0x0e6 /* "old connection exists on new connection setup" */);
|
|
581
584
|
assert(!connection.disposed, 0x28a /* "can't be disposed - Callers need to ensure that!" */);
|
|
@@ -599,7 +602,7 @@ export class ConnectionManager {
|
|
|
599
602
|
this.set_readonlyPermissions(readonly);
|
|
600
603
|
if (this._disposed) {
|
|
601
604
|
// Raise proper events, Log telemetry event and close connection.
|
|
602
|
-
this.disconnectFromDeltaStream("ConnectionManager already closed");
|
|
605
|
+
this.disconnectFromDeltaStream({ text: "ConnectionManager already closed" });
|
|
603
606
|
return;
|
|
604
607
|
}
|
|
605
608
|
this._outbound.resume();
|
|
@@ -656,7 +659,7 @@ export class ConnectionManager {
|
|
|
656
659
|
}),
|
|
657
660
|
};
|
|
658
661
|
this.props.signalHandler(clearSignal);
|
|
659
|
-
for (const priorClient of
|
|
662
|
+
for (const priorClient of connection.initialClients ?? []) {
|
|
660
663
|
const joinSignal = {
|
|
661
664
|
clientId: null,
|
|
662
665
|
content: JSON.stringify({
|
|
@@ -684,7 +687,7 @@ export class ConnectionManager {
|
|
|
684
687
|
* @returns A promise that resolves when the connection is reestablished or we stop trying
|
|
685
688
|
*/
|
|
686
689
|
reconnectOnError(requestedMode, error) {
|
|
687
|
-
this.reconnect(requestedMode, error.message, error).catch(this.props.closeHandler);
|
|
690
|
+
this.reconnect(requestedMode, { text: error.message, error }).catch(this.props.closeHandler);
|
|
688
691
|
}
|
|
689
692
|
/**
|
|
690
693
|
* Disconnect the current connection and reconnect.
|
|
@@ -693,20 +696,20 @@ export class ConnectionManager {
|
|
|
693
696
|
* @param error - Error reconnect information including whether or not to reconnect
|
|
694
697
|
* @returns A promise that resolves when the connection is reestablished or we stop trying
|
|
695
698
|
*/
|
|
696
|
-
async reconnect(requestedMode,
|
|
699
|
+
async reconnect(requestedMode, reason) {
|
|
697
700
|
// We quite often get protocol errors before / after observing nack/disconnect
|
|
698
701
|
// we do not want to run through same sequence twice.
|
|
699
702
|
// If we're already disconnected/disconnecting it's not appropriate to call this again.
|
|
700
703
|
assert(this.connection !== undefined, 0x0eb /* "Missing connection for reconnect" */);
|
|
701
|
-
this.disconnectFromDeltaStream(
|
|
704
|
+
this.disconnectFromDeltaStream(reason);
|
|
702
705
|
// We will always trigger reconnect, even if canRetry is false.
|
|
703
706
|
// Any truly fatal error state will result in container close upon attempted reconnect,
|
|
704
707
|
// which is a preferable to closing abruptly when a live connection fails.
|
|
705
|
-
if (error
|
|
708
|
+
if (reason.error?.canRetry === false) {
|
|
706
709
|
this.logger.sendTelemetryEvent({
|
|
707
710
|
eventName: "reconnectingDespiteFatalError",
|
|
708
711
|
reconnectMode: this.reconnectMode,
|
|
709
|
-
}, error);
|
|
712
|
+
}, reason.error);
|
|
710
713
|
}
|
|
711
714
|
if (this.reconnectMode === ReconnectMode.Never) {
|
|
712
715
|
// Do not raise container error if we are closing just because we lost connection.
|
|
@@ -719,9 +722,9 @@ export class ConnectionManager {
|
|
|
719
722
|
return;
|
|
720
723
|
}
|
|
721
724
|
// If the error tells us to wait before retrying, then do so.
|
|
722
|
-
const delayMs = getRetryDelayFromError(error);
|
|
723
|
-
if (error !== undefined && delayMs !== undefined) {
|
|
724
|
-
this.props.reconnectionDelayHandler(delayMs, error);
|
|
725
|
+
const delayMs = getRetryDelayFromError(reason.error);
|
|
726
|
+
if (reason.error !== undefined && delayMs !== undefined) {
|
|
727
|
+
this.props.reconnectionDelayHandler(delayMs, reason.error);
|
|
725
728
|
await new Promise((resolve) => {
|
|
726
729
|
setTimeout(resolve, delayMs);
|
|
727
730
|
});
|
|
@@ -730,12 +733,14 @@ export class ConnectionManager {
|
|
|
730
733
|
// NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic
|
|
731
734
|
// should probably live in the driver.
|
|
732
735
|
await waitForOnline();
|
|
733
|
-
this.triggerConnect(
|
|
734
|
-
|
|
735
|
-
|
|
736
|
+
this.triggerConnect({
|
|
737
|
+
text: reason.error !== undefined
|
|
738
|
+
? "Reconnecting due to Error"
|
|
739
|
+
: `Reconnecting due to: ${reason.text}`,
|
|
740
|
+
error: reason.error,
|
|
741
|
+
}, requestedMode);
|
|
736
742
|
}
|
|
737
743
|
prepareMessageToSend(message) {
|
|
738
|
-
var _a, _b;
|
|
739
744
|
if (this.readonly === true) {
|
|
740
745
|
assert(this.readOnlyInfo.readonly === true, 0x1f0 /* "Unexpected mismatch in readonly" */);
|
|
741
746
|
const error = new GenericError("deltaManagerReadonlySubmit", undefined /* error */, {
|
|
@@ -752,8 +757,8 @@ export class ConnectionManager {
|
|
|
752
757
|
// we keep info about old connection as long as possible to be able to account for all non-acked ops
|
|
753
758
|
// that we pick up on next connection.
|
|
754
759
|
assert(!!this.connection, 0x0e4 /* "Lost old connection!" */);
|
|
755
|
-
if (this.lastSubmittedClientId !==
|
|
756
|
-
this.lastSubmittedClientId =
|
|
760
|
+
if (this.lastSubmittedClientId !== this.connection?.clientId) {
|
|
761
|
+
this.lastSubmittedClientId = this.connection?.clientId;
|
|
757
762
|
this.clientSequenceNumber = 0;
|
|
758
763
|
this.clientSequenceNumberObserved = 0;
|
|
759
764
|
}
|
|
@@ -763,7 +768,10 @@ export class ConnectionManager {
|
|
|
763
768
|
else {
|
|
764
769
|
this.localOpsToIgnore = 0;
|
|
765
770
|
}
|
|
766
|
-
return
|
|
771
|
+
return {
|
|
772
|
+
...message,
|
|
773
|
+
clientSequenceNumber: ++this.clientSequenceNumber,
|
|
774
|
+
};
|
|
767
775
|
}
|
|
768
776
|
submitSignal(content) {
|
|
769
777
|
if (this.connection !== undefined) {
|
|
@@ -789,7 +797,7 @@ export class ConnectionManager {
|
|
|
789
797
|
if (this.pendingReconnect) {
|
|
790
798
|
// still valid?
|
|
791
799
|
await this.reconnect("write", // connectionMode
|
|
792
|
-
"Switch to write");
|
|
800
|
+
{ text: "Switch to write" });
|
|
793
801
|
}
|
|
794
802
|
})
|
|
795
803
|
.catch(() => { });
|
|
@@ -822,7 +830,7 @@ export class ConnectionManager {
|
|
|
822
830
|
// Clients need to be able to transition to "read" state after some time of inactivity!
|
|
823
831
|
// Note - this may close container!
|
|
824
832
|
this.reconnect("read", // connectionMode
|
|
825
|
-
"Switch to read").catch((error) => {
|
|
833
|
+
{ text: "Switch to read" }).catch((error) => {
|
|
826
834
|
this.logger.sendErrorEvent({ eventName: "SwitchToReadConnection" }, error);
|
|
827
835
|
});
|
|
828
836
|
}
|