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

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 (44) 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 +17 -2
  11. package/dist/container.js.map +1 -1
  12. package/dist/packageVersion.d.ts +1 -1
  13. package/dist/packageVersion.d.ts.map +1 -1
  14. package/dist/packageVersion.js +1 -1
  15. package/dist/packageVersion.js.map +1 -1
  16. package/dist/protocol.d.ts +3 -8
  17. package/dist/protocol.d.ts.map +1 -1
  18. package/dist/protocol.js +8 -34
  19. package/dist/protocol.js.map +1 -1
  20. package/lib/audience.d.ts +4 -0
  21. package/lib/audience.d.ts.map +1 -1
  22. package/lib/audience.js +11 -6
  23. package/lib/audience.js.map +1 -1
  24. package/lib/connectionManager.d.ts.map +1 -1
  25. package/lib/connectionManager.js +4 -30
  26. package/lib/connectionManager.js.map +1 -1
  27. package/lib/container.d.ts +1 -0
  28. package/lib/container.d.ts.map +1 -1
  29. package/lib/container.js +17 -2
  30. package/lib/container.js.map +1 -1
  31. package/lib/packageVersion.d.ts +1 -1
  32. package/lib/packageVersion.d.ts.map +1 -1
  33. package/lib/packageVersion.js +1 -1
  34. package/lib/packageVersion.js.map +1 -1
  35. package/lib/protocol.d.ts +3 -8
  36. package/lib/protocol.d.ts.map +1 -1
  37. package/lib/protocol.js +7 -33
  38. package/lib/protocol.js.map +1 -1
  39. package/package.json +10 -10
  40. package/src/audience.ts +12 -6
  41. package/src/connectionManager.ts +6 -33
  42. package/src/container.ts +19 -0
  43. package/src/packageVersion.ts +1 -1
  44. package/src/protocol.ts +8 -31
@@ -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/container-loader";
8
- export declare const pkgVersion = "2.0.0-dev.1.3.0.96595";
8
+ export declare const pkgVersion = "2.0.0-dev.1.4.5.105745";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,qCAAqC,CAAC;AAC1D,eAAO,MAAM,UAAU,0BAA0B,CAAC"}
1
+ {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,qCAAqC,CAAC;AAC1D,eAAO,MAAM,UAAU,2BAA2B,CAAC"}
@@ -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/container-loader";
8
- export const pkgVersion = "2.0.0-dev.1.3.0.96595";
8
+ export const pkgVersion = "2.0.0-dev.1.4.5.105745";
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,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,uBAAuB,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/container-loader\";\nexport const pkgVersion = \"2.0.0-dev.1.3.0.96595\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,wBAAwB,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/container-loader\";\nexport const pkgVersion = \"2.0.0-dev.1.4.5.105745\";\n"]}
package/lib/protocol.d.ts CHANGED
@@ -4,23 +4,18 @@
4
4
  */
5
5
  import { IAudienceOwner } from "@fluidframework/container-definitions";
6
6
  import { IProtocolHandler as IBaseProtocolHandler, IQuorumSnapshot, ProtocolOpHandler } from "@fluidframework/protocol-base";
7
- import { IDocumentAttributes, IProcessMessageResult, ISequencedDocumentMessage, ISignalMessage } from "@fluidframework/protocol-definitions";
8
- export declare enum SignalType {
9
- ClientJoin = "join",
10
- ClientLeave = "leave",
11
- Clear = "clear"
12
- }
7
+ import { IDocumentAttributes, IProcessMessageResult, ISequencedDocumentMessage, ISignalClient, ISignalMessage } from "@fluidframework/protocol-definitions";
13
8
  /**
14
9
  * Function to be used for creating a protocol handler.
15
10
  */
16
- export declare type ProtocolHandlerBuilder = (attributes: IDocumentAttributes, snapshot: IQuorumSnapshot, sendProposal: (key: string, value: any) => number) => IProtocolHandler;
11
+ export declare type ProtocolHandlerBuilder = (attributes: IDocumentAttributes, snapshot: IQuorumSnapshot, sendProposal: (key: string, value: any) => number, initialClients: ISignalClient[]) => IProtocolHandler;
17
12
  export interface IProtocolHandler extends IBaseProtocolHandler {
18
13
  readonly audience: IAudienceOwner;
19
14
  processSignal(message: ISignalMessage): any;
20
15
  }
21
16
  export declare class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandler {
22
17
  readonly audience: IAudienceOwner;
23
- constructor(attributes: IDocumentAttributes, quorumSnapshot: IQuorumSnapshot, sendProposal: (key: string, value: any) => number, audience: IAudienceOwner);
18
+ constructor(attributes: IDocumentAttributes, quorumSnapshot: IQuorumSnapshot, sendProposal: (key: string, value: any) => number, initialClients: ISignalClient[], audience: IAudienceOwner);
24
19
  processMessage(message: ISequencedDocumentMessage, local: boolean): IProcessMessageResult;
25
20
  processSignal(message: ISignalMessage): void;
26
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AACvE,OAAO,EAEH,gBAAgB,IAAI,oBAAoB,EACxC,eAAe,EACf,iBAAiB,EACpB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACH,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EAEzB,cAAc,EAEjB,MAAM,sCAAsC,CAAC;AAI9C,oBAAY,UAAU;IAClB,UAAU,SAAS;IACnB,WAAW,UAAU;IACrB,KAAK,UAAU;CAClB;AAED;;GAEG;AACH,oBAAY,sBAAsB,GAAG,CACjC,UAAU,EAAE,mBAAmB,EAC/B,QAAQ,EAAE,eAAe,EACzB,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,MAAM,KAChD,gBAAgB,CAAC;AAEtB,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB;IAC1D,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,aAAa,CAAC,OAAO,EAAE,cAAc,OAAE;CAC1C;AAED,qBAAa,eAAgB,SAAQ,iBAAkB,YAAW,gBAAgB;IAK1E,QAAQ,CAAC,QAAQ,EAAE,cAAc;gBAHjC,UAAU,EAAE,mBAAmB,EAC/B,cAAc,EAAE,eAAe,EAC/B,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,MAAM,EACxC,QAAQ,EAAE,cAAc;IAoB9B,cAAc,CAAC,OAAO,EAAE,yBAAyB,EAAE,KAAK,EAAE,OAAO,GAAG,qBAAqB;IAoBzF,aAAa,CAAC,OAAO,EAAE,cAAc;CA+B/C"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AACvE,OAAO,EAEH,gBAAgB,IAAI,oBAAoB,EACxC,eAAe,EACf,iBAAiB,EACpB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACH,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,aAAa,EACb,cAAc,EAEjB,MAAM,sCAAsC,CAAC;AAG9C;;GAEG;AACH,oBAAY,sBAAsB,GAAG,CACjC,UAAU,EAAE,mBAAmB,EAC/B,QAAQ,EAAE,eAAe,EACzB,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,MAAM,EACjD,cAAc,EAAE,aAAa,EAAE,KAC9B,gBAAgB,CAAC;AAEtB,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB;IAC1D,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,aAAa,CAAC,OAAO,EAAE,cAAc,OAAE;CAC1C;AAED,qBAAa,eAAgB,SAAQ,iBAAkB,YAAW,gBAAgB;IAM1E,QAAQ,CAAC,QAAQ,EAAE,cAAc;gBAJjC,UAAU,EAAE,mBAAmB,EAC/B,cAAc,EAAE,eAAe,EAC/B,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,MAAM,EACjD,cAAc,EAAE,aAAa,EAAE,EACtB,QAAQ,EAAE,cAAc;IAiB9B,cAAc,CAAC,OAAO,EAAE,yBAAyB,EAAE,KAAK,EAAE,OAAO,GAAG,qBAAqB;IAoBzF,aAAa,CAAC,OAAO,EAAE,cAAc;CAgB/C"}
package/lib/protocol.js CHANGED
@@ -5,22 +5,12 @@
5
5
  import { ProtocolOpHandler, } from "@fluidframework/protocol-base";
6
6
  import { MessageType, } from "@fluidframework/protocol-definitions";
7
7
  import { canBeCoalescedByService } from "@fluidframework/driver-utils";
8
- // ADO: #1986: Start using enum from protocol-base.
9
- export var SignalType;
10
- (function (SignalType) {
11
- SignalType["ClientJoin"] = "join";
12
- SignalType["ClientLeave"] = "leave";
13
- SignalType["Clear"] = "clear";
14
- })(SignalType || (SignalType = {}));
15
8
  export class ProtocolHandler extends ProtocolOpHandler {
16
- constructor(attributes, quorumSnapshot, sendProposal, audience) {
9
+ constructor(attributes, quorumSnapshot, sendProposal, initialClients, audience) {
17
10
  super(attributes.minimumSequenceNumber, attributes.sequenceNumber, attributes.term, quorumSnapshot.members, quorumSnapshot.proposals, quorumSnapshot.values, sendProposal);
18
11
  this.audience = audience;
19
- // Join / leave signals are ignored for "write" clients in favor of join / leave ops
20
- this.quorum.on("addMember", (clientId, details) => audience.addMember(clientId, details.client));
21
- this.quorum.on("removeMember", (clientId) => audience.removeMember(clientId));
22
- for (const [clientId, details] of this.quorum.getMembers()) {
23
- this.audience.addMember(clientId, details.client);
12
+ for (const initialClient of initialClients) {
13
+ this.audience.addMember(initialClient.clientId, initialClient.client);
24
14
  }
25
15
  }
26
16
  processMessage(message, local) {
@@ -40,32 +30,16 @@ export class ProtocolHandler extends ProtocolOpHandler {
40
30
  return super.processMessage(message, local);
41
31
  }
42
32
  processSignal(message) {
43
- var _a;
44
33
  const innerContent = message.content;
45
34
  switch (innerContent.type) {
46
- case SignalType.Clear: {
47
- const members = this.audience.getMembers();
48
- for (const [clientId, client] of members) {
49
- if (client.mode === "read") {
50
- this.audience.removeMember(clientId);
51
- }
52
- }
53
- break;
54
- }
55
- case SignalType.ClientJoin: {
35
+ case MessageType.ClientJoin: {
56
36
  const newClient = innerContent.content;
57
- // Ignore write clients - quorum will control such clients.
58
- if (newClient.client.mode === "read") {
59
- this.audience.addMember(newClient.clientId, newClient.client);
60
- }
37
+ this.audience.addMember(newClient.clientId, newClient.client);
61
38
  break;
62
39
  }
63
- case SignalType.ClientLeave: {
40
+ case MessageType.ClientLeave: {
64
41
  const leftClientId = innerContent.content;
65
- // Ignore write clients - quorum will control such clients.
66
- if (((_a = this.audience.getMember(leftClientId)) === null || _a === void 0 ? void 0 : _a.mode) === "read") {
67
- this.audience.removeMember(leftClientId);
68
- }
42
+ this.audience.removeMember(leftClientId);
69
43
  break;
70
44
  }
71
45
  default: break;
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.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 { IAudienceOwner } from \"@fluidframework/container-definitions\";\nimport {\n ILocalSequencedClient,\n IProtocolHandler as IBaseProtocolHandler,\n IQuorumSnapshot,\n ProtocolOpHandler,\n} from \"@fluidframework/protocol-base\";\nimport {\n IDocumentAttributes,\n IProcessMessageResult,\n ISequencedDocumentMessage,\n ISignalClient,\n ISignalMessage,\n MessageType,\n} from \"@fluidframework/protocol-definitions\";\nimport { canBeCoalescedByService } from \"@fluidframework/driver-utils\";\n\n// ADO: #1986: Start using enum from protocol-base.\nexport enum SignalType {\n ClientJoin = \"join\", // same value as MessageType.ClientJoin,\n ClientLeave = \"leave\", // same value as MessageType.ClientLeave,\n Clear = \"clear\", // used only by client for synthetic signals\n}\n\n/**\n * Function to be used for creating a protocol handler.\n */\nexport type ProtocolHandlerBuilder = (\n attributes: IDocumentAttributes,\n snapshot: IQuorumSnapshot,\n sendProposal: (key: string, value: any) => number,\n) => IProtocolHandler;\n\nexport interface IProtocolHandler extends IBaseProtocolHandler {\n readonly audience: IAudienceOwner;\n processSignal(message: ISignalMessage);\n}\n\nexport class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandler {\n constructor(\n attributes: IDocumentAttributes,\n quorumSnapshot: IQuorumSnapshot,\n sendProposal: (key: string, value: any) => number,\n readonly audience: IAudienceOwner,\n ) {\n super(\n attributes.minimumSequenceNumber,\n attributes.sequenceNumber,\n attributes.term,\n quorumSnapshot.members,\n quorumSnapshot.proposals,\n quorumSnapshot.values,\n sendProposal,\n );\n\n // Join / leave signals are ignored for \"write\" clients in favor of join / leave ops\n this.quorum.on(\"addMember\", (clientId, details) => audience.addMember(clientId, details.client));\n this.quorum.on(\"removeMember\", (clientId) => audience.removeMember(clientId));\n for (const [clientId, details] of this.quorum.getMembers()) {\n this.audience.addMember(clientId, details.client);\n }\n }\n\n public processMessage(message: ISequencedDocumentMessage, local: boolean): IProcessMessageResult {\n const client: ILocalSequencedClient | undefined = this.quorum.getMember(message.clientId);\n\n // Check and report if we're getting messages from a clientId that we previously\n // flagged as shouldHaveLeft, or from a client that's not in the quorum but should be\n if (message.clientId != null) {\n if (client === undefined && message.type !== MessageType.ClientJoin) {\n // pre-0.58 error message: messageClientIdMissingFromQuorum\n throw new Error(\"Remote message's clientId is missing from the quorum\");\n }\n\n if (client?.shouldHaveLeft === true && !canBeCoalescedByService(message)) {\n // pre-0.58 error message: messageClientIdShouldHaveLeft\n throw new Error(\"Remote message's clientId already should have left\");\n }\n }\n\n return super.processMessage(message, local);\n }\n\n public processSignal(message: ISignalMessage) {\n const innerContent = message.content as { content: any; type: string; };\n switch (innerContent.type) {\n case SignalType.Clear: {\n const members = this.audience.getMembers();\n for (const [clientId, client] of members) {\n if (client.mode === \"read\") {\n this.audience.removeMember(clientId);\n }\n }\n break;\n }\n case SignalType.ClientJoin: {\n const newClient = innerContent.content as ISignalClient;\n // Ignore write clients - quorum will control such clients.\n if (newClient.client.mode === \"read\") {\n this.audience.addMember(newClient.clientId, newClient.client);\n }\n break;\n }\n case SignalType.ClientLeave: {\n const leftClientId = innerContent.content as string;\n // Ignore write clients - quorum will control such clients.\n if (this.audience.getMember(leftClientId)?.mode === \"read\") {\n this.audience.removeMember(leftClientId);\n }\n break;\n }\n default: break;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAIH,iBAAiB,GACpB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAMH,WAAW,GACd,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAiBvE,MAAM,OAAO,eAAgB,SAAQ,iBAAiB;IAClD,YACI,UAA+B,EAC/B,cAA+B,EAC/B,YAAiD,EACjD,cAA+B,EACtB,QAAwB;QAEjC,KAAK,CACD,UAAU,CAAC,qBAAqB,EAChC,UAAU,CAAC,cAAc,EACzB,UAAU,CAAC,IAAI,EACf,cAAc,CAAC,OAAO,EACtB,cAAc,CAAC,SAAS,EACxB,cAAc,CAAC,MAAM,EACrB,YAAY,CACf,CAAC;QAVO,aAAQ,GAAR,QAAQ,CAAgB;QAYjC,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE;YACxC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,aAAa,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;SACzE;IACL,CAAC;IAEM,cAAc,CAAC,OAAkC,EAAE,KAAc;QACpE,MAAM,MAAM,GAAsC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAE1F,gFAAgF;QAChF,qFAAqF;QACrF,IAAI,OAAO,CAAC,QAAQ,IAAI,IAAI,EAAE;YAC1B,IAAI,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjE,2DAA2D;gBAC3D,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;aAC3E;YAED,IAAI,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,cAAc,MAAK,IAAI,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,EAAE;gBACtE,wDAAwD;gBACxD,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;aACzE;SACJ;QAED,OAAO,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAChD,CAAC;IAEM,aAAa,CAAC,OAAuB;QACxC,MAAM,YAAY,GAAG,OAAO,CAAC,OAA0C,CAAC;QACxE,QAAQ,YAAY,CAAC,IAAI,EAAE;YACvB,KAAK,WAAW,CAAC,UAAU,CAAC,CAAC;gBACzB,MAAM,SAAS,GAAG,YAAY,CAAC,OAAwB,CAAC;gBACxD,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;gBAC9D,MAAM;aACT;YACD,KAAK,WAAW,CAAC,WAAW,CAAC,CAAC;gBAC1B,MAAM,YAAY,GAAG,YAAY,CAAC,OAAiB,CAAC;gBACpD,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;gBACzC,MAAM;aACT;YACD,OAAO,CAAC,CAAC,MAAM;SAClB;IACL,CAAC;CACJ","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IAudienceOwner } from \"@fluidframework/container-definitions\";\nimport {\n ILocalSequencedClient,\n IProtocolHandler as IBaseProtocolHandler,\n IQuorumSnapshot,\n ProtocolOpHandler,\n} from \"@fluidframework/protocol-base\";\nimport {\n IDocumentAttributes,\n IProcessMessageResult,\n ISequencedDocumentMessage,\n ISignalClient,\n ISignalMessage,\n MessageType,\n} from \"@fluidframework/protocol-definitions\";\nimport { canBeCoalescedByService } from \"@fluidframework/driver-utils\";\n\n/**\n * Function to be used for creating a protocol handler.\n */\nexport type ProtocolHandlerBuilder = (\n attributes: IDocumentAttributes,\n snapshot: IQuorumSnapshot,\n sendProposal: (key: string, value: any) => number,\n initialClients: ISignalClient[],\n) => IProtocolHandler;\n\nexport interface IProtocolHandler extends IBaseProtocolHandler {\n readonly audience: IAudienceOwner;\n processSignal(message: ISignalMessage);\n}\n\nexport class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandler {\n constructor(\n attributes: IDocumentAttributes,\n quorumSnapshot: IQuorumSnapshot,\n sendProposal: (key: string, value: any) => number,\n initialClients: ISignalClient[],\n readonly audience: IAudienceOwner,\n ) {\n super(\n attributes.minimumSequenceNumber,\n attributes.sequenceNumber,\n attributes.term,\n quorumSnapshot.members,\n quorumSnapshot.proposals,\n quorumSnapshot.values,\n sendProposal,\n );\n\n for (const initialClient of initialClients) {\n this.audience.addMember(initialClient.clientId, initialClient.client);\n }\n }\n\n public processMessage(message: ISequencedDocumentMessage, local: boolean): IProcessMessageResult {\n const client: ILocalSequencedClient | undefined = this.quorum.getMember(message.clientId);\n\n // Check and report if we're getting messages from a clientId that we previously\n // flagged as shouldHaveLeft, or from a client that's not in the quorum but should be\n if (message.clientId != null) {\n if (client === undefined && message.type !== MessageType.ClientJoin) {\n // pre-0.58 error message: messageClientIdMissingFromQuorum\n throw new Error(\"Remote message's clientId is missing from the quorum\");\n }\n\n if (client?.shouldHaveLeft === true && !canBeCoalescedByService(message)) {\n // pre-0.58 error message: messageClientIdShouldHaveLeft\n throw new Error(\"Remote message's clientId already should have left\");\n }\n }\n\n return super.processMessage(message, local);\n }\n\n public processSignal(message: ISignalMessage) {\n const innerContent = message.content as { content: any; type: string; };\n switch (innerContent.type) {\n case MessageType.ClientJoin: {\n const newClient = innerContent.content as ISignalClient;\n this.audience.addMember(newClient.clientId, newClient.client);\n break;\n }\n case MessageType.ClientLeave: {\n const leftClientId = innerContent.content as string;\n this.audience.removeMember(leftClientId);\n break;\n }\n default: break;\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-loader",
3
- "version": "2.0.0-dev.1.3.0.96595",
3
+ "version": "2.0.0-dev.1.4.5.105745",
4
4
  "description": "Fluid container loader",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -63,14 +63,14 @@
63
63
  "dependencies": {
64
64
  "@fluidframework/common-definitions": "^0.20.1",
65
65
  "@fluidframework/common-utils": "^1.0.0",
66
- "@fluidframework/container-definitions": "2.0.0-dev.1.3.0.96595",
67
- "@fluidframework/container-utils": "2.0.0-dev.1.3.0.96595",
68
- "@fluidframework/core-interfaces": "2.0.0-dev.1.3.0.96595",
69
- "@fluidframework/driver-definitions": "2.0.0-dev.1.3.0.96595",
70
- "@fluidframework/driver-utils": "2.0.0-dev.1.3.0.96595",
66
+ "@fluidframework/container-definitions": "2.0.0-dev.1.4.5.105745",
67
+ "@fluidframework/container-utils": "2.0.0-dev.1.4.5.105745",
68
+ "@fluidframework/core-interfaces": "2.0.0-dev.1.4.5.105745",
69
+ "@fluidframework/driver-definitions": "2.0.0-dev.1.4.5.105745",
70
+ "@fluidframework/driver-utils": "2.0.0-dev.1.4.5.105745",
71
71
  "@fluidframework/protocol-base": "^0.1037.2001",
72
72
  "@fluidframework/protocol-definitions": "^1.0.0",
73
- "@fluidframework/telemetry-utils": "2.0.0-dev.1.3.0.96595",
73
+ "@fluidframework/telemetry-utils": "2.0.0-dev.1.4.5.105745",
74
74
  "abort-controller": "^3.0.0",
75
75
  "double-ended-queue": "^2.1.0-0",
76
76
  "lodash": "^4.17.21",
@@ -79,11 +79,11 @@
79
79
  },
80
80
  "devDependencies": {
81
81
  "@fluidframework/build-common": "^1.0.0",
82
- "@fluidframework/build-tools": "^0.4.6000",
82
+ "@fluidframework/build-tools": "^0.4.4000",
83
83
  "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@^1.0.0",
84
84
  "@fluidframework/eslint-config-fluid": "^1.0.0",
85
- "@fluidframework/mocha-test-setup": "2.0.0-dev.1.3.0.96595",
86
- "@fluidframework/test-loader-utils": "2.0.0-dev.1.3.0.96595",
85
+ "@fluidframework/mocha-test-setup": "2.0.0-dev.1.4.5.105745",
86
+ "@fluidframework/test-loader-utils": "2.0.0-dev.1.4.5.105745",
87
87
  "@microsoft/api-extractor": "^7.22.2",
88
88
  "@rushstack/eslint-config": "^2.5.1",
89
89
  "@types/double-ended-queue": "^2.1.0",
package/src/audience.ts CHANGED
@@ -21,12 +21,8 @@ export class Audience extends EventEmitter implements IAudienceOwner {
21
21
  * Adds a new client to the audience
22
22
  */
23
23
  public addMember(clientId: string, details: IClient) {
24
- // Given that signal delivery is unreliable process, we might observe same client being added twice
25
- // In such case we should see exactly same payload (IClient), and should not raise event twice!
26
- if (!this.members.has(clientId)) {
27
- this.members.set(clientId, details);
28
- this.emit("addMember", clientId, details);
29
- }
24
+ this.members.set(clientId, details);
25
+ this.emit("addMember", clientId, details);
30
26
  }
31
27
 
32
28
  /**
@@ -57,4 +53,14 @@ export class Audience extends EventEmitter implements IAudienceOwner {
57
53
  public getMember(clientId: string): IClient | undefined {
58
54
  return this.members.get(clientId);
59
55
  }
56
+
57
+ /**
58
+ * Clears the audience
59
+ */
60
+ public clear(): void {
61
+ const clientIds = this.members.keys();
62
+ for (const clientId of clientIds) {
63
+ this.removeMember(clientId);
64
+ }
65
+ }
60
66
  }
@@ -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,
@@ -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.5.105745";
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;