@matter/protocol 0.13.1-alpha.0-20250509-28e1567e1 → 0.13.1-alpha.0-20250515-a4c61c546
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/action/protocols.d.ts +59 -2
- package/dist/cjs/action/protocols.d.ts.map +1 -1
- package/dist/cjs/action/request/Read.d.ts +2 -2
- package/dist/cjs/action/request/Read.d.ts.map +1 -1
- package/dist/cjs/action/request/Read.js +4 -4
- package/dist/cjs/action/request/Read.js.map +1 -1
- package/dist/cjs/action/response/ReadResult.d.ts +6 -2
- package/dist/cjs/action/response/ReadResult.d.ts.map +1 -1
- package/dist/cjs/action/server/AttributeResponse.d.ts +46 -17
- package/dist/cjs/action/server/AttributeResponse.d.ts.map +1 -1
- package/dist/cjs/action/server/AttributeResponse.js +128 -110
- package/dist/cjs/action/server/AttributeResponse.js.map +2 -2
- package/dist/cjs/action/server/AttributeSubscriptionResponse.d.ts +36 -0
- package/dist/cjs/action/server/AttributeSubscriptionResponse.d.ts.map +1 -0
- package/dist/cjs/action/server/AttributeSubscriptionResponse.js +86 -0
- package/dist/cjs/action/server/AttributeSubscriptionResponse.js.map +6 -0
- package/dist/cjs/action/server/DataResponse.d.ts +45 -0
- package/dist/cjs/action/server/DataResponse.d.ts.map +1 -0
- package/dist/cjs/action/server/DataResponse.js +69 -0
- package/dist/cjs/action/server/DataResponse.js.map +6 -0
- package/dist/cjs/action/server/EventResponse.d.ts +28 -0
- package/dist/cjs/action/server/EventResponse.d.ts.map +1 -0
- package/dist/cjs/action/server/EventResponse.js +318 -0
- package/dist/cjs/action/server/EventResponse.js.map +6 -0
- package/dist/cjs/action/server/ServerInteraction.d.ts.map +1 -1
- package/dist/cjs/action/server/ServerInteraction.js +15 -2
- package/dist/cjs/action/server/ServerInteraction.js.map +1 -1
- package/dist/cjs/action/server/index.d.ts +3 -0
- package/dist/cjs/action/server/index.d.ts.map +1 -1
- package/dist/cjs/action/server/index.js +3 -0
- package/dist/cjs/action/server/index.js.map +1 -1
- package/dist/cjs/events/OccurrenceManager.d.ts +20 -11
- package/dist/cjs/events/OccurrenceManager.d.ts.map +1 -1
- package/dist/cjs/events/OccurrenceManager.js +113 -74
- package/dist/cjs/events/OccurrenceManager.js.map +1 -1
- package/dist/cjs/interaction/InteractionMessenger.d.ts +14 -2
- package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionMessenger.js +87 -3
- package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
- package/dist/cjs/interaction/index.d.ts +0 -1
- package/dist/cjs/interaction/index.d.ts.map +1 -1
- package/dist/cjs/interaction/index.js +0 -1
- package/dist/cjs/interaction/index.js.map +1 -1
- package/dist/cjs/peer/ControllerCommissioningFlow.js +1 -1
- package/dist/cjs/protocol/MessageExchange.d.ts.map +1 -1
- package/dist/cjs/protocol/MessageExchange.js +11 -1
- package/dist/cjs/protocol/MessageExchange.js.map +1 -1
- package/dist/esm/action/protocols.d.ts +59 -2
- package/dist/esm/action/protocols.d.ts.map +1 -1
- package/dist/esm/action/request/Read.d.ts +2 -2
- package/dist/esm/action/request/Read.d.ts.map +1 -1
- package/dist/esm/action/request/Read.js +4 -4
- package/dist/esm/action/request/Read.js.map +1 -1
- package/dist/esm/action/response/ReadResult.d.ts +6 -2
- package/dist/esm/action/response/ReadResult.d.ts.map +1 -1
- package/dist/esm/action/server/AttributeResponse.d.ts +46 -17
- package/dist/esm/action/server/AttributeResponse.d.ts.map +1 -1
- package/dist/esm/action/server/AttributeResponse.js +129 -113
- package/dist/esm/action/server/AttributeResponse.js.map +1 -1
- package/dist/esm/action/server/AttributeSubscriptionResponse.d.ts +36 -0
- package/dist/esm/action/server/AttributeSubscriptionResponse.d.ts.map +1 -0
- package/dist/esm/action/server/AttributeSubscriptionResponse.js +66 -0
- package/dist/esm/action/server/AttributeSubscriptionResponse.js.map +6 -0
- package/dist/esm/action/server/DataResponse.d.ts +45 -0
- package/dist/esm/action/server/DataResponse.d.ts.map +1 -0
- package/dist/esm/action/server/DataResponse.js +49 -0
- package/dist/esm/action/server/DataResponse.js.map +6 -0
- package/dist/esm/action/server/EventResponse.d.ts +28 -0
- package/dist/esm/action/server/EventResponse.d.ts.map +1 -0
- package/dist/esm/action/server/EventResponse.js +305 -0
- package/dist/esm/action/server/EventResponse.js.map +6 -0
- package/dist/esm/action/server/ServerInteraction.d.ts.map +1 -1
- package/dist/esm/action/server/ServerInteraction.js +16 -3
- package/dist/esm/action/server/ServerInteraction.js.map +1 -1
- package/dist/esm/action/server/index.d.ts +3 -0
- package/dist/esm/action/server/index.d.ts.map +1 -1
- package/dist/esm/action/server/index.js +3 -0
- package/dist/esm/action/server/index.js.map +1 -1
- package/dist/esm/events/OccurrenceManager.d.ts +20 -11
- package/dist/esm/events/OccurrenceManager.d.ts.map +1 -1
- package/dist/esm/events/OccurrenceManager.js +117 -80
- package/dist/esm/events/OccurrenceManager.js.map +1 -1
- package/dist/esm/interaction/InteractionMessenger.d.ts +14 -2
- package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionMessenger.js +87 -3
- package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
- package/dist/esm/interaction/index.d.ts +0 -1
- package/dist/esm/interaction/index.d.ts.map +1 -1
- package/dist/esm/interaction/index.js +0 -1
- package/dist/esm/interaction/index.js.map +1 -1
- package/dist/esm/peer/ControllerCommissioningFlow.js +1 -1
- package/dist/esm/protocol/MessageExchange.d.ts.map +1 -1
- package/dist/esm/protocol/MessageExchange.js +11 -1
- package/dist/esm/protocol/MessageExchange.js.map +1 -1
- package/package.json +6 -6
- package/src/action/protocols.ts +68 -2
- package/src/action/request/Read.ts +2 -2
- package/src/action/response/ReadResult.ts +8 -1
- package/src/action/server/AttributeResponse.ts +145 -118
- package/src/action/server/AttributeSubscriptionResponse.ts +90 -0
- package/src/action/server/DataResponse.ts +70 -0
- package/src/action/server/EventResponse.ts +381 -0
- package/src/action/server/ServerInteraction.ts +18 -4
- package/src/action/server/index.ts +3 -0
- package/src/events/OccurrenceManager.ts +126 -100
- package/src/interaction/InteractionMessenger.ts +93 -8
- package/src/interaction/index.ts +0 -1
- package/src/peer/ControllerCommissioningFlow.ts +1 -1
- package/src/protocol/MessageExchange.ts +13 -1
- package/dist/cjs/interaction/ServerSubscription.d.ts +0 -116
- package/dist/cjs/interaction/ServerSubscription.d.ts.map +0 -1
- package/dist/cjs/interaction/ServerSubscription.js +0 -778
- package/dist/cjs/interaction/ServerSubscription.js.map +0 -6
- package/dist/esm/interaction/ServerSubscription.d.ts +0 -116
- package/dist/esm/interaction/ServerSubscription.d.ts.map +0 -1
- package/dist/esm/interaction/ServerSubscription.js +0 -778
- package/dist/esm/interaction/ServerSubscription.js.map +0 -6
- package/src/interaction/ServerSubscription.ts +0 -1038
|
@@ -1,778 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
import {
|
|
7
|
-
Diagnostic,
|
|
8
|
-
InternalError,
|
|
9
|
-
Logger,
|
|
10
|
-
MatterAggregateError,
|
|
11
|
-
MatterError,
|
|
12
|
-
MaybePromise,
|
|
13
|
-
NetworkError,
|
|
14
|
-
NoResponseTimeoutError,
|
|
15
|
-
Time,
|
|
16
|
-
isObject
|
|
17
|
-
} from "#general";
|
|
18
|
-
import { Specification } from "#model";
|
|
19
|
-
import {
|
|
20
|
-
EventNumber,
|
|
21
|
-
INTERACTION_PROTOCOL_ID,
|
|
22
|
-
StatusCode,
|
|
23
|
-
StatusResponseError
|
|
24
|
-
} from "#types";
|
|
25
|
-
import { FabricScopedAttributeServer } from "../cluster/server/AttributeServer.js";
|
|
26
|
-
import { FabricSensitiveEventServer } from "../cluster/server/EventServer.js";
|
|
27
|
-
import { NoChannelError } from "../protocol/ChannelManager.js";
|
|
28
|
-
import {
|
|
29
|
-
attributePathToId,
|
|
30
|
-
clusterPathToId,
|
|
31
|
-
eventPathToId
|
|
32
|
-
} from "./InteractionEndpointStructure.js";
|
|
33
|
-
import { InteractionServerMessenger } from "./InteractionMessenger.js";
|
|
34
|
-
import { Subscription } from "./Subscription.js";
|
|
35
|
-
const logger = Logger.get("ServerSubscription");
|
|
36
|
-
const MAX_INTERVAL_PUBLISHER_LIMIT_S = 60 * 60;
|
|
37
|
-
const INTERNAL_INTERVAL_PUBLISHER_LIMIT_S = 3 * 60;
|
|
38
|
-
const MIN_INTERVAL_S = 2;
|
|
39
|
-
const DEFAULT_RANDOMIZATION_WINDOW_S = 10;
|
|
40
|
-
var ServerSubscriptionConfig;
|
|
41
|
-
((ServerSubscriptionConfig2) => {
|
|
42
|
-
function of(options) {
|
|
43
|
-
return {
|
|
44
|
-
maxIntervalSeconds: options?.maxIntervalSeconds ?? INTERNAL_INTERVAL_PUBLISHER_LIMIT_S,
|
|
45
|
-
minIntervalSeconds: Math.max(options?.minIntervalSeconds ?? MIN_INTERVAL_S, MIN_INTERVAL_S),
|
|
46
|
-
randomizationWindowSeconds: options?.randomizationWindowSeconds ?? DEFAULT_RANDOMIZATION_WINDOW_S
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
ServerSubscriptionConfig2.of = of;
|
|
50
|
-
})(ServerSubscriptionConfig || (ServerSubscriptionConfig = {}));
|
|
51
|
-
class ServerSubscription extends Subscription {
|
|
52
|
-
#context;
|
|
53
|
-
#structure;
|
|
54
|
-
#lastUpdateTimeMs = 0;
|
|
55
|
-
#updateTimer;
|
|
56
|
-
#sendDelayTimer = Time.getTimer(
|
|
57
|
-
`Subscription ${this.id} delay`,
|
|
58
|
-
50,
|
|
59
|
-
() => this.#triggerSendUpdate()
|
|
60
|
-
);
|
|
61
|
-
#outstandingAttributeUpdates = /* @__PURE__ */ new Map();
|
|
62
|
-
#outstandingEventUpdates = /* @__PURE__ */ new Set();
|
|
63
|
-
#attributeListeners = /* @__PURE__ */ new Map();
|
|
64
|
-
#eventListeners = /* @__PURE__ */ new Map();
|
|
65
|
-
#sendUpdatesActivated = false;
|
|
66
|
-
#sendIntervalMs;
|
|
67
|
-
#minIntervalFloorMs;
|
|
68
|
-
#maxIntervalCeilingMs;
|
|
69
|
-
#peerAddress;
|
|
70
|
-
#sendNextUpdateImmediately = false;
|
|
71
|
-
#sendUpdateErrorCounter = 0;
|
|
72
|
-
#attributeUpdatePromises = /* @__PURE__ */ new Set();
|
|
73
|
-
#currentUpdatePromise;
|
|
74
|
-
constructor(options) {
|
|
75
|
-
const {
|
|
76
|
-
id,
|
|
77
|
-
context,
|
|
78
|
-
criteria,
|
|
79
|
-
minIntervalFloorSeconds,
|
|
80
|
-
maxIntervalCeilingSeconds,
|
|
81
|
-
subscriptionOptions,
|
|
82
|
-
useAsMaxInterval,
|
|
83
|
-
useAsSendInterval
|
|
84
|
-
} = options;
|
|
85
|
-
super(context.session, id, criteria);
|
|
86
|
-
this.#context = context;
|
|
87
|
-
this.#structure = context.structure;
|
|
88
|
-
this.#peerAddress = this.session.peerAddress;
|
|
89
|
-
this.#minIntervalFloorMs = minIntervalFloorSeconds * 1e3;
|
|
90
|
-
this.#maxIntervalCeilingMs = maxIntervalCeilingSeconds * 1e3;
|
|
91
|
-
let maxInterval;
|
|
92
|
-
let sendInterval;
|
|
93
|
-
if (useAsMaxInterval !== void 0 && useAsSendInterval !== void 0) {
|
|
94
|
-
maxInterval = useAsMaxInterval * 1e3;
|
|
95
|
-
sendInterval = useAsSendInterval * 1e3;
|
|
96
|
-
} else {
|
|
97
|
-
({ maxInterval, sendInterval } = this.#determineSendingIntervals(
|
|
98
|
-
subscriptionOptions.minIntervalSeconds * 1e3,
|
|
99
|
-
subscriptionOptions.maxIntervalSeconds * 1e3,
|
|
100
|
-
subscriptionOptions.randomizationWindowSeconds * 1e3
|
|
101
|
-
));
|
|
102
|
-
}
|
|
103
|
-
this.maxIntervalMs = maxInterval;
|
|
104
|
-
this.#sendIntervalMs = sendInterval;
|
|
105
|
-
this.#updateTimer = Time.getTimer(
|
|
106
|
-
`Subscription ${this.id} update`,
|
|
107
|
-
this.#sendIntervalMs,
|
|
108
|
-
() => this.#prepareDataUpdate()
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
#determineSendingIntervals(subscriptionMinIntervalMs, subscriptionMaxIntervalMs, subscriptionRandomizationWindowMs) {
|
|
112
|
-
const maxInterval = Math.min(
|
|
113
|
-
Math.max(
|
|
114
|
-
subscriptionMinIntervalMs,
|
|
115
|
-
Math.max(this.#minIntervalFloorMs, Math.min(subscriptionMaxIntervalMs, this.#maxIntervalCeilingMs))
|
|
116
|
-
) + Math.floor(subscriptionRandomizationWindowMs * Math.random()),
|
|
117
|
-
MAX_INTERVAL_PUBLISHER_LIMIT_S * 1e3
|
|
118
|
-
);
|
|
119
|
-
let sendInterval = Math.floor(maxInterval / 2);
|
|
120
|
-
if (sendInterval < 6e4) {
|
|
121
|
-
sendInterval = Math.max(this.#minIntervalFloorMs, Math.floor(maxInterval * 0.8));
|
|
122
|
-
}
|
|
123
|
-
if (sendInterval < subscriptionMinIntervalMs) {
|
|
124
|
-
logger.warn(
|
|
125
|
-
`Determined subscription send interval of ${sendInterval}ms is too low. Using maxInterval (${maxInterval}ms) instead.`
|
|
126
|
-
);
|
|
127
|
-
sendInterval = subscriptionMinIntervalMs;
|
|
128
|
-
}
|
|
129
|
-
return { maxInterval, sendInterval };
|
|
130
|
-
}
|
|
131
|
-
#registerNewAttributes() {
|
|
132
|
-
const newAttributes = new Array();
|
|
133
|
-
const attributeErrors = new Array();
|
|
134
|
-
const formerAttributes = new Set(this.#attributeListeners.keys());
|
|
135
|
-
if (this.criteria.attributeRequests !== void 0) {
|
|
136
|
-
this.criteria.attributeRequests.forEach((path) => {
|
|
137
|
-
const attributes = this.#structure.getAttributes([path]);
|
|
138
|
-
if (attributes.length === 0) {
|
|
139
|
-
const { endpointId, clusterId, attributeId } = path;
|
|
140
|
-
if (endpointId === void 0 || clusterId === void 0 || attributeId === void 0) {
|
|
141
|
-
logger.debug(
|
|
142
|
-
`Subscription attribute ${this.#structure.resolveAttributeName(
|
|
143
|
-
path
|
|
144
|
-
)}: ignore non-existing attribute`
|
|
145
|
-
);
|
|
146
|
-
} else {
|
|
147
|
-
try {
|
|
148
|
-
this.#structure.validateConcreteAttributePath(endpointId, clusterId, attributeId);
|
|
149
|
-
throw new InternalError(
|
|
150
|
-
"validateConcreteAttributePath check should throw StatusResponseError but did not."
|
|
151
|
-
);
|
|
152
|
-
} catch (e) {
|
|
153
|
-
StatusResponseError.accept(e);
|
|
154
|
-
logger.debug(
|
|
155
|
-
`Subscription attribute ${this.#structure.resolveAttributeName(
|
|
156
|
-
path
|
|
157
|
-
)}: unsupported path: Status=${e.code}`
|
|
158
|
-
);
|
|
159
|
-
attributeErrors.push({ path, status: { status: e.code } });
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
attributes.forEach(({ path: path2, attribute }) => {
|
|
165
|
-
formerAttributes.delete(attributePathToId(path2));
|
|
166
|
-
const existingAttributeListener = this.#attributeListeners.get(attributePathToId(path2));
|
|
167
|
-
if (existingAttributeListener !== void 0) {
|
|
168
|
-
const { attribute: existingAttribute, listener: existingListener } = existingAttributeListener;
|
|
169
|
-
if (existingAttribute !== attribute) {
|
|
170
|
-
if (existingListener !== void 0) {
|
|
171
|
-
existingAttribute.removeValueChangeListener(existingListener);
|
|
172
|
-
}
|
|
173
|
-
this.#attributeListeners.delete(attributePathToId(path2));
|
|
174
|
-
} else {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
if (attribute.isSubscribable) {
|
|
179
|
-
const listener = (value, version) => this.attributeChangeListener(path2, attribute.schema, version, value);
|
|
180
|
-
attribute.addValueChangeListener(listener);
|
|
181
|
-
this.#attributeListeners.set(attributePathToId(path2), { attribute, listener });
|
|
182
|
-
} else {
|
|
183
|
-
this.#attributeListeners.set(attributePathToId(path2), { attribute });
|
|
184
|
-
}
|
|
185
|
-
newAttributes.push({ path: path2, attribute });
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
this.unregisterAttributeListeners(Array.from(formerAttributes.values()));
|
|
190
|
-
return { newAttributes, attributeErrors };
|
|
191
|
-
}
|
|
192
|
-
unregisterAttributeListeners(list) {
|
|
193
|
-
for (const pathId of list) {
|
|
194
|
-
const existingAttributeListener = this.#attributeListeners.get(pathId);
|
|
195
|
-
if (existingAttributeListener !== void 0) {
|
|
196
|
-
const { attribute, listener } = existingAttributeListener;
|
|
197
|
-
if (listener !== void 0) {
|
|
198
|
-
attribute.removeValueChangeListener(listener);
|
|
199
|
-
}
|
|
200
|
-
this.#attributeListeners.delete(pathId);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
#registerNewEvents() {
|
|
205
|
-
const newEvents = new Array();
|
|
206
|
-
const eventErrors = new Array();
|
|
207
|
-
const formerEvents = new Set(this.#eventListeners.keys());
|
|
208
|
-
if (this.criteria.eventRequests !== void 0) {
|
|
209
|
-
this.criteria.eventRequests.forEach((path) => {
|
|
210
|
-
const events = this.#structure.getEvents([path]);
|
|
211
|
-
if (events.length === 0) {
|
|
212
|
-
const { endpointId, clusterId, eventId } = path;
|
|
213
|
-
if (endpointId === void 0 || clusterId === void 0 || eventId === void 0) {
|
|
214
|
-
logger.debug(
|
|
215
|
-
`Subscription event ${this.#structure.resolveEventName(path)}: ignore non-existing event`
|
|
216
|
-
);
|
|
217
|
-
} else {
|
|
218
|
-
try {
|
|
219
|
-
this.#structure.validateConcreteEventPath(endpointId, clusterId, eventId);
|
|
220
|
-
throw new InternalError(
|
|
221
|
-
"validateConcreteEventPath should throw StatusResponseError but did not."
|
|
222
|
-
);
|
|
223
|
-
} catch (e) {
|
|
224
|
-
StatusResponseError.accept(e);
|
|
225
|
-
logger.debug(
|
|
226
|
-
`Subscription event ${this.#structure.resolveEventName(
|
|
227
|
-
path
|
|
228
|
-
)}: unsupported path: Status=${e.code}`
|
|
229
|
-
);
|
|
230
|
-
eventErrors.push({ path, status: { status: e.code } });
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
events.forEach(({ path: path2, event }) => {
|
|
236
|
-
formerEvents.delete(eventPathToId(path2));
|
|
237
|
-
const existingEventListener = this.#eventListeners.get(eventPathToId(path2));
|
|
238
|
-
if (existingEventListener !== void 0) {
|
|
239
|
-
const { event: existingEvent, listener: existingListener } = existingEventListener;
|
|
240
|
-
if (existingEvent !== event) {
|
|
241
|
-
if (existingListener !== void 0) {
|
|
242
|
-
existingEvent.removeListener(existingListener);
|
|
243
|
-
}
|
|
244
|
-
this.#eventListeners.delete(eventPathToId(path2));
|
|
245
|
-
} else {
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
const listener = (newEvent) => this.eventChangeListener(path2, event.schema, newEvent);
|
|
250
|
-
event.addListener(listener);
|
|
251
|
-
newEvents.push({ path: path2, event });
|
|
252
|
-
this.#eventListeners.set(eventPathToId(path2), { event, listener });
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
this.unregisterEventListeners(Array.from(formerEvents.values()));
|
|
257
|
-
return { newEvents, eventErrors };
|
|
258
|
-
}
|
|
259
|
-
unregisterEventListeners(list) {
|
|
260
|
-
for (const pathId of list) {
|
|
261
|
-
const existingEventListener = this.#eventListeners.get(pathId);
|
|
262
|
-
if (existingEventListener !== void 0) {
|
|
263
|
-
const { event, listener } = existingEventListener;
|
|
264
|
-
if (listener !== void 0) {
|
|
265
|
-
event.removeListener(listener);
|
|
266
|
-
}
|
|
267
|
-
this.#eventListeners.delete(pathId);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Update the session after an endpoint structure change. The method will initialize all missing new attributes and
|
|
273
|
-
* events and will remove listeners no longer needed.
|
|
274
|
-
* Newly added attributes are then treated as "changed values" and will be sent as subscription data update to the
|
|
275
|
-
* controller. The data of newly added events are not sent automatically.
|
|
276
|
-
*/
|
|
277
|
-
async updateSubscription() {
|
|
278
|
-
const { newAttributes } = this.#registerNewAttributes();
|
|
279
|
-
for (const { path, attribute } of newAttributes) {
|
|
280
|
-
const { version, value } = this.#context.readAttribute(path, attribute);
|
|
281
|
-
this.#outstandingAttributeUpdates.set(attributePathToId(path), {
|
|
282
|
-
attribute,
|
|
283
|
-
path,
|
|
284
|
-
schema: attribute.schema,
|
|
285
|
-
version,
|
|
286
|
-
value
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
const { newEvents } = this.#registerNewEvents();
|
|
290
|
-
const occurrences = Array();
|
|
291
|
-
for (const { path, event } of newEvents) {
|
|
292
|
-
const { schema } = event;
|
|
293
|
-
let eventOccurrences = event.get(
|
|
294
|
-
this.session,
|
|
295
|
-
this.criteria.isFabricFiltered,
|
|
296
|
-
void 0,
|
|
297
|
-
this.criteria.eventFilters
|
|
298
|
-
);
|
|
299
|
-
if (MaybePromise.is(eventOccurrences)) {
|
|
300
|
-
eventOccurrences = await eventOccurrences;
|
|
301
|
-
}
|
|
302
|
-
occurrences.push(
|
|
303
|
-
...eventOccurrences.map((data) => ({
|
|
304
|
-
event,
|
|
305
|
-
schema,
|
|
306
|
-
path,
|
|
307
|
-
data
|
|
308
|
-
}))
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
occurrences.sort((a, b) => {
|
|
312
|
-
const eventNumberA = a.data?.number ?? EventNumber(0);
|
|
313
|
-
const eventNumberB = b.data?.number ?? EventNumber(0);
|
|
314
|
-
if (eventNumberA > eventNumberB) {
|
|
315
|
-
return 1;
|
|
316
|
-
} else if (eventNumberA < eventNumberB) {
|
|
317
|
-
return -1;
|
|
318
|
-
} else {
|
|
319
|
-
return 0;
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
for (const occurrence of occurrences) {
|
|
323
|
-
this.#outstandingEventUpdates.add(occurrence);
|
|
324
|
-
}
|
|
325
|
-
this.#prepareDataUpdate();
|
|
326
|
-
}
|
|
327
|
-
get sendInterval() {
|
|
328
|
-
return Math.ceil(this.#sendIntervalMs / 1e3);
|
|
329
|
-
}
|
|
330
|
-
get minIntervalFloorSeconds() {
|
|
331
|
-
return Math.ceil(this.#minIntervalFloorMs / 1e3);
|
|
332
|
-
}
|
|
333
|
-
get maxIntervalCeilingSeconds() {
|
|
334
|
-
return Math.ceil(this.#maxIntervalCeilingMs / 1e3);
|
|
335
|
-
}
|
|
336
|
-
activate() {
|
|
337
|
-
super.activate();
|
|
338
|
-
if (this.criteria.eventFilters !== void 0) this.criteria.eventFilters.length = 0;
|
|
339
|
-
if (this.criteria.dataVersionFilters !== void 0) this.criteria.dataVersionFilters.length = 0;
|
|
340
|
-
this.#sendUpdatesActivated = true;
|
|
341
|
-
if (this.#outstandingAttributeUpdates.size > 0 || this.#outstandingEventUpdates.size > 0) {
|
|
342
|
-
this.#triggerSendUpdate();
|
|
343
|
-
}
|
|
344
|
-
this.#updateTimer = Time.getTimer(
|
|
345
|
-
"Subscription update",
|
|
346
|
-
this.#sendIntervalMs,
|
|
347
|
-
() => this.#prepareDataUpdate()
|
|
348
|
-
).start();
|
|
349
|
-
this.#structure.change.on(() => {
|
|
350
|
-
if (this.isClosed) {
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
this.updateSubscription().catch(
|
|
354
|
-
(error) => logger.error("Error updating subscription after structure change:", error)
|
|
355
|
-
);
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Check if data should be sent straight away or delayed because the minimum interval is not reached. Delay real
|
|
360
|
-
* sending by 50ms in any case to mke sure to catch all updates.
|
|
361
|
-
*/
|
|
362
|
-
#prepareDataUpdate() {
|
|
363
|
-
if (this.#sendDelayTimer.isRunning || this.isClosed) {
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
if (!this.#sendUpdatesActivated) {
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
this.#updateTimer.stop();
|
|
370
|
-
const now = Time.nowMs();
|
|
371
|
-
const timeSinceLastUpdateMs = now - this.#lastUpdateTimeMs;
|
|
372
|
-
if (timeSinceLastUpdateMs < this.#minIntervalFloorMs) {
|
|
373
|
-
this.#updateTimer = Time.getTimer(
|
|
374
|
-
"Subscription update",
|
|
375
|
-
this.#minIntervalFloorMs - timeSinceLastUpdateMs,
|
|
376
|
-
() => this.#prepareDataUpdate()
|
|
377
|
-
).start();
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
this.#sendDelayTimer.start();
|
|
381
|
-
this.#updateTimer = Time.getTimer(
|
|
382
|
-
`Subscription update ${this.id}`,
|
|
383
|
-
this.#sendIntervalMs,
|
|
384
|
-
() => this.#prepareDataUpdate()
|
|
385
|
-
).start();
|
|
386
|
-
}
|
|
387
|
-
#triggerSendUpdate() {
|
|
388
|
-
if (this.#currentUpdatePromise !== void 0) {
|
|
389
|
-
logger.debug("Sending update already in progress, delaying update ...");
|
|
390
|
-
this.#sendNextUpdateImmediately = true;
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
this.#currentUpdatePromise = this.#sendUpdate().catch((error) => logger.warn("Sending subscription update failed:", error)).finally(() => this.#currentUpdatePromise = void 0);
|
|
394
|
-
}
|
|
395
|
-
/**
|
|
396
|
-
* Determine all attributes that have changed since the last update and send them tout to the subscriber.
|
|
397
|
-
* Important: This method MUST NOT be called directly. Use triggerSendUpdate() instead!
|
|
398
|
-
*/
|
|
399
|
-
async #sendUpdate(onlyWithData = false) {
|
|
400
|
-
const attributeUpdatesToSend = new Array();
|
|
401
|
-
const attributeUpdates = {};
|
|
402
|
-
Array.from(this.#outstandingAttributeUpdates.values()).forEach((entry) => {
|
|
403
|
-
const {
|
|
404
|
-
path: { nodeId, endpointId, clusterId }
|
|
405
|
-
} = entry;
|
|
406
|
-
const pathId = `${nodeId}-${endpointId}-${clusterId}`;
|
|
407
|
-
attributeUpdates[pathId] = attributeUpdates[pathId] ?? [];
|
|
408
|
-
attributeUpdates[pathId].push(entry);
|
|
409
|
-
});
|
|
410
|
-
this.#outstandingAttributeUpdates.clear();
|
|
411
|
-
Object.values(attributeUpdates).forEach(
|
|
412
|
-
(data) => attributeUpdatesToSend.push(
|
|
413
|
-
...data.sort(({ version: versionA }, { version: versionB }) => versionA - versionB)
|
|
414
|
-
)
|
|
415
|
-
);
|
|
416
|
-
const eventUpdatesToSend = Array.from(this.#outstandingEventUpdates.values());
|
|
417
|
-
this.#outstandingEventUpdates.clear();
|
|
418
|
-
if (onlyWithData && attributeUpdatesToSend.length === 0 && eventUpdatesToSend.length === 0) {
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
this.#lastUpdateTimeMs = Time.nowMs();
|
|
422
|
-
try {
|
|
423
|
-
await this.#sendUpdateMessage(attributeUpdatesToSend, eventUpdatesToSend);
|
|
424
|
-
this.#sendUpdateErrorCounter = 0;
|
|
425
|
-
} catch (error) {
|
|
426
|
-
if (this.isClosed) {
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
this.#sendUpdateErrorCounter++;
|
|
430
|
-
logger.info(
|
|
431
|
-
`Error sending subscription update message (error count=${this.#sendUpdateErrorCounter}):`,
|
|
432
|
-
error instanceof MatterError && error.message || error
|
|
433
|
-
);
|
|
434
|
-
if (this.#sendUpdateErrorCounter <= 2) {
|
|
435
|
-
const newAttributeUpdatesToSend = Array.from(this.#outstandingAttributeUpdates.values());
|
|
436
|
-
this.#outstandingAttributeUpdates.clear();
|
|
437
|
-
const newEventUpdatesToSend = Array.from(this.#outstandingEventUpdates.values());
|
|
438
|
-
this.#outstandingEventUpdates.clear();
|
|
439
|
-
[...attributeUpdatesToSend, ...newAttributeUpdatesToSend].forEach(
|
|
440
|
-
(update) => this.#outstandingAttributeUpdates.set(attributePathToId(update.path), update)
|
|
441
|
-
);
|
|
442
|
-
[...eventUpdatesToSend, ...newEventUpdatesToSend].forEach(
|
|
443
|
-
(update) => this.#outstandingEventUpdates.add(update)
|
|
444
|
-
);
|
|
445
|
-
} else {
|
|
446
|
-
logger.info(
|
|
447
|
-
`Sending update failed 3 times in a row, canceling subscription ${this.id} and let controller subscribe again.`
|
|
448
|
-
);
|
|
449
|
-
this.#sendNextUpdateImmediately = false;
|
|
450
|
-
if (error instanceof NoResponseTimeoutError || error instanceof NetworkError || error instanceof NoChannelError) {
|
|
451
|
-
this.isCanceledByPeer = true;
|
|
452
|
-
await this.destroy();
|
|
453
|
-
return;
|
|
454
|
-
} else {
|
|
455
|
-
throw error;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
if (this.#sendNextUpdateImmediately) {
|
|
460
|
-
logger.debug("Sending delayed update immediately after last one was sent.");
|
|
461
|
-
this.#sendNextUpdateImmediately = false;
|
|
462
|
-
await this.#sendUpdate(true);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
async #collectInitialEventReportPayloads(newEvents) {
|
|
466
|
-
let eventsFiltered = false;
|
|
467
|
-
const eventReportsPayload = new Array();
|
|
468
|
-
for (const { path, event } of newEvents) {
|
|
469
|
-
const { schema } = event;
|
|
470
|
-
try {
|
|
471
|
-
const matchingEvents = await this.#context.readEvent(path, event, this.criteria.eventFilters);
|
|
472
|
-
if (matchingEvents.length === 0) {
|
|
473
|
-
eventsFiltered = true;
|
|
474
|
-
} else {
|
|
475
|
-
matchingEvents.forEach(({ number, priority, epochTimestamp, payload }) => {
|
|
476
|
-
eventReportsPayload.push({
|
|
477
|
-
hasFabricSensitiveData: event.hasFabricSensitiveData,
|
|
478
|
-
eventData: {
|
|
479
|
-
path,
|
|
480
|
-
eventNumber: number,
|
|
481
|
-
priority,
|
|
482
|
-
epochTimestamp,
|
|
483
|
-
payload,
|
|
484
|
-
schema
|
|
485
|
-
}
|
|
486
|
-
});
|
|
487
|
-
});
|
|
488
|
-
}
|
|
489
|
-
} catch (error) {
|
|
490
|
-
if (StatusResponseError.is(error, StatusCode.UnsupportedAccess)) {
|
|
491
|
-
logger.warn(`Permission denied reading event ${this.#structure.resolveEventName(path)}`);
|
|
492
|
-
} else {
|
|
493
|
-
logger.warn(`Error reading event ${this.#structure.resolveEventName(path)}:`, error);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
eventReportsPayload.sort((a, b) => {
|
|
498
|
-
const eventNumberA = a.eventData?.eventNumber ?? 0;
|
|
499
|
-
const eventNumberB = b.eventData?.eventNumber ?? 0;
|
|
500
|
-
if (eventNumberA > eventNumberB) {
|
|
501
|
-
return 1;
|
|
502
|
-
} else if (eventNumberA < eventNumberB) {
|
|
503
|
-
return -1;
|
|
504
|
-
} else {
|
|
505
|
-
return 0;
|
|
506
|
-
}
|
|
507
|
-
});
|
|
508
|
-
return { eventReportsPayload, eventsFiltered };
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* Returns an iterator that yields the initial subscription data to be sent to the controller.
|
|
512
|
-
* The iterator will yield all attributes and events that match the subscription criteria.
|
|
513
|
-
* A thrown exception will cancel the sending process immediately.
|
|
514
|
-
* TODO: Streamline all this with the normal Read flow to also handle Concrete Path subscriptions with errors correctly
|
|
515
|
-
*/
|
|
516
|
-
async *#iterateInitialSubscriptionData(attributesToSend, eventsToSend) {
|
|
517
|
-
const dataVersionFilterMap = new Map(
|
|
518
|
-
this.criteria.dataVersionFilters?.map(({ path, dataVersion }) => [clusterPathToId(path), dataVersion]) ?? []
|
|
519
|
-
);
|
|
520
|
-
const { newAttributes, attributeErrors } = attributesToSend;
|
|
521
|
-
const { eventReportsPayload, eventsFiltered, eventErrors } = eventsToSend;
|
|
522
|
-
logger.debug(
|
|
523
|
-
`Initializes Subscription with ${newAttributes.length} attributes and ${eventReportsPayload.length} events.`
|
|
524
|
-
);
|
|
525
|
-
let attributesFilteredWithVersion = false;
|
|
526
|
-
const attributesPerCluster = /* @__PURE__ */ new Map();
|
|
527
|
-
for (const { path, attribute } of newAttributes) {
|
|
528
|
-
const { endpointId } = path;
|
|
529
|
-
const endpointAttributes = attributesPerCluster.get(endpointId) ?? new Array();
|
|
530
|
-
endpointAttributes.push({ path, attribute });
|
|
531
|
-
attributesPerCluster.set(endpointId, endpointAttributes);
|
|
532
|
-
}
|
|
533
|
-
let attributesCounter = 0;
|
|
534
|
-
for (const endpointId of attributesPerCluster.keys()) {
|
|
535
|
-
const endpointAttributes = attributesPerCluster.get(endpointId);
|
|
536
|
-
attributesPerCluster.delete(endpointId);
|
|
537
|
-
for (const { path, attribute, value, version } of this.#context.readEndpointAttributesForSubscription(
|
|
538
|
-
endpointAttributes
|
|
539
|
-
)) {
|
|
540
|
-
if (value === void 0) continue;
|
|
541
|
-
const { nodeId, endpointId: endpointId2, clusterId } = path;
|
|
542
|
-
const versionFilterValue = endpointId2 !== void 0 && clusterId !== void 0 ? dataVersionFilterMap.get(clusterPathToId({ nodeId, endpointId: endpointId2, clusterId })) : void 0;
|
|
543
|
-
if (versionFilterValue !== void 0 && versionFilterValue === version) {
|
|
544
|
-
attributesFilteredWithVersion = true;
|
|
545
|
-
continue;
|
|
546
|
-
}
|
|
547
|
-
attributesCounter++;
|
|
548
|
-
yield {
|
|
549
|
-
hasFabricSensitiveData: attribute.hasFabricSensitiveData,
|
|
550
|
-
attributeData: {
|
|
551
|
-
path,
|
|
552
|
-
dataVersion: version,
|
|
553
|
-
payload: value,
|
|
554
|
-
schema: attribute.schema
|
|
555
|
-
}
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
for (const attributeStatus of attributeErrors) {
|
|
560
|
-
yield {
|
|
561
|
-
hasFabricSensitiveData: false,
|
|
562
|
-
attributeStatus
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
|
-
if (attributesCounter === 0 && !attributesFilteredWithVersion && eventReportsPayload.length === 0 && !eventsFiltered) {
|
|
566
|
-
throw new StatusResponseError(
|
|
567
|
-
"Subscription failed because no attributes or events are matching the query",
|
|
568
|
-
StatusCode.InvalidAction
|
|
569
|
-
);
|
|
570
|
-
}
|
|
571
|
-
for (const eventReport of eventReportsPayload) {
|
|
572
|
-
yield eventReport;
|
|
573
|
-
}
|
|
574
|
-
for (const eventStatus of eventErrors) {
|
|
575
|
-
yield {
|
|
576
|
-
hasFabricSensitiveData: false,
|
|
577
|
-
eventStatus
|
|
578
|
-
};
|
|
579
|
-
}
|
|
580
|
-
this.#lastUpdateTimeMs = Time.nowMs();
|
|
581
|
-
}
|
|
582
|
-
async sendInitialReport(messenger) {
|
|
583
|
-
this.#updateTimer.stop();
|
|
584
|
-
const { newAttributes, attributeErrors } = this.#registerNewAttributes();
|
|
585
|
-
const { newEvents, eventErrors } = this.#registerNewEvents();
|
|
586
|
-
const { eventReportsPayload, eventsFiltered } = await this.#collectInitialEventReportPayloads(newEvents);
|
|
587
|
-
await messenger.sendDataReport(
|
|
588
|
-
{
|
|
589
|
-
suppressResponse: false,
|
|
590
|
-
// we always need proper response for initial report
|
|
591
|
-
subscriptionId: this.id,
|
|
592
|
-
interactionModelRevision: Specification.INTERACTION_MODEL_REVISION
|
|
593
|
-
},
|
|
594
|
-
this.criteria.isFabricFiltered,
|
|
595
|
-
this.#iterateInitialSubscriptionData(
|
|
596
|
-
{ newAttributes, attributeErrors },
|
|
597
|
-
{ eventReportsPayload, eventsFiltered, eventErrors }
|
|
598
|
-
)
|
|
599
|
-
);
|
|
600
|
-
}
|
|
601
|
-
attributeChangeListener(path, schema, version, value) {
|
|
602
|
-
const changeResult = this.attributeChangeHandler(path, schema, version, value);
|
|
603
|
-
if (MaybePromise.is(changeResult)) {
|
|
604
|
-
const resolver = Promise.resolve(changeResult).catch((error) => logger.error(`Error handling attribute change:`, error)).finally(() => this.#attributeUpdatePromises.delete(resolver));
|
|
605
|
-
this.#attributeUpdatePromises.add(resolver);
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
attributeChangeHandler(path, schema, version, value) {
|
|
609
|
-
const attributeListenerData = this.#attributeListeners.get(attributePathToId(path));
|
|
610
|
-
if (attributeListenerData === void 0) return;
|
|
611
|
-
const { attribute } = attributeListenerData;
|
|
612
|
-
if (attribute instanceof FabricScopedAttributeServer) {
|
|
613
|
-
const { value: value2 } = this.#context.readAttribute(path, attribute, true);
|
|
614
|
-
this.#outstandingAttributeUpdates.set(attributePathToId(path), {
|
|
615
|
-
attribute,
|
|
616
|
-
path,
|
|
617
|
-
schema,
|
|
618
|
-
version,
|
|
619
|
-
value: value2
|
|
620
|
-
});
|
|
621
|
-
this.#prepareDataUpdate();
|
|
622
|
-
}
|
|
623
|
-
this.#outstandingAttributeUpdates.set(attributePathToId(path), { attribute, path, schema, version, value });
|
|
624
|
-
this.#prepareDataUpdate();
|
|
625
|
-
}
|
|
626
|
-
eventChangeListener(path, schema, newEvent) {
|
|
627
|
-
const eventListenerData = this.#eventListeners.get(eventPathToId(path));
|
|
628
|
-
if (eventListenerData === void 0) return;
|
|
629
|
-
const { event } = eventListenerData;
|
|
630
|
-
if (event instanceof FabricSensitiveEventServer) {
|
|
631
|
-
const { payload } = newEvent;
|
|
632
|
-
if (isObject(payload) && "fabricIndex" in payload && payload.fabricIndex !== this.session.fabric?.fabricIndex) {
|
|
633
|
-
return;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
this.#outstandingEventUpdates.add({ event, path, schema, data: newEvent });
|
|
637
|
-
if (path.isUrgent) {
|
|
638
|
-
this.#prepareDataUpdate();
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
async #flush() {
|
|
642
|
-
this.#sendDelayTimer.stop();
|
|
643
|
-
if (this.#outstandingAttributeUpdates.size > 0 || this.#outstandingEventUpdates.size > 0) {
|
|
644
|
-
logger.debug(
|
|
645
|
-
`Flushing subscription ${this.id} with ${this.#outstandingAttributeUpdates.size} attributes and ${this.#outstandingEventUpdates.size} events${this.isClosed ? " (for closing)" : ""}`
|
|
646
|
-
);
|
|
647
|
-
this.#triggerSendUpdate();
|
|
648
|
-
if (this.#currentUpdatePromise) {
|
|
649
|
-
await this.#currentUpdatePromise;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
async destroy() {
|
|
654
|
-
this.#sendUpdatesActivated = false;
|
|
655
|
-
this.unregisterAttributeListeners(Array.from(this.#attributeListeners.keys()));
|
|
656
|
-
this.unregisterEventListeners(Array.from(this.#eventListeners.keys()));
|
|
657
|
-
if (this.#attributeUpdatePromises.size) {
|
|
658
|
-
const resolvers = [...this.#attributeUpdatePromises.values()];
|
|
659
|
-
this.#attributeUpdatePromises.clear();
|
|
660
|
-
await MatterAggregateError.allSettled(resolvers, "Error receiving all outstanding attribute values").catch(
|
|
661
|
-
(error) => logger.error(error)
|
|
662
|
-
);
|
|
663
|
-
}
|
|
664
|
-
this.#updateTimer.stop();
|
|
665
|
-
this.#sendDelayTimer.stop();
|
|
666
|
-
await super.destroy();
|
|
667
|
-
}
|
|
668
|
-
/**
|
|
669
|
-
* Closes the subscription and flushes all outstanding data updates if requested.
|
|
670
|
-
*/
|
|
671
|
-
async close(graceful = false, cancelledByPeer = false) {
|
|
672
|
-
if (this.isClosed) {
|
|
673
|
-
return;
|
|
674
|
-
}
|
|
675
|
-
if (cancelledByPeer) {
|
|
676
|
-
this.isCanceledByPeer = true;
|
|
677
|
-
}
|
|
678
|
-
await this.destroy();
|
|
679
|
-
if (graceful) {
|
|
680
|
-
await this.#flush();
|
|
681
|
-
}
|
|
682
|
-
if (this.#currentUpdatePromise) {
|
|
683
|
-
await this.#currentUpdatePromise;
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
/**
|
|
687
|
-
* Iterates over all attributes and events that have changed since the last update and sends them to
|
|
688
|
-
* the controller.
|
|
689
|
-
* A thrown exception will cancel the sending process immediately.
|
|
690
|
-
*/
|
|
691
|
-
async *#iterateDataUpdate(attributes, events) {
|
|
692
|
-
for (const {
|
|
693
|
-
path,
|
|
694
|
-
schema,
|
|
695
|
-
value: payload,
|
|
696
|
-
version: dataVersion,
|
|
697
|
-
attribute: { hasFabricSensitiveData }
|
|
698
|
-
} of attributes) {
|
|
699
|
-
yield {
|
|
700
|
-
hasFabricSensitiveData,
|
|
701
|
-
attributeData: { path, dataVersion, schema, payload }
|
|
702
|
-
};
|
|
703
|
-
}
|
|
704
|
-
for (const {
|
|
705
|
-
path,
|
|
706
|
-
schema,
|
|
707
|
-
event,
|
|
708
|
-
data: { number: eventNumber, priority, epochTimestamp, payload }
|
|
709
|
-
} of events) {
|
|
710
|
-
yield {
|
|
711
|
-
hasFabricSensitiveData: event.hasFabricSensitiveData,
|
|
712
|
-
eventData: { path, eventNumber, priority, epochTimestamp, schema, payload }
|
|
713
|
-
};
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
async #sendUpdateMessage(attributes, events) {
|
|
717
|
-
const exchange = this.#context.initiateExchange(this.#peerAddress, INTERACTION_PROTOCOL_ID);
|
|
718
|
-
if (exchange === void 0) return;
|
|
719
|
-
if (attributes.length) {
|
|
720
|
-
logger.debug(
|
|
721
|
-
`Subscription attribute changes for ID ${this.id}: ${attributes.map(
|
|
722
|
-
({ path, value, version }) => `${this.#structure.resolveAttributeName(path)}=${Diagnostic.json(value)} (${version})`
|
|
723
|
-
).join(", ")}`
|
|
724
|
-
);
|
|
725
|
-
}
|
|
726
|
-
const messenger = new InteractionServerMessenger(exchange);
|
|
727
|
-
try {
|
|
728
|
-
if (attributes.length === 0 && events.length === 0) {
|
|
729
|
-
await messenger.sendDataReport(
|
|
730
|
-
{
|
|
731
|
-
suppressResponse: true,
|
|
732
|
-
// suppressResponse true for empty DataReports
|
|
733
|
-
subscriptionId: this.id,
|
|
734
|
-
interactionModelRevision: Specification.INTERACTION_MODEL_REVISION
|
|
735
|
-
},
|
|
736
|
-
this.criteria.isFabricFiltered,
|
|
737
|
-
void 0,
|
|
738
|
-
!this.isClosed
|
|
739
|
-
// Do not wait for ack when closed
|
|
740
|
-
);
|
|
741
|
-
} else {
|
|
742
|
-
await messenger.sendDataReport(
|
|
743
|
-
{
|
|
744
|
-
suppressResponse: false,
|
|
745
|
-
// Non-empty data reports always need to send response
|
|
746
|
-
subscriptionId: this.id,
|
|
747
|
-
interactionModelRevision: Specification.INTERACTION_MODEL_REVISION
|
|
748
|
-
},
|
|
749
|
-
this.criteria.isFabricFiltered,
|
|
750
|
-
this.#iterateDataUpdate(attributes, events),
|
|
751
|
-
!this.isClosed
|
|
752
|
-
// Do not wait for ack when closed
|
|
753
|
-
);
|
|
754
|
-
}
|
|
755
|
-
} catch (error) {
|
|
756
|
-
if (StatusResponseError.is(error, StatusCode.InvalidSubscription, StatusCode.Failure)) {
|
|
757
|
-
logger.info(`Subscription ${this.id} cancelled by peer.`);
|
|
758
|
-
this.isCanceledByPeer = true;
|
|
759
|
-
await this.close(false);
|
|
760
|
-
} else {
|
|
761
|
-
StatusResponseError.accept(error);
|
|
762
|
-
logger.info(`Subscription ${this.id} update failed:`, error);
|
|
763
|
-
await this.close(false);
|
|
764
|
-
}
|
|
765
|
-
} finally {
|
|
766
|
-
await messenger.close();
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
export {
|
|
771
|
-
DEFAULT_RANDOMIZATION_WINDOW_S,
|
|
772
|
-
INTERNAL_INTERVAL_PUBLISHER_LIMIT_S,
|
|
773
|
-
MAX_INTERVAL_PUBLISHER_LIMIT_S,
|
|
774
|
-
MIN_INTERVAL_S,
|
|
775
|
-
ServerSubscription,
|
|
776
|
-
ServerSubscriptionConfig
|
|
777
|
-
};
|
|
778
|
-
//# sourceMappingURL=ServerSubscription.js.map
|