forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathInvokeInteraction.h
162 lines (141 loc) · 7.92 KB
/
InvokeInteraction.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
/*
*
* Copyright (c) 2021 Project CHIP Authors
* All rights reserved.
*
* 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
#include <controller/TypedCommandCallback.h>
#include <lib/core/Optional.h>
#include <functional>
namespace chip {
namespace Controller {
namespace Internal {
// Cancellation functions on InvokeCommandRequest() are for internal use only.
typedef std::function<void()> InvokeCancelFn;
} // namespace Internal
/*
* A typed command invocation function that takes as input a cluster-object representation of a command request and
* callbacks for success and failure and either returns a decoded cluster-object representation of the response through
* the provided success callback or calls the provided failure callback.
*
* The RequestObjectT is generally expected to be a ClusterName::Commands::CommandName::Type struct, but any object
* that can be encoded using the DataModel::Encode machinery and exposes the
* GetClusterId() and GetCommandId() functions and a ResponseType type
* is expected to work.
*
* The ResponseType is expected to be one of two things:
*
* - If a data response is expected on success, a struct type decodable via DataModel::Decode which has GetClusterId() and
* GetCommandId() methods. A ClusterName::Commands::ResponseCommandName::DecodableType is typically used.
* - If a status response is expected on success, DataModel::NullObjectType.
*
*/
template <typename RequestObjectT>
CHIP_ERROR
InvokeCommandRequest(Messaging::ExchangeManager * aExchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId,
const RequestObjectT & requestCommandData,
typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnSuccessCallbackType onSuccessCb,
typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnErrorCallbackType onErrorCb,
const Optional<uint16_t> & timedInvokeTimeoutMs,
const Optional<System::Clock::Timeout> & responseTimeout = NullOptional,
Internal::InvokeCancelFn * outCancelFn = nullptr)
{
// InvokeCommandRequest expects responses, so cannot happen over a group session.
VerifyOrReturnError(!sessionHandle->IsGroupSession(), CHIP_ERROR_INVALID_ARGUMENT);
app::CommandPathParams commandPath = { endpointId, 0, RequestObjectT::GetClusterId(), RequestObjectT::GetCommandId(),
(app::CommandPathFlags::kEndpointIdValid) };
//
// Let's create a handle version of the decoder to ensure we do correct clean-up of it if things go south at any point below
//
auto decoder = chip::Platform::MakeUnique<TypedCommandCallback<typename RequestObjectT::ResponseType>>(onSuccessCb, onErrorCb);
VerifyOrReturnError(decoder != nullptr, CHIP_ERROR_NO_MEMORY);
//
// Upon successful completion of SendCommandRequest below, we're expected to free up the respective allocated objects
// in the OnDone callback.
//
auto onDone = [rawDecoderPtr = decoder.get()](app::CommandSender * commandSender) {
chip::Platform::Delete(commandSender);
chip::Platform::Delete(rawDecoderPtr);
};
decoder->SetOnDoneCallback(onDone);
auto commandSender =
chip::Platform::MakeUnique<app::CommandSender>(decoder.get(), aExchangeMgr, timedInvokeTimeoutMs.HasValue());
VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY);
ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, requestCommandData, timedInvokeTimeoutMs));
ReturnErrorOnFailure(commandSender->SendCommandRequest(sessionHandle, responseTimeout));
// If requested by the caller, provide a way to cancel the invoke interaction.
if (outCancelFn != nullptr)
{
*outCancelFn = [rawDecoderPtr = decoder.get(), rawCommandSender = commandSender.get()]() {
chip::Platform::Delete(rawCommandSender);
chip::Platform::Delete(rawDecoderPtr);
};
}
//
// We've effectively transferred ownership of the above allocated objects to CommandSender, and we need to wait for it to call
// us back when processing is completed (through OnDone) to eventually free up resources.
//
// So signal that by releasing the smart pointer.
//
decoder.release();
commandSender.release();
return CHIP_NO_ERROR;
}
/*
* A typed group command invocation function that takes as input a cluster-object representation of a command request.
*
* The RequestObjectT is generally expected to be a ClusterName::Commands::CommandName::Type struct, but any object
* that can be encoded using the DataModel::Encode machinery and exposes the GetClusterId() and GetCommandId() functions
* and a ResponseType type is expected to work.
*
* Since this sends a group command, no response will be received and all allocated resources will be cleared before exiting this
* function
*/
template <typename RequestObjectT>
CHIP_ERROR InvokeGroupCommandRequest(Messaging::ExchangeManager * exchangeMgr, chip::FabricIndex fabric, chip::GroupId groupId,
const RequestObjectT & requestCommandData)
{
app::CommandPathParams commandPath = { groupId, RequestObjectT::GetClusterId(), RequestObjectT::GetCommandId(),
app::CommandPathFlags::kGroupIdValid };
Transport::OutgoingGroupSession session(groupId, fabric);
auto commandSender = chip::Platform::MakeUnique<app::CommandSender>(nullptr, exchangeMgr);
VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY);
ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, requestCommandData));
return commandSender->SendGroupCommandRequest(SessionHandle(session));
}
template <typename RequestObjectT>
CHIP_ERROR
InvokeCommandRequest(Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId,
const RequestObjectT & requestCommandData,
typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnSuccessCallbackType onSuccessCb,
typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnErrorCallbackType onErrorCb,
uint16_t timedInvokeTimeoutMs, const Optional<System::Clock::Timeout> & responseTimeout = NullOptional)
{
return InvokeCommandRequest(exchangeMgr, sessionHandle, endpointId, requestCommandData, onSuccessCb, onErrorCb,
MakeOptional(timedInvokeTimeoutMs), responseTimeout);
}
template <typename RequestObjectT, typename std::enable_if_t<!RequestObjectT::MustUseTimedInvoke(), int> = 0>
CHIP_ERROR
InvokeCommandRequest(Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle, chip::EndpointId endpointId,
const RequestObjectT & requestCommandData,
typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnSuccessCallbackType onSuccessCb,
typename TypedCommandCallback<typename RequestObjectT::ResponseType>::OnErrorCallbackType onErrorCb,
const Optional<System::Clock::Timeout> & responseTimeout = NullOptional)
{
return InvokeCommandRequest(exchangeMgr, sessionHandle, endpointId, requestCommandData, onSuccessCb, onErrorCb, NullOptional,
responseTimeout);
}
} // namespace Controller
} // namespace chip