2022-12-27 09:32:52 +05:30
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Copyright (c) 2020-2022 Project CHIP Authors
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
use core::time::Duration;
|
2023-01-03 15:25:44 +05:30
|
|
|
|
2022-12-27 09:32:52 +05:30
|
|
|
use crate::{
|
2023-02-02 18:22:21 +00:00
|
|
|
data_model::core::DataHandler,
|
2022-12-27 09:32:52 +05:30
|
|
|
error::*,
|
2023-02-02 18:22:21 +00:00
|
|
|
tlv::{get_root_node_struct, print_tlv_list, FromTLV, TLVElement, TLVWriter, TagType, ToTLV},
|
|
|
|
transport::{exchange::ExchangeCtx, packet::Packet, proto_ctx::ProtoCtx, session::Session},
|
2022-12-27 09:32:52 +05:30
|
|
|
};
|
|
|
|
use colored::Colorize;
|
|
|
|
use log::{error, info};
|
|
|
|
use num;
|
|
|
|
use num_derive::FromPrimitive;
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
use super::messages::msg::{self, InvReq, ReadReq, StatusResp, TimedReq, WriteReq};
|
2022-12-27 09:32:52 +05:30
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! cmd_enter {
|
|
|
|
($e:expr) => {{
|
|
|
|
use colored::Colorize;
|
|
|
|
info! {"{} {}", "Handling Command".cyan(), $e.cyan()}
|
|
|
|
}};
|
|
|
|
}
|
2022-12-27 09:32:52 +05:30
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
#[derive(FromPrimitive, Debug, Clone, Copy, PartialEq)]
|
|
|
|
pub enum IMStatusCode {
|
|
|
|
Success = 0,
|
|
|
|
Failure = 1,
|
|
|
|
InvalidSubscription = 0x7D,
|
|
|
|
UnsupportedAccess = 0x7E,
|
|
|
|
UnsupportedEndpoint = 0x7F,
|
|
|
|
InvalidAction = 0x80,
|
|
|
|
UnsupportedCommand = 0x81,
|
|
|
|
InvalidCommand = 0x85,
|
|
|
|
UnsupportedAttribute = 0x86,
|
|
|
|
ConstraintError = 0x87,
|
|
|
|
UnsupportedWrite = 0x88,
|
|
|
|
ResourceExhausted = 0x89,
|
|
|
|
NotFound = 0x8b,
|
|
|
|
UnreportableAttribute = 0x8c,
|
|
|
|
InvalidDataType = 0x8d,
|
|
|
|
UnsupportedRead = 0x8f,
|
|
|
|
DataVersionMismatch = 0x92,
|
|
|
|
Timeout = 0x94,
|
|
|
|
Busy = 0x9c,
|
|
|
|
UnsupportedCluster = 0xc3,
|
|
|
|
NoUpstreamSubscription = 0xc5,
|
|
|
|
NeedsTimedInteraction = 0xc6,
|
|
|
|
UnsupportedEvent = 0xc7,
|
|
|
|
PathsExhausted = 0xc8,
|
|
|
|
TimedRequestMisMatch = 0xc9,
|
|
|
|
FailSafeRequired = 0xca,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Error> for IMStatusCode {
|
|
|
|
fn from(e: Error) -> Self {
|
|
|
|
match e {
|
|
|
|
Error::EndpointNotFound => IMStatusCode::UnsupportedEndpoint,
|
|
|
|
Error::ClusterNotFound => IMStatusCode::UnsupportedCluster,
|
|
|
|
Error::AttributeNotFound => IMStatusCode::UnsupportedAttribute,
|
|
|
|
Error::CommandNotFound => IMStatusCode::UnsupportedCommand,
|
|
|
|
Error::InvalidAction => IMStatusCode::InvalidAction,
|
|
|
|
Error::InvalidCommand => IMStatusCode::InvalidCommand,
|
|
|
|
Error::UnsupportedAccess => IMStatusCode::UnsupportedAccess,
|
|
|
|
Error::Busy => IMStatusCode::Busy,
|
|
|
|
Error::DataVersionMismatch => IMStatusCode::DataVersionMismatch,
|
|
|
|
Error::ResourceExhausted => IMStatusCode::ResourceExhausted,
|
|
|
|
_ => IMStatusCode::Failure,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromTLV<'_> for IMStatusCode {
|
|
|
|
fn from_tlv(t: &TLVElement) -> Result<Self, Error> {
|
|
|
|
num::FromPrimitive::from_u16(t.u16()?).ok_or(Error::Invalid)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToTLV for IMStatusCode {
|
|
|
|
fn to_tlv(&self, tw: &mut TLVWriter, tag_type: TagType) -> Result<(), Error> {
|
|
|
|
tw.u16(tag_type, *self as u16)
|
|
|
|
}
|
|
|
|
}
|
2022-12-27 09:32:52 +05:30
|
|
|
|
2023-01-06 07:44:46 +05:30
|
|
|
#[derive(FromPrimitive, Debug, Copy, Clone, PartialEq)]
|
2022-12-27 09:32:52 +05:30
|
|
|
pub enum OpCode {
|
|
|
|
Reserved = 0,
|
|
|
|
StatusResponse = 1,
|
|
|
|
ReadRequest = 2,
|
|
|
|
SubscribeRequest = 3,
|
|
|
|
SubscriptResponse = 4,
|
|
|
|
ReportData = 5,
|
|
|
|
WriteRequest = 6,
|
|
|
|
WriteResponse = 7,
|
|
|
|
InvokeRequest = 8,
|
|
|
|
InvokeResponse = 9,
|
|
|
|
TimedRequest = 10,
|
|
|
|
}
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
#[derive(PartialEq)]
|
|
|
|
pub enum TransactionState {
|
|
|
|
Ongoing,
|
|
|
|
Complete,
|
|
|
|
Terminate,
|
|
|
|
}
|
|
|
|
pub struct Transaction<'a, 'b> {
|
|
|
|
state: TransactionState,
|
|
|
|
ctx: &'a mut ExchangeCtx<'b>,
|
|
|
|
}
|
|
|
|
|
2023-04-01 21:27:37 +08:00
|
|
|
impl<'a, 'b> Transaction<'a, 'b> {
|
2023-02-02 18:22:21 +00:00
|
|
|
pub fn new(ctx: &'a mut ExchangeCtx<'b>) -> Self {
|
2022-12-27 09:32:52 +05:30
|
|
|
Self {
|
|
|
|
state: TransactionState::Ongoing,
|
2023-02-02 18:22:21 +00:00
|
|
|
ctx,
|
2022-12-27 09:32:52 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
pub fn session(&self) -> &Session {
|
|
|
|
self.ctx.sess.session()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn session_mut(&mut self) -> &mut Session {
|
|
|
|
self.ctx.sess.session_mut()
|
|
|
|
}
|
|
|
|
|
2023-03-04 13:04:13 +05:30
|
|
|
/// Terminates the transaction, no communication (even ACKs) happens hence forth
|
|
|
|
pub fn terminate(&mut self) {
|
|
|
|
self.state = TransactionState::Terminate
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_terminate(&self) -> bool {
|
|
|
|
self.state == TransactionState::Terminate
|
|
|
|
}
|
|
|
|
/// Marks the transaction as completed from the application's perspective
|
2022-12-27 09:32:52 +05:30
|
|
|
pub fn complete(&mut self) {
|
|
|
|
self.state = TransactionState::Complete
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_complete(&self) -> bool {
|
|
|
|
self.state == TransactionState::Complete
|
|
|
|
}
|
2023-01-03 15:25:44 +05:30
|
|
|
|
|
|
|
pub fn set_timeout(&mut self, timeout: u64) {
|
2023-02-02 18:22:21 +00:00
|
|
|
let now = (self.ctx.epoch)();
|
|
|
|
|
|
|
|
self.ctx
|
|
|
|
.exch
|
|
|
|
.set_data_time(now.checked_add(Duration::from_millis(timeout)));
|
2023-01-04 08:38:18 +05:30
|
|
|
}
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
pub fn get_timeout(&mut self) -> Option<Duration> {
|
|
|
|
self.ctx.exch.get_data_time()
|
2023-01-03 15:25:44 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
pub fn has_timed_out(&self) -> bool {
|
2023-02-02 18:22:21 +00:00
|
|
|
if let Some(timeout) = self.ctx.exch.get_data_time() {
|
|
|
|
if (self.ctx.epoch)() > timeout {
|
2023-01-03 15:25:44 +05:30
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
2022-12-27 09:32:52 +05:30
|
|
|
}
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
/* Interaction Model ID as per the Matter Spec */
|
|
|
|
const PROTO_ID_INTERACTION_MODEL: usize = 0x01;
|
2023-01-03 15:25:44 +05:30
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
pub enum Interaction<'a> {
|
|
|
|
Read(ReadReq<'a>),
|
|
|
|
Write(WriteReq<'a>),
|
|
|
|
Invoke(InvReq<'a>),
|
|
|
|
Timed(TimedReq),
|
|
|
|
}
|
2023-02-21 16:44:17 +05:30
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
impl<'a> Interaction<'a> {
|
|
|
|
pub fn new(rx: &'a Packet) -> Result<Self, Error> {
|
|
|
|
let opcode: OpCode =
|
|
|
|
num::FromPrimitive::from_u8(rx.get_proto_opcode()).ok_or(Error::Invalid)?;
|
|
|
|
|
|
|
|
let rx_data = rx.as_slice();
|
|
|
|
|
|
|
|
info!("{} {:?}", "Received command".cyan(), opcode);
|
|
|
|
print_tlv_list(rx_data);
|
|
|
|
|
|
|
|
match opcode {
|
|
|
|
OpCode::ReadRequest => Ok(Self::Read(ReadReq::from_tlv(&get_root_node_struct(
|
|
|
|
rx_data,
|
|
|
|
)?)?)),
|
|
|
|
OpCode::WriteRequest => Ok(Self::Write(WriteReq::from_tlv(&get_root_node_struct(
|
|
|
|
rx_data,
|
|
|
|
)?)?)),
|
|
|
|
OpCode::InvokeRequest => Ok(Self::Invoke(InvReq::from_tlv(&get_root_node_struct(
|
|
|
|
rx_data,
|
|
|
|
)?)?)),
|
|
|
|
OpCode::TimedRequest => Ok(Self::Timed(TimedReq::from_tlv(&get_root_node_struct(
|
|
|
|
rx_data,
|
|
|
|
)?)?)),
|
|
|
|
// TODO
|
|
|
|
// OpCode::SubscribeRequest => self.handle_subscribe_req(&mut trans, buf, &mut ctx.tx)?,
|
|
|
|
// OpCode::StatusResponse => self.handle_status_resp(&mut trans, buf, &mut ctx.tx)?,
|
|
|
|
_ => {
|
|
|
|
error!("Opcode Not Handled: {:?}", opcode);
|
|
|
|
Err(Error::InvalidOpcode)
|
|
|
|
}
|
|
|
|
}
|
2023-01-13 20:01:43 +05:30
|
|
|
}
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
pub fn initiate_tx(
|
|
|
|
&self,
|
|
|
|
tx: &mut Packet,
|
|
|
|
transaction: &mut Transaction,
|
|
|
|
) -> Result<bool, Error> {
|
|
|
|
let reply = match self {
|
|
|
|
Self::Read(request) => {
|
|
|
|
tx.set_proto_id(PROTO_ID_INTERACTION_MODEL as u16);
|
|
|
|
tx.set_proto_opcode(OpCode::ReportData as u8);
|
|
|
|
|
|
|
|
let mut tw = TLVWriter::new(tx.get_writebuf()?);
|
|
|
|
|
|
|
|
tw.start_struct(TagType::Anonymous)?;
|
|
|
|
|
|
|
|
if request.attr_requests.is_some() {
|
|
|
|
tw.start_array(TagType::Context(msg::ReportDataTag::AttributeReports as u8))?;
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
Interaction::Write(_) => {
|
|
|
|
if transaction.has_timed_out() {
|
|
|
|
Self::create_status_response(tx, IMStatusCode::Timeout)?;
|
|
|
|
|
|
|
|
transaction.complete();
|
|
|
|
transaction.ctx.exch.close();
|
|
|
|
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
tx.set_proto_id(PROTO_ID_INTERACTION_MODEL as u16);
|
|
|
|
tx.set_proto_opcode(OpCode::WriteResponse as u8);
|
|
|
|
|
|
|
|
let mut tw = TLVWriter::new(tx.get_writebuf()?);
|
|
|
|
|
|
|
|
tw.start_struct(TagType::Anonymous)?;
|
|
|
|
tw.start_array(TagType::Context(msg::WriteRespTag::WriteResponses as u8))?;
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Interaction::Invoke(request) => {
|
|
|
|
if transaction.has_timed_out() {
|
|
|
|
Self::create_status_response(tx, IMStatusCode::Timeout)?;
|
|
|
|
|
|
|
|
transaction.complete();
|
|
|
|
transaction.ctx.exch.close();
|
|
|
|
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
let timed_tx = transaction.get_timeout().map(|_| true);
|
|
|
|
let timed_request = request.timed_request.filter(|a| *a);
|
|
|
|
|
|
|
|
// Either both should be None, or both should be Some(true)
|
|
|
|
if timed_tx != timed_request {
|
|
|
|
Self::create_status_response(tx, IMStatusCode::TimedRequestMisMatch)?;
|
|
|
|
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
tx.set_proto_id(PROTO_ID_INTERACTION_MODEL as u16);
|
|
|
|
tx.set_proto_opcode(OpCode::InvokeResponse as u8);
|
|
|
|
|
|
|
|
let mut tw = TLVWriter::new(tx.get_writebuf()?);
|
|
|
|
|
|
|
|
tw.start_struct(TagType::Anonymous)?;
|
|
|
|
|
|
|
|
// Suppress Response -> TODO: Need to revisit this for cases where we send a command back
|
|
|
|
tw.bool(
|
|
|
|
TagType::Context(msg::InvRespTag::SupressResponse as u8),
|
|
|
|
false,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
if request.inv_requests.is_some() {
|
|
|
|
tw.start_array(TagType::Context(
|
|
|
|
msg::InvRespTag::InvokeResponses as u8,
|
|
|
|
))?;
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Interaction::Timed(request) => {
|
|
|
|
tx.set_proto_id(PROTO_ID_INTERACTION_MODEL as u16);
|
|
|
|
tx.set_proto_opcode(OpCode::StatusResponse as u8);
|
|
|
|
|
|
|
|
let mut tw = TLVWriter::new(tx.get_writebuf()?);
|
|
|
|
|
|
|
|
transaction.set_timeout(request.timeout.into());
|
|
|
|
|
|
|
|
let status = StatusResp {
|
|
|
|
status: IMStatusCode::Success,
|
|
|
|
};
|
|
|
|
|
|
|
|
status.to_tlv(&mut tw, TagType::Anonymous)?;
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
2023-01-03 15:25:44 +05:30
|
|
|
};
|
2023-02-02 18:22:21 +00:00
|
|
|
|
|
|
|
Ok(!reply)
|
2023-01-03 15:25:44 +05:30
|
|
|
}
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
pub fn complete_tx(
|
|
|
|
&self,
|
|
|
|
tx: &mut Packet,
|
|
|
|
transaction: &mut Transaction,
|
2023-01-03 15:25:44 +05:30
|
|
|
) -> Result<bool, Error> {
|
2023-02-02 18:22:21 +00:00
|
|
|
let reply = match self {
|
|
|
|
Self::Read(request) => {
|
|
|
|
let mut tw = TLVWriter::new(tx.get_writebuf()?);
|
2023-01-03 15:25:44 +05:30
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
if request.attr_requests.is_some() {
|
|
|
|
tw.end_container()?;
|
|
|
|
}
|
2022-12-27 09:32:52 +05:30
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
// Suppress response always true for read interaction
|
|
|
|
tw.bool(
|
|
|
|
TagType::Context(msg::ReportDataTag::SupressResponse as u8),
|
|
|
|
true,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
tw.end_container()?;
|
|
|
|
|
|
|
|
transaction.complete();
|
|
|
|
|
|
|
|
true
|
2022-12-27 09:32:52 +05:30
|
|
|
}
|
2023-02-02 18:22:21 +00:00
|
|
|
Self::Write(request) => {
|
|
|
|
let suppress = request.supress_response.unwrap_or_default();
|
|
|
|
|
|
|
|
let mut tw = TLVWriter::new(tx.get_writebuf()?);
|
|
|
|
|
|
|
|
tw.end_container()?;
|
|
|
|
tw.end_container()?;
|
|
|
|
|
|
|
|
transaction.complete();
|
|
|
|
|
|
|
|
if suppress {
|
|
|
|
error!("Supress response is set, is this the expected handling?");
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Self::Invoke(request) => {
|
|
|
|
let mut tw = TLVWriter::new(tx.get_writebuf()?);
|
|
|
|
|
|
|
|
if request.inv_requests.is_some() {
|
|
|
|
tw.end_container()?;
|
|
|
|
}
|
|
|
|
|
|
|
|
tw.end_container()?;
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
Self::Timed(_) => false,
|
2022-12-27 09:32:52 +05:30
|
|
|
};
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
if reply {
|
2022-12-27 09:32:52 +05:30
|
|
|
info!("Sending response");
|
2023-02-02 18:22:21 +00:00
|
|
|
print_tlv_list(tx.as_slice());
|
2022-12-27 09:32:52 +05:30
|
|
|
}
|
2023-02-02 18:22:21 +00:00
|
|
|
|
|
|
|
if transaction.is_terminate() {
|
|
|
|
transaction.ctx.exch.terminate();
|
|
|
|
} else if transaction.is_complete() {
|
|
|
|
transaction.ctx.exch.close();
|
2022-12-27 09:32:52 +05:30
|
|
|
}
|
2023-02-02 18:22:21 +00:00
|
|
|
|
|
|
|
Ok(true)
|
2022-12-27 09:32:52 +05:30
|
|
|
}
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
fn create_status_response(tx: &mut Packet, status: IMStatusCode) -> Result<(), Error> {
|
|
|
|
tx.set_proto_id(PROTO_ID_INTERACTION_MODEL as u16);
|
|
|
|
tx.set_proto_opcode(OpCode::StatusResponse as u8);
|
|
|
|
|
|
|
|
let mut tw = TLVWriter::new(tx.get_writebuf()?);
|
|
|
|
|
|
|
|
let status = StatusResp { status };
|
|
|
|
status.to_tlv(&mut tw, TagType::Anonymous)
|
2022-12-27 09:32:52 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
pub trait InteractionHandler {
|
|
|
|
fn handle<'a>(&mut self, ctx: &'a mut ProtoCtx) -> Result<Option<&'a [u8]>, Error>;
|
2022-12-27 09:32:52 +05:30
|
|
|
}
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
impl<T> InteractionHandler for &mut T
|
|
|
|
where
|
|
|
|
T: InteractionHandler,
|
|
|
|
{
|
|
|
|
fn handle<'a>(&mut self, ctx: &'a mut ProtoCtx) -> Result<Option<&'a [u8]>, Error> {
|
|
|
|
(**self).handle(ctx)
|
2022-12-27 09:32:52 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
pub struct InteractionModel<T>(pub T);
|
|
|
|
|
|
|
|
impl<T> InteractionModel<T>
|
|
|
|
where
|
|
|
|
T: DataHandler,
|
|
|
|
{
|
|
|
|
pub fn handle<'a>(&mut self, ctx: &'a mut ProtoCtx) -> Result<Option<&'a [u8]>, Error> {
|
|
|
|
let interaction = Interaction::new(ctx.rx)?;
|
|
|
|
let mut transaction = Transaction::new(&mut ctx.exch_ctx);
|
|
|
|
|
|
|
|
let reply = if interaction.initiate_tx(ctx.tx, &mut transaction)? {
|
|
|
|
self.0.handle(&interaction, ctx.tx, &mut transaction)?;
|
|
|
|
interaction.complete_tx(ctx.tx, &mut transaction)?
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(reply.then_some(ctx.tx.as_slice()))
|
2022-12-27 09:32:52 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-02 18:22:21 +00:00
|
|
|
#[cfg(feature = "nightly")]
|
|
|
|
impl<T> InteractionModel<T>
|
|
|
|
where
|
|
|
|
T: crate::data_model::core::asynch::AsyncDataHandler,
|
|
|
|
{
|
|
|
|
pub async fn handle_async<'a>(
|
|
|
|
&mut self,
|
|
|
|
ctx: &'a mut ProtoCtx<'_, '_>,
|
|
|
|
) -> Result<Option<&'a [u8]>, Error> {
|
|
|
|
let interaction = Interaction::new(ctx.rx)?;
|
|
|
|
let mut transaction = Transaction::new(&mut ctx.exch_ctx);
|
|
|
|
|
|
|
|
let reply = if interaction.initiate_tx(ctx.tx, &mut transaction)? {
|
|
|
|
self.0
|
|
|
|
.handle(&interaction, ctx.tx, &mut transaction)
|
|
|
|
.await?;
|
|
|
|
interaction.complete_tx(ctx.tx, &mut transaction)?
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(reply.then_some(ctx.tx.as_slice()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> InteractionHandler for InteractionModel<T>
|
|
|
|
where
|
|
|
|
T: DataHandler,
|
|
|
|
{
|
|
|
|
fn handle<'a>(&mut self, ctx: &'a mut ProtoCtx) -> Result<Option<&'a [u8]>, Error> {
|
|
|
|
InteractionModel::handle(self, ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "nightly")]
|
|
|
|
pub mod asynch {
|
|
|
|
use crate::{
|
|
|
|
data_model::core::asynch::AsyncDataHandler, error::Error, transport::proto_ctx::ProtoCtx,
|
|
|
|
};
|
|
|
|
|
|
|
|
use super::InteractionModel;
|
|
|
|
|
|
|
|
pub trait AsyncInteractionHandler {
|
|
|
|
async fn handle<'a>(
|
|
|
|
&mut self,
|
|
|
|
ctx: &'a mut ProtoCtx<'_, '_>,
|
|
|
|
) -> Result<Option<&'a [u8]>, Error>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> AsyncInteractionHandler for &mut T
|
|
|
|
where
|
|
|
|
T: AsyncInteractionHandler,
|
|
|
|
{
|
|
|
|
async fn handle<'a>(
|
|
|
|
&mut self,
|
|
|
|
ctx: &'a mut ProtoCtx<'_, '_>,
|
|
|
|
) -> Result<Option<&'a [u8]>, Error> {
|
|
|
|
(**self).handle(ctx).await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> AsyncInteractionHandler for InteractionModel<T>
|
|
|
|
where
|
|
|
|
T: AsyncDataHandler,
|
|
|
|
{
|
|
|
|
async fn handle<'a>(
|
|
|
|
&mut self,
|
|
|
|
ctx: &'a mut ProtoCtx<'_, '_>,
|
|
|
|
) -> Result<Option<&'a [u8]>, Error> {
|
|
|
|
InteractionModel::handle_async(self, ctx).await
|
|
|
|
}
|
2022-12-27 09:32:52 +05:30
|
|
|
}
|
|
|
|
}
|