blob: b3a127c074aaa170a09a84220fbcb8b91497f0f8 [file] [log] [blame]
/*
* Copyright (c) 2024 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 <lib/core/TLVReader.h>
#include <lib/core/TLVWriter.h>
#include <app/AttributeValueDecoder.h>
#include <app/AttributeValueEncoder.h>
#include <app/interaction-model/Actions.h>
#include <app/interaction-model/InvokeResponder.h>
#include <app/interaction-model/IterationTypes.h>
#include <app/interaction-model/OperationTypes.h>
namespace chip {
namespace app {
namespace InteractionModel {
/// Represents operations against a matter-defined data model.
///
/// Class is SINGLE-THREADED:
/// - operations are assumed to only be ever run in a single event-loop
/// thread or equivalent
/// - class is allowed to attempt to cache indexes/locations for faster
/// lookups of things (e.g during iterations)
class Model : public AttributeTreeIterator
{
public:
virtual ~Model() = default;
// `actions` pointers will be guaranteed valid until Shutdown is called()
virtual CHIP_ERROR Startup(InteractionModelActions actions)
{
mActions = actions;
return CHIP_NO_ERROR;
}
virtual CHIP_ERROR Shutdown() = 0;
// During the transition phase, we expect a large subset of code to require access to
// event emitting, path marking and other operations
virtual InteractionModelActions CurrentActions() { return mActions; }
/// List reading has specific handling logic:
/// `state` contains in/out data about the current list reading. MUST start with kInvalidListIndex on first call
///
/// Return codes:
/// CHIP_ERROR_MORE_LIST_DATA_AVAILABLE (NOTE: new error defined for this purpose)
/// - partial data written to the destination
/// - destination will contain AT LEAST one valid list entry fully serialized
/// - destination will be fully valid (it will be rolled back on partial list writes)
/// CHIP_IM_GLOBAL_STATUS(code):
/// - error codes that are translatable in IM status codes (otherwise we expect Failure to be reported)
/// - In particular, some handlers rely on special handling for:
/// - `UnsupportedAccess` - for ACL checks (e.g. wildcard expansion may choose to skip these)
/// - to check for this, CHIP_ERROR provides:
/// - ::IsPart(ChipError::SdkPart::kIMGlobalStatus) -> bool
/// - ::GetSdkCode() -> uint8_t to translate to the actual code
virtual CHIP_ERROR ReadAttribute(const ReadAttributeRequest & request, ReadState & state, AttributeValueEncoder & encoder) = 0;
/// Requests a write of an attribute.
///
/// When this is invoked, caller is expected to have already done some validations:
/// - cluster `data version` has been checked for the incoming request if applicable
///
/// List operation support:
/// - the first list write will have `request.writeFlags.Has(WriteFlags::kListBegin)`
/// - the last list write will have `request.writeFlags.Has(WriteFlags::kListEnd)`
/// - the last list write MAY have empty data (no list items)
///
/// When `request.writeFlags.Has(WriteFlags::kForceInternal)` the request is from an internal app update
/// and SHOULD bypass some internal checks (like timed enforcement, potentially read-only restrictions)
///
/// Return codes
/// CHIP_IM_GLOBAL_STATUS(code):
/// - error codes that are translatable to specific IM codes
/// - in particular, the following codes are interesting/expected
/// - `UnsupportedWrite` for attempts to write read-only data
/// - `UnsupportedAccess` for ACL failures
/// - `NeedsTimedInteraction` for writes that are not timed however are required to be so
virtual CHIP_ERROR WriteAttribute(const WriteAttributeRequest & request, AttributeValueDecoder & decoder) = 0;
/// `responder` is used to send back the reply.
/// - calling Reply() or ReplyAsync() will let the application control the reply
/// - returning a CHIP_NO_ERROR without reply/reply_async implies a Status::Success reply without data
/// - returning a CHIP_*_ERROR implies an error reply (error and data are mutually exclusive)
///
/// See InvokeReply/AutoCompleteInvokeResponder for details on how to send back replies and expected
/// error handling. If you require knowledge if a response was successfully sent, use the underlying
/// `reply` object instead of returning an error codes from Invoke.
///
/// Return codes
/// CHIP_IM_GLOBAL_STATUS(code):
/// - error codes that are translatable to specific IM codes
/// - in particular, the following codes are interesting/expected
/// - `UnsupportedEndpoint` for invalid endpoint
/// - `UnsupportedCluster` for no such cluster on the endpoint
/// - `UnsupportedCommand` for no such command in the cluster
/// - `UnsupportedAccess` for permission errors (ACL or fabric scoped with invalid fabric)
/// - `NeedsTimedInteraction` if the invoke requires timed interaction support
virtual CHIP_ERROR Invoke(const InvokeRequest & request, chip::TLV::TLVReader & input_arguments, InvokeReply & reply) = 0;
private:
InteractionModelActions mActions = { nullptr };
};
} // namespace InteractionModel
} // namespace app
} // namespace chip