1use std::collections::BTreeSet;
4use std::str::FromStr;
5
6use ave_identity::{DigestIdentifier, PublicKey, Signed};
7
8use crate::{
9 Namespace, SchemaType, ValueWrapper,
10 bridge::request::{
11 BridgeConfirmRequest, BridgeCreateRequest, BridgeEOLRequest,
12 BridgeEventRequest, BridgeFactRequest, BridgeRejectRequest,
13 BridgeSignedEventRequest, BridgeTransferRequest,
14 },
15 error::ConversionError,
16 request::{
17 ConfirmRequest, CreateRequest, EOLRequest, EventRequest, FactRequest,
18 RejectRequest, TransferRequest,
19 },
20 signature::BridgeSignature,
21};
22
23impl From<Signed<EventRequest>> for BridgeSignedEventRequest {
28 fn from(value: Signed<EventRequest>) -> Self {
29 let request = BridgeEventRequest::from(value.content().clone());
30 let signature = Some(BridgeSignature::from(value.signature().clone()));
31
32 Self { request, signature }
33 }
34}
35
36impl From<EventRequest> for BridgeSignedEventRequest {
37 fn from(value: EventRequest) -> Self {
38 let request = BridgeEventRequest::from(value);
39 let signature = None;
40
41 Self { request, signature }
42 }
43}
44
45impl From<EventRequest> for BridgeEventRequest {
46 fn from(request: EventRequest) -> Self {
47 match request {
48 EventRequest::Create(req) => Self::Create(req.into()),
49 EventRequest::Fact(req) => Self::Fact(req.into()),
50 EventRequest::Transfer(req) => Self::Transfer(req.into()),
51 EventRequest::EOL(req) => Self::Eol(req.into()),
52 EventRequest::Confirm(req) => Self::Confirm(req.into()),
53 EventRequest::Reject(req) => Self::Reject(req.into()),
54 }
55 }
56}
57
58impl TryFrom<BridgeEventRequest> for EventRequest {
59 type Error = ConversionError;
60
61 fn try_from(request: BridgeEventRequest) -> Result<Self, Self::Error> {
62 match request {
63 BridgeEventRequest::Create(req) => {
64 Ok(Self::Create(req.try_into()?))
65 }
66 BridgeEventRequest::Fact(req) => Ok(Self::Fact(req.try_into()?)),
67 BridgeEventRequest::Transfer(req) => {
68 Ok(Self::Transfer(req.try_into()?))
69 }
70 BridgeEventRequest::Eol(req) => Ok(Self::EOL(req.try_into()?)),
71 BridgeEventRequest::Confirm(req) => {
72 Ok(Self::Confirm(req.try_into()?))
73 }
74 BridgeEventRequest::Reject(req) => {
75 Ok(Self::Reject(req.try_into()?))
76 }
77 }
78 }
79}
80
81impl From<CreateRequest> for BridgeCreateRequest {
86 fn from(request: CreateRequest) -> Self {
87 Self {
88 name: request.name,
89 description: request.description,
90 governance_id: Some(request.governance_id.to_string()),
91 schema_id: request.schema_id.to_string(),
92 namespace: Some(request.namespace.to_string()),
93 }
94 }
95}
96
97impl TryFrom<BridgeCreateRequest> for CreateRequest {
98 type Error = ConversionError;
99
100 fn try_from(request: BridgeCreateRequest) -> Result<Self, Self::Error> {
101 let governance_id = if let Some(governance_id) = request.governance_id {
102 DigestIdentifier::from_str(&governance_id).map_err(|e| {
103 ConversionError::InvalidGovernanceId(e.to_string())
104 })?
105 } else {
106 DigestIdentifier::default()
107 };
108
109 let schema_id = SchemaType::from_str(&request.schema_id)
110 .map_err(ConversionError::InvalidSchemaId)?;
111
112 let namespace = request
113 .namespace
114 .map_or_else(Namespace::new, Namespace::from);
115
116 Ok(Self {
117 name: request.name,
118 description: request.description,
119 governance_id,
120 schema_id,
121 namespace,
122 })
123 }
124}
125
126impl From<FactRequest> for BridgeFactRequest {
131 fn from(request: FactRequest) -> Self {
132 Self {
133 subject_id: request.subject_id.to_string(),
134 payload: request.payload.0,
135 viewpoints: request.viewpoints.into_iter().collect(),
136 }
137 }
138}
139
140impl TryFrom<BridgeFactRequest> for FactRequest {
141 type Error = ConversionError;
142
143 fn try_from(request: BridgeFactRequest) -> Result<Self, Self::Error> {
144 let subject_id = DigestIdentifier::from_str(&request.subject_id)
145 .map_err(|e| ConversionError::InvalidSubjectId(e.to_string()))?;
146
147 let mut viewpoints = BTreeSet::new();
148 for viewpoint in request.viewpoints {
149 if !viewpoints.insert(viewpoint.clone()) {
150 return Err(ConversionError::InvalidViewpoints(format!(
151 "duplicated viewpoint '{viewpoint}'"
152 )));
153 }
154 }
155
156 Ok(Self {
157 subject_id,
158 payload: ValueWrapper(request.payload),
159 viewpoints,
160 })
161 }
162}
163
164impl From<TransferRequest> for BridgeTransferRequest {
169 fn from(request: TransferRequest) -> Self {
170 Self {
171 subject_id: request.subject_id.to_string(),
172 new_owner: request.new_owner.to_string(),
173 }
174 }
175}
176
177impl TryFrom<BridgeTransferRequest> for TransferRequest {
178 type Error = ConversionError;
179
180 fn try_from(request: BridgeTransferRequest) -> Result<Self, Self::Error> {
181 let subject_id = DigestIdentifier::from_str(&request.subject_id)
182 .map_err(|e| ConversionError::InvalidSubjectId(e.to_string()))?;
183
184 let new_owner = PublicKey::from_str(&request.new_owner)
185 .map_err(|e| ConversionError::InvalidPublicKey(e.to_string()))?;
186
187 Ok(Self {
188 subject_id,
189 new_owner,
190 })
191 }
192}
193
194impl From<EOLRequest> for BridgeEOLRequest {
199 fn from(request: EOLRequest) -> Self {
200 Self {
201 subject_id: request.subject_id.to_string(),
202 }
203 }
204}
205
206impl TryFrom<BridgeEOLRequest> for EOLRequest {
207 type Error = ConversionError;
208
209 fn try_from(request: BridgeEOLRequest) -> Result<Self, Self::Error> {
210 let subject_id = DigestIdentifier::from_str(&request.subject_id)
211 .map_err(|e| ConversionError::InvalidSubjectId(e.to_string()))?;
212
213 Ok(Self { subject_id })
214 }
215}
216
217impl From<ConfirmRequest> for BridgeConfirmRequest {
222 fn from(request: ConfirmRequest) -> Self {
223 Self {
224 subject_id: request.subject_id.to_string(),
225 name_old_owner: request.name_old_owner,
226 }
227 }
228}
229
230impl TryFrom<BridgeConfirmRequest> for ConfirmRequest {
231 type Error = ConversionError;
232
233 fn try_from(request: BridgeConfirmRequest) -> Result<Self, Self::Error> {
234 let subject_id = DigestIdentifier::from_str(&request.subject_id)
235 .map_err(|e| ConversionError::InvalidSubjectId(e.to_string()))?;
236
237 Ok(Self {
238 subject_id,
239 name_old_owner: request.name_old_owner,
240 })
241 }
242}
243
244impl From<RejectRequest> for BridgeRejectRequest {
249 fn from(request: RejectRequest) -> Self {
250 Self {
251 subject_id: request.subject_id.to_string(),
252 }
253 }
254}
255
256impl TryFrom<BridgeRejectRequest> for RejectRequest {
257 type Error = ConversionError;
258
259 fn try_from(request: BridgeRejectRequest) -> Result<Self, Self::Error> {
260 let subject_id = DigestIdentifier::from_str(&request.subject_id)
261 .map_err(|e| ConversionError::InvalidSubjectId(e.to_string()))?;
262
263 Ok(Self { subject_id })
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270 use serde_json::json;
271
272 #[test]
273 fn test_fact_request_conversion() {
274 let bridge_fact = BridgeFactRequest {
275 subject_id: "BKZgYibuHNJjiNS179FUDpLGgdLq0C04TZRGb6AXMd1s"
276 .to_string(),
277 payload: json!({"test": "value"}),
278 viewpoints: vec![],
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_bridge_fact_request_defaults_missing_viewpoints_to_empty() {
291 let bridge_fact = serde_json::from_value::<BridgeFactRequest>(json!({
292 "subject_id": "BKZgYibuHNJjiNS179FUDpLGgdLq0C04TZRGb6AXMd1s",
293 "payload": {"test": "value"}
294 }))
295 .unwrap();
296
297 assert!(bridge_fact.viewpoints.is_empty());
298 }
299
300 #[test]
301 fn test_create_request_conversion() {
302 let bridge_create = BridgeCreateRequest {
303 name: Some("Test".to_string()),
304 description: Some("Test description".to_string()),
305 governance_id: Some(
306 "BKZgYibuHNJjiNS179FUDpLGgdLq0C04TZRGb6AXMd1s".to_string(),
307 ),
308 schema_id: "governance".to_string(),
309 namespace: Some("test.namespace".to_string()),
310 };
311
312 let create: Result<CreateRequest, _> = bridge_create.try_into();
313 assert!(create.is_ok());
314 }
315
316 #[test]
317 fn test_create_request_missing_governance_id() {
318 let bridge_create = BridgeCreateRequest {
319 name: Some("Test".to_string()),
320 description: Some("Test description".to_string()),
321 governance_id: None,
322 schema_id: "governance".to_string(),
323 namespace: Some("test.namespace".to_string()),
324 };
325
326 let create: Result<CreateRequest, _> = bridge_create.try_into();
327 assert!(create.is_ok());
328 }
329
330 #[test]
331 fn test_invalid_subject_id() {
332 let bridge_fact = BridgeFactRequest {
333 subject_id: "invalid_id".to_string(),
334 payload: json!({"test": "value"}),
335 viewpoints: vec![],
336 };
337
338 let fact: Result<FactRequest, _> = bridge_fact.try_into();
339 assert!(fact.is_err());
340 assert!(matches!(
341 fact.unwrap_err(),
342 ConversionError::InvalidSubjectId(_)
343 ));
344 }
345
346 #[test]
347 fn test_fact_request_conversion_rejects_duplicated_viewpoints() {
348 let bridge_fact = BridgeFactRequest {
349 subject_id: "BKZgYibuHNJjiNS179FUDpLGgdLq0C04TZRGb6AXMd1s"
350 .to_string(),
351 payload: json!({"test": "value"}),
352 viewpoints: vec!["agua".to_string(), "agua".to_string()],
353 };
354
355 let fact: Result<FactRequest, _> = bridge_fact.try_into();
356 assert!(matches!(
357 fact.unwrap_err(),
358 ConversionError::InvalidViewpoints(_)
359 ));
360 }
361}