Skip to main content

endhost_api_protobuf/
convert.rs

1// Copyright 2025 Anapaya Systems
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//   http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//! Conversions between endhost API protobuf types and endhost API models.
15
16use scion_proto::path::{Segments, convert::segment::InvalidSegmentError};
17
18use crate::endhost::api_service::v1::{
19    ListSegmentsResponse, ListUnderlaysResponse, Router, Snap, SnapUnderlay, UdpUnderlay,
20};
21
22impl From<endhost_api_models::underlays::Underlays> for ListUnderlaysResponse {
23    fn from(underlays: endhost_api_models::underlays::Underlays) -> Self {
24        ListUnderlaysResponse {
25            udp: Some(UdpUnderlay::from(underlays.udp_underlay)),
26            snap: Some(SnapUnderlay::from(underlays.snap_underlay)),
27        }
28    }
29}
30
31impl TryFrom<ListUnderlaysResponse> for endhost_api_models::underlays::Underlays {
32    type Error = url::ParseError;
33    fn try_from(response: ListUnderlaysResponse) -> Result<Self, Self::Error> {
34        Ok(endhost_api_models::underlays::Underlays {
35            udp_underlay: match response.udp {
36                Some(udp) => udp.routers.into_iter().map(Into::into).collect(),
37                None => Vec::new(),
38            },
39            snap_underlay: match response.snap {
40                Some(snap) => {
41                    snap.snaps
42                        .into_iter()
43                        .map(TryInto::try_into)
44                        .collect::<Result<_, _>>()?
45                }
46                None => Vec::new(),
47            },
48        })
49    }
50}
51
52impl From<Vec<endhost_api_models::underlays::ScionRouter>> for UdpUnderlay {
53    fn from(routers: Vec<endhost_api_models::underlays::ScionRouter>) -> Self {
54        UdpUnderlay {
55            routers: routers.into_iter().map(Into::into).collect(),
56        }
57    }
58}
59
60impl From<UdpUnderlay> for Vec<endhost_api_models::underlays::ScionRouter> {
61    fn from(udp: UdpUnderlay) -> Self {
62        udp.routers.into_iter().map(Into::into).collect()
63    }
64}
65
66impl From<endhost_api_models::underlays::ScionRouter> for Router {
67    fn from(r: endhost_api_models::underlays::ScionRouter) -> Self {
68        Router {
69            isd_as: r.isd_as.into(),
70            address: r.internal_interface.to_string(),
71            // XXX(bunert): protobuf doesn't support u16
72            interfaces: r.interfaces.into_iter().map(|i| i as u32).collect(),
73        }
74    }
75}
76
77impl From<Router> for endhost_api_models::underlays::ScionRouter {
78    fn from(r: Router) -> Self {
79        endhost_api_models::underlays::ScionRouter {
80            isd_as: r.isd_as.into(),
81            internal_interface: r.address.parse().unwrap(),
82            interfaces: r.interfaces.into_iter().map(|i| i as u16).collect(),
83        }
84    }
85}
86
87impl From<Vec<endhost_api_models::underlays::Snap>> for SnapUnderlay {
88    fn from(snaps: Vec<endhost_api_models::underlays::Snap>) -> Self {
89        SnapUnderlay {
90            snaps: snaps.into_iter().map(Into::into).collect(),
91        }
92    }
93}
94
95impl TryFrom<SnapUnderlay> for Vec<endhost_api_models::underlays::Snap> {
96    type Error = url::ParseError;
97    fn try_from(snap: SnapUnderlay) -> Result<Self, Self::Error> {
98        snap.snaps.into_iter().map(TryFrom::try_from).collect()
99    }
100}
101
102impl From<endhost_api_models::underlays::Snap> for Snap {
103    fn from(s: endhost_api_models::underlays::Snap) -> Self {
104        Snap {
105            address: s.address.to_string(),
106            isd_ases: s.isd_ases.into_iter().map(Into::into).collect(),
107        }
108    }
109}
110
111impl TryFrom<Snap> for endhost_api_models::underlays::Snap {
112    type Error = url::ParseError;
113    fn try_from(s: Snap) -> Result<Self, Self::Error> {
114        Ok(endhost_api_models::underlays::Snap {
115            address: s.address.parse()?,
116            isd_ases: s.isd_ases.into_iter().map(Into::into).collect(),
117        })
118    }
119}
120
121impl From<scion_proto::path::segment::SegmentsPage> for ListSegmentsResponse {
122    fn from(page: scion_proto::path::segment::SegmentsPage) -> Self {
123        Self {
124            up_segments: page
125                .segments
126                .up_segments
127                .into_iter()
128                .map(Into::into)
129                .collect(),
130            down_segments: page
131                .segments
132                .down_segments
133                .into_iter()
134                .map(Into::into)
135                .collect(),
136            core_segments: page
137                .segments
138                .core_segments
139                .into_iter()
140                .map(Into::into)
141                .collect(),
142            next_page_token: page.next_page_token,
143        }
144    }
145}
146
147impl TryFrom<ListSegmentsResponse> for scion_proto::path::segment::SegmentsPage {
148    type Error = InvalidSegmentError;
149    fn try_from(response: ListSegmentsResponse) -> Result<Self, Self::Error> {
150        let convert = |segs: Vec<_>| {
151            segs.into_iter()
152                .map(scion_proto::path::PathSegment::try_from)
153                .collect::<Result<_, _>>()
154        };
155        Ok(scion_proto::path::segment::SegmentsPage {
156            segments: Segments {
157                up_segments: convert(response.up_segments)?,
158                down_segments: convert(response.down_segments)?,
159                core_segments: convert(response.core_segments)?,
160            },
161            next_page_token: response.next_page_token,
162        })
163    }
164}