Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #pragma once
20 :
21 : #include "lib/core/CHIPError.h"
22 : #include "system/SystemPacketBuffer.h"
23 : #include "system/TLVPacketBufferBackingStore.h"
24 : #include <app/AppConfig.h>
25 : #include <app/AttributePathParams.h>
26 : #include <app/BufferedReadCallback.h>
27 : #include <app/ReadClient.h>
28 : #include <app/data-model/DecodableList.h>
29 : #include <app/data-model/Decode.h>
30 : #include <lib/support/Variant.h>
31 : #include <list>
32 : #include <map>
33 : #include <queue>
34 : #include <set>
35 : #include <vector>
36 :
37 : #if CHIP_CONFIG_ENABLE_READ_CLIENT
38 : namespace chip {
39 : namespace app {
40 : /*
41 : * This implements a cluster state cache designed to aggregate both attribute and event data received by a client
42 : * from either read or subscribe interactions and keep it resident and available for clients to
43 : * query at any time while the cache is active.
44 : *
45 : * The cache can be used with either read/subscribe, with the consumer connecting it up appropriately
46 : * to the right ReadClient instance.
47 : *
48 : * The cache provides an up-to-date and consistent view of the state of a target node, with the scope of the
49 : * state being determined by the associated ReadClient's path set.
50 : *
51 : * The cache provides a number of getters and helper functions to iterate over the topology
52 : * of the received data which is organized by endpoint, cluster and attribute ID (for attributes). These permit greater
53 : * flexibility when dealing with interactions that use wildcards heavily.
54 : *
55 : * For events, functions that permit iteration over the cached events sorted by event number are provided.
56 : *
57 : * The data is stored internally in the cache as TLV. This permits re-use of the existing cluster objects
58 : * to de-serialize the state on-demand.
59 : *
60 : * The cache serves as a callback adapter as well in that it 'forwards' the ReadClient::Callback calls transparently
61 : * through to a registered callback. In addition, it provides its own enhancements to the base ReadClient::Callback
62 : * to make it easier to know what has changed in the cache.
63 : *
64 : * **NOTE**
65 : * 1. This already includes the BufferedReadCallback, so there is no need to add that to the ReadClient callback chain.
66 : * 2. The same cache cannot be used by multiple subscribe/read interactions at the same time.
67 : *
68 : */
69 : class ClusterStateCache : protected ReadClient::Callback
70 : {
71 : public:
72 : class Callback : public ReadClient::Callback
73 : {
74 : public:
75 0 : Callback() = default;
76 :
77 : // Callbacks are not expected to be copyable or movable.
78 : Callback(const Callback &) = delete;
79 : Callback(Callback &&) = delete;
80 : Callback & operator=(const Callback &) = delete;
81 : Callback & operator=(Callback &&) = delete;
82 :
83 : /*
84 : * Called anytime an attribute value has changed in the cache
85 : */
86 0 : virtual void OnAttributeChanged(ClusterStateCache * cache, const ConcreteAttributePath & path){};
87 :
88 : /*
89 : * Called anytime any attribute in a cluster has changed in the cache
90 : */
91 0 : virtual void OnClusterChanged(ClusterStateCache * cache, EndpointId endpointId, ClusterId clusterId){};
92 :
93 : /*
94 : * Called anytime an endpoint was added to the cache
95 : */
96 0 : virtual void OnEndpointAdded(ClusterStateCache * cache, EndpointId endpointId){};
97 : };
98 :
99 : /**
100 : *
101 : * @param [in] callback the derived callback which inherit from ReadClient::Callback
102 : * @param [in] highestReceivedEventNumber optional highest received event number, if cache receive the events with the number
103 : * less than or equal to this value, skip those events
104 : * @param [in] cacheData boolean to decide whether this cache would store attribute/event data/status,
105 : * the default is true.
106 : */
107 0 : ClusterStateCache(Callback & callback, Optional<EventNumber> highestReceivedEventNumber = Optional<EventNumber>::Missing(),
108 0 : bool cacheData = true) :
109 0 : mCallback(callback),
110 0 : mBufferedReader(*this), mCacheData(cacheData)
111 : {
112 0 : mHighestReceivedEventNumber = highestReceivedEventNumber;
113 0 : }
114 :
115 : ClusterStateCache(const ClusterStateCache &) = delete;
116 : ClusterStateCache(ClusterStateCache &&) = delete;
117 : ClusterStateCache & operator=(const ClusterStateCache &) = delete;
118 : ClusterStateCache & operator=(ClusterStateCache &&) = delete;
119 :
120 : void SetHighestReceivedEventNumber(EventNumber highestReceivedEventNumber)
121 : {
122 : mHighestReceivedEventNumber.SetValue(highestReceivedEventNumber);
123 : }
124 :
125 : /*
126 : * When registering as a callback to the ReadClient, the ClusterStateCache cannot not be passed as a callback
127 : * directly. Instead, utilize this method below to correctly set up the callback chain such that
128 : * the buffered reader is the first callback in the chain before calling into cache subsequently.
129 : */
130 0 : ReadClient::Callback & GetBufferedCallback() { return mBufferedReader; }
131 :
132 : /*
133 : * Retrieve the value of an attribute from the cache (if present) given a concrete path by decoding
134 : * it using DataModel::Decode into the in-out argument 'value'.
135 : *
136 : * For some types of attributes, the value for the attribute is directly backed by the underlying TLV buffer
137 : * and has pointers into that buffer. (e.g octet strings, char strings and lists). This buffer only remains
138 : * valid until the cached value for that path is updated, so it must not be held
139 : * across any async call boundaries.
140 : *
141 : * The template parameter AttributeObjectTypeT is generally expected to be a
142 : * ClusterName::Attributes::AttributeName::DecodableType, but any
143 : * object that can be decoded using the DataModel::Decode machinery will work.
144 : *
145 : * Notable return values:
146 : * - If the provided attribute object's Cluster and Attribute IDs don't match that of the provided path,
147 : * a CHIP_ERROR_SCHEMA_MISMATCH shall be returned.
148 : *
149 : * - If neither data or status for the specified path don't exist in the cache, CHIP_ERROR_KEY_NOT_FOUND
150 : * shall be returned.
151 : *
152 : * - If a StatusIB is present in the cache instead of data, a CHIP_ERROR_IM_STATUS_CODE_RECEIVED error
153 : * shall be returned from this call instead. The actual StatusIB can be retrieved using the GetStatus() API below.
154 : *
155 : */
156 : template <typename AttributeObjectTypeT>
157 0 : CHIP_ERROR Get(const ConcreteAttributePath & path, typename AttributeObjectTypeT::DecodableType & value) const
158 : {
159 : TLV::TLVReader reader;
160 :
161 0 : if (path.mClusterId != AttributeObjectTypeT::GetClusterId() || path.mAttributeId != AttributeObjectTypeT::GetAttributeId())
162 : {
163 0 : return CHIP_ERROR_SCHEMA_MISMATCH;
164 : }
165 :
166 0 : ReturnErrorOnFailure(Get(path, reader));
167 0 : return DataModel::Decode(reader, value);
168 : }
169 :
170 : /**
171 : * Get the value of a particular attribute for the given endpoint. See the
172 : * documentation for Get() with a ConcreteAttributePath above.
173 : */
174 : template <typename AttributeObjectTypeT>
175 0 : CHIP_ERROR Get(EndpointId endpoint, typename AttributeObjectTypeT::DecodableType & value) const
176 : {
177 0 : ConcreteAttributePath path(endpoint, AttributeObjectTypeT::GetClusterId(), AttributeObjectTypeT::GetAttributeId());
178 0 : return Get<AttributeObjectTypeT>(path, value);
179 : }
180 :
181 : /*
182 : * Retrieve the StatusIB for a given attribute if one exists currently in the cache.
183 : *
184 : * Notable return values:
185 : * - If neither data or status for the specified path don't exist in the cache, CHIP_ERROR_KEY_NOT_FOUND
186 : * shall be returned.
187 : *
188 : * - If data exists in the cache instead of status, CHIP_ERROR_INVALID_ARGUMENT shall be returned.
189 : *
190 : */
191 : CHIP_ERROR GetStatus(const ConcreteAttributePath & path, StatusIB & status) const;
192 :
193 : /*
194 : * Encapsulates a StatusIB and a ConcreteAttributePath pair.
195 : */
196 : struct AttributeStatus
197 : {
198 : AttributeStatus(const ConcreteAttributePath & path, StatusIB & status) : mPath(path), mStatus(status) {}
199 : ConcreteAttributePath mPath;
200 : StatusIB mStatus;
201 : };
202 :
203 : /*
204 : * Retrieve the value of an entire cluster instance from the cache (if present) given a path
205 : * and decode it using DataModel::Decode into the in-out argument 'value'. If any StatusIBs
206 : * are present in the cache instead of data, they will be provided in the statusList argument.
207 : *
208 : * For some types of attributes, the value for the attribute is directly backed by the underlying TLV buffer
209 : * and has pointers into that buffer. (e.g octet strings, char strings and lists). This buffer only remains
210 : * valid until the cached value for that path is updated, so it must not be held
211 : * across any async call boundaries.
212 : *
213 : * The template parameter ClusterObjectT is generally expected to be a
214 : * ClusterName::Attributes::DecodableType, but any
215 : * object that can be decoded using the DataModel::Decode machinery will work.
216 : *
217 : * Notable return values:
218 : * - If neither data or status for the specified path exist in the cache, CHIP_ERROR_KEY_NOT_FOUND
219 : * shall be returned.
220 : *
221 : */
222 : template <typename ClusterObjectTypeT>
223 : CHIP_ERROR Get(EndpointId endpointId, ClusterId clusterId, ClusterObjectTypeT & value,
224 : std::list<AttributeStatus> & statusList) const
225 : {
226 : statusList.clear();
227 :
228 : return ForEachAttribute(endpointId, clusterId, [&value, this, &statusList](const ConcreteAttributePath & path) {
229 : TLV::TLVReader reader;
230 : CHIP_ERROR err;
231 :
232 : err = Get(path, reader);
233 : if (err == CHIP_ERROR_IM_STATUS_CODE_RECEIVED)
234 : {
235 : StatusIB status;
236 : ReturnErrorOnFailure(GetStatus(path, status));
237 : statusList.push_back(AttributeStatus(path, status));
238 : err = CHIP_NO_ERROR;
239 : }
240 : else if (err == CHIP_NO_ERROR)
241 : {
242 : ReturnErrorOnFailure(DataModel::Decode(reader, path, value));
243 : }
244 : else
245 : {
246 : return err;
247 : }
248 :
249 : return CHIP_NO_ERROR;
250 : });
251 : }
252 :
253 : /*
254 : * Retrieve the value of an attribute by updating a in-out TLVReader to be positioned
255 : * right at the attribute value.
256 : *
257 : * The underlying TLV buffer only remains valid until the cached value for that path is updated, so it must
258 : * not be held across any async call boundaries.
259 : *
260 : * Notable return values:
261 : * - If neither data nor status for the specified path exist in the cache, CHIP_ERROR_KEY_NOT_FOUND
262 : * shall be returned.
263 : *
264 : * - If a StatusIB is present in the cache instead of data, a CHIP_ERROR_IM_STATUS_CODE_RECEIVED error
265 : * shall be returned from this call instead. The actual StatusIB can be retrieved using the GetStatus() API above.
266 : *
267 : */
268 : CHIP_ERROR Get(const ConcreteAttributePath & path, TLV::TLVReader & reader) const;
269 :
270 : /*
271 : * Retrieve the data version for the given cluster. If there is no data for the specified path in the cache,
272 : * CHIP_ERROR_KEY_NOT_FOUND shall be returned. Otherwise aVersion will be set to the
273 : * current data version for the cluster (which may have no value if we don't have a known data version
274 : * for it, for example because none of our paths were wildcards that covered the whole cluster).
275 : */
276 : CHIP_ERROR GetVersion(const ConcreteClusterPath & path, Optional<DataVersion> & aVersion) const;
277 :
278 : /*
279 : * Get highest received event number.
280 : */
281 2 : virtual CHIP_ERROR GetHighestReceivedEventNumber(Optional<EventNumber> & aEventNumber) final
282 : {
283 2 : aEventNumber = mHighestReceivedEventNumber;
284 2 : return CHIP_NO_ERROR;
285 : }
286 :
287 : /*
288 : * Retrieve the value of an event from the cache given an EventNumber by decoding
289 : * it using DataModel::Decode into the in-out argument 'value'.
290 : *
291 : * This should be used in conjunction with the ForEachEvent() iterator function to
292 : * retrieve the EventHeader (and corresponding metadata information for the event) along with its EventNumber.
293 : *
294 : * For some types of events, the values for the fields in the event are directly backed by the underlying TLV buffer
295 : * and have pointers into that buffer. (e.g octet strings, char strings and lists). Unlike its attribute counterpart,
296 : * these pointers are stable and will not change until a call to `ClearEventCache` happens.
297 : *
298 : * The template parameter EventObjectTypeT is generally expected to be a
299 : * ClusterName::Events::EventName::DecodableType, but any
300 : * object that can be decoded using the DataModel::Decode machinery will work.
301 : *
302 : * Notable return values:
303 : * - If the provided event object's Cluster and Event IDs don't match those of the event in the cache,
304 : * a CHIP_ERROR_SCHEMA_MISMATCH shall be returned.
305 : *
306 : * - If event doesn't exist in the cache, CHIP_ERROR_KEY_NOT_FOUND
307 : * shall be returned.
308 : */
309 :
310 : template <typename EventObjectTypeT>
311 : CHIP_ERROR Get(EventNumber eventNumber, EventObjectTypeT & value) const
312 : {
313 : TLV::TLVReader reader;
314 : CHIP_ERROR err;
315 :
316 : auto * eventData = GetEventData(eventNumber, err);
317 : ReturnErrorOnFailure(err);
318 :
319 : if (eventData->first.mPath.mClusterId != value.GetClusterId() || eventData->first.mPath.mEventId != value.GetEventId())
320 : {
321 : return CHIP_ERROR_SCHEMA_MISMATCH;
322 : }
323 :
324 : ReturnErrorOnFailure(Get(eventNumber, reader));
325 : return DataModel::Decode(reader, value);
326 : }
327 :
328 : /*
329 : * Retrieve the data of an event by updating a in-out TLVReader to be positioned
330 : * right at the structure that encapsulates the event payload.
331 : *
332 : * Notable return values:
333 : * - If no event with a matching eventNumber exists in the cache, CHIP_ERROR_KEY_NOT_FOUND
334 : * shall be returned.
335 : *
336 : */
337 : CHIP_ERROR Get(EventNumber eventNumber, TLV::TLVReader & reader) const;
338 :
339 : /*
340 : * Retrieve the StatusIB for a specific event from the event status cache (if one exists).
341 : * Otherwise, a CHIP_ERROR_KEY_NOT_FOUND error will be returned.
342 : *
343 : * This is to be used with the `ForEachEventStatus` iterator function.
344 : *
345 : * NOTE: Receipt of a StatusIB does not affect any pre-existing or future event data entries in the cache (and vice-versa).
346 : *
347 : */
348 : CHIP_ERROR GetStatus(const ConcreteEventPath & path, StatusIB & status) const;
349 :
350 : /*
351 : * Execute an iterator function that is called for every attribute
352 : * in a given endpoint and cluster. The function when invoked is provided a concrete attribute path
353 : * to every attribute that matches in the cache.
354 : *
355 : * The iterator is expected to have this signature:
356 : * CHIP_ERROR IteratorFunc(const ConcreteAttributePath &path);
357 : *
358 : * Notable return values:
359 : * - If a cluster instance corresponding to endpointId and clusterId doesn't exist in the cache,
360 : * CHIP_ERROR_KEY_NOT_FOUND shall be returned.
361 : *
362 : * - If func returns an error, that will result in termination of any further iteration over attributes
363 : * and that error shall be returned back up to the original call to this function.
364 : *
365 : */
366 : template <typename IteratorFunc>
367 : CHIP_ERROR ForEachAttribute(EndpointId endpointId, ClusterId clusterId, IteratorFunc func) const
368 : {
369 : CHIP_ERROR err;
370 :
371 : auto clusterState = GetClusterState(endpointId, clusterId, err);
372 : ReturnErrorOnFailure(err);
373 :
374 : for (auto & attributeIter : clusterState->mAttributes)
375 : {
376 : const ConcreteAttributePath path(endpointId, clusterId, attributeIter.first);
377 : ReturnErrorOnFailure(func(path));
378 : }
379 :
380 : return CHIP_NO_ERROR;
381 : }
382 :
383 : /*
384 : * Execute an iterator function that is called for every attribute
385 : * for a given cluster across all endpoints in the cache. The function is passed a
386 : * concrete attribute path to every attribute that matches in the cache.
387 : *
388 : * The iterator is expected to have this signature:
389 : * CHIP_ERROR IteratorFunc(const ConcreteAttributePath &path);
390 : *
391 : * Notable return values:
392 : * - If func returns an error, that will result in termination of any further iteration over attributes
393 : * and that error shall be returned back up to the original call to this function.
394 : *
395 : */
396 : template <typename IteratorFunc>
397 0 : CHIP_ERROR ForEachAttribute(ClusterId clusterId, IteratorFunc func) const
398 : {
399 0 : for (auto & endpointIter : mCache)
400 : {
401 0 : for (auto & clusterIter : endpointIter.second)
402 : {
403 0 : if (clusterIter.first == clusterId)
404 : {
405 0 : for (auto & attributeIter : clusterIter.second.mAttributes)
406 : {
407 0 : const ConcreteAttributePath path(endpointIter.first, clusterId, attributeIter.first);
408 0 : ReturnErrorOnFailure(func(path));
409 : }
410 : }
411 : }
412 : }
413 0 : return CHIP_NO_ERROR;
414 : }
415 :
416 : /*
417 : * Execute an iterator function that is called for every cluster
418 : * in a given endpoint and passed a ClusterId for every cluster that
419 : * matches.
420 : *
421 : * The iterator is expected to have this signature:
422 : * CHIP_ERROR IteratorFunc(ClusterId clusterId);
423 : *
424 : * Notable return values:
425 : * - If func returns an error, that will result in termination of any further iteration over attributes
426 : * and that error shall be returned back up to the original call to this function.
427 : *
428 : */
429 : template <typename IteratorFunc>
430 : CHIP_ERROR ForEachCluster(EndpointId endpointId, IteratorFunc func) const
431 : {
432 : auto endpointIter = mCache.find(endpointId);
433 : if (endpointIter->first == endpointId)
434 : {
435 : for (auto & clusterIter : endpointIter->second)
436 : {
437 : ReturnErrorOnFailure(func(clusterIter.first));
438 : }
439 : }
440 : return CHIP_NO_ERROR;
441 : }
442 :
443 : /*
444 : * Execute an iterator function that is called for every event in the event data cache that satisfies the following
445 : * conditions:
446 : * - It matches the provided path filter
447 : * - Its event number is greater than or equal to the provided minimum event number filter.
448 : *
449 : * Each filter argument can be omitted from the match criteria above by passing in an empty EventPathParams() and/or
450 : * a minimum event filter of 0.
451 : *
452 : * This iterator is called in increasing order from the event with the lowest event number to the highest.
453 : *
454 : * The function is passed a const reference to the EventHeader associated with that event.
455 : *
456 : * The iterator is expected to have this signature:
457 : * CHIP_ERROR IteratorFunc(const EventHeader & eventHeader);
458 : *
459 : * Notable return values:
460 : * - If func returns an error, that will result in termination of any further iteration over events
461 : * and that error shall be returned back up to the original call to this function.
462 : *
463 : */
464 : template <typename IteratorFunc>
465 : CHIP_ERROR ForEachEventData(IteratorFunc func, EventPathParams pathFilter = EventPathParams(),
466 : EventNumber minEventNumberFilter = 0) const
467 : {
468 : for (const auto & item : mEventDataCache)
469 : {
470 : if (pathFilter.IsEventPathSupersetOf(item.first.mPath) && item.first.mEventNumber >= minEventNumberFilter)
471 : {
472 : ReturnErrorOnFailure(func(item.first));
473 : }
474 : }
475 :
476 : return CHIP_NO_ERROR;
477 : }
478 :
479 : /*
480 : * Execute an iterator function that is called for every StatusIB in the event status cache.
481 : *
482 : * The iterator is expected to have this signature:
483 : * CHIP_ERROR IteratorFunc(const ConcreteEventPath & eventPath, const StatusIB & statusIB);
484 : *
485 : * Notable return values:
486 : * - If func returns an error, that will result in termination of any further iteration over events
487 : * and that error shall be returned back up to the original call to this function.
488 : *
489 : * NOTE: Receipt of a StatusIB does not affect any pre-existing event data entries in the cache (and vice-versa).
490 : *
491 : */
492 : template <typename IteratorFunc>
493 : CHIP_ERROR ForEachEventStatus(IteratorFunc func) const
494 : {
495 : for (const auto & item : mEventStatusCache)
496 : {
497 : ReturnErrorOnFailure(func(item.first, item.second));
498 : }
499 : }
500 :
501 : /*
502 : * Clear out the event data and status caches.
503 : *
504 : * By default, this will not clear out any internally tracked event counters, specifically:
505 : * - the highest event number seen so far. This is used in reads/subscribe requests to express to the receiving
506 : * server to not send events that the client has already seen so far.
507 : *
508 : * That can be over-ridden by passing in 'true' to `resetTrackedEventCounters`.
509 : *
510 : */
511 : void ClearEventCache(bool resetTrackedEventCounters = false)
512 : {
513 : mEventDataCache.clear();
514 : if (resetTrackedEventCounters)
515 : {
516 : mHighestReceivedEventNumber.ClearValue();
517 : }
518 :
519 : mEventStatusCache.clear();
520 : }
521 :
522 : /*
523 : * Get the last concrete report data path, if path is not concrete cluster path, return CHIP_ERROR_NOT_FOUND
524 : *
525 : */
526 : CHIP_ERROR GetLastReportDataPath(ConcreteClusterPath & aPath);
527 :
528 : private:
529 : // An attribute state can be one of three things:
530 : // * If we got a path-specific error for the attribute, the corresponding
531 : // status.
532 : // * If we got data for the attribute and we are storing data ourselves, the
533 : // data.
534 : // * If we got data for the attribute and we are not storing data
535 : // oureselves, the size of the data, so we can still prioritize sending
536 : // DataVersions correctly.
537 : using AttributeData = Platform::ScopedMemoryBufferWithSize<uint8_t>;
538 : using AttributeState = Variant<StatusIB, AttributeData, size_t>;
539 : // mPendingDataVersion represents a tentative data version for a cluster that we have gotten some reports for.
540 : //
541 : // mCurrentDataVersion represents a known data version for a cluster. In order for this to have a
542 : // value the cluster must be included in a path in mRequestPathSet that has a wildcard attribute
543 : // and we must not be in the middle of receiving reports for that cluster.
544 : struct ClusterState
545 : {
546 : std::map<AttributeId, AttributeState> mAttributes;
547 : Optional<DataVersion> mPendingDataVersion;
548 : Optional<DataVersion> mCommittedDataVersion;
549 : };
550 : using EndpointState = std::map<ClusterId, ClusterState>;
551 : using NodeState = std::map<EndpointId, EndpointState>;
552 :
553 : struct Comparator
554 : {
555 1054 : bool operator()(const AttributePathParams & x, const AttributePathParams & y) const
556 : {
557 1054 : return x.mEndpointId < y.mEndpointId || x.mClusterId < y.mClusterId;
558 : }
559 : };
560 :
561 : using EventData = std::pair<EventHeader, System::PacketBufferHandle>;
562 :
563 : //
564 : // This is a custom comparator for use with the std::set<EventData> below. Uniqueness
565 : // is determined solely by the event number associated with each event.
566 : //
567 : struct EventDataCompare
568 : {
569 422 : bool operator()(const EventData & lhs, const EventData & rhs) const
570 : {
571 422 : return (lhs.first.mEventNumber < rhs.first.mEventNumber);
572 : }
573 : };
574 :
575 : /*
576 : * These functions provide a way to index into the cached state with different sub-sets of a path, returning
577 : * appropriate slices of the data as requested.
578 : *
579 : * In all variants, the respective slice is returned if a valid path is provided. 'err' is updated to reflect
580 : * the status of the operation.
581 : *
582 : * Notable status values:
583 : * - If a cluster instance corresponding to endpointId and clusterId doesn't exist in the cache,
584 : * CHIP_ERROR_KEY_NOT_FOUND shall be returned.
585 : *
586 : */
587 : const EndpointState * GetEndpointState(EndpointId endpointId, CHIP_ERROR & err) const;
588 : const ClusterState * GetClusterState(EndpointId endpointId, ClusterId clusterId, CHIP_ERROR & err) const;
589 : const AttributeState * GetAttributeState(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId,
590 : CHIP_ERROR & err) const;
591 :
592 : const EventData * GetEventData(EventNumber number, CHIP_ERROR & err) const;
593 :
594 : /*
595 : * Updates the state of an attribute in the cache given a reader. If the reader is null, the state is updated
596 : * with the provided status.
597 : */
598 : CHIP_ERROR UpdateCache(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus);
599 :
600 : /*
601 : * If apData is not null, updates the cached event set with the specified event header + payload.
602 : * If apData is null and apStatus is not null, the StatusIB is stored in the event status cache.
603 : *
604 : * Storage of either of these do not affect pre-existing data for the other events in the cache.
605 : *
606 : */
607 : CHIP_ERROR UpdateEventCache(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus);
608 :
609 : //
610 : // ReadClient::Callback
611 : //
612 : void OnReportBegin() override;
613 : void OnReportEnd() override;
614 : void OnAttributeData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus) override;
615 0 : void OnError(CHIP_ERROR aError) override { return mCallback.OnError(aError); }
616 :
617 : void OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus) override;
618 :
619 20 : void OnDone(ReadClient * apReadClient) override
620 : {
621 20 : mRequestPathSet.clear();
622 20 : return mCallback.OnDone(apReadClient);
623 : }
624 :
625 0 : void OnSubscriptionEstablished(SubscriptionId aSubscriptionId) override
626 : {
627 0 : mCallback.OnSubscriptionEstablished(aSubscriptionId);
628 0 : }
629 :
630 0 : CHIP_ERROR OnResubscriptionNeeded(ReadClient * apReadClient, CHIP_ERROR aTerminationCause) override
631 : {
632 0 : return mCallback.OnResubscriptionNeeded(apReadClient, aTerminationCause);
633 : }
634 :
635 0 : void OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams) override
636 : {
637 0 : mCallback.OnDeallocatePaths(std::move(aReadPrepareParams));
638 0 : }
639 :
640 : virtual CHIP_ERROR OnUpdateDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
641 : const Span<AttributePathParams> & aAttributePaths,
642 : bool & aEncodedDataVersionList) override;
643 :
644 0 : void OnUnsolicitedMessageFromPublisher(ReadClient * apReadClient) override
645 : {
646 0 : return mCallback.OnUnsolicitedMessageFromPublisher(apReadClient);
647 : }
648 :
649 0 : void OnCASESessionEstablished(const SessionHandle & aSession, ReadPrepareParams & aSubscriptionParams) override
650 : {
651 0 : return mCallback.OnCASESessionEstablished(aSession, aSubscriptionParams);
652 : }
653 :
654 : // Commit the pending cluster data version, if there is one.
655 : void CommitPendingDataVersion();
656 :
657 : // Get our list of data version filters, sorted from larges to smallest by the total size of the TLV
658 : // payload for the filter's cluster. Applying filters in this order should maximize space savings
659 : // on the wire if not all filters can be applied.
660 : void GetSortedFilters(std::vector<std::pair<DataVersionFilter, size_t>> & aVector) const;
661 :
662 : CHIP_ERROR GetElementTLVSize(TLV::TLVReader * apData, size_t & aSize);
663 :
664 : Callback & mCallback;
665 : NodeState mCache;
666 : std::set<ConcreteAttributePath> mChangedAttributeSet;
667 : std::set<AttributePathParams, Comparator> mRequestPathSet; // wildcard attribute request path only
668 : std::vector<EndpointId> mAddedEndpoints;
669 :
670 : std::set<EventData, EventDataCompare> mEventDataCache;
671 : Optional<EventNumber> mHighestReceivedEventNumber;
672 : std::map<ConcreteEventPath, StatusIB> mEventStatusCache;
673 : BufferedReadCallback mBufferedReader;
674 : ConcreteClusterPath mLastReportDataPath = ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId);
675 : const bool mCacheData = true;
676 : };
677 :
678 : }; // namespace app
679 : }; // namespace chip
680 : #endif // CHIP_CONFIG_ENABLE_READ_CLIENT
|