tap_node/message/
trust_ping_processor.rs1use crate::error::{Error, Result};
6use crate::event::EventBus;
7use crate::message::processor::PlainMessageProcessor;
8use async_trait::async_trait;
9use serde_json;
10use std::collections::HashMap;
11use std::sync::Arc;
12use tap_msg::didcomm::PlainMessage;
13use tap_msg::message::tap_message_trait::TapMessageBody;
14use tap_msg::message::{TrustPing, TrustPingResponse};
15
16pub struct TrustPingProcessor {
18 event_bus: Option<Arc<EventBus>>,
20}
21
22impl std::fmt::Debug for TrustPingProcessor {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 f.debug_struct("TrustPingProcessor")
26 .field("event_bus", &self.event_bus.is_some())
27 .finish()
28 }
29}
30
31impl Clone for TrustPingProcessor {
33 fn clone(&self) -> Self {
34 Self {
35 event_bus: self.event_bus.clone(),
36 }
37 }
38}
39
40impl Default for TrustPingProcessor {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl TrustPingProcessor {
47 pub fn new() -> Self {
49 Self { event_bus: None }
50 }
51
52 pub fn with_event_bus(event_bus: Arc<EventBus>) -> Self {
54 Self {
55 event_bus: Some(event_bus),
56 }
57 }
58
59 fn generate_ping_response(ping_message: &PlainMessage) -> Result<PlainMessage> {
61 let _ping: TrustPing = serde_json::from_value(ping_message.body.clone())
63 .map_err(|e| Error::Serialization(format!("Failed to parse TrustPing: {}", e)))?;
64
65 let response =
67 TrustPingResponse::with_comment(ping_message.id.clone(), "Pong!".to_string());
68
69 let response_message = PlainMessage {
71 id: uuid::Uuid::new_v4().to_string(),
72 typ: "application/didcomm-plain+json".to_string(),
73 type_: TrustPingResponse::message_type().to_string(),
74 body: serde_json::to_value(&response).map_err(|e| {
75 Error::Serialization(format!("Failed to serialize response: {}", e))
76 })?,
77 from: ping_message.to[0].clone(), to: vec![ping_message.from.clone()], thid: Some(ping_message.id.clone()), pthid: None,
81 extra_headers: HashMap::new(),
82 attachments: None,
83 created_time: Some(chrono::Utc::now().timestamp_millis() as u64),
84 expires_time: None,
85 from_prior: None,
86 };
87
88 Ok(response_message)
89 }
90
91 fn should_respond_to_ping(message: &PlainMessage) -> bool {
93 if message.type_ != TrustPing::message_type() {
94 return false;
95 }
96
97 if let Ok(ping) = serde_json::from_value::<TrustPing>(message.body.clone()) {
99 ping.response_requested
100 } else {
101 false
102 }
103 }
104}
105
106#[async_trait]
107impl PlainMessageProcessor for TrustPingProcessor {
108 async fn process_incoming(&self, message: PlainMessage) -> Result<Option<PlainMessage>> {
109 if Self::should_respond_to_ping(&message) {
111 log::debug!(
112 "Received Trust Ping from {}, generating response",
113 message.from
114 );
115
116 match Self::generate_ping_response(&message) {
118 Ok(response) => {
119 log::debug!("Generated Trust Ping response for message {}", message.id);
120
121 if let Some(ref event_bus) = self.event_bus {
123 let from = response.from.clone();
125 let to = response.to.first().cloned().unwrap_or_default();
126
127 event_bus.publish_message_sent(response, from, to).await;
129 log::info!("Successfully published Trust Ping response via event bus");
130 } else {
131 log::info!("Trust Ping response generated (no event bus configured): id={}, to={:?}", response.id, response.to);
133 }
134 }
135 Err(e) => {
136 log::warn!("Failed to generate Trust Ping response: {}", e);
137 }
138 }
139 }
140
141 Ok(Some(message))
143 }
144
145 async fn process_outgoing(&self, message: PlainMessage) -> Result<Option<PlainMessage>> {
146 Ok(Some(message))
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154 use tap_msg::message::TrustPing;
155
156 #[test]
157 fn test_should_respond_to_ping() {
158 let ping = TrustPing::new().response_requested(true);
160 let ping_message = PlainMessage {
161 id: "ping-123".to_string(),
162 typ: "application/didcomm-plain+json".to_string(),
163 type_: TrustPing::message_type().to_string(),
164 body: serde_json::to_value(&ping).unwrap(),
165 from: "did:example:sender".to_string(),
166 to: vec!["did:example:recipient".to_string()],
167 thid: None,
168 pthid: None,
169 extra_headers: HashMap::new(),
170 attachments: None,
171 created_time: Some(chrono::Utc::now().timestamp_millis() as u64),
172 expires_time: None,
173 from_prior: None,
174 };
175
176 assert!(TrustPingProcessor::should_respond_to_ping(&ping_message));
177
178 let ping_no_response = TrustPing::new().response_requested(false);
180 let ping_message_no_response = PlainMessage {
181 id: "ping-456".to_string(),
182 typ: "application/didcomm-plain+json".to_string(),
183 type_: TrustPing::message_type().to_string(),
184 body: serde_json::to_value(&ping_no_response).unwrap(),
185 from: "did:example:sender".to_string(),
186 to: vec!["did:example:recipient".to_string()],
187 thid: None,
188 pthid: None,
189 extra_headers: HashMap::new(),
190 attachments: None,
191 created_time: Some(chrono::Utc::now().timestamp_millis() as u64),
192 expires_time: None,
193 from_prior: None,
194 };
195
196 assert!(!TrustPingProcessor::should_respond_to_ping(
197 &ping_message_no_response
198 ));
199 }
200
201 #[test]
202 fn test_generate_ping_response() {
203 let ping = TrustPing::with_comment("Hello!".to_string()).response_requested(true);
204
205 let ping_message = PlainMessage {
206 id: "ping-123".to_string(),
207 typ: "application/didcomm-plain+json".to_string(),
208 type_: TrustPing::message_type().to_string(),
209 body: serde_json::to_value(&ping).unwrap(),
210 from: "did:example:sender".to_string(),
211 to: vec!["did:example:recipient".to_string()],
212 thid: None,
213 pthid: None,
214 extra_headers: HashMap::new(),
215 attachments: None,
216 created_time: Some(chrono::Utc::now().timestamp_millis() as u64),
217 expires_time: None,
218 from_prior: None,
219 };
220
221 let response = TrustPingProcessor::generate_ping_response(&ping_message).unwrap();
222
223 assert_eq!(response.type_, TrustPingResponse::message_type());
224 assert_eq!(response.from, "did:example:recipient");
225 assert_eq!(response.to, vec!["did:example:sender"]);
226 assert_eq!(response.thid, Some("ping-123".to_string()));
227
228 let response_body: TrustPingResponse = serde_json::from_value(response.body).unwrap();
230 assert_eq!(response_body.thread_id, "ping-123");
231 assert_eq!(response_body.comment, Some("Pong!".to_string()));
232 }
233}