Line data Source code
1 : /*
2 : * Copyright (c) 2024 Project CHIP Authors
3 : * All rights reserved.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #pragma once
18 :
19 : #include <app/EventLoggingDelegate.h>
20 : #include <app/EventLoggingTypes.h>
21 : #include <app/MessageDef/EventDataIB.h>
22 : #include <app/data-model/Encode.h>
23 : #include <app/data-model/FabricScoped.h>
24 : #include <lib/core/CHIPError.h>
25 : #include <lib/support/logging/CHIPLogging.h>
26 :
27 : #include <optional>
28 : #include <type_traits>
29 :
30 : namespace chip {
31 : namespace app {
32 : namespace DataModel {
33 :
34 : namespace internal {
35 : template <typename T>
36 : class SimpleEventPayloadWriter : public EventLoggingDelegate
37 : {
38 : public:
39 : SimpleEventPayloadWriter(const T & aEventData) : mEventData(aEventData){};
40 : CHIP_ERROR WriteEvent(chip::TLV::TLVWriter & aWriter) final override
41 : {
42 : return DataModel::Encode(aWriter, TLV::ContextTag(EventDataIB::Tag::kData), mEventData);
43 : }
44 :
45 : private:
46 : const T & mEventData;
47 : };
48 :
49 : template <typename G, typename T, std::enable_if_t<DataModel::IsFabricScoped<T>::value, bool> = true>
50 : std::optional<EventNumber> GenerateEvent(G & generator, const T & aEventData, EndpointId aEndpoint)
51 : {
52 : internal::SimpleEventPayloadWriter<T> eventPayloadWriter(aEventData);
53 : ConcreteEventPath path(aEndpoint, aEventData.GetClusterId(), aEventData.GetEventId());
54 : EventOptions eventOptions;
55 : eventOptions.mPath = path;
56 : eventOptions.mPriority = aEventData.GetPriorityLevel();
57 : eventOptions.mFabricIndex = aEventData.GetFabricIndex();
58 :
59 : // this skips generating the event if it is fabric-scoped but the provided event data is not
60 : // associated with any fabric.
61 : if (eventOptions.mFabricIndex == kUndefinedFabricIndex)
62 : {
63 : ChipLogError(EventLogging, "Event encode failure: no fabric index for fabric scoped event");
64 : return std::nullopt;
65 : }
66 :
67 : //
68 : // Unlike attributes which have a different 'EncodeForRead' for fabric-scoped structs,
69 : // fabric-sensitive events don't require that since the actual omission of the event in its entirety
70 : // happens within the event management framework itself at the time of access.
71 : //
72 : // The 'mFabricIndex' field in the event options above is encoded out-of-band alongside the event payload
73 : // and used to match against the accessing fabric.
74 : //
75 : EventNumber eventNumber;
76 : CHIP_ERROR err = generator.GenerateEvent(&eventPayloadWriter, eventOptions, eventNumber);
77 : if (err != CHIP_NO_ERROR)
78 : {
79 : ChipLogError(EventLogging, "Failed to generate event: %" CHIP_ERROR_FORMAT, err.Format());
80 : return std::nullopt;
81 : }
82 :
83 : return eventNumber;
84 : }
85 :
86 : template <typename G, typename T, std::enable_if_t<!DataModel::IsFabricScoped<T>::value, bool> = true>
87 : std::optional<EventNumber> GenerateEvent(G & generator, const T & aEventData, EndpointId endpointId)
88 : {
89 : internal::SimpleEventPayloadWriter<T> eventPayloadWriter(aEventData);
90 : ConcreteEventPath path(endpointId, aEventData.GetClusterId(), aEventData.GetEventId());
91 : EventOptions eventOptions;
92 : eventOptions.mPath = path;
93 : eventOptions.mPriority = aEventData.GetPriorityLevel();
94 : EventNumber eventNumber;
95 : CHIP_ERROR err = generator.GenerateEvent(&eventPayloadWriter, eventOptions, eventNumber);
96 : if (err != CHIP_NO_ERROR)
97 : {
98 : ChipLogError(EventLogging, "Failed to generate event: %" CHIP_ERROR_FORMAT, err.Format());
99 : return std::nullopt;
100 : }
101 :
102 : return eventNumber;
103 : }
104 :
105 : } // namespace internal
106 :
107 : /// Exposes event generation capabilities.
108 : ///
109 : /// Allows callers to "generate events" which effectively notifies of an event having
110 : /// ocurred.
111 : class EventsGenerator
112 : {
113 : public:
114 60 : virtual ~EventsGenerator() = default;
115 :
116 : /// Generates the given event.
117 : ///
118 : /// Events are generally expected to be sent to subscribed clients and also
119 : /// be available for read later until they get overwritten by new events
120 : /// that are being generated.
121 : virtual CHIP_ERROR GenerateEvent(EventLoggingDelegate * eventPayloadWriter, const EventOptions & options,
122 : EventNumber & generatedEventNumber) = 0;
123 :
124 : // Convenience methods for event logging using cluster-object structures
125 : //
126 : // On error, these log and return nullopt.
127 : template <typename T>
128 : std::optional<EventNumber> GenerateEvent(const T & eventData, EndpointId endpointId)
129 : {
130 : return internal::GenerateEvent(*this, eventData, endpointId);
131 : }
132 : };
133 :
134 : } // namespace DataModel
135 : } // namespace app
136 : } // namespace chip
|