Skip to content

Commit ce47e22

Browse files
sxb427tcarmelveilleuxandy31415
authored
Create an AAI registry for PwRPC services to allow registration of custom AAI classes (#37351)
* Allow custom AAI registration for PwRPC Reads/Writes. Update PwRPC Writes to look for custom AAIs before using datamodel provider * Add succes log * Make TryWriteViaAAI public * Make TryWriteViaAAI public * Fix compilation errors * Fix compilation errors * Fix compilation errors * Update examples/common/pigweed/rpc_services/Attributes.h Co-authored-by: Tennessee Carmel-Veilleux <tennessee.carmelveilleux@gmail.com> * Add new attribute accessor and registry for PwRPC * Fix compilation error * Fix compilation error * Fix compilation error * Revert changes * Revert changes * Accessors will not be indexed by EndpointId/ClusterId. Caller queries all accessors to satisfy the request and returns as soon as a succes/failure is encountered. Accessors will return 'pw::Status::NotFound()' as a way of hinting the caller 'look for an alternative'. If no accessors were registered or all returned 'NotFound' the fallback path is taken. * fix compilation bug * Review comments * Fix compilation * Fix nits * Fix ESP32 compilation * Update examples/common/pigweed/rpc_services/AccessInterceptor.h Nit : rename parameter names. Co-authored-by: Andrei Litvin <andy314@gmail.com> * Update examples/common/pigweed/rpc_services/AccessInterceptor.h Review suggestion. Co-authored-by: Andrei Litvin <andy314@gmail.com> * Update examples/common/pigweed/rpc_services/AccessInterceptorRegistry.h Review suggestion. Co-authored-by: Andrei Litvin <andy314@gmail.com> * Review comments * Update examples/common/pigweed/rpc_services/AccessInterceptor.h --------- Co-authored-by: Tennessee Carmel-Veilleux <tennessee.carmelveilleux@gmail.com> Co-authored-by: Andrei Litvin <andy314@gmail.com>
1 parent cbe17ed commit ce47e22

File tree

3 files changed

+164
-0
lines changed

3 files changed

+164
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 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 "pw_status/status.h"
22+
#include <app/AttributeReportBuilder.h>
23+
#include <app/AttributeValueDecoder.h>
24+
#include <app/AttributeValueEncoder.h>
25+
26+
namespace chip {
27+
namespace rpc {
28+
29+
/**
30+
* Callback class that clusters can implement in order to interpose custom
31+
* interception logic.
32+
*/
33+
class PigweedDebugAccessInterceptor
34+
{
35+
public:
36+
PigweedDebugAccessInterceptor() = default;
37+
virtual ~PigweedDebugAccessInterceptor() = default;
38+
39+
/**
40+
* Callback for writing attributes.
41+
*
42+
* The implementation can do one of three things:
43+
*
44+
* Returns:
45+
* - `std::nullopt` if the `path` was not handled by this Interceptor.
46+
* Interceptor MUST NOT have attepted to decode `decoder`.
47+
* - A `::pw::Status` value that is considered the FINAL result of the
48+
* write (i.e. write handled) either with success or failure.
49+
*/
50+
virtual std::optional<::pw::Status> Write(const chip::app::ConcreteDataAttributePath & path,
51+
chip::app::AttributeValueDecoder & decoder) = 0;
52+
};
53+
54+
} // namespace rpc
55+
} // namespace chip
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 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 "pw_status/status.h"
22+
#include <pigweed/rpc_services/AccessInterceptor.h>
23+
#include <set>
24+
25+
namespace chip {
26+
namespace rpc {
27+
28+
/** @brief Custom debug request interceptors.
29+
*
30+
* This class is specifically meant for registering custom Accessors that
31+
* allow mini-handlers to process PigweedRPC read/writes separately from the cluster
32+
* code. It is meant to be used by samples using this PigweedRPC services to allow the RPC
33+
* interface to be used in more ways than simply for example, simulating writes from a Matter
34+
* client at the IM level. Handlers registered here by applications should be attempted before any
35+
* standard processing.
36+
*/
37+
class PigweedDebugAccessInterceptorRegistry
38+
{
39+
public:
40+
/**
41+
* Registers an attribute access inteceptor within this registry. Use `Unregister` to
42+
* unregister an interceptor that was previously registered.
43+
* @param attrOverride - the interceptor to be registered.
44+
*/
45+
void Register(PigweedDebugAccessInterceptor * attrOverride) { mAccessors.insert(attrOverride); }
46+
47+
void Unregister(PigweedDebugAccessInterceptor * attrOverride)
48+
{
49+
if (mAccessors.find(attrOverride) == mAccessors.end())
50+
{
51+
ChipLogError(Support, "Attempt to unregister accessor that is not registered.");
52+
return;
53+
}
54+
mAccessors.erase(attrOverride);
55+
}
56+
57+
const std::set<PigweedDebugAccessInterceptor *> & GetAllAccessors() const { return mAccessors; }
58+
59+
/**
60+
* Returns the singleton instance of the attribute accessor registory.
61+
*/
62+
static PigweedDebugAccessInterceptorRegistry & Instance()
63+
{
64+
static PigweedDebugAccessInterceptorRegistry instance;
65+
return instance;
66+
}
67+
68+
private:
69+
std::set<PigweedDebugAccessInterceptor *> mAccessors;
70+
};
71+
72+
} // namespace rpc
73+
} // namespace chip

examples/common/pigweed/rpc_services/Attributes.h

+36
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,42 @@
3333
#include <app/data-model-provider/Provider.h>
3434
#include <app/util/attribute-storage.h>
3535
#include <app/util/attribute-table.h>
36+
#include <data-model-providers/codegen/CodegenDataModelProvider.h>
3637
#include <lib/core/TLV.h>
3738
#include <lib/core/TLVTags.h>
3839
#include <lib/core/TLVTypes.h>
40+
#include <pigweed/rpc_services/AccessInterceptor.h>
41+
#include <pigweed/rpc_services/AccessInterceptorRegistry.h>
3942
#include <platform/PlatformManager.h>
43+
#include <set>
4044

4145
namespace chip {
4246
namespace rpc {
4347

48+
std::optional<::pw::Status> TryWriteViaAccessor(const chip::app::ConcreteDataAttributePath & path,
49+
chip::app::AttributeValueDecoder & decoder)
50+
{
51+
std::set<PigweedDebugAccessInterceptor *> accessors = PigweedDebugAccessInterceptorRegistry::Instance().GetAllAccessors();
52+
53+
for (PigweedDebugAccessInterceptor * accessor : accessors)
54+
{
55+
std::optional<::pw::Status> result = accessor->Write(path, decoder);
56+
if (result.has_value()) // Write was either a success or failure.
57+
{
58+
return result;
59+
}
60+
else if (decoder.TriedDecode())
61+
{
62+
ChipLogError(Support, "Interceptor tried decode but did not return status.");
63+
return ::pw::Status::FailedPrecondition();
64+
}
65+
}
66+
67+
VerifyOrReturnError(!decoder.TriedDecode(), ::pw::Status::FailedPrecondition());
68+
69+
return std::nullopt;
70+
}
71+
4472
// Implementation class for chip.rpc.Attributes.
4573
class Attributes : public pw_rpc::nanopb::Attributes::Service<Attributes>
4674
{
@@ -207,6 +235,14 @@ class Attributes : public pw_rpc::nanopb::Attributes::Service<Attributes>
207235
}
208236

209237
app::AttributeValueDecoder decoder(tlvReader.value(), subjectDescriptor);
238+
239+
std::optional<::pw::Status> interceptResult = TryWriteViaAccessor(write_request.path, decoder);
240+
if (interceptResult.has_value())
241+
{
242+
return *interceptResult;
243+
}
244+
ChipLogProgress(Support, "No custom PigweedRPC Attribute Accessor registration found, using fake write access.");
245+
210246
app::DataModel::ActionReturnStatus result = provider->WriteAttribute(write_request, decoder);
211247

212248
if (!result.IsSuccess())

0 commit comments

Comments
 (0)