forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMTRBaseSubscriptionCallback.h
192 lines (161 loc) · 8.41 KB
/
MTRBaseSubscriptionCallback.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/**
* Copyright (c) 2022 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#import "Foundation/Foundation.h"
#import "MTRBaseDevice.h"
#include <app/BufferedReadCallback.h>
#include <app/ClusterStateCache.h>
#include <app/ConcreteAttributePath.h>
#include <app/ConcreteClusterPath.h>
#include <app/EventHeader.h>
#include <app/MessageDef/StatusIB.h>
#include <app/ReadClient.h>
#include <app/ReadPrepareParams.h>
#include <lib/core/CHIPError.h>
#include <lib/core/DataModelTypes.h>
#include <lib/core/TLV.h>
#include <memory>
/**
* This file defines a base class for subscription callbacks used by
* MTRBaseDevice and MTRDevice. This base class handles everything except the
* actual conversion from the incoming data to the desired data and the dispatch
* of callbacks to the relevant client queues. Its callbacks are called on the
* Matter queue. This allows MTRDevice and MTRBaseDevice to do any necessary
* sync cleanup work before dispatching to the client callbacks on the client
* queue.
*
* After onDoneHandler is invoked, this object will at some point delete itself
* and destroy anything it owns (such as the ReadClient or the
* ClusterStateCache). Consumers should drop references to all the relevant
* objects in that handler. This deletion will happen on the Matter queue.
*
* The desired data is assumed to be NSObjects that can be stored in NSArray.
*/
NS_ASSUME_NONNULL_BEGIN
typedef void (^DataReportCallback)(NSArray * value);
typedef void (^ErrorCallback)(NSError * error);
typedef void (^SubscriptionEstablishedHandler)(void);
typedef void (^OnDoneHandler)(void);
typedef void (^UnsolicitedMessageFromPublisherHandler)(void);
typedef void (^ReportBeginHandler)(void);
typedef void (^ReportEndHandler)(void);
class MTRBaseSubscriptionCallback : public chip::app::ClusterStateCache::Callback {
public:
MTRBaseSubscriptionCallback(DataReportCallback attributeReportCallback, DataReportCallback eventReportCallback,
ErrorCallback errorCallback, MTRDeviceResubscriptionScheduledHandler _Nullable resubscriptionCallback,
SubscriptionEstablishedHandler _Nullable subscriptionEstablishedHandler, OnDoneHandler _Nullable onDoneHandler,
UnsolicitedMessageFromPublisherHandler _Nullable unsolicitedMessageFromPublisherHandler = nil,
ReportBeginHandler _Nullable reportBeginHandler = nil, ReportEndHandler _Nullable reportEndHandler = nil)
: mAttributeReportCallback(attributeReportCallback)
, mEventReportCallback(eventReportCallback)
, mErrorCallback(errorCallback)
, mResubscriptionCallback(resubscriptionCallback)
, mSubscriptionEstablishedHandler(subscriptionEstablishedHandler)
, mBufferedReadAdapter(*this)
, mOnDoneHandler(onDoneHandler)
, mUnsolicitedMessageFromPublisherHandler(unsolicitedMessageFromPublisherHandler)
, mReportBeginHandler(reportBeginHandler)
, mReportEndHandler(reportEndHandler)
{
}
virtual ~MTRBaseSubscriptionCallback()
{
// Ensure we release the ReadClient before we tear down anything else,
// so it can call our OnDeallocatePaths properly.
mReadClient = nullptr;
// Make sure the block isn't run after object destruction
if (mInterimReportBlock) {
dispatch_block_cancel(mInterimReportBlock);
}
}
chip::app::BufferedReadCallback & GetBufferedCallback() { return mBufferedReadAdapter; }
// Methods to clear state from our cluster state cache. Must be called on
// the Matter queue.
void ClearCachedAttributeState(chip::EndpointId aEndpoint);
void ClearCachedAttributeState(const chip::app::ConcreteClusterPath & aCluster);
void ClearCachedAttributeState(const chip::app::ConcreteAttributePath & aAttribute);
// We need to exist to get a ReadClient, so can't take this as a constructor argument.
void AdoptReadClient(std::unique_ptr<chip::app::ReadClient> aReadClient) { mReadClient = std::move(aReadClient); }
void AdoptClusterStateCache(std::unique_ptr<chip::app::ClusterStateCache> aClusterStateCache)
{
mClusterStateCache = std::move(aClusterStateCache);
}
protected:
// Report an error, which may be due to issues in our own internal state or
// due to the OnError callback happening.
//
// aCancelSubscription should be false for the OnError case, since it will
// be immediately followed by OnDone and we want to do the deletion there.
void ReportError(CHIP_ERROR aError, bool aCancelSubscription = true);
// Called at attribute/event report time to queue a block to report on the Matter queue so that for multi-packet reports, this
// block is run and reports in batch. No-op if the block is already queued.
void QueueInterimReport();
private:
void OnReportBegin() override;
void OnReportEnd() override;
// OnEventData and OnAttributeData must be implemented by subclasses.
void OnEventData(const chip::app::EventHeader & aEventHeader, chip::TLV::TLVReader * apData,
const chip::app::StatusIB * apStatus) override
= 0;
void OnAttributeData(const chip::app::ConcreteDataAttributePath & aPath, chip::TLV::TLVReader * apData,
const chip::app::StatusIB & aStatus) override
= 0;
void OnError(CHIP_ERROR aError) override;
void OnDone(chip::app::ReadClient * aReadClient) override;
void OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams) override;
CHIP_ERROR OnResubscriptionNeeded(chip::app::ReadClient * apReadClient, CHIP_ERROR aTerminationCause) override;
void OnUnsolicitedMessageFromPublisher(chip::app::ReadClient * apReadClient) override;
void ReportData();
protected:
NSMutableArray * _Nullable mAttributeReports = nil;
NSMutableArray * _Nullable mEventReports = nil;
void CallResubscriptionScheduledHandler(NSError * error, NSNumber * resubscriptionDelay);
void OnSubscriptionEstablished(chip::SubscriptionId aSubscriptionId) override;
private:
DataReportCallback _Nullable mAttributeReportCallback = nil;
DataReportCallback _Nullable mEventReportCallback = nil;
// We set mErrorCallback to nil before calling the error callback, so we
// make sure to only report one error.
ErrorCallback _Nullable mErrorCallback = nil;
MTRDeviceResubscriptionScheduledHandler _Nullable mResubscriptionCallback = nil;
SubscriptionEstablishedHandler _Nullable mSubscriptionEstablishedHandler = nil;
UnsolicitedMessageFromPublisherHandler _Nullable mUnsolicitedMessageFromPublisherHandler = nil;
ReportBeginHandler _Nullable mReportBeginHandler = nil;
ReportEndHandler _Nullable mReportEndHandler = nil;
chip::app::BufferedReadCallback mBufferedReadAdapter;
// Our lifetime management is a little complicated. On errors that don't
// originate with the ReadClient we attempt to delete ourselves (and hence
// the ReadClient), but asynchronously, because the ReadClient API doesn't
// allow sync deletion under callbacks other than OnDone. While that's
// pending, something else (e.g. an error it runs into) could end up calling
// OnDone on us. And generally if OnDone is called we want to delete
// ourselves as well.
//
// To handle this, enforce the following rules:
//
// 1) We guarantee that mErrorCallback is only invoked with an error once.
// 2) We guarantee that mOnDoneHandler is only invoked once, and always
// invoked before we delete ourselves.
// 3) We ensure that we delete ourselves and the passed in ReadClient only
// from OnDone or from an error callback but not both, by tracking whether
// we have a queued-up deletion.
std::unique_ptr<chip::app::ReadClient> mReadClient;
std::unique_ptr<chip::app::ClusterStateCache> mClusterStateCache;
bool mHaveQueuedDeletion = false;
OnDoneHandler _Nullable mOnDoneHandler = nil;
dispatch_block_t mInterimReportBlock = nil;
};
NS_ASSUME_NONNULL_END