1use crate::didcomm::PlainMessage;
7use crate::error::{Error, Result};
8use crate::message::{
9 AddAgents, AuthorizationRequired, Authorize, Cancel, ConfirmRelationship, Connect,
10 DIDCommPresentation, ErrorBody, OutOfBand, Payment, Presentation, Reject, RemoveAgent,
11 ReplaceAgent, RequestPresentation, Revert, Settle, Transfer, UpdateParty, UpdatePolicies,
12};
13use serde::{Deserialize, Serialize};
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
17#[serde(untagged)]
18#[allow(clippy::large_enum_variant)]
19pub enum TapMessage {
20 AddAgents(AddAgents),
22 Authorize(Authorize),
24 AuthorizationRequired(AuthorizationRequired),
26 Cancel(Cancel),
28 ConfirmRelationship(ConfirmRelationship),
30 Connect(Connect),
32 DIDCommPresentation(DIDCommPresentation),
34 Error(ErrorBody),
36 OutOfBand(OutOfBand),
38 Payment(Payment),
40 Presentation(Presentation),
42 Reject(Reject),
44 RemoveAgent(RemoveAgent),
46 ReplaceAgent(ReplaceAgent),
48 RequestPresentation(RequestPresentation),
50 Revert(Revert),
52 Settle(Settle),
54 Transfer(Transfer),
56 UpdateParty(UpdateParty),
58 UpdatePolicies(UpdatePolicies),
60}
61
62impl TapMessage {
63 pub fn from_plain_message(plain_msg: &PlainMessage) -> Result<Self> {
66 let message_type =
68 if !plain_msg.type_.is_empty() && plain_msg.type_ != "application/didcomm-plain+json" {
69 &plain_msg.type_
70 } else if let Some(body_obj) = plain_msg.body.as_object() {
71 if let Some(type_val) = body_obj.get("@type") {
72 type_val.as_str().unwrap_or("")
73 } else {
74 ""
75 }
76 } else {
77 ""
78 };
79
80 if message_type.is_empty() {
81 return Err(Error::Validation(
82 "Message type not found in PlainMessage".to_string(),
83 ));
84 }
85
86 match message_type {
88 "https://tap.rsvp/schema/1.0#AddAgents" => {
89 let msg: AddAgents =
90 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
91 Error::SerializationError(format!("Failed to parse AddAgents: {}", e))
92 })?;
93 Ok(TapMessage::AddAgents(msg))
94 }
95 "https://tap.rsvp/schema/1.0#Authorize" => {
96 let msg: Authorize =
97 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
98 Error::SerializationError(format!("Failed to parse Authorize: {}", e))
99 })?;
100 Ok(TapMessage::Authorize(msg))
101 }
102 "https://tap.rsvp/schema/1.0#AuthorizationRequired" => {
103 let msg: AuthorizationRequired = serde_json::from_value(plain_msg.body.clone())
104 .map_err(|e| {
105 Error::SerializationError(format!(
106 "Failed to parse AuthorizationRequired: {}",
107 e
108 ))
109 })?;
110 Ok(TapMessage::AuthorizationRequired(msg))
111 }
112 "https://tap.rsvp/schema/1.0#Cancel" => {
113 let msg: Cancel = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
114 Error::SerializationError(format!("Failed to parse Cancel: {}", e))
115 })?;
116 Ok(TapMessage::Cancel(msg))
117 }
118 "https://tap.rsvp/schema/1.0#ConfirmRelationship" => {
119 let msg: ConfirmRelationship = serde_json::from_value(plain_msg.body.clone())
120 .map_err(|e| {
121 Error::SerializationError(format!(
122 "Failed to parse ConfirmRelationship: {}",
123 e
124 ))
125 })?;
126 Ok(TapMessage::ConfirmRelationship(msg))
127 }
128 "https://tap.rsvp/schema/1.0#Connect" => {
129 let msg: Connect = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
130 Error::SerializationError(format!("Failed to parse Connect: {}", e))
131 })?;
132 Ok(TapMessage::Connect(msg))
133 }
134 "https://didcomm.org/present-proof/3.0/presentation" => {
135 let msg: DIDCommPresentation = serde_json::from_value(plain_msg.body.clone())
136 .map_err(|e| {
137 Error::SerializationError(format!(
138 "Failed to parse DIDCommPresentation: {}",
139 e
140 ))
141 })?;
142 Ok(TapMessage::DIDCommPresentation(msg))
143 }
144 "https://tap.rsvp/schema/1.0#Error" => {
145 let msg: ErrorBody =
146 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
147 Error::SerializationError(format!("Failed to parse Error: {}", e))
148 })?;
149 Ok(TapMessage::Error(msg))
150 }
151 "https://tap.rsvp/schema/1.0#OutOfBand" => {
152 let msg: OutOfBand =
153 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
154 Error::SerializationError(format!("Failed to parse OutOfBand: {}", e))
155 })?;
156 Ok(TapMessage::OutOfBand(msg))
157 }
158 "https://tap.rsvp/schema/1.0#Payment" => {
159 let msg: Payment = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
160 Error::SerializationError(format!("Failed to parse Payment: {}", e))
161 })?;
162 Ok(TapMessage::Payment(msg))
163 }
164 "https://tap.rsvp/schema/1.0#Presentation" => {
165 let msg: Presentation =
166 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
167 Error::SerializationError(format!("Failed to parse Presentation: {}", e))
168 })?;
169 Ok(TapMessage::Presentation(msg))
170 }
171 "https://tap.rsvp/schema/1.0#Reject" => {
172 let msg: Reject = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
173 Error::SerializationError(format!("Failed to parse Reject: {}", e))
174 })?;
175 Ok(TapMessage::Reject(msg))
176 }
177 "https://tap.rsvp/schema/1.0#RemoveAgent" => {
178 let msg: RemoveAgent =
179 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
180 Error::SerializationError(format!("Failed to parse RemoveAgent: {}", e))
181 })?;
182 Ok(TapMessage::RemoveAgent(msg))
183 }
184 "https://tap.rsvp/schema/1.0#ReplaceAgent" => {
185 let msg: ReplaceAgent =
186 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
187 Error::SerializationError(format!("Failed to parse ReplaceAgent: {}", e))
188 })?;
189 Ok(TapMessage::ReplaceAgent(msg))
190 }
191 "https://tap.rsvp/schema/1.0#RequestPresentation" => {
192 let msg: RequestPresentation = serde_json::from_value(plain_msg.body.clone())
193 .map_err(|e| {
194 Error::SerializationError(format!(
195 "Failed to parse RequestPresentation: {}",
196 e
197 ))
198 })?;
199 Ok(TapMessage::RequestPresentation(msg))
200 }
201 "https://tap.rsvp/schema/1.0#Revert" => {
202 let msg: Revert = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
203 Error::SerializationError(format!("Failed to parse Revert: {}", e))
204 })?;
205 Ok(TapMessage::Revert(msg))
206 }
207 "https://tap.rsvp/schema/1.0#Settle" => {
208 let msg: Settle = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
209 Error::SerializationError(format!("Failed to parse Settle: {}", e))
210 })?;
211 Ok(TapMessage::Settle(msg))
212 }
213 "https://tap.rsvp/schema/1.0#Transfer" => {
214 let msg: Transfer =
215 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
216 Error::SerializationError(format!("Failed to parse Transfer: {}", e))
217 })?;
218 Ok(TapMessage::Transfer(msg))
219 }
220 "https://tap.rsvp/schema/1.0#UpdateParty" => {
221 let msg: UpdateParty =
222 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
223 Error::SerializationError(format!("Failed to parse UpdateParty: {}", e))
224 })?;
225 Ok(TapMessage::UpdateParty(msg))
226 }
227 "https://tap.rsvp/schema/1.0#UpdatePolicies" => {
228 let msg: UpdatePolicies =
229 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
230 Error::SerializationError(format!("Failed to parse UpdatePolicies: {}", e))
231 })?;
232 Ok(TapMessage::UpdatePolicies(msg))
233 }
234 _ => Err(Error::Validation(format!(
235 "Unknown message type: {}",
236 message_type
237 ))),
238 }
239 }
240
241 pub fn message_type(&self) -> &'static str {
243 match self {
244 TapMessage::AddAgents(_) => "https://tap.rsvp/schema/1.0#AddAgents",
245 TapMessage::Authorize(_) => "https://tap.rsvp/schema/1.0#Authorize",
246 TapMessage::AuthorizationRequired(_) => {
247 "https://tap.rsvp/schema/1.0#AuthorizationRequired"
248 }
249 TapMessage::Cancel(_) => "https://tap.rsvp/schema/1.0#Cancel",
250 TapMessage::ConfirmRelationship(_) => "https://tap.rsvp/schema/1.0#ConfirmRelationship",
251 TapMessage::Connect(_) => "https://tap.rsvp/schema/1.0#Connect",
252 TapMessage::DIDCommPresentation(_) => {
253 "https://didcomm.org/present-proof/3.0/presentation"
254 }
255 TapMessage::Error(_) => "https://tap.rsvp/schema/1.0#Error",
256 TapMessage::OutOfBand(_) => "https://tap.rsvp/schema/1.0#OutOfBand",
257 TapMessage::Payment(_) => "https://tap.rsvp/schema/1.0#Payment",
258 TapMessage::Presentation(_) => "https://tap.rsvp/schema/1.0#Presentation",
259 TapMessage::Reject(_) => "https://tap.rsvp/schema/1.0#Reject",
260 TapMessage::RemoveAgent(_) => "https://tap.rsvp/schema/1.0#RemoveAgent",
261 TapMessage::ReplaceAgent(_) => "https://tap.rsvp/schema/1.0#ReplaceAgent",
262 TapMessage::RequestPresentation(_) => "https://tap.rsvp/schema/1.0#RequestPresentation",
263 TapMessage::Revert(_) => "https://tap.rsvp/schema/1.0#Revert",
264 TapMessage::Settle(_) => "https://tap.rsvp/schema/1.0#Settle",
265 TapMessage::Transfer(_) => "https://tap.rsvp/schema/1.0#Transfer",
266 TapMessage::UpdateParty(_) => "https://tap.rsvp/schema/1.0#UpdateParty",
267 TapMessage::UpdatePolicies(_) => "https://tap.rsvp/schema/1.0#UpdatePolicies",
268 }
269 }
270}
271
272#[cfg(test)]
273mod tests {
274 use super::*;
275 use serde_json::json;
276
277 #[test]
278 fn test_parse_transfer_body() {
279 let body = json!({
280 "@type": "https://tap.rsvp/schema/1.0#Transfer",
281 "transaction_id": "test-tx-123",
282 "asset": {
283 "chain_id": {
284 "namespace": "eip155",
285 "reference": "1"
286 },
287 "namespace": "slip44",
288 "reference": "60"
289 },
290 "originator": {
291 "@id": "did:example:alice"
292 },
293 "amount": "100",
294 "agents": [],
295 "metadata": {}
296 });
297
298 match serde_json::from_value::<Transfer>(body.clone()) {
299 Ok(transfer) => {
300 println!("Successfully parsed Transfer: {:?}", transfer);
301 assert_eq!(transfer.amount, "100");
302 }
303 Err(e) => {
304 panic!("Failed to parse Transfer: {}", e);
305 }
306 }
307 }
308
309 #[test]
310 fn test_from_plain_message_transfer() {
311 let plain_msg = PlainMessage {
312 id: "test-123".to_string(),
313 typ: "application/didcomm-plain+json".to_string(),
314 type_: "https://tap.rsvp/schema/1.0#Transfer".to_string(),
315 body: json!({
316 "@type": "https://tap.rsvp/schema/1.0#Transfer",
317 "transaction_id": "test-tx-456",
318 "asset": {
319 "chain_id": {
320 "namespace": "eip155",
321 "reference": "1"
322 },
323 "namespace": "slip44",
324 "reference": "60"
325 },
326 "originator": {
327 "@id": "did:example:alice"
328 },
329 "amount": "100",
330 "agents": [],
331 "metadata": {}
332 }),
333 from: "did:example:alice".to_string(),
334 to: vec!["did:example:bob".to_string()],
335 thid: None,
336 pthid: None,
337 created_time: Some(1234567890),
338 expires_time: None,
339 from_prior: None,
340 attachments: None,
341 extra_headers: Default::default(),
342 };
343
344 let tap_msg = TapMessage::from_plain_message(&plain_msg).unwrap();
345
346 match tap_msg {
347 TapMessage::Transfer(transfer) => {
348 assert_eq!(transfer.amount, "100");
349 assert_eq!(transfer.originator.id, "did:example:alice");
350 }
351 _ => panic!("Expected Transfer message"),
352 }
353 }
354
355 #[test]
356 fn test_message_type() {
357 let transfer = Transfer {
358 asset: "eip155:1/slip44:60".parse().unwrap(),
359 originator: crate::message::Party::new("did:example:alice"),
360 beneficiary: None,
361 amount: "100".to_string(),
362 agents: vec![],
363 memo: None,
364 settlement_id: None,
365 connection_id: None,
366 transaction_id: "tx-123".to_string(),
367 metadata: Default::default(),
368 };
369
370 let tap_msg = TapMessage::Transfer(transfer);
371 assert_eq!(
372 tap_msg.message_type(),
373 "https://tap.rsvp/schema/1.0#Transfer"
374 );
375 }
376}