tap_msg/message/
context.rs1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9pub trait MessageContext {
11 fn participant_dids(&self) -> Vec<String>;
14
15 fn routing_hints(&self) -> RoutingHints {
17 RoutingHints::default()
18 }
19
20 fn transaction_context(&self) -> Option<TransactionContext> {
22 None
23 }
24
25 fn transaction_id(&self) -> Option<String> {
27 self.transaction_context().map(|ctx| ctx.transaction_id)
28 }
29}
30
31#[derive(Debug, Clone, Default, Serialize, Deserialize)]
33pub struct RoutingHints {
34 pub preferred_endpoints: Vec<String>,
36
37 pub priority: Priority,
39
40 pub require_encryption: bool,
42
43 pub metadata: HashMap<String, serde_json::Value>,
45}
46
47#[derive(Debug, Clone, Default, Serialize, Deserialize)]
49pub enum Priority {
50 High,
51 #[default]
52 Normal,
53 Low,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct TransactionContext {
59 pub transaction_id: String,
61
62 pub parent_transaction_id: Option<String>,
64
65 pub transaction_type: String,
67
68 pub metadata: HashMap<String, serde_json::Value>,
70}
71
72impl TransactionContext {
73 pub fn new(transaction_id: String, transaction_type: String) -> Self {
75 Self {
76 transaction_id,
77 parent_transaction_id: None,
78 transaction_type,
79 metadata: HashMap::new(),
80 }
81 }
82
83 pub fn with_parent(mut self, parent_id: String) -> Self {
85 self.parent_transaction_id = Some(parent_id);
86 self
87 }
88
89 pub fn with_metadata(mut self, key: String, value: serde_json::Value) -> Self {
91 self.metadata.insert(key, value);
92 self
93 }
94}
95
96pub trait ParticipantExtractor {
98 fn extract_single_participant_dids(&self) -> Vec<String>;
100
101 fn extract_list_participant_dids(&self) -> Vec<String>;
103
104 fn extract_optional_participant_dids(&self) -> Vec<String>;
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use crate::message::agent::TapParticipant;
112 use crate::message::{Agent, Party};
113
114 #[test]
115 fn test_routing_hints_default() {
116 let hints = RoutingHints::default();
117 assert!(hints.preferred_endpoints.is_empty());
118 assert!(matches!(hints.priority, Priority::Normal));
119 assert!(!hints.require_encryption);
120 assert!(hints.metadata.is_empty());
121 }
122
123 #[test]
124 fn test_transaction_context() {
125 let ctx = TransactionContext::new("tx-123".to_string(), "transfer".to_string())
126 .with_parent("parent-tx-456".to_string())
127 .with_metadata(
128 "key".to_string(),
129 serde_json::Value::String("value".to_string()),
130 );
131
132 assert_eq!(ctx.transaction_id, "tx-123");
133 assert_eq!(ctx.transaction_type, "transfer");
134 assert_eq!(ctx.parent_transaction_id, Some("parent-tx-456".to_string()));
135 assert_eq!(
136 ctx.metadata.get("key").unwrap(),
137 &serde_json::Value::String("value".to_string())
138 );
139 }
140
141 struct TestMessage {
143 originator: Party,
144 beneficiary: Option<Party>,
145 agents: Vec<Agent>,
146 transaction_id: String,
147 }
148
149 impl MessageContext for TestMessage {
150 fn participant_dids(&self) -> Vec<String> {
151 let mut dids = vec![self.originator.id().to_string()];
152 if let Some(ref beneficiary) = self.beneficiary {
153 dids.push(beneficiary.id().to_string());
154 }
155 for agent in &self.agents {
156 dids.push(agent.id().to_string());
157 }
158 dids
159 }
160
161 fn transaction_context(&self) -> Option<TransactionContext> {
162 Some(TransactionContext::new(
163 self.transaction_id.clone(),
164 "test".to_string(),
165 ))
166 }
167 }
168
169 #[test]
170 fn test_message_context() {
171 let msg = TestMessage {
172 originator: Party::new("did:example:alice"),
173 beneficiary: Some(Party::new("did:example:bob")),
174 agents: vec![Agent::new(
175 "did:example:agent",
176 "Exchange",
177 "did:example:alice",
178 )],
179 transaction_id: "tx-123".to_string(),
180 };
181
182 let dids = msg.participant_dids();
183 assert_eq!(dids.len(), 3);
184 assert!(dids.contains(&"did:example:alice".to_string()));
185 assert!(dids.contains(&"did:example:bob".to_string()));
186 assert!(dids.contains(&"did:example:agent".to_string()));
187
188 assert_eq!(msg.transaction_id(), Some("tx-123".to_string()));
189 }
190}