@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/src/deltaManager.ts
CHANGED
|
@@ -7,13 +7,11 @@ import { v4 as uuid } from "uuid";
|
|
|
7
7
|
import { IEventProvider } from "@fluidframework/common-definitions";
|
|
8
8
|
import { ITelemetryProperties, ITelemetryErrorEvent } from "@fluidframework/core-interfaces";
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
ICriticalContainerError,
|
|
11
11
|
IDeltaManager,
|
|
12
12
|
IDeltaManagerEvents,
|
|
13
13
|
IDeltaQueue,
|
|
14
|
-
ICriticalContainerError,
|
|
15
14
|
IThrottlingWarning,
|
|
16
|
-
IConnectionDetailsInternal,
|
|
17
15
|
} from "@fluidframework/container-definitions";
|
|
18
16
|
import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
|
|
19
17
|
import {
|
|
@@ -27,7 +25,6 @@ import {
|
|
|
27
25
|
IDocumentDeltaStorageService,
|
|
28
26
|
IDocumentService,
|
|
29
27
|
DriverErrorType,
|
|
30
|
-
IAnyDriverError,
|
|
31
28
|
} from "@fluidframework/driver-definitions";
|
|
32
29
|
import {
|
|
33
30
|
IDocumentMessage,
|
|
@@ -44,14 +41,19 @@ import {
|
|
|
44
41
|
DataProcessingError,
|
|
45
42
|
UsageError,
|
|
46
43
|
} from "@fluidframework/container-utils";
|
|
47
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
IConnectionDetailsInternal,
|
|
46
|
+
IConnectionManager,
|
|
47
|
+
IConnectionManagerFactoryArgs,
|
|
48
|
+
IConnectionStateChangeReason,
|
|
49
|
+
} from "./contracts";
|
|
48
50
|
import { DeltaQueue } from "./deltaQueue";
|
|
49
51
|
import { OnlyValidTermValue } from "./protocol";
|
|
50
52
|
|
|
51
53
|
export interface IConnectionArgs {
|
|
52
54
|
mode?: ConnectionMode;
|
|
53
55
|
fetchOpsFromStorage?: boolean;
|
|
54
|
-
reason:
|
|
56
|
+
reason: IConnectionStateChangeReason;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
/**
|
|
@@ -62,8 +64,11 @@ export interface IDeltaManagerInternalEvents extends IDeltaManagerEvents {
|
|
|
62
64
|
(event: "throttled", listener: (error: IThrottlingWarning) => void);
|
|
63
65
|
(event: "closed" | "disposed", listener: (error?: ICriticalContainerError) => void);
|
|
64
66
|
(event: "connect", listener: (details: IConnectionDetailsInternal, opsBehind?: number) => void);
|
|
65
|
-
(event: "establishingConnection", listener: (reason:
|
|
66
|
-
(
|
|
67
|
+
(event: "establishingConnection", listener: (reason: IConnectionStateChangeReason) => void);
|
|
68
|
+
(
|
|
69
|
+
event: "cancelEstablishingConnection",
|
|
70
|
+
listener: (reason: IConnectionStateChangeReason) => void,
|
|
71
|
+
);
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
/**
|
|
@@ -73,6 +78,21 @@ interface IBatchMetadata {
|
|
|
73
78
|
batch?: boolean;
|
|
74
79
|
}
|
|
75
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Interface used to define a strategy for handling incoming delta messages
|
|
83
|
+
*/
|
|
84
|
+
export interface IDeltaHandlerStrategy {
|
|
85
|
+
/**
|
|
86
|
+
* Processes the message.
|
|
87
|
+
*/
|
|
88
|
+
process: (message: ISequencedDocumentMessage) => void;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Processes the signal.
|
|
92
|
+
*/
|
|
93
|
+
processSignal: (message: ISignalMessage) => void;
|
|
94
|
+
}
|
|
95
|
+
|
|
76
96
|
/**
|
|
77
97
|
* Determines if message was sent by client, not service
|
|
78
98
|
*/
|
|
@@ -330,6 +350,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
330
350
|
return {
|
|
331
351
|
sequenceNumber: this.lastSequenceNumber,
|
|
332
352
|
opsSize: this.opsSize > 0 ? this.opsSize : undefined,
|
|
353
|
+
deltaManagerState: this._disposed ? "disposed" : this._closed ? "closed" : "open",
|
|
333
354
|
...this.connectionManager.connectionProps,
|
|
334
355
|
};
|
|
335
356
|
}
|
|
@@ -383,15 +404,17 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
383
404
|
reconnectionDelayHandler: (delayMs: number, error: unknown) =>
|
|
384
405
|
this.emitDelayInfo(this.deltaStreamDelayId, delayMs, error),
|
|
385
406
|
closeHandler: (error: any) => this.close(error),
|
|
386
|
-
disconnectHandler: (reason:
|
|
387
|
-
this.disconnectHandler(reason
|
|
407
|
+
disconnectHandler: (reason: IConnectionStateChangeReason) =>
|
|
408
|
+
this.disconnectHandler(reason),
|
|
388
409
|
connectHandler: (connection: IConnectionDetailsInternal) =>
|
|
389
410
|
this.connectHandler(connection),
|
|
390
411
|
pongHandler: (latency: number) => this.emit("pong", latency),
|
|
391
412
|
readonlyChangeHandler: (readonly?: boolean) =>
|
|
392
413
|
safeRaiseEvent(this, this.logger, "readonly", readonly),
|
|
393
|
-
establishConnectionHandler: (reason:
|
|
394
|
-
|
|
414
|
+
establishConnectionHandler: (reason: IConnectionStateChangeReason) =>
|
|
415
|
+
this.establishingConnection(reason),
|
|
416
|
+
cancelConnectionHandler: (reason: IConnectionStateChangeReason) =>
|
|
417
|
+
this.cancelEstablishingConnection(reason),
|
|
395
418
|
};
|
|
396
419
|
|
|
397
420
|
this.connectionManager = createConnectionManager(props);
|
|
@@ -431,11 +454,11 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
431
454
|
// - inbound & inboundSignal are resumed in attachOpHandler() when we have handler setup
|
|
432
455
|
}
|
|
433
456
|
|
|
434
|
-
private cancelEstablishingConnection(reason:
|
|
457
|
+
private cancelEstablishingConnection(reason: IConnectionStateChangeReason) {
|
|
435
458
|
this.emit("cancelEstablishingConnection", reason);
|
|
436
459
|
}
|
|
437
460
|
|
|
438
|
-
private establishingConnection(reason:
|
|
461
|
+
private establishingConnection(reason: IConnectionStateChangeReason) {
|
|
439
462
|
this.emit("establishingConnection", reason);
|
|
440
463
|
}
|
|
441
464
|
|
|
@@ -495,7 +518,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
495
518
|
minSequenceNumber: number,
|
|
496
519
|
sequenceNumber: number,
|
|
497
520
|
handler: IDeltaHandlerStrategy,
|
|
498
|
-
prefetchType: "cached" | "all" | "none" = "none",
|
|
521
|
+
prefetchType: "sequenceNumber" | "cached" | "all" | "none" = "none",
|
|
499
522
|
) {
|
|
500
523
|
this.initSequenceNumber = sequenceNumber;
|
|
501
524
|
this.lastProcessedSequenceNumber = sequenceNumber;
|
|
@@ -569,7 +592,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
569
592
|
// on the wire, we might be always behind.
|
|
570
593
|
// See comment at the end of "connect" handler
|
|
571
594
|
if (fetchOpsFromStorage) {
|
|
572
|
-
this.fetchMissingDeltas(args.reason);
|
|
595
|
+
this.fetchMissingDeltas(args.reason.text);
|
|
573
596
|
}
|
|
574
597
|
|
|
575
598
|
this.connectionManager.connect(args.reason, args.mode);
|
|
@@ -755,9 +778,9 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
755
778
|
}
|
|
756
779
|
}
|
|
757
780
|
|
|
758
|
-
private disconnectHandler(reason:
|
|
781
|
+
private disconnectHandler(reason: IConnectionStateChangeReason) {
|
|
759
782
|
this.messageBuffer.length = 0;
|
|
760
|
-
this.emit("disconnect", reason
|
|
783
|
+
this.emit("disconnect", reason);
|
|
761
784
|
}
|
|
762
785
|
|
|
763
786
|
/**
|
package/src/loader.ts
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
IResolvedUrl,
|
|
38
38
|
IUrlResolver,
|
|
39
39
|
} from "@fluidframework/driver-definitions";
|
|
40
|
-
import {
|
|
40
|
+
import { UsageError } from "@fluidframework/container-utils";
|
|
41
41
|
import { Container, IPendingContainerState } from "./container";
|
|
42
42
|
import { IParsedUrl, parseUrl } from "./utils";
|
|
43
43
|
import { pkgVersion } from "./packageVersion";
|
|
@@ -45,11 +45,7 @@ import { ProtocolHandlerBuilder } from "./protocol";
|
|
|
45
45
|
import { DebugLogger } from "./debugLogger";
|
|
46
46
|
|
|
47
47
|
function canUseCache(request: IRequest): boolean {
|
|
48
|
-
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return request.headers[LoaderHeader.cache] !== false;
|
|
48
|
+
return request.headers?.[LoaderHeader.cache] === true;
|
|
53
49
|
}
|
|
54
50
|
|
|
55
51
|
function ensureResolvedUrlDefined(
|
|
@@ -68,6 +64,9 @@ export class RelativeLoader implements ILoader {
|
|
|
68
64
|
private readonly loader: ILoader | undefined,
|
|
69
65
|
) {}
|
|
70
66
|
|
|
67
|
+
/**
|
|
68
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the Container's IFluidRouter/request.
|
|
69
|
+
*/
|
|
71
70
|
public get IFluidRouter(): IFluidRouter {
|
|
72
71
|
return this;
|
|
73
72
|
}
|
|
@@ -99,6 +98,9 @@ export class RelativeLoader implements ILoader {
|
|
|
99
98
|
return this.loader.resolve(request);
|
|
100
99
|
}
|
|
101
100
|
|
|
101
|
+
/**
|
|
102
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the Container's IFluidRouter/request.
|
|
103
|
+
*/
|
|
102
104
|
public async request(request: IRequest): Promise<IResponse> {
|
|
103
105
|
if (request.url.startsWith("/")) {
|
|
104
106
|
const container = await this.resolve(request);
|
|
@@ -348,6 +350,9 @@ export class Loader implements IHostLoader {
|
|
|
348
350
|
});
|
|
349
351
|
}
|
|
350
352
|
|
|
353
|
+
/**
|
|
354
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the Container's IFluidRouter/request.
|
|
355
|
+
*/
|
|
351
356
|
public get IFluidRouter(): IFluidRouter {
|
|
352
357
|
return this;
|
|
353
358
|
}
|
|
@@ -383,6 +388,9 @@ export class Loader implements IHostLoader {
|
|
|
383
388
|
});
|
|
384
389
|
}
|
|
385
390
|
|
|
391
|
+
/**
|
|
392
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the Container's IFluidRouter/request.
|
|
393
|
+
*/
|
|
386
394
|
public async request(request: IRequest): Promise<IResponse> {
|
|
387
395
|
return PerformanceEvent.timedExecAsync(
|
|
388
396
|
this.mc.logger,
|
|
@@ -456,11 +464,29 @@ export class Loader implements IHostLoader {
|
|
|
456
464
|
// If set in both query string and headers, use query string. Also write the value from the query string into the header either way.
|
|
457
465
|
request.headers[LoaderHeader.version] =
|
|
458
466
|
parsed.version ?? request.headers[LoaderHeader.version];
|
|
467
|
+
const cacheHeader = request.headers[LoaderHeader.cache];
|
|
459
468
|
const canCache =
|
|
460
|
-
|
|
461
|
-
|
|
469
|
+
// Take header value if present, else use ILoaderOptions.cache value
|
|
470
|
+
(cacheHeader !== undefined ? cacheHeader === true : this.cachingEnabled) &&
|
|
462
471
|
pendingLocalState === undefined;
|
|
463
|
-
const fromSequenceNumber = request.headers[LoaderHeader.sequenceNumber]
|
|
472
|
+
const fromSequenceNumber = request.headers[LoaderHeader.sequenceNumber] as
|
|
473
|
+
| number
|
|
474
|
+
| undefined;
|
|
475
|
+
const opsBeforeReturn = request.headers[LoaderHeader.loadMode]?.opsBeforeReturn as
|
|
476
|
+
| string
|
|
477
|
+
| undefined;
|
|
478
|
+
|
|
479
|
+
if (
|
|
480
|
+
opsBeforeReturn === "sequenceNumber" &&
|
|
481
|
+
(fromSequenceNumber === undefined || fromSequenceNumber < 0)
|
|
482
|
+
) {
|
|
483
|
+
// If opsBeforeReturn is set to "sequenceNumber", then fromSequenceNumber should be set to a non-negative integer.
|
|
484
|
+
throw new UsageError("sequenceNumber must be set to a non-negative integer");
|
|
485
|
+
} else if (opsBeforeReturn !== "sequenceNumber" && fromSequenceNumber !== undefined) {
|
|
486
|
+
// If opsBeforeReturn is not set to "sequenceNumber", then fromSequenceNumber should be undefined (default value).
|
|
487
|
+
// In this case, we should throw an error since opsBeforeReturn is not explicitly set to "sequenceNumber".
|
|
488
|
+
throw new UsageError('opsBeforeReturn must be set to "sequenceNumber"');
|
|
489
|
+
}
|
|
464
490
|
|
|
465
491
|
let container: Container;
|
|
466
492
|
if (canCache) {
|
|
@@ -477,24 +503,11 @@ export class Loader implements IHostLoader {
|
|
|
477
503
|
container = await this.loadContainer(request, resolvedAsFluid, pendingLocalState);
|
|
478
504
|
}
|
|
479
505
|
|
|
480
|
-
if (container.deltaManager.lastSequenceNumber <= fromSequenceNumber) {
|
|
481
|
-
await new Promise<void>((resolve, reject) => {
|
|
482
|
-
function opHandler(message: ISequencedDocumentMessage) {
|
|
483
|
-
if (message.sequenceNumber > fromSequenceNumber) {
|
|
484
|
-
resolve();
|
|
485
|
-
container.removeListener("op", opHandler);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
container.on("op", opHandler);
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
|
|
493
506
|
return { container, parsed };
|
|
494
507
|
}
|
|
495
508
|
|
|
496
509
|
private get cachingEnabled() {
|
|
497
|
-
return this.services.options.cache
|
|
510
|
+
return this.services.options.cache === true;
|
|
498
511
|
}
|
|
499
512
|
|
|
500
513
|
private async loadContainer(
|
|
@@ -508,6 +521,7 @@ export class Loader implements IHostLoader {
|
|
|
508
521
|
version: request.headers?.[LoaderHeader.version] ?? undefined,
|
|
509
522
|
loadMode: request.headers?.[LoaderHeader.loadMode],
|
|
510
523
|
pendingLocalState,
|
|
524
|
+
loadToSequenceNumber: request.headers?.[LoaderHeader.sequenceNumber],
|
|
511
525
|
},
|
|
512
526
|
{
|
|
513
527
|
canReconnect: request.headers?.[LoaderHeader.reconnect],
|
package/src/packageVersion.ts
CHANGED
package/src/protocol.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { IAudienceOwner } from "@fluidframework/container-definitions";
|
|
7
|
+
import { canBeCoalescedByService } from "@fluidframework/driver-utils";
|
|
7
8
|
import {
|
|
8
9
|
IProtocolHandler as IBaseProtocolHandler,
|
|
9
10
|
IQuorumSnapshot,
|
|
@@ -11,8 +12,12 @@ import {
|
|
|
11
12
|
} from "@fluidframework/protocol-base";
|
|
12
13
|
import {
|
|
13
14
|
IDocumentAttributes,
|
|
15
|
+
IProcessMessageResult,
|
|
16
|
+
ISequencedClient,
|
|
17
|
+
ISequencedDocumentMessage,
|
|
14
18
|
ISignalClient,
|
|
15
19
|
ISignalMessage,
|
|
20
|
+
MessageType,
|
|
16
21
|
} from "@fluidframework/protocol-definitions";
|
|
17
22
|
|
|
18
23
|
// "term" was an experimental feature that is being removed. The only safe value to use is 1.
|
|
@@ -44,12 +49,12 @@ export class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandl
|
|
|
44
49
|
attributes: IDocumentAttributes,
|
|
45
50
|
quorumSnapshot: IQuorumSnapshot,
|
|
46
51
|
sendProposal: (key: string, value: any) => number,
|
|
47
|
-
readonly audience: IAudienceOwner,
|
|
52
|
+
public readonly audience: IAudienceOwner,
|
|
53
|
+
private readonly shouldClientHaveLeft: (clientId: string) => boolean,
|
|
48
54
|
) {
|
|
49
55
|
super(
|
|
50
56
|
attributes.minimumSequenceNumber,
|
|
51
57
|
attributes.sequenceNumber,
|
|
52
|
-
OnlyValidTermValue,
|
|
53
58
|
quorumSnapshot.members,
|
|
54
59
|
quorumSnapshot.proposals,
|
|
55
60
|
quorumSnapshot.values,
|
|
@@ -66,6 +71,32 @@ export class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandl
|
|
|
66
71
|
}
|
|
67
72
|
}
|
|
68
73
|
|
|
74
|
+
public processMessage(
|
|
75
|
+
message: ISequencedDocumentMessage,
|
|
76
|
+
local: boolean,
|
|
77
|
+
): IProcessMessageResult {
|
|
78
|
+
const client: ISequencedClient | undefined = this.quorum.getMember(message.clientId);
|
|
79
|
+
|
|
80
|
+
// Check and report if we're getting messages from a clientId that we previously
|
|
81
|
+
// flagged as shouldHaveLeft, or from a client that's not in the quorum but should be
|
|
82
|
+
if (message.clientId != null) {
|
|
83
|
+
if (client === undefined && message.type !== MessageType.ClientJoin) {
|
|
84
|
+
// pre-0.58 error message: messageClientIdMissingFromQuorum
|
|
85
|
+
throw new Error("Remote message's clientId is missing from the quorum");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Here checking canBeCoalescedByService is used as an approximation of "is benign to process despite being unexpected".
|
|
89
|
+
// It's still not good to see these messages from unexpected clientIds, but since they don't harm the integrity of the
|
|
90
|
+
// document we don't need to blow up aggressively.
|
|
91
|
+
if (this.shouldClientHaveLeft(message.clientId) && !canBeCoalescedByService(message)) {
|
|
92
|
+
// pre-0.58 error message: messageClientIdShouldHaveLeft
|
|
93
|
+
throw new Error("Remote message's clientId already should have left");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return super.processMessage(message, local);
|
|
98
|
+
}
|
|
99
|
+
|
|
69
100
|
public processSignal(message: ISignalMessage) {
|
|
70
101
|
const innerContent = message.content as { content: any; type: string };
|
|
71
102
|
switch (innerContent.type) {
|
package/src/utils.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { ISummaryTree, ISnapshotTree, SummaryType } from "@fluidframework/protocol-definitions";
|
|
15
15
|
import { LoggingError } from "@fluidframework/telemetry-utils";
|
|
16
16
|
import {
|
|
17
|
+
CombinedAppAndProtocolSummary,
|
|
17
18
|
DeltaStreamConnectionForbiddenError,
|
|
18
19
|
isCombinedAppAndProtocolSummary,
|
|
19
20
|
} from "@fluidframework/driver-utils";
|
|
@@ -51,6 +52,34 @@ export function parseUrl(url: string): IParsedUrl | undefined {
|
|
|
51
52
|
: undefined;
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Combine the app summary and protocol summary in 1 tree.
|
|
57
|
+
* @param appSummary - Summary of the app.
|
|
58
|
+
* @param protocolSummary - Summary of the protocol.
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
export function combineAppAndProtocolSummary(
|
|
62
|
+
appSummary: ISummaryTree,
|
|
63
|
+
protocolSummary: ISummaryTree,
|
|
64
|
+
): CombinedAppAndProtocolSummary {
|
|
65
|
+
assert(
|
|
66
|
+
!isCombinedAppAndProtocolSummary(appSummary),
|
|
67
|
+
0x5a8 /* app summary is already a combined tree! */,
|
|
68
|
+
);
|
|
69
|
+
assert(
|
|
70
|
+
!isCombinedAppAndProtocolSummary(protocolSummary),
|
|
71
|
+
0x5a9 /* protocol summary is already a combined tree! */,
|
|
72
|
+
);
|
|
73
|
+
const createNewSummary: CombinedAppAndProtocolSummary = {
|
|
74
|
+
type: SummaryType.Tree,
|
|
75
|
+
tree: {
|
|
76
|
+
".protocol": protocolSummary,
|
|
77
|
+
".app": appSummary,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
return createNewSummary;
|
|
81
|
+
}
|
|
82
|
+
|
|
54
83
|
/**
|
|
55
84
|
* Converts summary tree (for upload) to snapshot tree (for download).
|
|
56
85
|
* Summary tree blobs contain contents, but snapshot tree blobs normally
|