1use crate::dm::{
28 AsyncHandler, AttrDetails, CmdDetails, HandlerContext, InvokeContextInstance,
29 InvokeReplyInstance, ReadContextInstance, ReadReplyInstance, WriteContextInstance,
30};
31use crate::error::{Error, ErrorCode};
32use crate::im::encoding::{AttrResp, AttrStatus, CmdResp, CmdStatus, IMStatusCode};
33use crate::tlv::{TLVElement, TLVWrite, TagType, ToTLV};
34use crate::transport::exchange::Exchange;
35use crate::utils::storage::WriteBuf;
36
37pub struct HandlerInvoker<'a, 'b, C> {
38 exchange: &'b mut Exchange<'a>,
39 context: C,
40}
41
42impl<'a, 'b, C> HandlerInvoker<'a, 'b, C>
43where
44 C: HandlerContext,
45{
46 pub const fn new(exchange: &'b mut Exchange<'a>, context: C) -> Self {
47 Self { exchange, context }
48 }
49
50 pub fn exchange(&mut self) -> &mut Exchange<'a> {
51 self.exchange
52 }
53
54 pub async fn process_read(
55 &mut self,
56 item: &Result<AttrDetails, AttrStatus>,
57 tw: &mut WriteBuf<'_>,
58 ) -> Result<(), Error> {
59 let tail = tw.get_tail();
60
61 let result = self.do_process_read(item, &mut *tw).await;
62
63 if result.is_err() {
64 tw.rewind_to(tail);
66 }
67
68 result
69 }
70
71 async fn do_process_read(
72 &mut self,
73 item: &Result<AttrDetails, AttrStatus>,
74 tw: &mut WriteBuf<'_>,
75 ) -> Result<(), Error> {
76 let result = match item {
77 Ok(attr) => {
78 let pos = tw.get_tail();
79
80 let result = self.read(attr, &mut *tw).await;
81
82 match result {
83 Ok(()) => Ok(None),
84 Err(e) if e.code() != ErrorCode::NoSpace => {
85 error!("Error reading attribute: {}", e);
86
87 tw.rewind_to(pos);
88
89 Ok(attr.status(e.into()))
90 }
91 Err(e) => Err(e),
92 }
93 }
94 Err(status) => {
95 error!("Error processing attribute read: {:?}", status);
96 Ok(Some(status.clone()))
97 }
98 };
99
100 match result {
101 Ok(Some(status)) => AttrResp::Status(status).to_tlv(&TagType::Anonymous, tw),
102 Ok(None) => Ok(()),
103 Err(err) => Err(err),
104 }
105 }
106
107 pub async fn read(&mut self, attr: &AttrDetails, tw: &mut WriteBuf<'_>) -> Result<(), Error> {
108 self.context
109 .handler()
110 .read(
111 ReadContextInstance::new(self.exchange, &self.context, attr),
112 ReadReplyInstance::new(attr, tw),
113 )
114 .await
115 }
116
117 pub async fn process_write(
118 &mut self,
119 item: &Result<(AttrDetails, TLVElement<'_>), AttrStatus>,
120 tw: &mut WriteBuf<'_>,
121 ) -> Result<(), Error> {
122 let tail = tw.get_tail();
123
124 let result = self.do_process_write(item, &mut *tw).await;
125
126 if result.is_err() {
127 tw.rewind_to(tail);
129 }
130
131 result
132 }
133
134 async fn do_process_write(
135 &mut self,
136 item: &Result<(AttrDetails, TLVElement<'_>), AttrStatus>,
137 tw: &mut WriteBuf<'_>,
138 ) -> Result<(), Error> {
139 let result = match item {
140 Ok((attr, data)) => {
141 let pos = tw.get_tail();
142
143 let result = self.write(attr, data).await;
144
145 match result {
146 Ok(()) => {
147 self.context.notify_attr_changed(
153 attr.endpoint_id,
154 attr.cluster_id,
155 attr.attr_id,
156 );
157 Ok(attr.status(IMStatusCode::Success))
158 }
159 Err(err) if err.code() != ErrorCode::NoSpace => {
160 error!("Error writing attribute: {}", err);
161
162 tw.rewind_to(pos);
163
164 Ok(attr.status(err.into()))
165 }
166 Err(err) => Err(err),
167 }
168 }
169 Err(status) => {
170 error!("Error processing attribute write: {:?}", status);
171 Ok(Some(status.clone()))
172 }
173 };
174
175 match result {
176 Ok(Some(status)) => status.to_tlv(&TagType::Anonymous, tw),
177 Ok(None) => Ok(()),
178 Err(err) => Err(err),
179 }
180 }
181
182 pub async fn write(&mut self, attr: &AttrDetails, data: &TLVElement<'_>) -> Result<(), Error> {
183 self.context
184 .handler()
185 .write(WriteContextInstance::new(
186 self.exchange,
187 &self.context,
188 attr,
189 data,
190 ))
191 .await
192 }
193
194 pub async fn process_invoke(
199 &mut self,
200 item: &Result<(CmdDetails, TLVElement<'_>), CmdStatus>,
201 tw: &mut WriteBuf<'_>,
202 ) -> Result<bool, Error> {
203 let tail = tw.get_tail();
204
205 let result = self.do_process_invoke(item, &mut *tw).await;
206
207 if result.is_err() {
208 tw.rewind_to(tail);
210 }
211
212 result
213 }
214
215 async fn do_process_invoke(
216 &mut self,
217 item: &Result<(CmdDetails, TLVElement<'_>), CmdStatus>,
218 tw: &mut WriteBuf<'_>,
219 ) -> Result<bool, Error> {
220 let (result, invoked) = match item {
221 Ok((cmd, data)) => {
222 let pos = tw.get_tail();
223
224 let result = self.invoke(cmd, data, &mut *tw).await;
225
226 match result {
227 Ok(()) => {
228 if pos == tw.get_tail() {
229 (Ok(cmd.status(IMStatusCode::Success)), true)
230 } else {
231 (Ok(None), true)
232 }
233 }
234 Err(err) if err.code() != ErrorCode::NoSpace => {
235 error!("Error invoking command: {}", err);
236
237 tw.rewind_to(pos);
238
239 (Ok(cmd.status(err.into())), false)
240 }
241 Err(err) => (Err(err), false),
242 }
243 }
244 Err(status) => {
245 error!("Error processing command: {:?}", status);
246 (Ok(Some(status.clone())), false)
247 }
248 };
249
250 match result {
251 Ok(Some(status)) => {
252 CmdResp::Status(status).to_tlv(&TagType::Anonymous, tw)?;
253 Ok(invoked)
254 }
255 Ok(None) => Ok(invoked),
256 Err(err) => Err(err),
257 }
258 }
259
260 pub async fn invoke(
261 &mut self,
262 cmd: &CmdDetails,
263 data: &TLVElement<'_>,
264 tw: &mut WriteBuf<'_>,
265 ) -> Result<(), Error> {
266 self.context
267 .handler()
268 .invoke(
269 InvokeContextInstance::new(self.exchange, &self.context, cmd, data),
270 InvokeReplyInstance::new(cmd, tw),
271 )
272 .await
273 }
274}