@fluidframework/container-loader 2.0.0-dev.1.3.0.96595 → 2.0.0-dev.1.4.6.106135

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.
Files changed (49) hide show
  1. package/dist/audience.d.ts +4 -0
  2. package/dist/audience.d.ts.map +1 -1
  3. package/dist/audience.js +11 -6
  4. package/dist/audience.js.map +1 -1
  5. package/dist/connectionManager.d.ts.map +1 -1
  6. package/dist/connectionManager.js +4 -30
  7. package/dist/connectionManager.js.map +1 -1
  8. package/dist/container.d.ts +1 -0
  9. package/dist/container.d.ts.map +1 -1
  10. package/dist/container.js +20 -3
  11. package/dist/container.js.map +1 -1
  12. package/dist/deltaManager.js +1 -1
  13. package/dist/deltaManager.js.map +1 -1
  14. package/dist/packageVersion.d.ts +1 -1
  15. package/dist/packageVersion.d.ts.map +1 -1
  16. package/dist/packageVersion.js +1 -1
  17. package/dist/packageVersion.js.map +1 -1
  18. package/dist/protocol.d.ts +3 -8
  19. package/dist/protocol.d.ts.map +1 -1
  20. package/dist/protocol.js +8 -34
  21. package/dist/protocol.js.map +1 -1
  22. package/lib/audience.d.ts +4 -0
  23. package/lib/audience.d.ts.map +1 -1
  24. package/lib/audience.js +11 -6
  25. package/lib/audience.js.map +1 -1
  26. package/lib/connectionManager.d.ts.map +1 -1
  27. package/lib/connectionManager.js +4 -30
  28. package/lib/connectionManager.js.map +1 -1
  29. package/lib/container.d.ts +1 -0
  30. package/lib/container.d.ts.map +1 -1
  31. package/lib/container.js +20 -3
  32. package/lib/container.js.map +1 -1
  33. package/lib/deltaManager.js +1 -1
  34. package/lib/deltaManager.js.map +1 -1
  35. package/lib/packageVersion.d.ts +1 -1
  36. package/lib/packageVersion.d.ts.map +1 -1
  37. package/lib/packageVersion.js +1 -1
  38. package/lib/packageVersion.js.map +1 -1
  39. package/lib/protocol.d.ts +3 -8
  40. package/lib/protocol.d.ts.map +1 -1
  41. package/lib/protocol.js +7 -33
  42. package/lib/protocol.js.map +1 -1
  43. package/package.json +10 -10
  44. package/src/audience.ts +12 -6
  45. package/src/connectionManager.ts +6 -33
  46. package/src/container.ts +22 -1
  47. package/src/deltaManager.ts +1 -1
  48. package/src/packageVersion.ts +1 -1
  49. package/src/protocol.ts +8 -31
@@ -59,7 +59,6 @@ import {
59
59
  IConnectionManagerFactoryArgs,
60
60
  } from "./contracts";
61
61
  import { DeltaQueue } from "./deltaQueue";
62
- import { SignalType } from "./protocol";
63
62
 
64
63
  const MaxReconnectDelayInMs = 8000;
65
64
  const InitialReconnectDelayInMs = 1000;
@@ -714,43 +713,17 @@ export class ConnectionManager implements IConnectionManager {
714
713
  initialMessages,
715
714
  this.connectFirstConnection ? "InitialOps" : "ReconnectOps");
716
715
 
717
- const details = ConnectionManager.detailsFromConnection(connection);
718
- details.checkpointSequenceNumber = checkpointSequenceNumber;
719
- this.props.connectHandler(details);
720
-
721
- this.connectFirstConnection = false;
722
-
723
- // Synthesize clear & join signals out of initialClients state.
724
- // This allows us to have single way to process signals, and makes it simpler to initialize
725
- // protocol in Container.
726
- const clearSignal: ISignalMessage = {
727
- clientId: null, // system message
728
- content: JSON.stringify({
729
- type: SignalType.Clear,
730
- }),
731
- };
732
- this.props.signalHandler(clearSignal);
733
-
734
- for (const priorClient of connection.initialClients ?? []) {
735
- const joinSignal: ISignalMessage = {
736
- clientId: null, // system signal
737
- content: JSON.stringify({
738
- type: SignalType.ClientJoin,
739
- content: priorClient, // ISignalClient
740
- }),
741
- };
742
- this.props.signalHandler(joinSignal);
743
- }
744
-
745
- // Unfortunately, there is no defined order between initialSignals (including join & leave signals)
746
- // and connection.initialClients. In practice, connection.initialSignals quite often contains join signal
747
- // for "self" and connection.initialClients does not contain "self", so we have to process them after
748
- // "clear" signal above.
749
716
  if (connection.initialSignals !== undefined) {
750
717
  for (const signal of connection.initialSignals) {
751
718
  this.props.signalHandler(signal);
752
719
  }
753
720
  }
721
+
722
+ const details = ConnectionManager.detailsFromConnection(connection);
723
+ details.checkpointSequenceNumber = checkpointSequenceNumber;
724
+ this.props.connectHandler(details);
725
+
726
+ this.connectFirstConnection = false;
754
727
  }
755
728
 
756
729
  /**
package/src/container.ts CHANGED
@@ -64,6 +64,7 @@ import {
64
64
  ISequencedClient,
65
65
  ISequencedDocumentMessage,
66
66
  ISequencedProposal,
67
+ ISignalClient,
67
68
  ISignalMessage,
68
69
  ISnapshotTree,
69
70
  ISummaryContent,
@@ -411,6 +412,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
411
412
  private readonly clientDetailsOverride: IClientDetails | undefined;
412
413
  private readonly _deltaManager: DeltaManager<ConnectionManager>;
413
414
  private service: IDocumentService | undefined;
415
+ private _initialClients: ISignalClient[] | undefined;
414
416
 
415
417
  private _context: ContainerContext | undefined;
416
418
  private get context() {
@@ -1381,8 +1383,11 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1381
1383
  attributes,
1382
1384
  quorumSnapshot,
1383
1385
  (key, value) => this.submitMessage(MessageType.Propose, JSON.stringify({ key, value })),
1386
+ this._initialClients ?? [],
1384
1387
  );
1385
1388
 
1389
+ this._initialClients = undefined;
1390
+
1386
1391
  const protocolLogger = ChildLogger.create(this.subLogger, "ProtocolHandler");
1387
1392
 
1388
1393
  protocol.quorum.on("error", (error) => {
@@ -1507,6 +1512,20 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1507
1512
  deltaManager.inboundSignal.pause();
1508
1513
 
1509
1514
  deltaManager.on("connect", (details: IConnectionDetails, _opsBehind?: number) => {
1515
+ if (this._protocolHandler === undefined) {
1516
+ // Store the initial clients so that they can be submitted to the
1517
+ // protocol handler when it is created.
1518
+ this._initialClients = details.initialClients;
1519
+ } else {
1520
+ // When reconnecting, the protocol handler is already created,
1521
+ // so we can update the audience right now.
1522
+ this._protocolHandler.audience.clear();
1523
+
1524
+ for (const priorClient of details.initialClients ?? []) {
1525
+ this._protocolHandler.audience.addMember(priorClient.clientId, priorClient.client);
1526
+ }
1527
+ }
1528
+
1510
1529
  this.connectionStateHandler.receivedConnectEvent(
1511
1530
  this.connectionMode,
1512
1531
  details,
@@ -1721,7 +1740,9 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1721
1740
  (type) => {
1722
1741
  assert(this.activeConnection(),
1723
1742
  0x241 /* "disconnect should result in stopSequenceNumberUpdate() call" */);
1724
- this.submitMessage(type);
1743
+ // back-compat: There is a bug in 1.2 runtime where clients cannot handle
1744
+ // ops whose contents are undefined
1745
+ this.submitMessage(type, null as any);
1725
1746
  },
1726
1747
  this.serviceConfiguration.noopTimeFrequency,
1727
1748
  this.serviceConfiguration.noopCountFrequency,
@@ -218,7 +218,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
218
218
  return -1;
219
219
  }
220
220
 
221
- if (contents !== undefined) {
221
+ if (contents !== undefined && contents !== null) {
222
222
  this.opsSize += contents.length;
223
223
  }
224
224
 
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "2.0.0-dev.1.3.0.96595";
9
+ export const pkgVersion = "2.0.0-dev.1.4.6.106135";
package/src/protocol.ts CHANGED
@@ -20,13 +20,6 @@ import {
20
20
  } from "@fluidframework/protocol-definitions";
21
21
  import { canBeCoalescedByService } from "@fluidframework/driver-utils";
22
22
 
23
- // ADO: #1986: Start using enum from protocol-base.
24
- export enum SignalType {
25
- ClientJoin = "join", // same value as MessageType.ClientJoin,
26
- ClientLeave = "leave", // same value as MessageType.ClientLeave,
27
- Clear = "clear", // used only by client for synthetic signals
28
- }
29
-
30
23
  /**
31
24
  * Function to be used for creating a protocol handler.
32
25
  */
@@ -34,6 +27,7 @@ export type ProtocolHandlerBuilder = (
34
27
  attributes: IDocumentAttributes,
35
28
  snapshot: IQuorumSnapshot,
36
29
  sendProposal: (key: string, value: any) => number,
30
+ initialClients: ISignalClient[],
37
31
  ) => IProtocolHandler;
38
32
 
39
33
  export interface IProtocolHandler extends IBaseProtocolHandler {
@@ -46,6 +40,7 @@ export class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandl
46
40
  attributes: IDocumentAttributes,
47
41
  quorumSnapshot: IQuorumSnapshot,
48
42
  sendProposal: (key: string, value: any) => number,
43
+ initialClients: ISignalClient[],
49
44
  readonly audience: IAudienceOwner,
50
45
  ) {
51
46
  super(
@@ -58,11 +53,8 @@ export class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandl
58
53
  sendProposal,
59
54
  );
60
55
 
61
- // Join / leave signals are ignored for "write" clients in favor of join / leave ops
62
- this.quorum.on("addMember", (clientId, details) => audience.addMember(clientId, details.client));
63
- this.quorum.on("removeMember", (clientId) => audience.removeMember(clientId));
64
- for (const [clientId, details] of this.quorum.getMembers()) {
65
- this.audience.addMember(clientId, details.client);
56
+ for (const initialClient of initialClients) {
57
+ this.audience.addMember(initialClient.clientId, initialClient.client);
66
58
  }
67
59
  }
68
60
 
@@ -89,29 +81,14 @@ export class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandl
89
81
  public processSignal(message: ISignalMessage) {
90
82
  const innerContent = message.content as { content: any; type: string; };
91
83
  switch (innerContent.type) {
92
- case SignalType.Clear: {
93
- const members = this.audience.getMembers();
94
- for (const [clientId, client] of members) {
95
- if (client.mode === "read") {
96
- this.audience.removeMember(clientId);
97
- }
98
- }
99
- break;
100
- }
101
- case SignalType.ClientJoin: {
84
+ case MessageType.ClientJoin: {
102
85
  const newClient = innerContent.content as ISignalClient;
103
- // Ignore write clients - quorum will control such clients.
104
- if (newClient.client.mode === "read") {
105
- this.audience.addMember(newClient.clientId, newClient.client);
106
- }
86
+ this.audience.addMember(newClient.clientId, newClient.client);
107
87
  break;
108
88
  }
109
- case SignalType.ClientLeave: {
89
+ case MessageType.ClientLeave: {
110
90
  const leftClientId = innerContent.content as string;
111
- // Ignore write clients - quorum will control such clients.
112
- if (this.audience.getMember(leftClientId)?.mode === "read") {
113
- this.audience.removeMember(leftClientId);
114
- }
91
+ this.audience.removeMember(leftClientId);
115
92
  break;
116
93
  }
117
94
  default: break;