Skip to main content

ave_common/bridge/
conversions.rs

1//! Type conversions between Bridge API types and internal types
2//!
3//! This module provides trait-based conversions between the lightweight bridge types
4//! used for API communication and the internal types used for business logic.
5
6use std::str::FromStr;
7
8use ave_identity::{DigestIdentifier, PublicKey, Signed};
9
10use crate::{
11    Namespace, SchemaType, ValueWrapper,
12    bridge::request::{
13        BridgeConfirmRequest, BridgeCreateRequest, BridgeEOLRequest,
14        BridgeEventRequest, BridgeFactRequest, BridgeRejectRequest,
15        BridgeSignedEventRequest, BridgeTransferRequest,
16    },
17    error::ConversionError,
18    request::{
19        ConfirmRequest, CreateRequest, EOLRequest, EventRequest, FactRequest,
20        RejectRequest, TransferRequest,
21    },
22    signature::BridgeSignature,
23};
24
25// ============================================================================
26// EventRequest conversions
27// ============================================================================
28
29impl From<Signed<EventRequest>> for BridgeSignedEventRequest {
30    fn from(value: Signed<EventRequest>) -> Self {
31        let request = BridgeEventRequest::from(value.content().clone());
32        let signature = Some(BridgeSignature::from(value.signature().clone()));
33
34        Self { request, signature }
35    }
36}
37
38impl From<EventRequest> for BridgeSignedEventRequest {
39    fn from(value: EventRequest) -> Self {
40        let request = BridgeEventRequest::from(value.clone());
41        let signature = None;
42
43        Self { request, signature }
44    }
45}
46
47impl From<EventRequest> for BridgeEventRequest {
48    fn from(request: EventRequest) -> Self {
49        match request {
50            EventRequest::Create(req) => BridgeEventRequest::Create(req.into()),
51            EventRequest::Fact(req) => BridgeEventRequest::Fact(req.into()),
52            EventRequest::Transfer(req) => {
53                BridgeEventRequest::Transfer(req.into())
54            }
55            EventRequest::EOL(req) => BridgeEventRequest::Eol(req.into()),
56            EventRequest::Confirm(req) => {
57                BridgeEventRequest::Confirm(req.into())
58            }
59            EventRequest::Reject(req) => BridgeEventRequest::Reject(req.into()),
60        }
61    }
62}
63
64impl TryFrom<BridgeEventRequest> for EventRequest {
65    type Error = ConversionError;
66
67    fn try_from(request: BridgeEventRequest) -> Result<Self, Self::Error> {
68        match request {
69            BridgeEventRequest::Create(req) => {
70                Ok(EventRequest::Create(req.try_into()?))
71            }
72            BridgeEventRequest::Fact(req) => {
73                Ok(EventRequest::Fact(req.try_into()?))
74            }
75            BridgeEventRequest::Transfer(req) => {
76                Ok(EventRequest::Transfer(req.try_into()?))
77            }
78            BridgeEventRequest::Eol(req) => {
79                Ok(EventRequest::EOL(req.try_into()?))
80            }
81            BridgeEventRequest::Confirm(req) => {
82                Ok(EventRequest::Confirm(req.try_into()?))
83            }
84            BridgeEventRequest::Reject(req) => {
85                Ok(EventRequest::Reject(req.try_into()?))
86            }
87        }
88    }
89}
90
91// ============================================================================
92// CreateRequest conversions
93// ============================================================================
94
95impl From<CreateRequest> for BridgeCreateRequest {
96    fn from(request: CreateRequest) -> Self {
97        BridgeCreateRequest {
98            name: request.name,
99            description: request.description,
100            governance_id: Some(request.governance_id.to_string()),
101            schema_id: request.schema_id.to_string(),
102            namespace: Some(request.namespace.to_string()),
103        }
104    }
105}
106
107impl TryFrom<BridgeCreateRequest> for CreateRequest {
108    type Error = ConversionError;
109
110    fn try_from(request: BridgeCreateRequest) -> Result<Self, Self::Error> {
111        let governance_id = if let Some(governance_id) = request.governance_id {
112            DigestIdentifier::from_str(&governance_id).map_err(|e| {
113                ConversionError::InvalidGovernanceId(e.to_string())
114            })?
115        } else {
116            DigestIdentifier::default()
117        };
118
119        let schema_id = SchemaType::from_str(&request.schema_id)
120            .map_err(ConversionError::InvalidSchemaId)?;
121
122        let namespace = if let Some(namespace) = request.namespace {
123            Namespace::from(namespace)
124        } else {
125            Namespace::new()
126        };
127
128        Ok(CreateRequest {
129            name: request.name,
130            description: request.description,
131            governance_id,
132            schema_id,
133            namespace,
134        })
135    }
136}
137
138// ============================================================================
139// FactRequest conversions
140// ============================================================================
141
142impl From<FactRequest> for BridgeFactRequest {
143    fn from(request: FactRequest) -> Self {
144        BridgeFactRequest {
145            subject_id: request.subject_id.to_string(),
146            payload: request.payload.0,
147        }
148    }
149}
150
151impl TryFrom<BridgeFactRequest> for FactRequest {
152    type Error = ConversionError;
153
154    fn try_from(request: BridgeFactRequest) -> Result<Self, Self::Error> {
155        let subject_id = DigestIdentifier::from_str(&request.subject_id)
156            .map_err(|e| ConversionError::InvalidSubjectId(e.to_string()))?;
157
158        Ok(FactRequest {
159            subject_id,
160            payload: ValueWrapper(request.payload),
161        })
162    }
163}
164
165// ============================================================================
166// TransferRequest conversions
167// ============================================================================
168
169impl From<TransferRequest> for BridgeTransferRequest {
170    fn from(request: TransferRequest) -> Self {
171        BridgeTransferRequest {
172            subject_id: request.subject_id.to_string(),
173            new_owner: request.new_owner.to_string(),
174        }
175    }
176}
177
178impl TryFrom<BridgeTransferRequest> for TransferRequest {
179    type Error = ConversionError;
180
181    fn try_from(request: BridgeTransferRequest) -> Result<Self, Self::Error> {
182        let subject_id = DigestIdentifier::from_str(&request.subject_id)
183            .map_err(|e| ConversionError::InvalidSubjectId(e.to_string()))?;
184
185        let new_owner = PublicKey::from_str(&request.new_owner)
186            .map_err(|e| ConversionError::InvalidPublicKey(e.to_string()))?;
187
188        Ok(TransferRequest {
189            subject_id,
190            new_owner,
191        })
192    }
193}
194
195// ============================================================================
196// EOLRequest conversions
197// ============================================================================
198
199impl From<EOLRequest> for BridgeEOLRequest {
200    fn from(request: EOLRequest) -> Self {
201        BridgeEOLRequest {
202            subject_id: request.subject_id.to_string(),
203        }
204    }
205}
206
207impl TryFrom<BridgeEOLRequest> for EOLRequest {
208    type Error = ConversionError;
209
210    fn try_from(request: BridgeEOLRequest) -> Result<Self, Self::Error> {
211        let subject_id = DigestIdentifier::from_str(&request.subject_id)
212            .map_err(|e| ConversionError::InvalidSubjectId(e.to_string()))?;
213
214        Ok(EOLRequest { subject_id })
215    }
216}
217
218// ============================================================================
219// ConfirmRequest conversions
220// ============================================================================
221
222impl From<ConfirmRequest> for BridgeConfirmRequest {
223    fn from(request: ConfirmRequest) -> Self {
224        BridgeConfirmRequest {
225            subject_id: request.subject_id.to_string(),
226            name_old_owner: request.name_old_owner,
227        }
228    }
229}
230
231impl TryFrom<BridgeConfirmRequest> for ConfirmRequest {
232    type Error = ConversionError;
233
234    fn try_from(request: BridgeConfirmRequest) -> Result<Self, Self::Error> {
235        let subject_id = DigestIdentifier::from_str(&request.subject_id)
236            .map_err(|e| ConversionError::InvalidSubjectId(e.to_string()))?;
237
238        Ok(ConfirmRequest {
239            subject_id,
240            name_old_owner: request.name_old_owner,
241        })
242    }
243}
244
245// ============================================================================
246// RejectRequest conversions
247// ============================================================================
248
249impl From<RejectRequest> for BridgeRejectRequest {
250    fn from(request: RejectRequest) -> Self {
251        BridgeRejectRequest {
252            subject_id: request.subject_id.to_string(),
253        }
254    }
255}
256
257impl TryFrom<BridgeRejectRequest> for RejectRequest {
258    type Error = ConversionError;
259
260    fn try_from(request: BridgeRejectRequest) -> Result<Self, Self::Error> {
261        let subject_id = DigestIdentifier::from_str(&request.subject_id)
262            .map_err(|e| ConversionError::InvalidSubjectId(e.to_string()))?;
263
264        Ok(RejectRequest { subject_id })
265    }
266}
267
268#[cfg(test)]
269mod tests {
270    use super::*;
271    use serde_json::json;
272
273    #[test]
274    fn test_fact_request_conversion() {
275        let bridge_fact = BridgeFactRequest {
276            subject_id: "BKZgYibuHNJjiNS179FUDpLGgdLq0C04TZRGb6AXMd1s"
277                .to_string(),
278            payload: json!({"test": "value"}),
279        };
280
281        let fact: Result<FactRequest, _> = bridge_fact.clone().try_into();
282        assert!(fact.is_ok());
283
284        let fact = fact.unwrap();
285        let bridge_back: BridgeFactRequest = fact.into();
286        assert_eq!(bridge_back.subject_id, bridge_fact.subject_id);
287    }
288
289    #[test]
290    fn test_create_request_conversion() {
291        let bridge_create = BridgeCreateRequest {
292            name: Some("Test".to_string()),
293            description: Some("Test description".to_string()),
294            governance_id: Some(
295                "BKZgYibuHNJjiNS179FUDpLGgdLq0C04TZRGb6AXMd1s".to_string(),
296            ),
297            schema_id: "governance".to_string(),
298            namespace: Some("test.namespace".to_string()),
299        };
300
301        let create: Result<CreateRequest, _> = bridge_create.try_into();
302        assert!(create.is_ok());
303    }
304
305    #[test]
306    fn test_create_request_missing_governance_id() {
307        let bridge_create = BridgeCreateRequest {
308            name: Some("Test".to_string()),
309            description: Some("Test description".to_string()),
310            governance_id: None,
311            schema_id: "governance".to_string(),
312            namespace: Some("test.namespace".to_string()),
313        };
314
315        let create: Result<CreateRequest, _> = bridge_create.try_into();
316        assert!(create.is_ok());
317    }
318
319    #[test]
320    fn test_invalid_subject_id() {
321        let bridge_fact = BridgeFactRequest {
322            subject_id: "invalid_id".to_string(),
323            payload: json!({"test": "value"}),
324        };
325
326        let fact: Result<FactRequest, _> = bridge_fact.try_into();
327        assert!(fact.is_err());
328        assert!(matches!(
329            fact.unwrap_err(),
330            ConversionError::InvalidSubjectId(_)
331        ));
332    }
333}