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 sciparse::{
17    rpc::FromRpcError,
18    segment::{Segments, SegmentsPage, SignedPathSegment},
19};
20
21use crate::v1::{
22    ListSegmentsResponse, ListUnderlaysResponse, Router, Snap, SnapUnderlay, UdpUnderlay,
23};
24
25impl From<endhost_api_models::underlays::Underlays> for ListUnderlaysResponse {
26    fn from(underlays: endhost_api_models::underlays::Underlays) -> Self {
27        ListUnderlaysResponse {
28            udp: Some(UdpUnderlay::from(underlays.udp_underlay)),
29            snap: Some(SnapUnderlay::from(underlays.snap_underlay)),
30        }
31    }
32}
33
34impl TryFrom<ListUnderlaysResponse> for endhost_api_models::underlays::Underlays {
35    type Error = url::ParseError;
36    fn try_from(response: ListUnderlaysResponse) -> Result<Self, Self::Error> {
37        Ok(endhost_api_models::underlays::Underlays {
38            udp_underlay: match response.udp {
39                Some(udp) => udp.routers.into_iter().map(Into::into).collect(),
40                None => Vec::new(),
41            },
42            snap_underlay: match response.snap {
43                Some(snap) => {
44                    snap.snaps
45                        .into_iter()
46                        .map(TryInto::try_into)
47                        .collect::<Result<_, _>>()?
48                }
49                None => Vec::new(),
50            },
51        })
52    }
53}
54
55impl From<Vec<endhost_api_models::underlays::ScionRouter>> for UdpUnderlay {
56    fn from(routers: Vec<endhost_api_models::underlays::ScionRouter>) -> Self {
57        UdpUnderlay {
58            routers: routers.into_iter().map(Into::into).collect(),
59        }
60    }
61}
62
63impl From<UdpUnderlay> for Vec<endhost_api_models::underlays::ScionRouter> {
64    fn from(udp: UdpUnderlay) -> Self {
65        udp.routers.into_iter().map(Into::into).collect()
66    }
67}
68
69impl From<endhost_api_models::underlays::ScionRouter> for Router {
70    fn from(r: endhost_api_models::underlays::ScionRouter) -> Self {
71        Router {
72            isd_as: r.isd_as.into(),
73            address: r.internal_interface.to_string(),
74            // XXX(bunert): protobuf doesn't support u16
75            interfaces: r.interfaces.into_iter().map(|i| i as u32).collect(),
76        }
77    }
78}
79
80impl From<Router> for endhost_api_models::underlays::ScionRouter {
81    fn from(r: Router) -> Self {
82        endhost_api_models::underlays::ScionRouter {
83            isd_as: r.isd_as.into(),
84            internal_interface: r.address.parse().unwrap(),
85            interfaces: r.interfaces.into_iter().map(|i| i as u16).collect(),
86        }
87    }
88}
89
90impl From<Vec<endhost_api_models::underlays::Snap>> for SnapUnderlay {
91    fn from(snaps: Vec<endhost_api_models::underlays::Snap>) -> Self {
92        SnapUnderlay {
93            snaps: snaps.into_iter().map(Into::into).collect(),
94        }
95    }
96}
97
98impl TryFrom<SnapUnderlay> for Vec<endhost_api_models::underlays::Snap> {
99    type Error = url::ParseError;
100    fn try_from(snap: SnapUnderlay) -> Result<Self, Self::Error> {
101        snap.snaps.into_iter().map(TryFrom::try_from).collect()
102    }
103}
104
105impl From<endhost_api_models::underlays::Snap> for Snap {
106    fn from(s: endhost_api_models::underlays::Snap) -> Self {
107        Snap {
108            address: s.address.to_string(),
109            isd_ases: s.isd_ases.into_iter().map(Into::into).collect(),
110        }
111    }
112}
113
114impl TryFrom<Snap> for endhost_api_models::underlays::Snap {
115    type Error = url::ParseError;
116    fn try_from(s: Snap) -> Result<Self, Self::Error> {
117        Ok(endhost_api_models::underlays::Snap {
118            address: s.address.parse()?,
119            isd_ases: s.isd_ases.into_iter().map(Into::into).collect(),
120        })
121    }
122}
123
124impl From<SegmentsPage> for ListSegmentsResponse {
125    fn from(page: SegmentsPage) -> Self {
126        Self {
127            up_segments: page
128                .segments
129                .up_segments
130                .into_iter()
131                .map(Into::into)
132                .collect(),
133            down_segments: page
134                .segments
135                .down_segments
136                .into_iter()
137                .map(Into::into)
138                .collect(),
139            core_segments: page
140                .segments
141                .core_segments
142                .into_iter()
143                .map(Into::into)
144                .collect(),
145            next_page_token: page.next_page_token,
146        }
147    }
148}
149
150impl TryFrom<ListSegmentsResponse> for SegmentsPage {
151    type Error = FromRpcError;
152    fn try_from(response: ListSegmentsResponse) -> Result<Self, Self::Error> {
153        let convert = |segs: Vec<_>| {
154            segs.into_iter()
155                .map(SignedPathSegment::try_from)
156                .collect::<Result<_, _>>()
157        };
158        Ok(SegmentsPage {
159            segments: Segments {
160                up_segments: convert(response.up_segments)?,
161                down_segments: convert(response.down_segments)?,
162                core_segments: convert(response.core_segments)?,
163            },
164            next_page_token: response.next_page_token,
165        })
166    }
167}