1use std::string;
5
6use crate::api::ProtoName;
7use crate::api::ProtoSessionMessageType;
8use crate::api::proto::dataplane::v1::Message;
9use crate::messages::utils::MessageError;
10use agntcy_slim_proto::NameError;
11#[cfg(not(target_arch = "wasm32"))]
12use slim_config::errors::ConfigError;
13use thiserror::Error;
14
15#[derive(Error, Debug)]
17pub enum DataPathError {
18 #[error("connection error")]
20 ConnectionError,
21 #[error("disconnection error")]
22 DisconnectionError(u64),
23 #[cfg(not(target_arch = "wasm32"))]
24 #[error("grpc error")]
25 GrpcError(#[from] tonic::Status),
26 #[error("link negotiation error {0}")]
27 NegotiationError(String),
28
29 #[error("unknown message type")]
31 UnknownMsgType,
32 #[error("invalid message: {0}")]
33 InvalidMessage(MessageError),
34 #[error("invalid name id format: {0}")]
35 InvalidNameIdFormat(String),
36 #[error("invalid name format: {0}")]
37 InvalidNameFormat(String),
38
39 #[error("no matching found for [{:x}, {:x}, {:x}, {}]", .0, .1, .2, .3)]
41 NoMatchEncoded(u64, u64, u64, String),
42 #[error("subscription not found")]
43 SubscriptionNotFound(ProtoName),
44 #[error("subscription id not found: {0}")]
45 SubscriptionIdNotFound(u64),
46 #[error("id not found: {0}")]
47 IdNotFound(string::String),
48
49 #[error("connection not found: {0}")]
51 ConnectionNotFound(u64),
52 #[error("connection id not found: {0}")]
53 ConnectionIdNotFound(u64),
54
55 #[error("malformed message")]
57 MalformedMessage(#[from] MessageError),
58 #[error("message processing error: {0}")]
59 ProcessingError(MessageError),
60 #[error("connection send error")]
61 ConnectionSendError,
62 #[error("error adding connection to connection table")]
63 ConnectionTableAddError,
64 #[error("message processing error: {source}")]
65 MessageProcessingError {
66 #[source]
67 source: Box<DataPathError>,
68 msg: Box<Message>,
69 },
70
71 #[cfg(not(target_arch = "wasm32"))]
73 #[error("configuration error")]
74 ConfigurationError(#[from] ConfigError),
75
76 #[error("remote subscription ack timed out after {0} retries")]
78 RemoteSubscriptionAckTimeout(u32),
79
80 #[error("remote subscription ack error")]
81 RemoteSubscriptionAckError(String),
82
83 #[error("data path is already closed")]
85 AlreadyClosedError,
86 #[error("data plane is shutting down")]
87 ShuttingDownError,
88 #[error("timeout during shutdown")]
89 ShutdownTimeoutError,
90
91 #[cfg(not(target_arch = "wasm32"))]
92 #[error("SLIM header integrity: {0}")]
93 HeaderIntegrity(#[from] crate::header_mac::HeaderMacError),
94
95 #[error("header MAC requires completed link negotiation on connection {0}")]
96 HeaderMacAwaitingLinkNegotiation(u64),
97
98 #[error("inter-node ephemeral key generation failed")]
99 LinkKeyGeneration,
100
101 #[error("message TTL expired")]
102 TtlExpired,
103}
104
105#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
106pub struct MessageContext {
107 pub message_id: u32,
108 pub session_id: u32,
109 pub session_message_type: i32,
110}
111
112impl From<NameError> for DataPathError {
113 fn from(value: NameError) -> Self {
114 match value {
115 NameError::InvalidNameIdFormat(name) => Self::InvalidNameIdFormat(name),
116 NameError::InvalidNameFormat(name) => Self::InvalidNameFormat(name),
117 }
118 }
119}
120
121impl MessageContext {
122 pub fn from_msg(msg: &Message) -> Option<Self> {
123 msg.try_get_session_header().map(|header| Self {
124 message_id: header.get_message_id(),
125 session_id: header.get_session_id(),
126 session_message_type: header.session_message_type().into(),
127 })
128 }
129
130 pub fn get_session_message_type(&self) -> ProtoSessionMessageType {
131 self.session_message_type
132 .try_into()
133 .unwrap_or(ProtoSessionMessageType::Unspecified)
134 }
135}
136
137#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
140pub struct ErrorPayload {
141 pub error: String,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub session_context: Option<MessageContext>,
144}
145
146impl std::fmt::Display for ErrorPayload {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 write!(f, "ErrorPayload: {}", self.error)?;
149 match &self.session_context {
150 Some(ctx) => write!(
151 f,
152 " (session_id={}, message_id={}, session_message_type={:?})",
153 ctx.session_id,
154 ctx.message_id,
155 ctx.get_session_message_type()
156 ),
157 None => Ok(()),
158 }
159 }
160}
161
162impl ErrorPayload {
163 pub fn new(error: String, session_context: Option<MessageContext>) -> Self {
165 Self {
166 error,
167 session_context,
168 }
169 }
170
171 pub fn to_json_string(&self) -> String {
173 serde_json::to_string(self).expect("ErrorPayload should be serializable")
174 }
175
176 pub fn from_json_str(s: &str) -> Option<Self> {
178 serde_json::from_str(s).ok()
179 }
180}