@project-chip/matter.js 0.10.1 → 0.10.4
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/dist/cjs/behavior/definitions/descriptor/DescriptorServer.d.ts.map +1 -1
- package/dist/cjs/behavior/definitions/descriptor/DescriptorServer.js +5 -0
- package/dist/cjs/behavior/definitions/descriptor/DescriptorServer.js.map +2 -2
- package/dist/cjs/behavior/definitions/power-topology/PowerTopologyServer.d.ts.map +1 -1
- package/dist/cjs/behavior/definitions/power-topology/PowerTopologyServer.js +4 -2
- package/dist/cjs/behavior/definitions/power-topology/PowerTopologyServer.js.map +2 -2
- package/dist/cjs/protocol/ChannelManager.d.ts.map +1 -1
- package/dist/cjs/protocol/ChannelManager.js +16 -15
- package/dist/cjs/protocol/ChannelManager.js.map +2 -2
- package/dist/cjs/protocol/interaction/SubscriptionHandler.d.ts.map +1 -1
- package/dist/cjs/protocol/interaction/SubscriptionHandler.js +8 -4
- package/dist/cjs/protocol/interaction/SubscriptionHandler.js.map +2 -2
- package/dist/esm/behavior/definitions/descriptor/DescriptorServer.d.ts.map +1 -1
- package/dist/esm/behavior/definitions/descriptor/DescriptorServer.js +5 -0
- package/dist/esm/behavior/definitions/descriptor/DescriptorServer.js.map +2 -2
- package/dist/esm/behavior/definitions/power-topology/PowerTopologyServer.d.ts.map +1 -1
- package/dist/esm/behavior/definitions/power-topology/PowerTopologyServer.js +4 -2
- package/dist/esm/behavior/definitions/power-topology/PowerTopologyServer.js.map +2 -2
- package/dist/esm/protocol/ChannelManager.d.ts.map +1 -1
- package/dist/esm/protocol/ChannelManager.js +16 -15
- package/dist/esm/protocol/ChannelManager.js.map +2 -2
- package/dist/esm/protocol/interaction/SubscriptionHandler.d.ts.map +1 -1
- package/dist/esm/protocol/interaction/SubscriptionHandler.js +8 -4
- package/dist/esm/protocol/interaction/SubscriptionHandler.js.map +2 -2
- package/package.json +3 -3
- package/src/behavior/definitions/descriptor/DescriptorServer.ts +7 -1
- package/src/behavior/definitions/power-topology/PowerTopologyServer.ts +4 -3
- package/src/protocol/ChannelManager.ts +17 -15
- package/src/protocol/interaction/SubscriptionHandler.ts +6 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DescriptorServer.d.ts","sourceRoot":"","sources":["../../../../../src/behavior/definitions/descriptor/DescriptorServer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,mDAAmD,CAAC;AAC/E,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAG5D,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAKjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,kBAAkB;;IACpD,OAAgB,YAAY,2BAAmB;IAEhC,UAAU;
|
|
1
|
+
{"version":3,"file":"DescriptorServer.d.ts","sourceRoot":"","sources":["../../../../../src/behavior/definitions/descriptor/DescriptorServer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,mDAAmD,CAAC;AAC/E,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAG5D,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAKjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,kBAAkB;;IACpD,OAAgB,YAAY,2BAAmB;IAEhC,UAAU;IAqDzB;;;;OAIG;IACH,cAAc,CAAC,GAAG,WAAW,EAAE,CAAC,gBAAgB,CAAC,UAAU,GAAG,MAAM,CAAC,EAAE;IAsBvE;;;;OAIG;IACH,OAAO,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE;IA0BzB;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,YAAY;CAoGnC;AAED,yBAAiB,gBAAgB,CAAC;IAC9B,KAAY,UAAU,GAAG,cAAc,CAAC,OAAO,UAAU,CAAC,aAAa,CAAC,CAAC;CAC5E"}
|
|
@@ -46,6 +46,10 @@ class DescriptorServer extends import_DescriptorBehavior.DescriptorBehavior {
|
|
|
46
46
|
await this.#updatePartsList();
|
|
47
47
|
this.reactTo(this.endpoint.lifecycle.changed, this.#updateDescriptor);
|
|
48
48
|
this.state.serverList = this.#serverList;
|
|
49
|
+
this.#initializeDeviceTypeList();
|
|
50
|
+
}
|
|
51
|
+
/** Initialize device type list when it is not already initialized. */
|
|
52
|
+
#initializeDeviceTypeList() {
|
|
49
53
|
if (!this.state.deviceTypeList.length) {
|
|
50
54
|
const partType = this.endpoint.type;
|
|
51
55
|
this.state.deviceTypeList = [
|
|
@@ -62,6 +66,7 @@ class DescriptorServer extends import_DescriptorBehavior.DescriptorBehavior {
|
|
|
62
66
|
* @param deviceTypes an array of objects or named device types as defined in {@link MatterModel.standard}
|
|
63
67
|
*/
|
|
64
68
|
addDeviceTypes(...deviceTypes) {
|
|
69
|
+
this.#initializeDeviceTypeList();
|
|
65
70
|
const list = this.state.deviceTypeList;
|
|
66
71
|
nextInput: for (let newDeviceType of deviceTypes) {
|
|
67
72
|
if (typeof newDeviceType === "string") {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/behavior/definitions/descriptor/DescriptorServer.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Descriptor } from \"../../../cluster/definitions/DescriptorCluster.js\";\nimport { Semtag } from \"../../../cluster/globals/Semtag.js\";\nimport { ImplementationError } from \"../../../common/MatterError.js\";\nimport { ClusterId } from \"../../../datatype/ClusterId.js\";\nimport { DeviceTypeId } from \"../../../datatype/DeviceTypeId.js\";\nimport { EndpointNumber } from \"../../../datatype/EndpointNumber.js\";\nimport { Endpoint } from \"../../../endpoint/Endpoint.js\";\nimport { EndpointLifecycle } from \"../../../endpoint/properties/EndpointLifecycle.js\";\nimport { DeviceTypeModel, MatterModel } from \"../../../model/index.js\";\nimport { TypeFromSchema } from \"../../../tlv/TlvSchema.js\";\nimport { isDeepEqual } from \"../../../util/DeepEqual.js\";\nimport { IndexBehavior } from \"../../system/index/IndexBehavior.js\";\nimport { DescriptorBehavior } from \"./DescriptorBehavior.js\";\n\n/**\n * This is the default server implementation of DescriptorBehavior.\n */\nexport class DescriptorServer extends DescriptorBehavior {\n static override dependencies = [IndexBehavior];\n\n override async initialize() {\n // We update PartsList differently if there's an index\n if (this.endpoint.behaviors.has(IndexBehavior)) {\n // Note - do not use lock here because this reactor triggers frequently so it pollutes the logs. Instead\n // lock manually as necessary\n this.reactTo(this.agent.get(IndexBehavior).events.change, this.#updatePartsList);\n } else if (this.endpoint.hasParts) {\n for (const endpoint of this.endpoint.parts) {\n this.#monitorDestruction(endpoint);\n }\n }\n await this.#updatePartsList();\n\n // Handle lifecycle changes\n this.reactTo(this.endpoint.lifecycle.changed, this.#updateDescriptor);\n\n // Initialize ServerList\n this.state.serverList = this.#serverList;\n\n // Initialize device type list\n if (!this.state.deviceTypeList.length) {\n const partType = this.endpoint.type;\n this.state.deviceTypeList = [\n {\n deviceType: partType.deviceType,\n revision: partType.deviceRevision,\n },\n ];\n\n // For complete semantics it would be better to include all inherited device types. However there is\n // typical spec-level confusion that makes this of questionable practical utility so omitting for now\n // for (\n // let base = MatterModel.standard.get(DeviceTypeModel, partType.deviceType)?.base;\n // base;\n // { base } = base\n // ) {\n // if (!(base instanceof DeviceTypeModel) || base.id === undefined) {\n // continue;\n // }\n\n // this.state.deviceTypeList.push({\n // deviceType: DeviceTypeId(base.id),\n // revision: base.revision,\n // });\n // }\n }\n }\n\n /**\n * Extend device type metadata. This is a shortcut for deduped insert into the deviceTypeList cluster attribute.\n *\n * @param deviceTypes an array of objects or named device types as defined in {@link MatterModel.standard}\n */\n addDeviceTypes(...deviceTypes: (DescriptorServer.DeviceType | string)[]) {\n const list = this.state.deviceTypeList;\n\n nextInput: for (let newDeviceType of deviceTypes) {\n if (typeof newDeviceType === \"string\") {\n const dt = MatterModel.standard.get(DeviceTypeModel, newDeviceType);\n if (dt === undefined) {\n throw new ImplementationError(`Device type ${newDeviceType} not found`);\n }\n newDeviceType = { deviceType: DeviceTypeId(dt.id), revision: dt.revision };\n }\n\n for (const existingDeviceType of list) {\n if (isDeepEqual(newDeviceType, existingDeviceType)) {\n continue nextInput;\n }\n }\n list.push(newDeviceType);\n }\n }\n\n /**\n * Add semantic tags. This is a shortcut for deduped insert into the tagList cluster attribute.\n *\n * You must enable the \"TagList\" feature to use this method.\n */\n addTags(...tags: Semtag[]) {\n // TODO - should automatically enable the feature if it's not enabled\n if (!this.features.tagList) {\n throw new ImplementationError('You must enable the descriptor \"TagList\" feature to set tags');\n }\n\n const list = (this.state as unknown as { tagList: Semtag[] }).tagList;\n\n nextInput: for (const newTag of tags) {\n for (const existingTag of list) {\n if (\n existingTag.mfgCode === newTag.mfgCode &&\n existingTag.namespaceId === newTag.namespaceId &&\n existingTag.tag === newTag.tag\n ) {\n if (existingTag.label !== newTag.label && newTag.label !== null && newTag.label !== undefined) {\n existingTag.label = newTag.label;\n continue nextInput;\n }\n }\n }\n\n list.push(newTag);\n }\n }\n\n /**\n * Check for presence of a device type.\n */\n hasDeviceType(type: DeviceTypeId) {\n return this.state.deviceTypeList.findIndex(dt => dt.deviceType === type) !== -1;\n }\n\n /**\n * Process a structure change event and trigger state updates if necessary.\n */\n async #updateDescriptor(type: EndpointLifecycle.Change, endpoint: Endpoint) {\n switch (type) {\n case EndpointLifecycle.Change.Ready:\n if (!this.endpoint.parts.has(endpoint)) {\n return;\n }\n await this.#updatePartsList();\n this.#monitorDestruction(endpoint);\n break;\n\n case EndpointLifecycle.Change.ServersChanged:\n if (endpoint !== this.endpoint) {\n return;\n }\n\n await this.context.transaction.addResources(this);\n await this.context.transaction.begin();\n this.state.serverList = this.#serverList;\n break;\n }\n }\n\n /**\n * Monitor endpoint for removal.\n */\n #monitorDestruction(endpoint: Endpoint) {\n this.reactTo(endpoint.lifecycle.destroyed, this.#updatePartsList);\n }\n\n /**\n * Update the parts list.\n */\n async #updatePartsList() {\n const endpoint = this.endpoint;\n\n let numbers: number[];\n\n // The presence of IndexBehavior indicates a flat namespace as required by Matter standard for root and\n // aggregator endpoints\n if (this.agent.has(IndexBehavior)) {\n const index = this.agent.get(IndexBehavior);\n numbers = Object.keys(index.partsByNumber).map(n => Number.parseInt(n));\n\n // My endpoint should not appear in its own PartsList\n const pos = numbers.indexOf(this.endpoint.number);\n if (pos !== -1) {\n numbers.splice(pos, 1);\n }\n } else if (endpoint.hasParts) {\n // No IndexBehavior, just direct descendents\n numbers = [...endpoint.parts]\n .map(endpoint => (endpoint.lifecycle.hasNumber ? endpoint.number : undefined))\n .filter(n => n !== undefined) as number[];\n } else {\n // No sub-parts\n numbers = [];\n }\n\n numbers.sort();\n\n // Do a quick deep equal so we can avoid updating state since the filtering on events that trigger this function\n // is rather lazy\n if (this.state.partsList.length === numbers.length) {\n let i = numbers.length;\n for (; i < numbers.length; i++) {\n if (this.state.partsList[i] !== numbers[i]) {\n break;\n }\n }\n if (i === numbers.length) {\n return;\n }\n }\n\n await this.context.transaction.addResources(this);\n await this.context.transaction.begin();\n\n this.state.partsList = numbers as EndpointNumber[];\n }\n\n /**\n * Computed current server list.\n */\n get #serverList() {\n const list = new Array<ClusterId>();\n for (const type of Object.values(this.endpoint.behaviors.supported)) {\n const clusterId = (type as { cluster?: { id?: ClusterId } }).cluster?.id;\n if (clusterId) {\n list.push(clusterId);\n }\n }\n return list;\n }\n}\n\nexport namespace DescriptorServer {\n export type DeviceType = TypeFromSchema<typeof Descriptor.TlvDeviceType>;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Descriptor } from \"../../../cluster/definitions/DescriptorCluster.js\";\nimport { Semtag } from \"../../../cluster/globals/Semtag.js\";\nimport { ImplementationError } from \"../../../common/MatterError.js\";\nimport { ClusterId } from \"../../../datatype/ClusterId.js\";\nimport { DeviceTypeId } from \"../../../datatype/DeviceTypeId.js\";\nimport { EndpointNumber } from \"../../../datatype/EndpointNumber.js\";\nimport { Endpoint } from \"../../../endpoint/Endpoint.js\";\nimport { EndpointLifecycle } from \"../../../endpoint/properties/EndpointLifecycle.js\";\nimport { DeviceTypeModel, MatterModel } from \"../../../model/index.js\";\nimport { TypeFromSchema } from \"../../../tlv/TlvSchema.js\";\nimport { isDeepEqual } from \"../../../util/DeepEqual.js\";\nimport { IndexBehavior } from \"../../system/index/IndexBehavior.js\";\nimport { DescriptorBehavior } from \"./DescriptorBehavior.js\";\n\n/**\n * This is the default server implementation of DescriptorBehavior.\n */\nexport class DescriptorServer extends DescriptorBehavior {\n static override dependencies = [IndexBehavior];\n\n override async initialize() {\n // We update PartsList differently if there's an index\n if (this.endpoint.behaviors.has(IndexBehavior)) {\n // Note - do not use lock here because this reactor triggers frequently so it pollutes the logs. Instead\n // lock manually as necessary\n this.reactTo(this.agent.get(IndexBehavior).events.change, this.#updatePartsList);\n } else if (this.endpoint.hasParts) {\n for (const endpoint of this.endpoint.parts) {\n this.#monitorDestruction(endpoint);\n }\n }\n await this.#updatePartsList();\n\n // Handle lifecycle changes\n this.reactTo(this.endpoint.lifecycle.changed, this.#updateDescriptor);\n\n // Initialize ServerList\n this.state.serverList = this.#serverList;\n\n // Initialize DeviceTypeList\n this.#initializeDeviceTypeList();\n }\n\n /** Initialize device type list when it is not already initialized. */\n #initializeDeviceTypeList() {\n if (!this.state.deviceTypeList.length) {\n const partType = this.endpoint.type;\n this.state.deviceTypeList = [\n {\n deviceType: partType.deviceType,\n revision: partType.deviceRevision,\n },\n ];\n\n // For complete semantics it would be better to include all inherited device types. However there is\n // typical spec-level confusion that makes this of questionable practical utility so omitting for now\n // for (\n // let base = MatterModel.standard.get(DeviceTypeModel, partType.deviceType)?.base;\n // base;\n // { base } = base\n // ) {\n // if (!(base instanceof DeviceTypeModel) || base.id === undefined) {\n // continue;\n // }\n\n // this.state.deviceTypeList.push({\n // deviceType: DeviceTypeId(base.id),\n // revision: base.revision,\n // });\n // }\n }\n }\n\n /**\n * Extend device type metadata. This is a shortcut for deduped insert into the deviceTypeList cluster attribute.\n *\n * @param deviceTypes an array of objects or named device types as defined in {@link MatterModel.standard}\n */\n addDeviceTypes(...deviceTypes: (DescriptorServer.DeviceType | string)[]) {\n this.#initializeDeviceTypeList(); // Initialize if not already done\n const list = this.state.deviceTypeList;\n\n nextInput: for (let newDeviceType of deviceTypes) {\n if (typeof newDeviceType === \"string\") {\n const dt = MatterModel.standard.get(DeviceTypeModel, newDeviceType);\n if (dt === undefined) {\n throw new ImplementationError(`Device type ${newDeviceType} not found`);\n }\n newDeviceType = { deviceType: DeviceTypeId(dt.id), revision: dt.revision };\n }\n\n for (const existingDeviceType of list) {\n if (isDeepEqual(newDeviceType, existingDeviceType)) {\n continue nextInput;\n }\n }\n list.push(newDeviceType);\n }\n }\n\n /**\n * Add semantic tags. This is a shortcut for deduped insert into the tagList cluster attribute.\n *\n * You must enable the \"TagList\" feature to use this method.\n */\n addTags(...tags: Semtag[]) {\n // TODO - should automatically enable the feature if it's not enabled\n if (!this.features.tagList) {\n throw new ImplementationError('You must enable the descriptor \"TagList\" feature to set tags');\n }\n\n const list = (this.state as unknown as { tagList: Semtag[] }).tagList;\n\n nextInput: for (const newTag of tags) {\n for (const existingTag of list) {\n if (\n existingTag.mfgCode === newTag.mfgCode &&\n existingTag.namespaceId === newTag.namespaceId &&\n existingTag.tag === newTag.tag\n ) {\n if (existingTag.label !== newTag.label && newTag.label !== null && newTag.label !== undefined) {\n existingTag.label = newTag.label;\n continue nextInput;\n }\n }\n }\n\n list.push(newTag);\n }\n }\n\n /**\n * Check for presence of a device type.\n */\n hasDeviceType(type: DeviceTypeId) {\n return this.state.deviceTypeList.findIndex(dt => dt.deviceType === type) !== -1;\n }\n\n /**\n * Process a structure change event and trigger state updates if necessary.\n */\n async #updateDescriptor(type: EndpointLifecycle.Change, endpoint: Endpoint) {\n switch (type) {\n case EndpointLifecycle.Change.Ready:\n if (!this.endpoint.parts.has(endpoint)) {\n return;\n }\n await this.#updatePartsList();\n this.#monitorDestruction(endpoint);\n break;\n\n case EndpointLifecycle.Change.ServersChanged:\n if (endpoint !== this.endpoint) {\n return;\n }\n\n await this.context.transaction.addResources(this);\n await this.context.transaction.begin();\n this.state.serverList = this.#serverList;\n break;\n }\n }\n\n /**\n * Monitor endpoint for removal.\n */\n #monitorDestruction(endpoint: Endpoint) {\n this.reactTo(endpoint.lifecycle.destroyed, this.#updatePartsList);\n }\n\n /**\n * Update the parts list.\n */\n async #updatePartsList() {\n const endpoint = this.endpoint;\n\n let numbers: number[];\n\n // The presence of IndexBehavior indicates a flat namespace as required by Matter standard for root and\n // aggregator endpoints\n if (this.agent.has(IndexBehavior)) {\n const index = this.agent.get(IndexBehavior);\n numbers = Object.keys(index.partsByNumber).map(n => Number.parseInt(n));\n\n // My endpoint should not appear in its own PartsList\n const pos = numbers.indexOf(this.endpoint.number);\n if (pos !== -1) {\n numbers.splice(pos, 1);\n }\n } else if (endpoint.hasParts) {\n // No IndexBehavior, just direct descendents\n numbers = [...endpoint.parts]\n .map(endpoint => (endpoint.lifecycle.hasNumber ? endpoint.number : undefined))\n .filter(n => n !== undefined) as number[];\n } else {\n // No sub-parts\n numbers = [];\n }\n\n numbers.sort();\n\n // Do a quick deep equal so we can avoid updating state since the filtering on events that trigger this function\n // is rather lazy\n if (this.state.partsList.length === numbers.length) {\n let i = numbers.length;\n for (; i < numbers.length; i++) {\n if (this.state.partsList[i] !== numbers[i]) {\n break;\n }\n }\n if (i === numbers.length) {\n return;\n }\n }\n\n await this.context.transaction.addResources(this);\n await this.context.transaction.begin();\n\n this.state.partsList = numbers as EndpointNumber[];\n }\n\n /**\n * Computed current server list.\n */\n get #serverList() {\n const list = new Array<ClusterId>();\n for (const type of Object.values(this.endpoint.behaviors.supported)) {\n const clusterId = (type as { cluster?: { id?: ClusterId } }).cluster?.id;\n if (clusterId) {\n list.push(clusterId);\n }\n }\n return list;\n }\n}\n\nexport namespace DescriptorServer {\n export type DeviceType = TypeFromSchema<typeof Descriptor.TlvDeviceType>;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["endpoint"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PowerTopologyServer.d.ts","sourceRoot":"","sources":["../../../../../src/behavior/definitions/power-topology/PowerTopologyServer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAErF,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAMrE,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGtB,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,wBAAyB,SAAQ,iBAAiB;;IAClD,UAAU,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"PowerTopologyServer.d.ts","sourceRoot":"","sources":["../../../../../src/behavior/definitions/power-topology/PowerTopologyServer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAErF,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAMrE,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGtB,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,wBAAyB,SAAQ,iBAAiB;;IAClD,UAAU,IAAI,IAAI;CAmB9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAED,qBAAa,mBAAoB,SAAQ,wBAA6D;CAAG"}
|
|
@@ -43,8 +43,10 @@ class PowerTopologyServerLogic extends PowerTopologyBase {
|
|
|
43
43
|
if (this.agent.has(import_ElectricalPowerMeasurementBehavior.ElectricalPowerMeasurementBehavior) || this.agent.has(import_ElectricalEnergyMeasurementBehavior.ElectricalEnergyMeasurementBehavior)) {
|
|
44
44
|
this.agent.get(import_DescriptorServer.DescriptorServer).addDeviceTypes("ElectricalSensor");
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
if (this.state.activeEndpoints !== void 0) {
|
|
47
|
+
this.#assertActiveEndpointsAllowed(this.state.activeEndpoints);
|
|
48
|
+
this.reactTo(this.events.activeEndpoints$Changing, this.#assertActiveEndpointsAllowed);
|
|
49
|
+
}
|
|
48
50
|
}
|
|
49
51
|
#assertActiveEndpointsAllowed(list) {
|
|
50
52
|
const availableEndpoints = this.state.availableEndpoints;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/behavior/definitions/power-topology/PowerTopologyServer.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { ClusterType } from \"../../../cluster/ClusterType.js\";\nimport { PowerTopology } from \"../../../cluster/definitions/PowerTopologyCluster.js\";\nimport { ImplementationError } from \"../../../common/MatterError.js\";\nimport { EndpointNumber } from \"../../../datatype/EndpointNumber.js\";\nimport { DescriptorServer } from \"../descriptor/DescriptorServer.js\";\nimport { ElectricalEnergyMeasurementBehavior } from \"../electrical-energy-measurement/ElectricalEnergyMeasurementBehavior.js\";\nimport { ElectricalPowerMeasurementBehavior } from \"../electrical-power-measurement/ElectricalPowerMeasurementBehavior.js\";\nimport { PowerTopologyBehavior } from \"./PowerTopologyBehavior.js\";\n\nconst PowerTopologyBase = PowerTopologyBehavior.with(\n PowerTopology.Feature.SetTopology,\n PowerTopology.Feature.DynamicPowerFlow,\n);\n\n/**\n * This is the default server implementation of {@link PowerTopologyBehavior}.\n *\n * The Matter specification requires the PowerTopology cluster to support features we do not enable by default. You\n * should use {@link PowerTopologyServer.with} to specialize the class for the features your implementation supports.\n *\n * The default implementation verifies that the active endpoints are a subset of the available endpoints when\n * the SetTopology and DynamicPowerFlow features are used.\n */\nexport class PowerTopologyServerLogic extends PowerTopologyBase {\n override initialize(): void {\n if (this.agent.has(ElectricalPowerMeasurementBehavior) || this.agent.has(ElectricalEnergyMeasurementBehavior)) {\n this.agent.get(DescriptorServer).addDeviceTypes(\"ElectricalSensor\");\n }\n\n this.#assertActiveEndpointsAllowed(this.state.activeEndpoints);\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,yBAA4B;AAC5B,kCAA8B;AAC9B,yBAAoC;AAEpC,8BAAiC;AACjC,iDAAoD;AACpD,gDAAmD;AACnD,mCAAsC;AAbtC;AAAA;AAAA;AAAA;AAAA;AAeA,MAAM,oBAAoB,mDAAsB;AAAA,EAC5C,0CAAc,QAAQ;AAAA,EACtB,0CAAc,QAAQ;AAC1B;AAWO,MAAM,iCAAiC,kBAAkB;AAAA,EACnD,aAAmB;AACxB,QAAI,KAAK,MAAM,IAAI,4EAAkC,KAAK,KAAK,MAAM,IAAI,8EAAmC,GAAG;AAC3G,WAAK,MAAM,IAAI,wCAAgB,EAAE,eAAe,kBAAkB;AAAA,IACtE;AAEA,
|
|
4
|
+
"sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { ClusterType } from \"../../../cluster/ClusterType.js\";\nimport { PowerTopology } from \"../../../cluster/definitions/PowerTopologyCluster.js\";\nimport { ImplementationError } from \"../../../common/MatterError.js\";\nimport { EndpointNumber } from \"../../../datatype/EndpointNumber.js\";\nimport { DescriptorServer } from \"../descriptor/DescriptorServer.js\";\nimport { ElectricalEnergyMeasurementBehavior } from \"../electrical-energy-measurement/ElectricalEnergyMeasurementBehavior.js\";\nimport { ElectricalPowerMeasurementBehavior } from \"../electrical-power-measurement/ElectricalPowerMeasurementBehavior.js\";\nimport { PowerTopologyBehavior } from \"./PowerTopologyBehavior.js\";\n\nconst PowerTopologyBase = PowerTopologyBehavior.with(\n PowerTopology.Feature.SetTopology,\n PowerTopology.Feature.DynamicPowerFlow,\n);\n\n/**\n * This is the default server implementation of {@link PowerTopologyBehavior}.\n *\n * The Matter specification requires the PowerTopology cluster to support features we do not enable by default. You\n * should use {@link PowerTopologyServer.with} to specialize the class for the features your implementation supports.\n *\n * The default implementation verifies that the active endpoints are a subset of the available endpoints when\n * the SetTopology and DynamicPowerFlow features are used.\n */\nexport class PowerTopologyServerLogic extends PowerTopologyBase {\n override initialize(): void {\n if (this.agent.has(ElectricalPowerMeasurementBehavior) || this.agent.has(ElectricalEnergyMeasurementBehavior)) {\n this.agent.get(DescriptorServer).addDeviceTypes(\"ElectricalSensor\");\n }\n\n if (this.state.activeEndpoints !== undefined) {\n this.#assertActiveEndpointsAllowed(this.state.activeEndpoints);\n this.reactTo(this.events.activeEndpoints$Changing, this.#assertActiveEndpointsAllowed);\n }\n }\n\n #assertActiveEndpointsAllowed(list: EndpointNumber[]) {\n const availableEndpoints = this.state.availableEndpoints;\n list.forEach(endpoint => {\n if (!availableEndpoints.includes(endpoint)) {\n throw new ImplementationError(`Endpoint ${endpoint} is not in the list of available endpoints`);\n }\n });\n }\n}\n\nexport class PowerTopologyServer extends PowerTopologyServerLogic.for(ClusterType(PowerTopology.Base)) {}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,yBAA4B;AAC5B,kCAA8B;AAC9B,yBAAoC;AAEpC,8BAAiC;AACjC,iDAAoD;AACpD,gDAAmD;AACnD,mCAAsC;AAbtC;AAAA;AAAA;AAAA;AAAA;AAeA,MAAM,oBAAoB,mDAAsB;AAAA,EAC5C,0CAAc,QAAQ;AAAA,EACtB,0CAAc,QAAQ;AAC1B;AAWO,MAAM,iCAAiC,kBAAkB;AAAA,EACnD,aAAmB;AACxB,QAAI,KAAK,MAAM,IAAI,4EAAkC,KAAK,KAAK,MAAM,IAAI,8EAAmC,GAAG;AAC3G,WAAK,MAAM,IAAI,wCAAgB,EAAE,eAAe,kBAAkB;AAAA,IACtE;AAEA,QAAI,KAAK,MAAM,oBAAoB,QAAW;AAC1C,WAAK,8BAA8B,KAAK,MAAM,eAAe;AAC7D,WAAK,QAAQ,KAAK,OAAO,0BAA0B,KAAK,6BAA6B;AAAA,IACzF;AAAA,EACJ;AAAA,EAEA,8BAA8B,MAAwB;AAClD,UAAM,qBAAqB,KAAK,MAAM;AACtC,SAAK,QAAQ,cAAY;AACrB,UAAI,CAAC,mBAAmB,SAAS,QAAQ,GAAG;AACxC,cAAM,IAAI,uCAAoB,YAAY,QAAQ,4CAA4C;AAAA,MAClG;AAAA,IACJ,CAAC;AAAA,EACL;AACJ;AAEO,MAAM,4BAA4B,yBAAyB,QAAI,gCAAY,0CAAc,IAAI,CAAC,EAAE;AAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChannelManager.d.ts","sourceRoot":"","sources":["../../../src/protocol/ChannelManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAG7C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAItD,qBAAa,cAAe,SAAQ,WAAW;CAAG;AAElD,qBAAa,cAAc;;gBAMX,4BAA4B,SAAI;IAkBtC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"ChannelManager.d.ts","sourceRoot":"","sources":["../../../src/protocol/ChannelManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAG7C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAItD,qBAAa,cAAe,SAAQ,WAAW;CAAG;AAElD,qBAAa,cAAc;;gBAMX,4BAA4B,SAAI;IAkBtC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC;IAqB7E,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC;IAYjE;;OAEG;IACH,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC;IAapC,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAQpD,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC;IAkBzE,OAAO,CAAC,wBAAwB;IAU1B,kBAAkB,CAAC,gBAAgB,EAAE,OAAO,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC;IA0B9E,KAAK;CAYd"}
|
|
@@ -57,23 +57,18 @@ class ChannelManager {
|
|
|
57
57
|
channel.closeCallback = async () => this.removeChannel(fabric, nodeId, channel.session);
|
|
58
58
|
const channelsKey = this.#getChannelKey(fabric, nodeId);
|
|
59
59
|
const currentChannels = this.#channels.get(channelsKey) ?? [];
|
|
60
|
-
|
|
60
|
+
currentChannels.push(channel);
|
|
61
|
+
this.#channels.set(channelsKey, currentChannels);
|
|
62
|
+
if (currentChannels.length > this.#caseSessionsPerFabricAndNode) {
|
|
61
63
|
const oldestChannel = this.#findLeastActiveChannel(currentChannels);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const { session } = oldestChannel;
|
|
66
|
-
if (session.id !== oldestChannel.session.id) {
|
|
67
|
-
logger.debug(
|
|
68
|
-
`Existing channel for fabricIndex ${fabric.fabricIndex} and node ${nodeId} with session ${session.name} gets replaced. Consider former session already inactive and so close it.`
|
|
69
|
-
);
|
|
70
|
-
await session.destroy(false, false);
|
|
64
|
+
const { session: oldSession } = oldestChannel;
|
|
65
|
+
if (channel.session.id !== oldSession.id) {
|
|
66
|
+
await oldSession.destroy(false, false);
|
|
71
67
|
}
|
|
72
|
-
logger.info(
|
|
68
|
+
logger.info(
|
|
69
|
+
`Close oldest channel for fabric ${fabric.fabricIndex} node ${nodeId} (from session ${oldSession.id})`
|
|
70
|
+
);
|
|
73
71
|
await oldestChannel.close();
|
|
74
|
-
} else {
|
|
75
|
-
currentChannels.push(channel);
|
|
76
|
-
this.#channels.set(channelsKey, currentChannels);
|
|
77
72
|
}
|
|
78
73
|
}
|
|
79
74
|
getChannel(fabric, nodeId, session) {
|
|
@@ -81,7 +76,10 @@ class ChannelManager {
|
|
|
81
76
|
if (session !== void 0) {
|
|
82
77
|
results = results.filter((channel) => channel.session.id === session.id);
|
|
83
78
|
}
|
|
84
|
-
if (results.length === 0)
|
|
79
|
+
if (results.length === 0)
|
|
80
|
+
throw new NoChannelError(
|
|
81
|
+
`Can't find a channel to node ${nodeId}${session !== void 0 ? ` and session ${session.id}` : ""}`
|
|
82
|
+
);
|
|
85
83
|
return results[results.length - 1];
|
|
86
84
|
}
|
|
87
85
|
/**
|
|
@@ -112,6 +110,9 @@ class ChannelManager {
|
|
|
112
110
|
const channelEntryIndex = fabricChannels.findIndex(
|
|
113
111
|
({ session: entrySession }) => entrySession.id === session.id
|
|
114
112
|
);
|
|
113
|
+
if (channelEntryIndex === -1) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
115
116
|
const channelEntry = fabricChannels.splice(channelEntryIndex, 1)[0];
|
|
116
117
|
if (channelEntry === void 0) {
|
|
117
118
|
return;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/protocol/ChannelManager.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Channel } from \"../common/Channel.js\";\nimport { MatterError } from \"../common/MatterError.js\";\nimport { NodeId } from \"../datatype/NodeId.js\";\nimport { Fabric } from \"../fabric/Fabric.js\";\nimport { Logger } from \"../log/Logger.js\";\nimport { SecureSession } from \"../session/SecureSession.js\";\nimport { Session } from \"../session/Session.js\";\nimport { ByteArray } from \"../util/ByteArray.js\";\nimport { MessageChannel } from \"./ExchangeManager.js\";\n\nconst logger = Logger.get(\"ChannelManager\");\n\nexport class NoChannelError extends MatterError {}\n\nexport class ChannelManager {\n readonly #channels = new Map<string, MessageChannel<any>[]>();\n readonly #paseChannels = new Map<Session<any>, MessageChannel<any>>();\n readonly #caseSessionsPerFabricAndNode: number;\n\n // TODO evaluate with controller the effects of limiting the entries just for FabricIndex and not also NodeId\n constructor(caseSessionsPerFabricAndNode = 3) {\n this.#caseSessionsPerFabricAndNode = caseSessionsPerFabricAndNode;\n }\n\n #getChannelKey(fabric: Fabric, nodeId: NodeId) {\n return `${fabric.fabricIndex}/${nodeId}`;\n }\n\n #findLeastActiveChannel(channels: MessageChannel<any>[]) {\n let oldest = channels[0];\n for (const channel of channels) {\n if (channel.session.timestamp < oldest.session.timestamp) {\n oldest = channel;\n }\n }\n return oldest;\n }\n\n async setChannel(fabric: Fabric, nodeId: NodeId, channel: MessageChannel<any>) {\n channel.closeCallback = async () => this.removeChannel(fabric, nodeId, channel.session);\n const channelsKey = this.#getChannelKey(fabric, nodeId);\n const currentChannels = this.#channels.get(channelsKey) ?? [];\n if (currentChannels.length
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,yBAA4B;AAG5B,oBAAuB;AAIvB,6BAA+B;AAd/B;AAAA;AAAA;AAAA;AAAA;AAgBA,MAAM,SAAS,qBAAO,IAAI,gBAAgB;AAEnC,MAAM,uBAAuB,+BAAY;AAAC;AAE1C,MAAM,eAAe;AAAA,EACf,YAAY,oBAAI,IAAmC;AAAA,EACnD,gBAAgB,oBAAI,IAAuC;AAAA,EAC3D;AAAA;AAAA,EAGT,YAAY,+BAA+B,GAAG;AAC1C,SAAK,gCAAgC;AAAA,EACzC;AAAA,EAEA,eAAe,QAAgB,QAAgB;AAC3C,WAAO,GAAG,OAAO,WAAW,IAAI,MAAM;AAAA,EAC1C;AAAA,EAEA,wBAAwB,UAAiC;AACrD,QAAI,SAAS,SAAS,CAAC;AACvB,eAAW,WAAW,UAAU;AAC5B,UAAI,QAAQ,QAAQ,YAAY,OAAO,QAAQ,WAAW;AACtD,iBAAS;AAAA,MACb;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAAA,EAEA,MAAM,WAAW,QAAgB,QAAgB,SAA8B;AAC3E,YAAQ,gBAAgB,YAAY,KAAK,cAAc,QAAQ,QAAQ,QAAQ,OAAO;AACtF,UAAM,cAAc,KAAK,eAAe,QAAQ,MAAM;AACtD,UAAM,kBAAkB,KAAK,UAAU,IAAI,WAAW,KAAK,CAAC;AAC5D,
|
|
4
|
+
"sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Channel } from \"../common/Channel.js\";\nimport { MatterError } from \"../common/MatterError.js\";\nimport { NodeId } from \"../datatype/NodeId.js\";\nimport { Fabric } from \"../fabric/Fabric.js\";\nimport { Logger } from \"../log/Logger.js\";\nimport { SecureSession } from \"../session/SecureSession.js\";\nimport { Session } from \"../session/Session.js\";\nimport { ByteArray } from \"../util/ByteArray.js\";\nimport { MessageChannel } from \"./ExchangeManager.js\";\n\nconst logger = Logger.get(\"ChannelManager\");\n\nexport class NoChannelError extends MatterError {}\n\nexport class ChannelManager {\n readonly #channels = new Map<string, MessageChannel<any>[]>();\n readonly #paseChannels = new Map<Session<any>, MessageChannel<any>>();\n readonly #caseSessionsPerFabricAndNode: number;\n\n // TODO evaluate with controller the effects of limiting the entries just for FabricIndex and not also NodeId\n constructor(caseSessionsPerFabricAndNode = 3) {\n this.#caseSessionsPerFabricAndNode = caseSessionsPerFabricAndNode;\n }\n\n #getChannelKey(fabric: Fabric, nodeId: NodeId) {\n return `${fabric.fabricIndex}/${nodeId}`;\n }\n\n #findLeastActiveChannel(channels: MessageChannel<any>[]) {\n let oldest = channels[0];\n for (const channel of channels) {\n if (channel.session.timestamp < oldest.session.timestamp) {\n oldest = channel;\n }\n }\n return oldest;\n }\n\n async setChannel(fabric: Fabric, nodeId: NodeId, channel: MessageChannel<any>) {\n channel.closeCallback = async () => this.removeChannel(fabric, nodeId, channel.session);\n const channelsKey = this.#getChannelKey(fabric, nodeId);\n const currentChannels = this.#channels.get(channelsKey) ?? [];\n currentChannels.push(channel);\n this.#channels.set(channelsKey, currentChannels);\n if (currentChannels.length > this.#caseSessionsPerFabricAndNode) {\n const oldestChannel = this.#findLeastActiveChannel(currentChannels);\n\n const { session: oldSession } = oldestChannel;\n // Should always be the case\n if (channel.session.id !== oldSession.id) {\n await oldSession.destroy(false, false);\n }\n logger.info(\n `Close oldest channel for fabric ${fabric.fabricIndex} node ${nodeId} (from session ${oldSession.id})`,\n );\n await oldestChannel.close();\n }\n }\n\n getChannel(fabric: Fabric, nodeId: NodeId, session?: Session<any>) {\n let results = this.#channels.get(this.#getChannelKey(fabric, nodeId)) ?? [];\n if (session !== undefined) {\n results = results.filter(channel => channel.session.id === session.id);\n }\n if (results.length === 0)\n throw new NoChannelError(\n `Can't find a channel to node ${nodeId}${session !== undefined ? ` and session ${session.id}` : \"\"}`,\n );\n return results[results.length - 1]; // Return the latest added channel (or the one belonging to the session requested)\n }\n\n /**\n * Returns the last established session for a Fabric and Node\n */\n getChannelForSession(session: Session<any>) {\n if (session.isSecure && !session.isPase) {\n const secureSession = session as SecureSession<any>;\n const fabric = secureSession.fabric;\n const nodeId = secureSession.peerNodeId;\n if (fabric === undefined) {\n return this.#paseChannels.get(session);\n }\n return this.getChannel(fabric, nodeId, session);\n }\n return this.#paseChannels.get(session);\n }\n\n async removeAllNodeChannels(fabric: Fabric, nodeId: NodeId) {\n const channelsKey = this.#getChannelKey(fabric, nodeId);\n const channelsToRemove = this.#channels.get(channelsKey) ?? [];\n for (const channel of channelsToRemove) {\n await channel.close();\n }\n }\n\n async removeChannel(fabric: Fabric, nodeId: NodeId, session: Session<any>) {\n const channelsKey = this.#getChannelKey(fabric, nodeId);\n const fabricChannels = this.#channels.get(channelsKey) ?? [];\n const channelEntryIndex = fabricChannels.findIndex(\n ({ session: entrySession }) => entrySession.id === session.id,\n );\n if (channelEntryIndex === -1) {\n // Seems already removed\n return;\n }\n const channelEntry = fabricChannels.splice(channelEntryIndex, 1)[0];\n if (channelEntry === undefined) {\n return;\n }\n await channelEntry.close();\n this.#channels.set(channelsKey, fabricChannels);\n }\n\n private getOrCreateAsPaseChannel(byteArrayChannel: Channel<ByteArray>, session: Session<any>) {\n const msgChannel = new MessageChannel(\n byteArrayChannel,\n session,\n async () => void this.#paseChannels.delete(session),\n );\n this.#paseChannels.set(session, msgChannel);\n return msgChannel;\n }\n\n async getOrCreateChannel(byteArrayChannel: Channel<ByteArray>, session: Session<any>) {\n if (!session.isSecure) {\n return this.getOrCreateAsPaseChannel(byteArrayChannel, session);\n }\n const secureSession = session as SecureSession<any>;\n const fabric = secureSession.fabric;\n const nodeId = secureSession.peerNodeId;\n if (fabric === undefined) {\n return this.getOrCreateAsPaseChannel(byteArrayChannel, session);\n }\n\n // Try to get\n try {\n return this.getChannel(fabric, nodeId, session);\n } catch (e) {\n NoChannelError.accept(e);\n }\n\n // Need to create\n const result = new MessageChannel(byteArrayChannel, session, async () =>\n this.removeChannel(fabric, nodeId, session),\n );\n await this.setChannel(fabric, nodeId, result);\n return result;\n }\n\n async close() {\n for (const channel of this.#paseChannels.values()) {\n await channel.close();\n }\n this.#paseChannels.clear();\n for (const channels of this.#channels.values()) {\n for (const channel of channels) {\n await channel.close();\n }\n }\n this.#channels.clear();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubscriptionHandler.d.ts","sourceRoot":"","sources":["../../../../src/protocol/interaction/SubscriptionHandler.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SubscriptionHandler.d.ts","sourceRoot":"","sources":["../../../../src/protocol/interaction/SubscriptionHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -111,7 +111,11 @@ class SubscriptionHandler {
|
|
|
111
111
|
this.#maxIntervalMs = maxInterval;
|
|
112
112
|
this.#sendIntervalMs = sendInterval;
|
|
113
113
|
this.updateTimer = import_Time.Time.getTimer("Subscription update", this.#sendIntervalMs, () => this.prepareDataUpdate());
|
|
114
|
-
this.sendDelayTimer = import_Time.Time.getTimer(
|
|
114
|
+
this.sendDelayTimer = import_Time.Time.getTimer(
|
|
115
|
+
"Subscription delay",
|
|
116
|
+
50,
|
|
117
|
+
() => this.sendUpdate().catch((error) => logger.warn("Sending subscription update failed:", error))
|
|
118
|
+
);
|
|
115
119
|
}
|
|
116
120
|
determineSendingIntervals(subscriptionMinIntervalMs, subscriptionMaxIntervalMs, subscriptionRandomizationWindowMs) {
|
|
117
121
|
const maxInterval = Math.min(
|
|
@@ -669,13 +673,13 @@ class SubscriptionHandler {
|
|
|
669
673
|
this.isFabricFiltered
|
|
670
674
|
);
|
|
671
675
|
}
|
|
672
|
-
} catch (
|
|
673
|
-
if (import_StatusCode.StatusResponseError.is(
|
|
676
|
+
} catch (error) {
|
|
677
|
+
if (import_StatusCode.StatusResponseError.is(error, import_StatusCode.StatusCode.InvalidSubscription, import_StatusCode.StatusCode.Failure)) {
|
|
674
678
|
logger.info(`Subscription ${this.subscriptionId} cancelled by peer.`);
|
|
675
679
|
await this.cancel(false, true);
|
|
676
680
|
} else {
|
|
681
|
+
import_StatusCode.StatusResponseError.accept(error);
|
|
677
682
|
await this.cancel(false);
|
|
678
|
-
throw e;
|
|
679
683
|
}
|
|
680
684
|
} finally {
|
|
681
685
|
await messenger.close();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/protocol/interaction/SubscriptionHandler.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { MatterDevice } from \"../../MatterDevice.js\";\nimport { AnyAttributeServer, FabricScopedAttributeServer } from \"../../cluster/server/AttributeServer.js\";\nimport { AnyEventServer, FabricSensitiveEventServer } from \"../../cluster/server/EventServer.js\";\nimport { InternalError } from \"../../common/MatterError.js\";\nimport { EventNumber } from \"../../datatype/EventNumber.js\";\nimport { NodeId } from \"../../datatype/NodeId.js\";\nimport { Fabric } from \"../../fabric/Fabric.js\";\nimport { Logger } from \"../../log/Logger.js\";\nimport { NetworkError } from \"../../net/Network.js\";\nimport { SecureSession } from \"../../session/SecureSession.js\";\nimport { Time, Timer } from \"../../time/Time.js\";\nimport { TlvSchema, TypeFromSchema } from \"../../tlv/TlvSchema.js\";\nimport { MaybePromise } from \"../../util/Promises.js\";\nimport { isObject } from \"../../util/Type.js\";\nimport { RetransmissionLimitReachedError } from \"../MessageExchange.js\";\nimport { AttributeReportPayload, EventReportPayload } from \"./AttributeDataEncoder.js\";\nimport { EventStorageData } from \"./EventHandler.js\";\nimport { InteractionEndpointStructure } from \"./InteractionEndpointStructure.js\";\nimport { InteractionServerMessenger } from \"./InteractionMessenger.js\";\nimport {\n TlvAttributePath,\n TlvAttributeStatus,\n TlvDataVersionFilter,\n TlvEventFilter,\n TlvEventPath,\n TlvEventStatus,\n} from \"./InteractionProtocol.js\";\nimport {\n AttributePath,\n AttributeWithPath,\n EventPath,\n EventWithPath,\n INTERACTION_MODEL_REVISION,\n INTERACTION_PROTOCOL_ID,\n attributePathToId,\n clusterPathToId,\n eventPathToId,\n} from \"./InteractionServer.js\";\nimport { StatusCode, StatusResponseError } from \"./StatusCode.js\";\nimport { MAX_INTERVAL_PUBLISHER_LIMIT_S, SubscriptionOptions } from \"./SubscriptionOptions.js\";\n\nconst logger = Logger.get(\"SubscriptionHandler\");\n\ninterface AttributePathWithValueVersion<T> {\n path: TypeFromSchema<typeof TlvAttributePath>;\n attribute: AnyAttributeServer<T>;\n schema: TlvSchema<T>;\n value: T;\n version: number;\n}\n\ninterface EventPathWithEventData<T> {\n path: TypeFromSchema<typeof TlvEventPath>;\n event: AnyEventServer<any, any>;\n schema: TlvSchema<T>;\n data: EventStorageData<T>;\n}\n\nexport class SubscriptionHandler {\n readonly subscriptionId: number;\n private readonly session: SecureSession<any>;\n private readonly endpointStructure: InteractionEndpointStructure;\n private readonly attributeRequests?: TypeFromSchema<typeof TlvAttributePath>[];\n private readonly dataVersionFilters?: TypeFromSchema<typeof TlvDataVersionFilter>[];\n private readonly eventRequests?: TypeFromSchema<typeof TlvEventPath>[];\n private readonly eventFilters?: TypeFromSchema<typeof TlvEventFilter>[];\n private readonly isFabricFiltered: boolean;\n private readonly cancelCallback: () => void;\n private readonly readAttribute: (path: AttributePath, attribute: AnyAttributeServer<any>) => Promise<any>;\n private readonly readEvent: (\n path: EventPath,\n event: AnyEventServer<any, any>,\n eventFilters: TypeFromSchema<typeof TlvEventFilter>[] | undefined,\n ) => Promise<EventStorageData<any>[]>;\n\n private lastUpdateTimeMs = 0;\n private updateTimer: Timer;\n private readonly sendDelayTimer: Timer;\n private readonly outstandingAttributeUpdates = new Map<string, AttributePathWithValueVersion<any>>();\n private readonly outstandingEventUpdates = new Set<EventPathWithEventData<any>>();\n private readonly attributeListeners = new Map<\n string,\n {\n attribute: AnyAttributeServer<any>;\n listener?: (value: any, version: number) => void;\n }\n >();\n private readonly eventListeners = new Map<\n string,\n {\n event: AnyEventServer<any, any>;\n listener?: (newEvent: EventStorageData<any>) => void;\n }\n >();\n private sendUpdatesActivated = false;\n readonly #maxIntervalMs: number;\n readonly #sendIntervalMs: number;\n private readonly minIntervalFloorMs: number;\n private readonly maxIntervalCeilingMs: number;\n private readonly server: MatterDevice;\n private readonly fabric: Fabric;\n private readonly peerNodeId: NodeId;\n\n private sendingUpdateInProgress = false;\n private sendNextUpdateImmediately = false;\n private sendUpdateErrorCounter = 0;\n private attributeUpdatePromises = new Set<PromiseLike<void>>();\n\n constructor(options: {\n subscriptionId: number;\n session: SecureSession<any>;\n endpointStructure: InteractionEndpointStructure;\n attributeRequests?: TypeFromSchema<typeof TlvAttributePath>[];\n dataVersionFilters?: TypeFromSchema<typeof TlvDataVersionFilter>[];\n eventRequests?: TypeFromSchema<typeof TlvEventPath>[];\n eventFilters?: TypeFromSchema<typeof TlvEventFilter>[];\n isFabricFiltered: boolean;\n minIntervalFloor: number;\n maxIntervalCeiling: number;\n cancelCallback: () => void;\n subscriptionOptions: SubscriptionOptions.Configuration;\n readAttribute: (path: AttributePath, attribute: AnyAttributeServer<any>) => Promise<any>;\n readEvent: (\n path: EventPath,\n event: AnyEventServer<any, any>,\n eventFilters: TypeFromSchema<typeof TlvEventFilter>[] | undefined,\n ) => Promise<EventStorageData<any>[]>;\n }) {\n const {\n subscriptionId,\n session,\n endpointStructure,\n attributeRequests,\n dataVersionFilters,\n eventRequests,\n eventFilters,\n isFabricFiltered,\n minIntervalFloor,\n maxIntervalCeiling,\n cancelCallback,\n subscriptionOptions,\n } = options;\n this.subscriptionId = subscriptionId;\n this.session = session;\n this.endpointStructure = endpointStructure;\n this.attributeRequests = attributeRequests;\n this.dataVersionFilters = dataVersionFilters;\n this.eventRequests = eventRequests;\n this.eventFilters = eventFilters;\n this.isFabricFiltered = isFabricFiltered;\n this.cancelCallback = cancelCallback;\n this.readAttribute = options.readAttribute;\n this.readEvent = options.readEvent;\n\n this.server = this.session.context;\n this.fabric = this.session.associatedFabric;\n this.peerNodeId = this.session.peerNodeId;\n this.minIntervalFloorMs = minIntervalFloor * 1000;\n this.maxIntervalCeilingMs = maxIntervalCeiling * 1000;\n\n const { maxInterval, sendInterval } = this.determineSendingIntervals(\n subscriptionOptions.minIntervalSeconds * 1000,\n subscriptionOptions.maxIntervalSeconds * 1000,\n subscriptionOptions.randomizationWindowSeconds * 1000,\n );\n this.#maxIntervalMs = maxInterval;\n this.#sendIntervalMs = sendInterval;\n\n this.updateTimer = Time.getTimer(\"Subscription update\", this.#sendIntervalMs, () => this.prepareDataUpdate()); // will be started later\n this.sendDelayTimer = Time.getTimer(\"Subscription delay\", 50, () => this.sendUpdate()); // will be started later\n }\n\n private determineSendingIntervals(\n subscriptionMinIntervalMs: number,\n subscriptionMaxIntervalMs: number,\n subscriptionRandomizationWindowMs: number,\n ): { maxInterval: number; sendInterval: number } {\n // Max Interval is the Max interval that the controller request, unless the configured one from the developer\n // is lower. In that case we use the configured one. But we make sure to not be smaller than the requested\n // controller minimum. But in general never faster than minimum interval configured or 2 seconds\n // (SUBSCRIPTION_MIN_INTERVAL_S). Additionally, we add a randomization window to the max interval to avoid all\n // devices sending at the same time. But we make sure not to exceed the global max interval.\n const maxInterval = Math.min(\n Math.max(\n subscriptionMinIntervalMs,\n Math.max(this.minIntervalFloorMs, Math.min(subscriptionMaxIntervalMs, this.maxIntervalCeilingMs)),\n ) + Math.floor(subscriptionRandomizationWindowMs * Math.random()),\n MAX_INTERVAL_PUBLISHER_LIMIT_S * 1000,\n );\n let sendInterval = Math.floor(maxInterval / 2); // Ideally we send at half the max interval\n if (sendInterval < 60_000) {\n // But if we have no chance of at least one full resubmission process we do like chip-tool.\n // One full resubmission process takes 33-45 seconds. So 60s means we reach at least first 2 retries of a\n // second subscription report after first failed.\n sendInterval = Math.max(this.minIntervalFloorMs, Math.floor(maxInterval * 0.8));\n }\n if (sendInterval < subscriptionMinIntervalMs) {\n // But not faster than once every 2s\n logger.warn(\n `Determined subscription send interval of ${sendInterval}ms is too low. Using maxInterval (${maxInterval}ms) instead.`,\n );\n sendInterval = subscriptionMinIntervalMs;\n }\n return { maxInterval, sendInterval };\n }\n\n private registerNewAttributes() {\n const newAttributes = new Array<AttributeWithPath>();\n const attributeErrors = new Array<TypeFromSchema<typeof TlvAttributeStatus>>();\n const formerAttributes = new Set<string>(this.attributeListeners.keys());\n\n if (this.attributeRequests !== undefined) {\n this.attributeRequests.forEach(path => {\n const attributes = this.endpointStructure.getAttributes([path]);\n\n if (attributes.length === 0) {\n // TODO: Also check nodeId\n const { endpointId, clusterId, attributeId } = path;\n if (endpointId === undefined || clusterId === undefined || attributeId === undefined) {\n // Wildcard path: Just leave out values\n logger.debug(\n `Subscription attribute ${this.endpointStructure.resolveAttributeName(\n path,\n )}: ignore non-existing attribute`,\n );\n } else {\n // was a concrete path\n try {\n this.endpointStructure.validateConcreteAttributePath(endpointId, clusterId, attributeId);\n throw new InternalError(\n \"validateConcreteAttributePath check should throw StatusResponseError but did not.\",\n );\n } catch (e) {\n StatusResponseError.accept(e);\n\n logger.debug(\n `Subscription attribute ${this.endpointStructure.resolveAttributeName(\n path,\n )}: unsupported path: Status=${e.code}`,\n );\n\n attributeErrors.push({ path, status: { status: e.code } });\n }\n }\n return;\n }\n\n attributes.forEach(({ path, attribute }) => {\n formerAttributes.delete(attributePathToId(path));\n\n const existingAttributeListener = this.attributeListeners.get(attributePathToId(path));\n if (existingAttributeListener !== undefined) {\n const { attribute: existingAttribute, listener: existingListener } = existingAttributeListener;\n if (existingAttribute !== attribute) {\n if (existingListener !== undefined) {\n existingAttribute.removeValueChangeListener(existingListener);\n }\n this.attributeListeners.delete(attributePathToId(path));\n } else {\n return; // Attribute is already registered and unchanged\n }\n }\n if (attribute.isSubscribable) {\n // If subscribable register listener\n // TODO: Move to state change listeners from behaviors to remove the dangling promise here\n const listener = (value: any, version: number) =>\n this.attributeChangeListener(path, attribute.schema, version, value);\n attribute.addValueChangeListener(listener);\n this.attributeListeners.set(attributePathToId(path), { attribute, listener });\n } else {\n this.attributeListeners.set(attributePathToId(path), { attribute });\n }\n newAttributes.push({ path, attribute });\n });\n });\n }\n\n // Remove all listeners to attributes that no longer match the subscription\n this.unregisterAttributeListeners(Array.from(formerAttributes.values()));\n return { newAttributes, attributeErrors };\n }\n\n unregisterAttributeListeners(list: Array<string>) {\n for (const pathId of list) {\n const existingAttributeListener = this.attributeListeners.get(pathId);\n if (existingAttributeListener !== undefined) {\n const { attribute, listener } = existingAttributeListener;\n if (listener !== undefined) {\n attribute.removeValueChangeListener(listener);\n }\n this.attributeListeners.delete(pathId);\n }\n }\n }\n\n private registerNewEvents() {\n const newEvents = new Array<EventWithPath>();\n const eventErrors = new Array<TypeFromSchema<typeof TlvEventStatus>>();\n const formerEvents = new Set<string>(this.eventListeners.keys());\n\n if (this.eventRequests !== undefined) {\n this.eventRequests.forEach(path => {\n const events = this.endpointStructure.getEvents([path]);\n if (events.length === 0) {\n const { endpointId, clusterId, eventId } = path;\n if (endpointId === undefined || clusterId === undefined || eventId === undefined) {\n // Wildcard path: Just leave out values\n logger.debug(\n `Subscription event ${this.endpointStructure.resolveEventName(\n path,\n )}: ignore non-existing event`,\n );\n } else {\n try {\n this.endpointStructure.validateConcreteEventPath(endpointId, clusterId, eventId);\n throw new InternalError(\n \"validateConcreteEventPath should throw StatusResponseError but did not.\",\n );\n } catch (e) {\n StatusResponseError.accept(e);\n\n logger.debug(\n `Subscription event ${this.endpointStructure.resolveEventName(\n path,\n )}: unsupported path: Status=${e.code}`,\n );\n\n eventErrors.push({ path, status: { status: e.code } });\n }\n }\n return;\n }\n\n events.forEach(({ path, event }) => {\n formerEvents.delete(eventPathToId(path));\n\n const existingEventListener = this.eventListeners.get(eventPathToId(path));\n if (existingEventListener !== undefined) {\n const { event: existingEvent, listener: existingListener } = existingEventListener;\n if (existingEvent !== event) {\n if (existingListener !== undefined) {\n existingEvent.removeListener(existingListener);\n }\n this.eventListeners.delete(eventPathToId(path));\n } else {\n return; // Event is already registered and unchanged\n }\n }\n const listener = (newEvent: EventStorageData<any>) =>\n this.eventChangeListener(path, event.schema, newEvent);\n event.addListener(listener);\n newEvents.push({ path, event });\n this.eventListeners.set(eventPathToId(path), { event, listener });\n });\n });\n }\n\n // Remove all listeners to events that no longer match the subscription\n this.unregisterEventListeners(Array.from(formerEvents.values()));\n\n return { newEvents, eventErrors };\n }\n\n unregisterEventListeners(list: Array<string>) {\n for (const pathId of list) {\n const existingEventListener = this.eventListeners.get(pathId);\n if (existingEventListener !== undefined) {\n const { event, listener } = existingEventListener;\n if (listener !== undefined) {\n event.removeListener(listener);\n }\n this.eventListeners.delete(pathId);\n }\n }\n }\n\n /**\n * Update the session after an endpoint structure change. The method will initialize all missing new attributes and\n * events and will remove listeners no longer needed.\n * Newly added attributes are then treated ad \"changed values\" and will be sent as subscription data update to the\n * controller. The data of newly added events are not sent automatically.\n */\n async updateSubscription() {\n const { newAttributes } = this.registerNewAttributes();\n\n for (const { path, attribute } of newAttributes) {\n const { version, value } = await this.readAttribute(path, attribute);\n\n // We do not do any version filtering for attributes that are newly added to make sure controller gets\n // most current state\n\n this.outstandingAttributeUpdates.set(attributePathToId(path), {\n attribute,\n path,\n schema: attribute.schema,\n version,\n value,\n });\n }\n\n const { newEvents } = this.registerNewEvents();\n newEvents\n .flatMap(({ path, event }): EventPathWithEventData<any>[] => {\n // But we use eventFilters because we do not want to send all events to the controller\n const { schema } = event;\n const matchingEvents = event.get(this.session, this.isFabricFiltered, undefined, this.eventFilters);\n return matchingEvents.map(data => ({\n event,\n schema,\n path,\n data,\n }));\n })\n .sort((a, b) => {\n const eventNumberA = a.data?.eventNumber ?? EventNumber(0);\n const eventNumberB = b.data?.eventNumber ?? EventNumber(0);\n if (eventNumberA > eventNumberB) {\n return 1;\n } else if (eventNumberA < eventNumberB) {\n return -1;\n } else {\n return 0;\n }\n })\n .forEach(event => this.outstandingEventUpdates.add(event));\n\n this.prepareDataUpdate();\n }\n\n get maxInterval(): number {\n return Math.ceil(this.#maxIntervalMs / 1000);\n }\n\n get sendInterval(): number {\n return Math.ceil(this.#sendIntervalMs / 1000);\n }\n\n activateSendingUpdates() {\n // We do not need these data anymore, so we can free some memory\n if (this.eventFilters !== undefined) this.eventFilters.length = 0;\n if (this.dataVersionFilters !== undefined) this.dataVersionFilters.length = 0;\n\n this.sendUpdatesActivated = true;\n if (this.outstandingAttributeUpdates.size > 0 || this.outstandingEventUpdates.size > 0) {\n void this.sendUpdate();\n }\n this.updateTimer = Time.getTimer(\"Subscription update\", this.#sendIntervalMs, () =>\n this.prepareDataUpdate(),\n ).start();\n }\n\n /**\n * Check if data should be sent straight away or delayed because the minimum interval is not reached. Delay real\n * sending by 50ms in any case to mke sure to catch all updates.\n */\n prepareDataUpdate() {\n if (this.sendDelayTimer.isRunning) {\n // sending data is already scheduled, data updates go in there\n return;\n }\n\n if (!this.sendUpdatesActivated) {\n return;\n }\n\n this.updateTimer.stop();\n const now = Time.nowMs();\n const timeSinceLastUpdateMs = now - this.lastUpdateTimeMs;\n if (timeSinceLastUpdateMs < this.minIntervalFloorMs) {\n // Respect minimum delay time between updates\n this.updateTimer = Time.getTimer(\n \"Subscription update\",\n this.minIntervalFloorMs - timeSinceLastUpdateMs,\n () => this.prepareDataUpdate(),\n ).start();\n return;\n }\n\n this.sendDelayTimer.start();\n this.updateTimer = Time.getTimer(\"Subscription update\", this.#sendIntervalMs, () =>\n this.prepareDataUpdate(),\n ).start();\n }\n\n /**\n * Determine all attributes that have changed since the last update and send them tout to the subscriber.\n */\n async sendUpdate() {\n if (this.sendingUpdateInProgress) {\n logger.debug(\"Sending update already in progress, delaying update ...\");\n this.sendNextUpdateImmediately = true;\n return;\n }\n\n // Get all outstanding updates, make sure the order is correct per endpoint and cluster\n const attributeUpdatesToSend = new Array<AttributePathWithValueVersion<any>>();\n const attributeUpdates: Record<string, AttributePathWithValueVersion<any>[]> = {};\n Array.from(this.outstandingAttributeUpdates.values()).forEach(entry => {\n const {\n path: { nodeId, endpointId, clusterId },\n } = entry;\n const pathId = `${nodeId}-${endpointId}-${clusterId}`;\n attributeUpdates[pathId] = attributeUpdates[pathId] ?? [];\n attributeUpdates[pathId].push(entry);\n });\n this.outstandingAttributeUpdates.clear();\n Object.values(attributeUpdates).forEach(data =>\n attributeUpdatesToSend.push(\n ...data.sort(({ version: versionA }, { version: versionB }) => versionA - versionB),\n ),\n );\n\n const eventUpdatesToSend = Array.from(this.outstandingEventUpdates.values());\n this.outstandingEventUpdates.clear();\n this.lastUpdateTimeMs = Time.nowMs();\n\n this.sendingUpdateInProgress = true;\n try {\n await this.sendUpdateMessage(attributeUpdatesToSend, eventUpdatesToSend);\n this.sendUpdateErrorCounter = 0;\n } catch (error) {\n if (this.server.isClosing) {\n // No need to care about resubmissions when the server is closing\n return;\n }\n\n this.sendUpdateErrorCounter++;\n logger.error(\n `Error sending subscription update message (error count=${this.sendUpdateErrorCounter}):`,\n error,\n );\n if (this.sendUpdateErrorCounter <= 2) {\n // fill the data back in the queue to resend with next try\n const newAttributeUpdatesToSend = Array.from(this.outstandingAttributeUpdates.values());\n this.outstandingAttributeUpdates.clear();\n const newEventUpdatesToSend = Array.from(this.outstandingEventUpdates.values());\n this.outstandingEventUpdates.clear();\n [...attributeUpdatesToSend, ...newAttributeUpdatesToSend].forEach(update =>\n this.outstandingAttributeUpdates.set(attributePathToId(update.path), update),\n );\n [...eventUpdatesToSend, ...newEventUpdatesToSend].forEach(update =>\n this.outstandingEventUpdates.add(update),\n );\n } else {\n logger.error(\n `Sending update failed 3 times in a row, canceling subscription ${this.subscriptionId} and let controller subscribe again.`,\n );\n this.sendNextUpdateImmediately = false;\n if (error instanceof RetransmissionLimitReachedError || error instanceof NetworkError) {\n // We could not send at all, consider session as dead\n await this.session.destroy(false);\n } else {\n throw error;\n }\n }\n }\n this.sendingUpdateInProgress = false;\n\n if (this.sendNextUpdateImmediately) {\n logger.debug(\"Sending delayed update immediately after last one was sent.\");\n this.sendNextUpdateImmediately = false;\n await this.sendUpdate();\n }\n }\n\n async sendInitialReport(messenger: InteractionServerMessenger) {\n this.updateTimer.stop();\n\n const { newAttributes, attributeErrors } = this.registerNewAttributes();\n\n const dataVersionFilterMap = new Map<string, number>(\n this.dataVersionFilters?.map(({ path, dataVersion }) => [clusterPathToId(path), dataVersion]) ?? [],\n );\n\n let attributesFilteredWithVersion = false;\n const attributes = new Array<{\n path: TypeFromSchema<typeof TlvAttributePath>;\n value: any;\n version: number;\n schema: TlvSchema<any>;\n attribute: AnyAttributeServer<any>;\n }>();\n for (const { path, attribute } of newAttributes) {\n try {\n const { value, version } = await this.readAttribute(path, attribute);\n if (value === undefined) continue;\n\n const { nodeId, endpointId, clusterId } = path;\n\n const versionFilterValue =\n endpointId !== undefined && clusterId !== undefined\n ? dataVersionFilterMap.get(clusterPathToId({ nodeId, endpointId, clusterId }))\n : undefined;\n if (versionFilterValue !== undefined && versionFilterValue === version) {\n attributesFilteredWithVersion = true;\n continue;\n }\n\n attributes.push({ path, value, version, schema: attribute.schema, attribute });\n } catch (error) {\n logger.error(`Error reading attribute ${this.endpointStructure.resolveAttributeName(path)}:`, error);\n }\n }\n const attributeReportsPayload: AttributeReportPayload[] = attributes.map(\n ({ path, schema, value, version, attribute }) => ({\n hasFabricSensitiveData: attribute.hasFabricSensitiveData,\n attributeData: {\n path,\n dataVersion: version,\n payload: value,\n schema,\n },\n }),\n );\n attributeErrors.forEach(attributeStatus =>\n attributeReportsPayload.push({\n hasFabricSensitiveData: false,\n attributeStatus,\n }),\n );\n\n const { newEvents, eventErrors } = this.registerNewEvents();\n\n let eventsFiltered = false;\n const eventReportsPayload = new Array<EventReportPayload>();\n for (const { path, event } of newEvents) {\n const { schema } = event;\n try {\n const matchingEvents = await this.readEvent(path, event, this.eventFilters);\n if (matchingEvents.length === 0) {\n eventsFiltered = true;\n } else {\n matchingEvents.forEach(({ eventNumber, priority, epochTimestamp, data }) => {\n eventReportsPayload.push({\n hasFabricSensitiveData: event.hasFabricSensitiveData,\n eventData: {\n path,\n eventNumber,\n priority,\n epochTimestamp,\n payload: data,\n schema,\n },\n });\n });\n }\n } catch (error) {\n logger.error(`Error reading event ${this.endpointStructure.resolveEventName(path)}:`, error);\n }\n }\n eventReportsPayload.sort((a, b) => {\n const eventNumberA = a.eventData?.eventNumber ?? 0;\n const eventNumberB = b.eventData?.eventNumber ?? 0;\n if (eventNumberA > eventNumberB) {\n return 1;\n } else if (eventNumberA < eventNumberB) {\n return -1;\n } else {\n return 0;\n }\n });\n\n if (\n attributes.length === 0 &&\n !attributesFilteredWithVersion &&\n eventReportsPayload.length === 0 &&\n !eventsFiltered\n ) {\n throw new StatusResponseError(\n \"Subscription failed because no attributes or events are matching the query\",\n StatusCode.InvalidAction,\n );\n }\n\n eventErrors.forEach(eventStatus =>\n eventReportsPayload.push({\n hasFabricSensitiveData: false,\n eventStatus,\n }),\n );\n\n logger.debug(\n `Initialize Subscription with ${attributes.length} attributes and ${eventReportsPayload.length} events.`,\n );\n this.lastUpdateTimeMs = Time.nowMs();\n\n await messenger.sendDataReport(\n {\n suppressResponse: false, // we always need proper response for initial report\n subscriptionId: this.subscriptionId,\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n attributeReportsPayload,\n eventReportsPayload,\n },\n this.isFabricFiltered,\n );\n }\n\n attributeChangeListener<T>(path: AttributePath, schema: TlvSchema<T>, version: number, value: T) {\n const changeResult = this.attributeChangeHandler(path, schema, version, value);\n if (MaybePromise.is(changeResult)) {\n const resolver = Promise.resolve(changeResult)\n .catch(error => logger.error(`Error handling attribute change:`, error))\n .finally(() => this.attributeUpdatePromises.delete(resolver));\n this.attributeUpdatePromises.add(resolver);\n }\n }\n\n attributeChangeHandler<T>(\n path: AttributePath,\n schema: TlvSchema<T>,\n version: number,\n value: T,\n ): MaybePromise<void> {\n const attributeListenerData = this.attributeListeners.get(attributePathToId(path));\n if (attributeListenerData === undefined) return; // Ignore changes to attributes that are not subscribed to\n\n const { attribute } = attributeListenerData;\n if (attribute instanceof FabricScopedAttributeServer) {\n // We cannot be sure what value we got for fabric filtered attributes (and from which fabric),\n // so get it again for this relevant fabric. This also makes sure that fabric sensitive fields are filtered\n // TODO: Maybe add try/catch when we add ACL handling and ignore the update if we cannot get the value?\n return this.readAttribute(path, attribute).then(({ value }) => {\n this.outstandingAttributeUpdates.set(attributePathToId(path), {\n attribute,\n path,\n schema,\n version,\n value,\n });\n this.prepareDataUpdate();\n });\n }\n this.outstandingAttributeUpdates.set(attributePathToId(path), { attribute, path, schema, version, value });\n this.prepareDataUpdate();\n }\n\n eventChangeListener<T>(path: EventPath, schema: TlvSchema<T>, newEvent: EventStorageData<T>) {\n const eventListenerData = this.eventListeners.get(eventPathToId(path));\n if (eventListenerData === undefined) return; // Ignore changes to attributes that are not subscribed to\n\n const { event } = eventListenerData;\n if (event instanceof FabricSensitiveEventServer) {\n const { data } = newEvent;\n if (isObject(data) && \"fabricIndex\" in data && data.fabricIndex !== this.session.fabric?.fabricIndex) {\n // Ignore events from different fabrics because events are kind of always fabric filtered\n return;\n }\n }\n this.outstandingEventUpdates.add({ event, path, schema, data: newEvent });\n if (path.isUrgent) {\n this.prepareDataUpdate();\n }\n }\n\n async flush() {\n this.sendDelayTimer.stop();\n logger.debug(\n `Flushing subscription ${this.subscriptionId} with ${this.outstandingAttributeUpdates.size} attributes and ${this.outstandingEventUpdates.size} events`,\n );\n if (this.outstandingAttributeUpdates.size > 0 || this.outstandingEventUpdates.size > 0) {\n void this.sendUpdate();\n }\n }\n\n async cancel(flush = false, cancelledByPeer = false) {\n this.sendUpdatesActivated = false;\n if (this.attributeUpdatePromises.size) {\n const resolvers = [...this.attributeUpdatePromises.values()];\n this.attributeUpdatePromises.clear();\n await Promise.all(resolvers);\n }\n this.updateTimer.stop();\n this.sendDelayTimer.stop();\n this.unregisterAttributeListeners(Array.from(this.attributeListeners.keys()));\n this.unregisterEventListeners(Array.from(this.eventListeners.keys()));\n if (flush) {\n await this.flush();\n }\n this.session.removeSubscription(this.subscriptionId);\n this.cancelCallback();\n if (cancelledByPeer) {\n await this.session.context.startAnnouncement();\n }\n }\n\n private async sendUpdateMessage(\n attributes: AttributePathWithValueVersion<any>[],\n events: EventPathWithEventData<any>[],\n ) {\n logger.debug(\n `Sending subscription update message for ID ${this.subscriptionId} with ${attributes.length} attributes and ${events.length} events`,\n );\n const exchange = this.server.initiateExchange(this.fabric, this.peerNodeId, INTERACTION_PROTOCOL_ID);\n if (exchange === undefined) return;\n logger.debug(\n `Sending subscription changes for ID ${this.subscriptionId}: ${attributes\n .map(\n ({ path, value, version }) =>\n `${this.endpointStructure.resolveAttributeName(path)}=${Logger.toJSON(value)} (${version})`,\n )\n .join(\", \")}`,\n ); // TODO Format path better using endpoint structure\n const messenger = new InteractionServerMessenger(exchange);\n\n try {\n if (attributes.length === 0 && events.length === 0) {\n await messenger.sendDataReport(\n {\n suppressResponse: true, // suppressResponse true for empty DataReports\n subscriptionId: this.subscriptionId,\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n },\n this.isFabricFiltered,\n );\n } else {\n await messenger.sendDataReport(\n {\n suppressResponse: false, // Non empty data reports always need to send response\n subscriptionId: this.subscriptionId,\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n attributeReportsPayload: attributes.map(({ path, schema, value, version, attribute }) => ({\n hasFabricSensitiveData: attribute.hasFabricSensitiveData,\n attributeData: {\n path,\n dataVersion: version,\n schema,\n payload: value,\n },\n })),\n eventReportsPayload: events.map(({ path, schema, event, data }) => {\n const { eventNumber, priority, epochTimestamp, data: payload } = data;\n return {\n hasFabricSensitiveData: event.hasFabricSensitiveData,\n eventData: {\n path,\n eventNumber,\n priority,\n epochTimestamp,\n schema,\n payload,\n },\n };\n }),\n },\n this.isFabricFiltered,\n );\n }\n } catch (e) {\n if (StatusResponseError.is(e, StatusCode.InvalidSubscription, StatusCode.Failure)) {\n logger.info(`Subscription ${this.subscriptionId} cancelled by peer.`);\n await this.cancel(false, true);\n } else {\n await this.cancel(false);\n throw e;\n }\n } finally {\n await messenger.close();\n }\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,6BAAgE;AAChE,yBAA2D;AAC3D,yBAA8B;AAC9B,yBAA4B;AAG5B,oBAAuB;AACvB,qBAA6B;AAE7B,kBAA4B;AAE5B,sBAA6B;AAC7B,kBAAyB;AACzB,6BAAgD;AAIhD,kCAA2C;AAS3C,+BAUO;AACP,wBAAgD;AAChD,iCAAoE;AA7CpE;AAAA;AAAA;AAAA;AAAA;AA+CA,MAAM,SAAS,qBAAO,IAAI,qBAAqB;AAiBxC,MAAM,oBAAoB;AAAA,EACpB;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAMT,mBAAmB;AAAA,EACnB;AAAA,EACS;AAAA,EACA,8BAA8B,oBAAI,IAAgD;AAAA,EAClF,0BAA0B,oBAAI,IAAiC;AAAA,EAC/D,qBAAqB,oBAAI,IAMxC;AAAA,EACe,iBAAiB,oBAAI,IAMpC;AAAA,EACM,uBAAuB;AAAA,EACtB;AAAA,EACA;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,0BAA0B;AAAA,EAC1B,4BAA4B;AAAA,EAC5B,yBAAyB;AAAA,EACzB,0BAA0B,oBAAI,IAAuB;AAAA,EAE7D,YAAY,SAmBT;AACC,UAAM;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ,IAAI;AACJ,SAAK,iBAAiB;AACtB,SAAK,UAAU;AACf,SAAK,oBAAoB;AACzB,SAAK,oBAAoB;AACzB,SAAK,qBAAqB;AAC1B,SAAK,gBAAgB;AACrB,SAAK,eAAe;AACpB,SAAK,mBAAmB;AACxB,SAAK,iBAAiB;AACtB,SAAK,gBAAgB,QAAQ;AAC7B,SAAK,YAAY,QAAQ;AAEzB,SAAK,SAAS,KAAK,QAAQ;AAC3B,SAAK,SAAS,KAAK,QAAQ;AAC3B,SAAK,aAAa,KAAK,QAAQ;AAC/B,SAAK,qBAAqB,mBAAmB;AAC7C,SAAK,uBAAuB,qBAAqB;AAEjD,UAAM,EAAE,aAAa,aAAa,IAAI,KAAK;AAAA,MACvC,oBAAoB,qBAAqB;AAAA,MACzC,oBAAoB,qBAAqB;AAAA,MACzC,oBAAoB,6BAA6B;AAAA,IACrD;AACA,SAAK,iBAAiB;AACtB,SAAK,kBAAkB;AAEvB,SAAK,cAAc,iBAAK,SAAS,uBAAuB,KAAK,iBAAiB,MAAM,KAAK,kBAAkB,CAAC;AAC5G,SAAK,iBAAiB,iBAAK,SAAS,sBAAsB,IAAI,MAAM,KAAK,WAAW,CAAC;AAAA,EACzF;AAAA,EAEQ,0BACJ,2BACA,2BACA,mCAC6C;AAM7C,UAAM,cAAc,KAAK;AAAA,MACrB,KAAK;AAAA,QACD;AAAA,QACA,KAAK,IAAI,KAAK,oBAAoB,KAAK,IAAI,2BAA2B,KAAK,oBAAoB,CAAC;AAAA,MACpG,IAAI,KAAK,MAAM,oCAAoC,KAAK,OAAO,CAAC;AAAA,MAChE,4DAAiC;AAAA,IACrC;AACA,QAAI,eAAe,KAAK,MAAM,cAAc,CAAC;AAC7C,QAAI,eAAe,KAAQ;AAIvB,qBAAe,KAAK,IAAI,KAAK,oBAAoB,KAAK,MAAM,cAAc,GAAG,CAAC;AAAA,IAClF;AACA,QAAI,eAAe,2BAA2B;AAE1C,aAAO;AAAA,QACH,4CAA4C,YAAY,qCAAqC,WAAW;AAAA,MAC5G;AACA,qBAAe;AAAA,IACnB;AACA,WAAO,EAAE,aAAa,aAAa;AAAA,EACvC;AAAA,EAEQ,wBAAwB;AAC5B,UAAM,gBAAgB,IAAI,MAAyB;AACnD,UAAM,kBAAkB,IAAI,MAAiD;AAC7E,UAAM,mBAAmB,IAAI,IAAY,KAAK,mBAAmB,KAAK,CAAC;AAEvE,QAAI,KAAK,sBAAsB,QAAW;AACtC,WAAK,kBAAkB,QAAQ,UAAQ;AACnC,cAAM,aAAa,KAAK,kBAAkB,cAAc,CAAC,IAAI,CAAC;AAE9D,YAAI,WAAW,WAAW,GAAG;AAEzB,gBAAM,EAAE,YAAY,WAAW,YAAY,IAAI;AAC/C,cAAI,eAAe,UAAa,cAAc,UAAa,gBAAgB,QAAW;AAElF,mBAAO;AAAA,cACH,0BAA0B,KAAK,kBAAkB;AAAA,gBAC7C;AAAA,cACJ,CAAC;AAAA,YACL;AAAA,UACJ,OAAO;AAEH,gBAAI;AACA,mBAAK,kBAAkB,8BAA8B,YAAY,WAAW,WAAW;AACvF,oBAAM,IAAI;AAAA,gBACN;AAAA,cACJ;AAAA,YACJ,SAAS,GAAG;AACR,oDAAoB,OAAO,CAAC;AAE5B,qBAAO;AAAA,gBACH,0BAA0B,KAAK,kBAAkB;AAAA,kBAC7C;AAAA,gBACJ,CAAC,8BAA8B,EAAE,IAAI;AAAA,cACzC;AAEA,8BAAgB,KAAK,EAAE,MAAM,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAAA,YAC7D;AAAA,UACJ;AACA;AAAA,QACJ;AAEA,mBAAW,QAAQ,CAAC,EAAE,MAAAA,OAAM,UAAU,MAAM;AACxC,2BAAiB,WAAO,4CAAkBA,KAAI,CAAC;AAE/C,gBAAM,4BAA4B,KAAK,mBAAmB,QAAI,4CAAkBA,KAAI,CAAC;AACrF,cAAI,8BAA8B,QAAW;AACzC,kBAAM,EAAE,WAAW,mBAAmB,UAAU,iBAAiB,IAAI;AACrE,gBAAI,sBAAsB,WAAW;AACjC,kBAAI,qBAAqB,QAAW;AAChC,kCAAkB,0BAA0B,gBAAgB;AAAA,cAChE;AACA,mBAAK,mBAAmB,WAAO,4CAAkBA,KAAI,CAAC;AAAA,YAC1D,OAAO;AACH;AAAA,YACJ;AAAA,UACJ;AACA,cAAI,UAAU,gBAAgB;AAG1B,kBAAM,WAAW,CAAC,OAAY,YAC1B,KAAK,wBAAwBA,OAAM,UAAU,QAAQ,SAAS,KAAK;AACvE,sBAAU,uBAAuB,QAAQ;AACzC,iBAAK,mBAAmB,QAAI,4CAAkBA,KAAI,GAAG,EAAE,WAAW,SAAS,CAAC;AAAA,UAChF,OAAO;AACH,iBAAK,mBAAmB,QAAI,4CAAkBA,KAAI,GAAG,EAAE,UAAU,CAAC;AAAA,UACtE;AACA,wBAAc,KAAK,EAAE,MAAAA,OAAM,UAAU,CAAC;AAAA,QAC1C,CAAC;AAAA,MACL,CAAC;AAAA,IACL;AAGA,SAAK,6BAA6B,MAAM,KAAK,iBAAiB,OAAO,CAAC,CAAC;AACvE,WAAO,EAAE,eAAe,gBAAgB;AAAA,EAC5C;AAAA,EAEA,6BAA6B,MAAqB;AAC9C,eAAW,UAAU,MAAM;AACvB,YAAM,4BAA4B,KAAK,mBAAmB,IAAI,MAAM;AACpE,UAAI,8BAA8B,QAAW;AACzC,cAAM,EAAE,WAAW,SAAS,IAAI;AAChC,YAAI,aAAa,QAAW;AACxB,oBAAU,0BAA0B,QAAQ;AAAA,QAChD;AACA,aAAK,mBAAmB,OAAO,MAAM;AAAA,MACzC;AAAA,IACJ;AAAA,EACJ;AAAA,EAEQ,oBAAoB;AACxB,UAAM,YAAY,IAAI,MAAqB;AAC3C,UAAM,cAAc,IAAI,MAA6C;AACrE,UAAM,eAAe,IAAI,IAAY,KAAK,eAAe,KAAK,CAAC;AAE/D,QAAI,KAAK,kBAAkB,QAAW;AAClC,WAAK,cAAc,QAAQ,UAAQ;AAC/B,cAAM,SAAS,KAAK,kBAAkB,UAAU,CAAC,IAAI,CAAC;AACtD,YAAI,OAAO,WAAW,GAAG;AACrB,gBAAM,EAAE,YAAY,WAAW,QAAQ,IAAI;AAC3C,cAAI,eAAe,UAAa,cAAc,UAAa,YAAY,QAAW;AAE9E,mBAAO;AAAA,cACH,sBAAsB,KAAK,kBAAkB;AAAA,gBACzC;AAAA,cACJ,CAAC;AAAA,YACL;AAAA,UACJ,OAAO;AACH,gBAAI;AACA,mBAAK,kBAAkB,0BAA0B,YAAY,WAAW,OAAO;AAC/E,oBAAM,IAAI;AAAA,gBACN;AAAA,cACJ;AAAA,YACJ,SAAS,GAAG;AACR,oDAAoB,OAAO,CAAC;AAE5B,qBAAO;AAAA,gBACH,sBAAsB,KAAK,kBAAkB;AAAA,kBACzC;AAAA,gBACJ,CAAC,8BAA8B,EAAE,IAAI;AAAA,cACzC;AAEA,0BAAY,KAAK,EAAE,MAAM,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAAA,YACzD;AAAA,UACJ;AACA;AAAA,QACJ;AAEA,eAAO,QAAQ,CAAC,EAAE,MAAAA,OAAM,MAAM,MAAM;AAChC,uBAAa,WAAO,wCAAcA,KAAI,CAAC;AAEvC,gBAAM,wBAAwB,KAAK,eAAe,QAAI,wCAAcA,KAAI,CAAC;AACzE,cAAI,0BAA0B,QAAW;AACrC,kBAAM,EAAE,OAAO,eAAe,UAAU,iBAAiB,IAAI;AAC7D,gBAAI,kBAAkB,OAAO;AACzB,kBAAI,qBAAqB,QAAW;AAChC,8BAAc,eAAe,gBAAgB;AAAA,cACjD;AACA,mBAAK,eAAe,WAAO,wCAAcA,KAAI,CAAC;AAAA,YAClD,OAAO;AACH;AAAA,YACJ;AAAA,UACJ;AACA,gBAAM,WAAW,CAAC,aACd,KAAK,oBAAoBA,OAAM,MAAM,QAAQ,QAAQ;AACzD,gBAAM,YAAY,QAAQ;AAC1B,oBAAU,KAAK,EAAE,MAAAA,OAAM,MAAM,CAAC;AAC9B,eAAK,eAAe,QAAI,wCAAcA,KAAI,GAAG,EAAE,OAAO,SAAS,CAAC;AAAA,QACpE,CAAC;AAAA,MACL,CAAC;AAAA,IACL;AAGA,SAAK,yBAAyB,MAAM,KAAK,aAAa,OAAO,CAAC,CAAC;AAE/D,WAAO,EAAE,WAAW,YAAY;AAAA,EACpC;AAAA,EAEA,yBAAyB,MAAqB;AAC1C,eAAW,UAAU,MAAM;AACvB,YAAM,wBAAwB,KAAK,eAAe,IAAI,MAAM;AAC5D,UAAI,0BAA0B,QAAW;AACrC,cAAM,EAAE,OAAO,SAAS,IAAI;AAC5B,YAAI,aAAa,QAAW;AACxB,gBAAM,eAAe,QAAQ;AAAA,QACjC;AACA,aAAK,eAAe,OAAO,MAAM;AAAA,MACrC;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,qBAAqB;AACvB,UAAM,EAAE,cAAc,IAAI,KAAK,sBAAsB;AAErD,eAAW,EAAE,MAAM,UAAU,KAAK,eAAe;AAC7C,YAAM,EAAE,SAAS,MAAM,IAAI,MAAM,KAAK,cAAc,MAAM,SAAS;AAKnE,WAAK,4BAA4B,QAAI,4CAAkB,IAAI,GAAG;AAAA,QAC1D;AAAA,QACA;AAAA,QACA,QAAQ,UAAU;AAAA,QAClB;AAAA,QACA;AAAA,MACJ,CAAC;AAAA,IACL;AAEA,UAAM,EAAE,UAAU,IAAI,KAAK,kBAAkB;AAC7C,cACK,QAAQ,CAAC,EAAE,MAAM,MAAM,MAAqC;AAEzD,YAAM,EAAE,OAAO,IAAI;AACnB,YAAM,iBAAiB,MAAM,IAAI,KAAK,SAAS,KAAK,kBAAkB,QAAW,KAAK,YAAY;AAClG,aAAO,eAAe,IAAI,WAAS;AAAA,QAC/B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACJ,EAAE;AAAA,IACN,CAAC,EACA,KAAK,CAAC,GAAG,MAAM;AACZ,YAAM,eAAe,EAAE,MAAM,mBAAe,gCAAY,CAAC;AACzD,YAAM,eAAe,EAAE,MAAM,mBAAe,gCAAY,CAAC;AACzD,UAAI,eAAe,cAAc;AAC7B,eAAO;AAAA,MACX,WAAW,eAAe,cAAc;AACpC,eAAO;AAAA,MACX,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ,CAAC,EACA,QAAQ,WAAS,KAAK,wBAAwB,IAAI,KAAK,CAAC;AAE7D,SAAK,kBAAkB;AAAA,EAC3B;AAAA,EAEA,IAAI,cAAsB;AACtB,WAAO,KAAK,KAAK,KAAK,iBAAiB,GAAI;AAAA,EAC/C;AAAA,EAEA,IAAI,eAAuB;AACvB,WAAO,KAAK,KAAK,KAAK,kBAAkB,GAAI;AAAA,EAChD;AAAA,EAEA,yBAAyB;AAErB,QAAI,KAAK,iBAAiB,OAAW,MAAK,aAAa,SAAS;AAChE,QAAI,KAAK,uBAAuB,OAAW,MAAK,mBAAmB,SAAS;AAE5E,SAAK,uBAAuB;AAC5B,QAAI,KAAK,4BAA4B,OAAO,KAAK,KAAK,wBAAwB,OAAO,GAAG;AACpF,WAAK,KAAK,WAAW;AAAA,IACzB;AACA,SAAK,cAAc,iBAAK;AAAA,MAAS;AAAA,MAAuB,KAAK;AAAA,MAAiB,MAC1E,KAAK,kBAAkB;AAAA,IAC3B,EAAE,MAAM;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,oBAAoB;AAChB,QAAI,KAAK,eAAe,WAAW;AAE/B;AAAA,IACJ;AAEA,QAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,IACJ;AAEA,SAAK,YAAY,KAAK;AACtB,UAAM,MAAM,iBAAK,MAAM;AACvB,UAAM,wBAAwB,MAAM,KAAK;AACzC,QAAI,wBAAwB,KAAK,oBAAoB;AAEjD,WAAK,cAAc,iBAAK;AAAA,QACpB;AAAA,QACA,KAAK,qBAAqB;AAAA,QAC1B,MAAM,KAAK,kBAAkB;AAAA,MACjC,EAAE,MAAM;AACR;AAAA,IACJ;AAEA,SAAK,eAAe,MAAM;AAC1B,SAAK,cAAc,iBAAK;AAAA,MAAS;AAAA,MAAuB,KAAK;AAAA,MAAiB,MAC1E,KAAK,kBAAkB;AAAA,IAC3B,EAAE,MAAM;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa;AACf,QAAI,KAAK,yBAAyB;AAC9B,aAAO,MAAM,yDAAyD;AACtE,WAAK,4BAA4B;AACjC;AAAA,IACJ;AAGA,UAAM,yBAAyB,IAAI,MAA0C;AAC7E,UAAM,mBAAyE,CAAC;AAChF,UAAM,KAAK,KAAK,4BAA4B,OAAO,CAAC,EAAE,QAAQ,WAAS;AACnE,YAAM;AAAA,QACF,MAAM,EAAE,QAAQ,YAAY,UAAU;AAAA,MAC1C,IAAI;AACJ,YAAM,SAAS,GAAG,MAAM,IAAI,UAAU,IAAI,SAAS;AACnD,uBAAiB,MAAM,IAAI,iBAAiB,MAAM,KAAK,CAAC;AACxD,uBAAiB,MAAM,EAAE,KAAK,KAAK;AAAA,IACvC,CAAC;AACD,SAAK,4BAA4B,MAAM;AACvC,WAAO,OAAO,gBAAgB,EAAE;AAAA,MAAQ,UACpC,uBAAuB;AAAA,QACnB,GAAG,KAAK,KAAK,CAAC,EAAE,SAAS,SAAS,GAAG,EAAE,SAAS,SAAS,MAAM,WAAW,QAAQ;AAAA,MACtF;AAAA,IACJ;AAEA,UAAM,qBAAqB,MAAM,KAAK,KAAK,wBAAwB,OAAO,CAAC;AAC3E,SAAK,wBAAwB,MAAM;AACnC,SAAK,mBAAmB,iBAAK,MAAM;AAEnC,SAAK,0BAA0B;AAC/B,QAAI;AACA,YAAM,KAAK,kBAAkB,wBAAwB,kBAAkB;AACvE,WAAK,yBAAyB;AAAA,IAClC,SAAS,OAAO;AACZ,UAAI,KAAK,OAAO,WAAW;AAEvB;AAAA,MACJ;AAEA,WAAK;AACL,aAAO;AAAA,QACH,0DAA0D,KAAK,sBAAsB;AAAA,QACrF;AAAA,MACJ;AACA,UAAI,KAAK,0BAA0B,GAAG;AAElC,cAAM,4BAA4B,MAAM,KAAK,KAAK,4BAA4B,OAAO,CAAC;AACtF,aAAK,4BAA4B,MAAM;AACvC,cAAM,wBAAwB,MAAM,KAAK,KAAK,wBAAwB,OAAO,CAAC;AAC9E,aAAK,wBAAwB,MAAM;AACnC,SAAC,GAAG,wBAAwB,GAAG,yBAAyB,EAAE;AAAA,UAAQ,YAC9D,KAAK,4BAA4B,QAAI,4CAAkB,OAAO,IAAI,GAAG,MAAM;AAAA,QAC/E;AACA,SAAC,GAAG,oBAAoB,GAAG,qBAAqB,EAAE;AAAA,UAAQ,YACtD,KAAK,wBAAwB,IAAI,MAAM;AAAA,QAC3C;AAAA,MACJ,OAAO;AACH,eAAO;AAAA,UACH,kEAAkE,KAAK,cAAc;AAAA,QACzF;AACA,aAAK,4BAA4B;AACjC,YAAI,iBAAiB,0DAAmC,iBAAiB,6BAAc;AAEnF,gBAAM,KAAK,QAAQ,QAAQ,KAAK;AAAA,QACpC,OAAO;AACH,gBAAM;AAAA,QACV;AAAA,MACJ;AAAA,IACJ;AACA,SAAK,0BAA0B;AAE/B,QAAI,KAAK,2BAA2B;AAChC,aAAO,MAAM,6DAA6D;AAC1E,WAAK,4BAA4B;AACjC,YAAM,KAAK,WAAW;AAAA,IAC1B;AAAA,EACJ;AAAA,EAEA,MAAM,kBAAkB,WAAuC;AAC3D,SAAK,YAAY,KAAK;AAEtB,UAAM,EAAE,eAAe,gBAAgB,IAAI,KAAK,sBAAsB;AAEtE,UAAM,uBAAuB,IAAI;AAAA,MAC7B,KAAK,oBAAoB,IAAI,CAAC,EAAE,MAAM,YAAY,MAAM,KAAC,0CAAgB,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC;AAAA,IACtG;AAEA,QAAI,gCAAgC;AACpC,UAAM,aAAa,IAAI,MAMpB;AACH,eAAW,EAAE,MAAM,UAAU,KAAK,eAAe;AAC7C,UAAI;AACA,cAAM,EAAE,OAAO,QAAQ,IAAI,MAAM,KAAK,cAAc,MAAM,SAAS;AACnE,YAAI,UAAU,OAAW;AAEzB,cAAM,EAAE,QAAQ,YAAY,UAAU,IAAI;AAE1C,cAAM,qBACF,eAAe,UAAa,cAAc,SACpC,qBAAqB,QAAI,0CAAgB,EAAE,QAAQ,YAAY,UAAU,CAAC,CAAC,IAC3E;AACV,YAAI,uBAAuB,UAAa,uBAAuB,SAAS;AACpE,0CAAgC;AAChC;AAAA,QACJ;AAEA,mBAAW,KAAK,EAAE,MAAM,OAAO,SAAS,QAAQ,UAAU,QAAQ,UAAU,CAAC;AAAA,MACjF,SAAS,OAAO;AACZ,eAAO,MAAM,2BAA2B,KAAK,kBAAkB,qBAAqB,IAAI,CAAC,KAAK,KAAK;AAAA,MACvG;AAAA,IACJ;AACA,UAAM,0BAAoD,WAAW;AAAA,MACjE,CAAC,EAAE,MAAM,QAAQ,OAAO,SAAS,UAAU,OAAO;AAAA,QAC9C,wBAAwB,UAAU;AAAA,QAClC,eAAe;AAAA,UACX;AAAA,UACA,aAAa;AAAA,UACb,SAAS;AAAA,UACT;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AACA,oBAAgB;AAAA,MAAQ,qBACpB,wBAAwB,KAAK;AAAA,QACzB,wBAAwB;AAAA,QACxB;AAAA,MACJ,CAAC;AAAA,IACL;AAEA,UAAM,EAAE,WAAW,YAAY,IAAI,KAAK,kBAAkB;AAE1D,QAAI,iBAAiB;AACrB,UAAM,sBAAsB,IAAI,MAA0B;AAC1D,eAAW,EAAE,MAAM,MAAM,KAAK,WAAW;AACrC,YAAM,EAAE,OAAO,IAAI;AACnB,UAAI;AACA,cAAM,iBAAiB,MAAM,KAAK,UAAU,MAAM,OAAO,KAAK,YAAY;AAC1E,YAAI,eAAe,WAAW,GAAG;AAC7B,2BAAiB;AAAA,QACrB,OAAO;AACH,yBAAe,QAAQ,CAAC,EAAE,aAAa,UAAU,gBAAgB,KAAK,MAAM;AACxE,gCAAoB,KAAK;AAAA,cACrB,wBAAwB,MAAM;AAAA,cAC9B,WAAW;AAAA,gBACP;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,SAAS;AAAA,gBACT;AAAA,cACJ;AAAA,YACJ,CAAC;AAAA,UACL,CAAC;AAAA,QACL;AAAA,MACJ,SAAS,OAAO;AACZ,eAAO,MAAM,uBAAuB,KAAK,kBAAkB,iBAAiB,IAAI,CAAC,KAAK,KAAK;AAAA,MAC/F;AAAA,IACJ;AACA,wBAAoB,KAAK,CAAC,GAAG,MAAM;AAC/B,YAAM,eAAe,EAAE,WAAW,eAAe;AACjD,YAAM,eAAe,EAAE,WAAW,eAAe;AACjD,UAAI,eAAe,cAAc;AAC7B,eAAO;AAAA,MACX,WAAW,eAAe,cAAc;AACpC,eAAO;AAAA,MACX,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ,CAAC;AAED,QACI,WAAW,WAAW,KACtB,CAAC,iCACD,oBAAoB,WAAW,KAC/B,CAAC,gBACH;AACE,YAAM,IAAI;AAAA,QACN;AAAA,QACA,6BAAW;AAAA,MACf;AAAA,IACJ;AAEA,gBAAY;AAAA,MAAQ,iBAChB,oBAAoB,KAAK;AAAA,QACrB,wBAAwB;AAAA,QACxB;AAAA,MACJ,CAAC;AAAA,IACL;AAEA,WAAO;AAAA,MACH,gCAAgC,WAAW,MAAM,mBAAmB,oBAAoB,MAAM;AAAA,IAClG;AACA,SAAK,mBAAmB,iBAAK,MAAM;AAEnC,UAAM,UAAU;AAAA,MACZ;AAAA,QACI,kBAAkB;AAAA;AAAA,QAClB,gBAAgB,KAAK;AAAA,QACrB,0BAA0B;AAAA,QAC1B;AAAA,QACA;AAAA,MACJ;AAAA,MACA,KAAK;AAAA,IACT;AAAA,EACJ;AAAA,EAEA,wBAA2B,MAAqB,QAAsB,SAAiB,OAAU;AAC7F,UAAM,eAAe,KAAK,uBAAuB,MAAM,QAAQ,SAAS,KAAK;AAC7E,QAAI,6BAAa,GAAG,YAAY,GAAG;AAC/B,YAAM,WAAW,QAAQ,QAAQ,YAAY,EACxC,MAAM,WAAS,OAAO,MAAM,oCAAoC,KAAK,CAAC,EACtE,QAAQ,MAAM,KAAK,wBAAwB,OAAO,QAAQ,CAAC;AAChE,WAAK,wBAAwB,IAAI,QAAQ;AAAA,IAC7C;AAAA,EACJ;AAAA,EAEA,uBACI,MACA,QACA,SACA,OACkB;AAClB,UAAM,wBAAwB,KAAK,mBAAmB,QAAI,4CAAkB,IAAI,CAAC;AACjF,QAAI,0BAA0B,OAAW;AAEzC,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,qBAAqB,oDAA6B;AAIlD,aAAO,KAAK,cAAc,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,OAAAC,OAAM,MAAM;AAC3D,aAAK,4BAA4B,QAAI,4CAAkB,IAAI,GAAG;AAAA,UAC1D;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,OAAAA;AAAA,QACJ,CAAC;AACD,aAAK,kBAAkB;AAAA,MAC3B,CAAC;AAAA,IACL;AACA,SAAK,4BAA4B,QAAI,4CAAkB,IAAI,GAAG,EAAE,WAAW,MAAM,QAAQ,SAAS,MAAM,CAAC;AACzG,SAAK,kBAAkB;AAAA,EAC3B;AAAA,EAEA,oBAAuB,MAAiB,QAAsB,UAA+B;AACzF,UAAM,oBAAoB,KAAK,eAAe,QAAI,wCAAc,IAAI,CAAC;AACrE,QAAI,sBAAsB,OAAW;AAErC,UAAM,EAAE,MAAM,IAAI;AAClB,QAAI,iBAAiB,+CAA4B;AAC7C,YAAM,EAAE,KAAK,IAAI;AACjB,cAAI,sBAAS,IAAI,KAAK,iBAAiB,QAAQ,KAAK,gBAAgB,KAAK,QAAQ,QAAQ,aAAa;AAElG;AAAA,MACJ;AAAA,IACJ;AACA,SAAK,wBAAwB,IAAI,EAAE,OAAO,MAAM,QAAQ,MAAM,SAAS,CAAC;AACxE,QAAI,KAAK,UAAU;AACf,WAAK,kBAAkB;AAAA,IAC3B;AAAA,EACJ;AAAA,EAEA,MAAM,QAAQ;AACV,SAAK,eAAe,KAAK;AACzB,WAAO;AAAA,MACH,yBAAyB,KAAK,cAAc,SAAS,KAAK,4BAA4B,IAAI,mBAAmB,KAAK,wBAAwB,IAAI;AAAA,IAClJ;AACA,QAAI,KAAK,4BAA4B,OAAO,KAAK,KAAK,wBAAwB,OAAO,GAAG;AACpF,WAAK,KAAK,WAAW;AAAA,IACzB;AAAA,EACJ;AAAA,EAEA,MAAM,OAAO,QAAQ,OAAO,kBAAkB,OAAO;AACjD,SAAK,uBAAuB;AAC5B,QAAI,KAAK,wBAAwB,MAAM;AACnC,YAAM,YAAY,CAAC,GAAG,KAAK,wBAAwB,OAAO,CAAC;AAC3D,WAAK,wBAAwB,MAAM;AACnC,YAAM,QAAQ,IAAI,SAAS;AAAA,IAC/B;AACA,SAAK,YAAY,KAAK;AACtB,SAAK,eAAe,KAAK;AACzB,SAAK,6BAA6B,MAAM,KAAK,KAAK,mBAAmB,KAAK,CAAC,CAAC;AAC5E,SAAK,yBAAyB,MAAM,KAAK,KAAK,eAAe,KAAK,CAAC,CAAC;AACpE,QAAI,OAAO;AACP,YAAM,KAAK,MAAM;AAAA,IACrB;AACA,SAAK,QAAQ,mBAAmB,KAAK,cAAc;AACnD,SAAK,eAAe;AACpB,QAAI,iBAAiB;AACjB,YAAM,KAAK,QAAQ,QAAQ,kBAAkB;AAAA,IACjD;AAAA,EACJ;AAAA,EAEA,MAAc,kBACV,YACA,QACF;AACE,WAAO;AAAA,MACH,8CAA8C,KAAK,cAAc,SAAS,WAAW,MAAM,mBAAmB,OAAO,MAAM;AAAA,IAC/H;AACA,UAAM,WAAW,KAAK,OAAO,iBAAiB,KAAK,QAAQ,KAAK,YAAY,gDAAuB;AACnG,QAAI,aAAa,OAAW;AAC5B,WAAO;AAAA,MACH,uCAAuC,KAAK,cAAc,KAAK,WAC1D;AAAA,QACG,CAAC,EAAE,MAAM,OAAO,QAAQ,MACpB,GAAG,KAAK,kBAAkB,qBAAqB,IAAI,CAAC,IAAI,qBAAO,OAAO,KAAK,CAAC,KAAK,OAAO;AAAA,MAChG,EACC,KAAK,IAAI,CAAC;AAAA,IACnB;AACA,UAAM,YAAY,IAAI,uDAA2B,QAAQ;AAEzD,QAAI;AACA,UAAI,WAAW,WAAW,KAAK,OAAO,WAAW,GAAG;AAChD,cAAM,UAAU;AAAA,UACZ;AAAA,YACI,kBAAkB;AAAA;AAAA,YAClB,gBAAgB,KAAK;AAAA,YACrB,0BAA0B;AAAA,UAC9B;AAAA,UACA,KAAK;AAAA,QACT;AAAA,MACJ,OAAO;AACH,cAAM,UAAU;AAAA,UACZ;AAAA,YACI,kBAAkB;AAAA;AAAA,YAClB,gBAAgB,KAAK;AAAA,YACrB,0BAA0B;AAAA,YAC1B,yBAAyB,WAAW,IAAI,CAAC,EAAE,MAAM,QAAQ,OAAO,SAAS,UAAU,OAAO;AAAA,cACtF,wBAAwB,UAAU;AAAA,cAClC,eAAe;AAAA,gBACX;AAAA,gBACA,aAAa;AAAA,gBACb;AAAA,gBACA,SAAS;AAAA,cACb;AAAA,YACJ,EAAE;AAAA,YACF,qBAAqB,OAAO,IAAI,CAAC,EAAE,MAAM,QAAQ,OAAO,KAAK,MAAM;AAC/D,oBAAM,EAAE,aAAa,UAAU,gBAAgB,MAAM,QAAQ,IAAI;AACjE,qBAAO;AAAA,gBACH,wBAAwB,MAAM;AAAA,gBAC9B,WAAW;AAAA,kBACP;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBACJ;AAAA,cACJ;AAAA,YACJ,CAAC;AAAA,UACL;AAAA,UACA,KAAK;AAAA,QACT;AAAA,MACJ;AAAA,IACJ,SAAS,GAAG;AACR,UAAI,sCAAoB,GAAG,GAAG,6BAAW,qBAAqB,6BAAW,OAAO,GAAG;AAC/E,eAAO,KAAK,gBAAgB,KAAK,cAAc,qBAAqB;AACpE,cAAM,KAAK,OAAO,OAAO,IAAI;AAAA,MACjC,OAAO;AACH,cAAM,KAAK,OAAO,KAAK;AACvB,cAAM;AAAA,MACV;AAAA,IACJ,UAAE;AACE,YAAM,UAAU,MAAM;AAAA,IAC1B;AAAA,EACJ;AACJ;",
|
|
4
|
+
"sourcesContent": ["/**\n * @license\n * Copyright 2022-2024 Matter.js Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { MatterDevice } from \"../../MatterDevice.js\";\nimport { AnyAttributeServer, FabricScopedAttributeServer } from \"../../cluster/server/AttributeServer.js\";\nimport { AnyEventServer, FabricSensitiveEventServer } from \"../../cluster/server/EventServer.js\";\nimport { InternalError } from \"../../common/MatterError.js\";\nimport { EventNumber } from \"../../datatype/EventNumber.js\";\nimport { NodeId } from \"../../datatype/NodeId.js\";\nimport { Fabric } from \"../../fabric/Fabric.js\";\nimport { Logger } from \"../../log/Logger.js\";\nimport { NetworkError } from \"../../net/Network.js\";\nimport { SecureSession } from \"../../session/SecureSession.js\";\nimport { Time, Timer } from \"../../time/Time.js\";\nimport { TlvSchema, TypeFromSchema } from \"../../tlv/TlvSchema.js\";\nimport { MaybePromise } from \"../../util/Promises.js\";\nimport { isObject } from \"../../util/Type.js\";\nimport { RetransmissionLimitReachedError } from \"../MessageExchange.js\";\nimport { AttributeReportPayload, EventReportPayload } from \"./AttributeDataEncoder.js\";\nimport { EventStorageData } from \"./EventHandler.js\";\nimport { InteractionEndpointStructure } from \"./InteractionEndpointStructure.js\";\nimport { InteractionServerMessenger } from \"./InteractionMessenger.js\";\nimport {\n TlvAttributePath,\n TlvAttributeStatus,\n TlvDataVersionFilter,\n TlvEventFilter,\n TlvEventPath,\n TlvEventStatus,\n} from \"./InteractionProtocol.js\";\nimport {\n AttributePath,\n AttributeWithPath,\n EventPath,\n EventWithPath,\n INTERACTION_MODEL_REVISION,\n INTERACTION_PROTOCOL_ID,\n attributePathToId,\n clusterPathToId,\n eventPathToId,\n} from \"./InteractionServer.js\";\nimport { StatusCode, StatusResponseError } from \"./StatusCode.js\";\nimport { MAX_INTERVAL_PUBLISHER_LIMIT_S, SubscriptionOptions } from \"./SubscriptionOptions.js\";\n\nconst logger = Logger.get(\"SubscriptionHandler\");\n\ninterface AttributePathWithValueVersion<T> {\n path: TypeFromSchema<typeof TlvAttributePath>;\n attribute: AnyAttributeServer<T>;\n schema: TlvSchema<T>;\n value: T;\n version: number;\n}\n\ninterface EventPathWithEventData<T> {\n path: TypeFromSchema<typeof TlvEventPath>;\n event: AnyEventServer<any, any>;\n schema: TlvSchema<T>;\n data: EventStorageData<T>;\n}\n\nexport class SubscriptionHandler {\n readonly subscriptionId: number;\n private readonly session: SecureSession<any>;\n private readonly endpointStructure: InteractionEndpointStructure;\n private readonly attributeRequests?: TypeFromSchema<typeof TlvAttributePath>[];\n private readonly dataVersionFilters?: TypeFromSchema<typeof TlvDataVersionFilter>[];\n private readonly eventRequests?: TypeFromSchema<typeof TlvEventPath>[];\n private readonly eventFilters?: TypeFromSchema<typeof TlvEventFilter>[];\n private readonly isFabricFiltered: boolean;\n private readonly cancelCallback: () => void;\n private readonly readAttribute: (path: AttributePath, attribute: AnyAttributeServer<any>) => Promise<any>;\n private readonly readEvent: (\n path: EventPath,\n event: AnyEventServer<any, any>,\n eventFilters: TypeFromSchema<typeof TlvEventFilter>[] | undefined,\n ) => Promise<EventStorageData<any>[]>;\n\n private lastUpdateTimeMs = 0;\n private updateTimer: Timer;\n private readonly sendDelayTimer: Timer;\n private readonly outstandingAttributeUpdates = new Map<string, AttributePathWithValueVersion<any>>();\n private readonly outstandingEventUpdates = new Set<EventPathWithEventData<any>>();\n private readonly attributeListeners = new Map<\n string,\n {\n attribute: AnyAttributeServer<any>;\n listener?: (value: any, version: number) => void;\n }\n >();\n private readonly eventListeners = new Map<\n string,\n {\n event: AnyEventServer<any, any>;\n listener?: (newEvent: EventStorageData<any>) => void;\n }\n >();\n private sendUpdatesActivated = false;\n readonly #maxIntervalMs: number;\n readonly #sendIntervalMs: number;\n private readonly minIntervalFloorMs: number;\n private readonly maxIntervalCeilingMs: number;\n private readonly server: MatterDevice;\n private readonly fabric: Fabric;\n private readonly peerNodeId: NodeId;\n\n private sendingUpdateInProgress = false;\n private sendNextUpdateImmediately = false;\n private sendUpdateErrorCounter = 0;\n private attributeUpdatePromises = new Set<PromiseLike<void>>();\n\n constructor(options: {\n subscriptionId: number;\n session: SecureSession<any>;\n endpointStructure: InteractionEndpointStructure;\n attributeRequests?: TypeFromSchema<typeof TlvAttributePath>[];\n dataVersionFilters?: TypeFromSchema<typeof TlvDataVersionFilter>[];\n eventRequests?: TypeFromSchema<typeof TlvEventPath>[];\n eventFilters?: TypeFromSchema<typeof TlvEventFilter>[];\n isFabricFiltered: boolean;\n minIntervalFloor: number;\n maxIntervalCeiling: number;\n cancelCallback: () => void;\n subscriptionOptions: SubscriptionOptions.Configuration;\n readAttribute: (path: AttributePath, attribute: AnyAttributeServer<any>) => Promise<any>;\n readEvent: (\n path: EventPath,\n event: AnyEventServer<any, any>,\n eventFilters: TypeFromSchema<typeof TlvEventFilter>[] | undefined,\n ) => Promise<EventStorageData<any>[]>;\n }) {\n const {\n subscriptionId,\n session,\n endpointStructure,\n attributeRequests,\n dataVersionFilters,\n eventRequests,\n eventFilters,\n isFabricFiltered,\n minIntervalFloor,\n maxIntervalCeiling,\n cancelCallback,\n subscriptionOptions,\n } = options;\n this.subscriptionId = subscriptionId;\n this.session = session;\n this.endpointStructure = endpointStructure;\n this.attributeRequests = attributeRequests;\n this.dataVersionFilters = dataVersionFilters;\n this.eventRequests = eventRequests;\n this.eventFilters = eventFilters;\n this.isFabricFiltered = isFabricFiltered;\n this.cancelCallback = cancelCallback;\n this.readAttribute = options.readAttribute;\n this.readEvent = options.readEvent;\n\n this.server = this.session.context;\n this.fabric = this.session.associatedFabric;\n this.peerNodeId = this.session.peerNodeId;\n this.minIntervalFloorMs = minIntervalFloor * 1000;\n this.maxIntervalCeilingMs = maxIntervalCeiling * 1000;\n\n const { maxInterval, sendInterval } = this.determineSendingIntervals(\n subscriptionOptions.minIntervalSeconds * 1000,\n subscriptionOptions.maxIntervalSeconds * 1000,\n subscriptionOptions.randomizationWindowSeconds * 1000,\n );\n this.#maxIntervalMs = maxInterval;\n this.#sendIntervalMs = sendInterval;\n\n this.updateTimer = Time.getTimer(\"Subscription update\", this.#sendIntervalMs, () => this.prepareDataUpdate()); // will be started later\n this.sendDelayTimer = Time.getTimer(\"Subscription delay\", 50, () =>\n this.sendUpdate().catch(error => logger.warn(\"Sending subscription update failed:\", error)),\n ); // will be started later\n }\n\n private determineSendingIntervals(\n subscriptionMinIntervalMs: number,\n subscriptionMaxIntervalMs: number,\n subscriptionRandomizationWindowMs: number,\n ): { maxInterval: number; sendInterval: number } {\n // Max Interval is the Max interval that the controller request, unless the configured one from the developer\n // is lower. In that case we use the configured one. But we make sure to not be smaller than the requested\n // controller minimum. But in general never faster than minimum interval configured or 2 seconds\n // (SUBSCRIPTION_MIN_INTERVAL_S). Additionally, we add a randomization window to the max interval to avoid all\n // devices sending at the same time. But we make sure not to exceed the global max interval.\n const maxInterval = Math.min(\n Math.max(\n subscriptionMinIntervalMs,\n Math.max(this.minIntervalFloorMs, Math.min(subscriptionMaxIntervalMs, this.maxIntervalCeilingMs)),\n ) + Math.floor(subscriptionRandomizationWindowMs * Math.random()),\n MAX_INTERVAL_PUBLISHER_LIMIT_S * 1000,\n );\n let sendInterval = Math.floor(maxInterval / 2); // Ideally we send at half the max interval\n if (sendInterval < 60_000) {\n // But if we have no chance of at least one full resubmission process we do like chip-tool.\n // One full resubmission process takes 33-45 seconds. So 60s means we reach at least first 2 retries of a\n // second subscription report after first failed.\n sendInterval = Math.max(this.minIntervalFloorMs, Math.floor(maxInterval * 0.8));\n }\n if (sendInterval < subscriptionMinIntervalMs) {\n // But not faster than once every 2s\n logger.warn(\n `Determined subscription send interval of ${sendInterval}ms is too low. Using maxInterval (${maxInterval}ms) instead.`,\n );\n sendInterval = subscriptionMinIntervalMs;\n }\n return { maxInterval, sendInterval };\n }\n\n private registerNewAttributes() {\n const newAttributes = new Array<AttributeWithPath>();\n const attributeErrors = new Array<TypeFromSchema<typeof TlvAttributeStatus>>();\n const formerAttributes = new Set<string>(this.attributeListeners.keys());\n\n if (this.attributeRequests !== undefined) {\n this.attributeRequests.forEach(path => {\n const attributes = this.endpointStructure.getAttributes([path]);\n\n if (attributes.length === 0) {\n // TODO: Also check nodeId\n const { endpointId, clusterId, attributeId } = path;\n if (endpointId === undefined || clusterId === undefined || attributeId === undefined) {\n // Wildcard path: Just leave out values\n logger.debug(\n `Subscription attribute ${this.endpointStructure.resolveAttributeName(\n path,\n )}: ignore non-existing attribute`,\n );\n } else {\n // was a concrete path\n try {\n this.endpointStructure.validateConcreteAttributePath(endpointId, clusterId, attributeId);\n throw new InternalError(\n \"validateConcreteAttributePath check should throw StatusResponseError but did not.\",\n );\n } catch (e) {\n StatusResponseError.accept(e);\n\n logger.debug(\n `Subscription attribute ${this.endpointStructure.resolveAttributeName(\n path,\n )}: unsupported path: Status=${e.code}`,\n );\n\n attributeErrors.push({ path, status: { status: e.code } });\n }\n }\n return;\n }\n\n attributes.forEach(({ path, attribute }) => {\n formerAttributes.delete(attributePathToId(path));\n\n const existingAttributeListener = this.attributeListeners.get(attributePathToId(path));\n if (existingAttributeListener !== undefined) {\n const { attribute: existingAttribute, listener: existingListener } = existingAttributeListener;\n if (existingAttribute !== attribute) {\n if (existingListener !== undefined) {\n existingAttribute.removeValueChangeListener(existingListener);\n }\n this.attributeListeners.delete(attributePathToId(path));\n } else {\n return; // Attribute is already registered and unchanged\n }\n }\n if (attribute.isSubscribable) {\n // If subscribable register listener\n // TODO: Move to state change listeners from behaviors to remove the dangling promise here\n const listener = (value: any, version: number) =>\n this.attributeChangeListener(path, attribute.schema, version, value);\n attribute.addValueChangeListener(listener);\n this.attributeListeners.set(attributePathToId(path), { attribute, listener });\n } else {\n this.attributeListeners.set(attributePathToId(path), { attribute });\n }\n newAttributes.push({ path, attribute });\n });\n });\n }\n\n // Remove all listeners to attributes that no longer match the subscription\n this.unregisterAttributeListeners(Array.from(formerAttributes.values()));\n return { newAttributes, attributeErrors };\n }\n\n unregisterAttributeListeners(list: Array<string>) {\n for (const pathId of list) {\n const existingAttributeListener = this.attributeListeners.get(pathId);\n if (existingAttributeListener !== undefined) {\n const { attribute, listener } = existingAttributeListener;\n if (listener !== undefined) {\n attribute.removeValueChangeListener(listener);\n }\n this.attributeListeners.delete(pathId);\n }\n }\n }\n\n private registerNewEvents() {\n const newEvents = new Array<EventWithPath>();\n const eventErrors = new Array<TypeFromSchema<typeof TlvEventStatus>>();\n const formerEvents = new Set<string>(this.eventListeners.keys());\n\n if (this.eventRequests !== undefined) {\n this.eventRequests.forEach(path => {\n const events = this.endpointStructure.getEvents([path]);\n if (events.length === 0) {\n const { endpointId, clusterId, eventId } = path;\n if (endpointId === undefined || clusterId === undefined || eventId === undefined) {\n // Wildcard path: Just leave out values\n logger.debug(\n `Subscription event ${this.endpointStructure.resolveEventName(\n path,\n )}: ignore non-existing event`,\n );\n } else {\n try {\n this.endpointStructure.validateConcreteEventPath(endpointId, clusterId, eventId);\n throw new InternalError(\n \"validateConcreteEventPath should throw StatusResponseError but did not.\",\n );\n } catch (e) {\n StatusResponseError.accept(e);\n\n logger.debug(\n `Subscription event ${this.endpointStructure.resolveEventName(\n path,\n )}: unsupported path: Status=${e.code}`,\n );\n\n eventErrors.push({ path, status: { status: e.code } });\n }\n }\n return;\n }\n\n events.forEach(({ path, event }) => {\n formerEvents.delete(eventPathToId(path));\n\n const existingEventListener = this.eventListeners.get(eventPathToId(path));\n if (existingEventListener !== undefined) {\n const { event: existingEvent, listener: existingListener } = existingEventListener;\n if (existingEvent !== event) {\n if (existingListener !== undefined) {\n existingEvent.removeListener(existingListener);\n }\n this.eventListeners.delete(eventPathToId(path));\n } else {\n return; // Event is already registered and unchanged\n }\n }\n const listener = (newEvent: EventStorageData<any>) =>\n this.eventChangeListener(path, event.schema, newEvent);\n event.addListener(listener);\n newEvents.push({ path, event });\n this.eventListeners.set(eventPathToId(path), { event, listener });\n });\n });\n }\n\n // Remove all listeners to events that no longer match the subscription\n this.unregisterEventListeners(Array.from(formerEvents.values()));\n\n return { newEvents, eventErrors };\n }\n\n unregisterEventListeners(list: Array<string>) {\n for (const pathId of list) {\n const existingEventListener = this.eventListeners.get(pathId);\n if (existingEventListener !== undefined) {\n const { event, listener } = existingEventListener;\n if (listener !== undefined) {\n event.removeListener(listener);\n }\n this.eventListeners.delete(pathId);\n }\n }\n }\n\n /**\n * Update the session after an endpoint structure change. The method will initialize all missing new attributes and\n * events and will remove listeners no longer needed.\n * Newly added attributes are then treated ad \"changed values\" and will be sent as subscription data update to the\n * controller. The data of newly added events are not sent automatically.\n */\n async updateSubscription() {\n const { newAttributes } = this.registerNewAttributes();\n\n for (const { path, attribute } of newAttributes) {\n const { version, value } = await this.readAttribute(path, attribute);\n\n // We do not do any version filtering for attributes that are newly added to make sure controller gets\n // most current state\n\n this.outstandingAttributeUpdates.set(attributePathToId(path), {\n attribute,\n path,\n schema: attribute.schema,\n version,\n value,\n });\n }\n\n const { newEvents } = this.registerNewEvents();\n newEvents\n .flatMap(({ path, event }): EventPathWithEventData<any>[] => {\n // But we use eventFilters because we do not want to send all events to the controller\n const { schema } = event;\n const matchingEvents = event.get(this.session, this.isFabricFiltered, undefined, this.eventFilters);\n return matchingEvents.map(data => ({\n event,\n schema,\n path,\n data,\n }));\n })\n .sort((a, b) => {\n const eventNumberA = a.data?.eventNumber ?? EventNumber(0);\n const eventNumberB = b.data?.eventNumber ?? EventNumber(0);\n if (eventNumberA > eventNumberB) {\n return 1;\n } else if (eventNumberA < eventNumberB) {\n return -1;\n } else {\n return 0;\n }\n })\n .forEach(event => this.outstandingEventUpdates.add(event));\n\n this.prepareDataUpdate();\n }\n\n get maxInterval(): number {\n return Math.ceil(this.#maxIntervalMs / 1000);\n }\n\n get sendInterval(): number {\n return Math.ceil(this.#sendIntervalMs / 1000);\n }\n\n activateSendingUpdates() {\n // We do not need these data anymore, so we can free some memory\n if (this.eventFilters !== undefined) this.eventFilters.length = 0;\n if (this.dataVersionFilters !== undefined) this.dataVersionFilters.length = 0;\n\n this.sendUpdatesActivated = true;\n if (this.outstandingAttributeUpdates.size > 0 || this.outstandingEventUpdates.size > 0) {\n void this.sendUpdate();\n }\n this.updateTimer = Time.getTimer(\"Subscription update\", this.#sendIntervalMs, () =>\n this.prepareDataUpdate(),\n ).start();\n }\n\n /**\n * Check if data should be sent straight away or delayed because the minimum interval is not reached. Delay real\n * sending by 50ms in any case to mke sure to catch all updates.\n */\n prepareDataUpdate() {\n if (this.sendDelayTimer.isRunning) {\n // sending data is already scheduled, data updates go in there\n return;\n }\n\n if (!this.sendUpdatesActivated) {\n return;\n }\n\n this.updateTimer.stop();\n const now = Time.nowMs();\n const timeSinceLastUpdateMs = now - this.lastUpdateTimeMs;\n if (timeSinceLastUpdateMs < this.minIntervalFloorMs) {\n // Respect minimum delay time between updates\n this.updateTimer = Time.getTimer(\n \"Subscription update\",\n this.minIntervalFloorMs - timeSinceLastUpdateMs,\n () => this.prepareDataUpdate(),\n ).start();\n return;\n }\n\n this.sendDelayTimer.start();\n this.updateTimer = Time.getTimer(\"Subscription update\", this.#sendIntervalMs, () =>\n this.prepareDataUpdate(),\n ).start();\n }\n\n /**\n * Determine all attributes that have changed since the last update and send them tout to the subscriber.\n */\n async sendUpdate() {\n if (this.sendingUpdateInProgress) {\n logger.debug(\"Sending update already in progress, delaying update ...\");\n this.sendNextUpdateImmediately = true;\n return;\n }\n\n // Get all outstanding updates, make sure the order is correct per endpoint and cluster\n const attributeUpdatesToSend = new Array<AttributePathWithValueVersion<any>>();\n const attributeUpdates: Record<string, AttributePathWithValueVersion<any>[]> = {};\n Array.from(this.outstandingAttributeUpdates.values()).forEach(entry => {\n const {\n path: { nodeId, endpointId, clusterId },\n } = entry;\n const pathId = `${nodeId}-${endpointId}-${clusterId}`;\n attributeUpdates[pathId] = attributeUpdates[pathId] ?? [];\n attributeUpdates[pathId].push(entry);\n });\n this.outstandingAttributeUpdates.clear();\n Object.values(attributeUpdates).forEach(data =>\n attributeUpdatesToSend.push(\n ...data.sort(({ version: versionA }, { version: versionB }) => versionA - versionB),\n ),\n );\n\n const eventUpdatesToSend = Array.from(this.outstandingEventUpdates.values());\n this.outstandingEventUpdates.clear();\n this.lastUpdateTimeMs = Time.nowMs();\n\n this.sendingUpdateInProgress = true;\n try {\n await this.sendUpdateMessage(attributeUpdatesToSend, eventUpdatesToSend);\n this.sendUpdateErrorCounter = 0;\n } catch (error) {\n if (this.server.isClosing) {\n // No need to care about resubmissions when the server is closing\n return;\n }\n\n this.sendUpdateErrorCounter++;\n logger.error(\n `Error sending subscription update message (error count=${this.sendUpdateErrorCounter}):`,\n error,\n );\n if (this.sendUpdateErrorCounter <= 2) {\n // fill the data back in the queue to resend with next try\n const newAttributeUpdatesToSend = Array.from(this.outstandingAttributeUpdates.values());\n this.outstandingAttributeUpdates.clear();\n const newEventUpdatesToSend = Array.from(this.outstandingEventUpdates.values());\n this.outstandingEventUpdates.clear();\n [...attributeUpdatesToSend, ...newAttributeUpdatesToSend].forEach(update =>\n this.outstandingAttributeUpdates.set(attributePathToId(update.path), update),\n );\n [...eventUpdatesToSend, ...newEventUpdatesToSend].forEach(update =>\n this.outstandingEventUpdates.add(update),\n );\n } else {\n logger.error(\n `Sending update failed 3 times in a row, canceling subscription ${this.subscriptionId} and let controller subscribe again.`,\n );\n this.sendNextUpdateImmediately = false;\n if (error instanceof RetransmissionLimitReachedError || error instanceof NetworkError) {\n // We could not send at all, consider session as dead\n await this.session.destroy(false);\n } else {\n throw error;\n }\n }\n }\n this.sendingUpdateInProgress = false;\n\n if (this.sendNextUpdateImmediately) {\n logger.debug(\"Sending delayed update immediately after last one was sent.\");\n this.sendNextUpdateImmediately = false;\n await this.sendUpdate();\n }\n }\n\n async sendInitialReport(messenger: InteractionServerMessenger) {\n this.updateTimer.stop();\n\n const { newAttributes, attributeErrors } = this.registerNewAttributes();\n\n const dataVersionFilterMap = new Map<string, number>(\n this.dataVersionFilters?.map(({ path, dataVersion }) => [clusterPathToId(path), dataVersion]) ?? [],\n );\n\n let attributesFilteredWithVersion = false;\n const attributes = new Array<{\n path: TypeFromSchema<typeof TlvAttributePath>;\n value: any;\n version: number;\n schema: TlvSchema<any>;\n attribute: AnyAttributeServer<any>;\n }>();\n for (const { path, attribute } of newAttributes) {\n try {\n const { value, version } = await this.readAttribute(path, attribute);\n if (value === undefined) continue;\n\n const { nodeId, endpointId, clusterId } = path;\n\n const versionFilterValue =\n endpointId !== undefined && clusterId !== undefined\n ? dataVersionFilterMap.get(clusterPathToId({ nodeId, endpointId, clusterId }))\n : undefined;\n if (versionFilterValue !== undefined && versionFilterValue === version) {\n attributesFilteredWithVersion = true;\n continue;\n }\n\n attributes.push({ path, value, version, schema: attribute.schema, attribute });\n } catch (error) {\n logger.error(`Error reading attribute ${this.endpointStructure.resolveAttributeName(path)}:`, error);\n }\n }\n const attributeReportsPayload: AttributeReportPayload[] = attributes.map(\n ({ path, schema, value, version, attribute }) => ({\n hasFabricSensitiveData: attribute.hasFabricSensitiveData,\n attributeData: {\n path,\n dataVersion: version,\n payload: value,\n schema,\n },\n }),\n );\n attributeErrors.forEach(attributeStatus =>\n attributeReportsPayload.push({\n hasFabricSensitiveData: false,\n attributeStatus,\n }),\n );\n\n const { newEvents, eventErrors } = this.registerNewEvents();\n\n let eventsFiltered = false;\n const eventReportsPayload = new Array<EventReportPayload>();\n for (const { path, event } of newEvents) {\n const { schema } = event;\n try {\n const matchingEvents = await this.readEvent(path, event, this.eventFilters);\n if (matchingEvents.length === 0) {\n eventsFiltered = true;\n } else {\n matchingEvents.forEach(({ eventNumber, priority, epochTimestamp, data }) => {\n eventReportsPayload.push({\n hasFabricSensitiveData: event.hasFabricSensitiveData,\n eventData: {\n path,\n eventNumber,\n priority,\n epochTimestamp,\n payload: data,\n schema,\n },\n });\n });\n }\n } catch (error) {\n logger.error(`Error reading event ${this.endpointStructure.resolveEventName(path)}:`, error);\n }\n }\n eventReportsPayload.sort((a, b) => {\n const eventNumberA = a.eventData?.eventNumber ?? 0;\n const eventNumberB = b.eventData?.eventNumber ?? 0;\n if (eventNumberA > eventNumberB) {\n return 1;\n } else if (eventNumberA < eventNumberB) {\n return -1;\n } else {\n return 0;\n }\n });\n\n if (\n attributes.length === 0 &&\n !attributesFilteredWithVersion &&\n eventReportsPayload.length === 0 &&\n !eventsFiltered\n ) {\n throw new StatusResponseError(\n \"Subscription failed because no attributes or events are matching the query\",\n StatusCode.InvalidAction,\n );\n }\n\n eventErrors.forEach(eventStatus =>\n eventReportsPayload.push({\n hasFabricSensitiveData: false,\n eventStatus,\n }),\n );\n\n logger.debug(\n `Initialize Subscription with ${attributes.length} attributes and ${eventReportsPayload.length} events.`,\n );\n this.lastUpdateTimeMs = Time.nowMs();\n\n await messenger.sendDataReport(\n {\n suppressResponse: false, // we always need proper response for initial report\n subscriptionId: this.subscriptionId,\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n attributeReportsPayload,\n eventReportsPayload,\n },\n this.isFabricFiltered,\n );\n }\n\n attributeChangeListener<T>(path: AttributePath, schema: TlvSchema<T>, version: number, value: T) {\n const changeResult = this.attributeChangeHandler(path, schema, version, value);\n if (MaybePromise.is(changeResult)) {\n const resolver = Promise.resolve(changeResult)\n .catch(error => logger.error(`Error handling attribute change:`, error))\n .finally(() => this.attributeUpdatePromises.delete(resolver));\n this.attributeUpdatePromises.add(resolver);\n }\n }\n\n attributeChangeHandler<T>(\n path: AttributePath,\n schema: TlvSchema<T>,\n version: number,\n value: T,\n ): MaybePromise<void> {\n const attributeListenerData = this.attributeListeners.get(attributePathToId(path));\n if (attributeListenerData === undefined) return; // Ignore changes to attributes that are not subscribed to\n\n const { attribute } = attributeListenerData;\n if (attribute instanceof FabricScopedAttributeServer) {\n // We cannot be sure what value we got for fabric filtered attributes (and from which fabric),\n // so get it again for this relevant fabric. This also makes sure that fabric sensitive fields are filtered\n // TODO: Maybe add try/catch when we add ACL handling and ignore the update if we cannot get the value?\n return this.readAttribute(path, attribute).then(({ value }) => {\n this.outstandingAttributeUpdates.set(attributePathToId(path), {\n attribute,\n path,\n schema,\n version,\n value,\n });\n this.prepareDataUpdate();\n });\n }\n this.outstandingAttributeUpdates.set(attributePathToId(path), { attribute, path, schema, version, value });\n this.prepareDataUpdate();\n }\n\n eventChangeListener<T>(path: EventPath, schema: TlvSchema<T>, newEvent: EventStorageData<T>) {\n const eventListenerData = this.eventListeners.get(eventPathToId(path));\n if (eventListenerData === undefined) return; // Ignore changes to attributes that are not subscribed to\n\n const { event } = eventListenerData;\n if (event instanceof FabricSensitiveEventServer) {\n const { data } = newEvent;\n if (isObject(data) && \"fabricIndex\" in data && data.fabricIndex !== this.session.fabric?.fabricIndex) {\n // Ignore events from different fabrics because events are kind of always fabric filtered\n return;\n }\n }\n this.outstandingEventUpdates.add({ event, path, schema, data: newEvent });\n if (path.isUrgent) {\n this.prepareDataUpdate();\n }\n }\n\n async flush() {\n this.sendDelayTimer.stop();\n logger.debug(\n `Flushing subscription ${this.subscriptionId} with ${this.outstandingAttributeUpdates.size} attributes and ${this.outstandingEventUpdates.size} events`,\n );\n if (this.outstandingAttributeUpdates.size > 0 || this.outstandingEventUpdates.size > 0) {\n void this.sendUpdate();\n }\n }\n\n async cancel(flush = false, cancelledByPeer = false) {\n this.sendUpdatesActivated = false;\n if (this.attributeUpdatePromises.size) {\n const resolvers = [...this.attributeUpdatePromises.values()];\n this.attributeUpdatePromises.clear();\n await Promise.all(resolvers);\n }\n this.updateTimer.stop();\n this.sendDelayTimer.stop();\n this.unregisterAttributeListeners(Array.from(this.attributeListeners.keys()));\n this.unregisterEventListeners(Array.from(this.eventListeners.keys()));\n if (flush) {\n await this.flush();\n }\n this.session.removeSubscription(this.subscriptionId);\n this.cancelCallback();\n if (cancelledByPeer) {\n await this.session.context.startAnnouncement();\n }\n }\n\n private async sendUpdateMessage(\n attributes: AttributePathWithValueVersion<any>[],\n events: EventPathWithEventData<any>[],\n ) {\n logger.debug(\n `Sending subscription update message for ID ${this.subscriptionId} with ${attributes.length} attributes and ${events.length} events`,\n );\n const exchange = this.server.initiateExchange(this.fabric, this.peerNodeId, INTERACTION_PROTOCOL_ID);\n if (exchange === undefined) return;\n logger.debug(\n `Sending subscription changes for ID ${this.subscriptionId}: ${attributes\n .map(\n ({ path, value, version }) =>\n `${this.endpointStructure.resolveAttributeName(path)}=${Logger.toJSON(value)} (${version})`,\n )\n .join(\", \")}`,\n ); // TODO Format path better using endpoint structure\n const messenger = new InteractionServerMessenger(exchange);\n\n try {\n if (attributes.length === 0 && events.length === 0) {\n await messenger.sendDataReport(\n {\n suppressResponse: true, // suppressResponse true for empty DataReports\n subscriptionId: this.subscriptionId,\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n },\n this.isFabricFiltered,\n );\n } else {\n await messenger.sendDataReport(\n {\n suppressResponse: false, // Non empty data reports always need to send response\n subscriptionId: this.subscriptionId,\n interactionModelRevision: INTERACTION_MODEL_REVISION,\n attributeReportsPayload: attributes.map(({ path, schema, value, version, attribute }) => ({\n hasFabricSensitiveData: attribute.hasFabricSensitiveData,\n attributeData: {\n path,\n dataVersion: version,\n schema,\n payload: value,\n },\n })),\n eventReportsPayload: events.map(({ path, schema, event, data }) => {\n const { eventNumber, priority, epochTimestamp, data: payload } = data;\n return {\n hasFabricSensitiveData: event.hasFabricSensitiveData,\n eventData: {\n path,\n eventNumber,\n priority,\n epochTimestamp,\n schema,\n payload,\n },\n };\n }),\n },\n this.isFabricFiltered,\n );\n }\n } catch (error) {\n if (StatusResponseError.is(error, StatusCode.InvalidSubscription, StatusCode.Failure)) {\n logger.info(`Subscription ${this.subscriptionId} cancelled by peer.`);\n await this.cancel(false, true);\n } else {\n StatusResponseError.accept(error);\n await this.cancel(false);\n }\n } finally {\n await messenger.close();\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["path", "value"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DescriptorServer.d.ts","sourceRoot":"","sources":["../../../../../src/behavior/definitions/descriptor/DescriptorServer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,mDAAmD,CAAC;AAC/E,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAG5D,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAKjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,kBAAkB;;IACpD,OAAgB,YAAY,2BAAmB;IAEhC,UAAU;
|
|
1
|
+
{"version":3,"file":"DescriptorServer.d.ts","sourceRoot":"","sources":["../../../../../src/behavior/definitions/descriptor/DescriptorServer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,mDAAmD,CAAC;AAC/E,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAG5D,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAKjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,kBAAkB;;IACpD,OAAgB,YAAY,2BAAmB;IAEhC,UAAU;IAqDzB;;;;OAIG;IACH,cAAc,CAAC,GAAG,WAAW,EAAE,CAAC,gBAAgB,CAAC,UAAU,GAAG,MAAM,CAAC,EAAE;IAsBvE;;;;OAIG;IACH,OAAO,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE;IA0BzB;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,YAAY;CAoGnC;AAED,yBAAiB,gBAAgB,CAAC;IAC9B,KAAY,UAAU,GAAG,cAAc,CAAC,OAAO,UAAU,CAAC,aAAa,CAAC,CAAC;CAC5E"}
|