1use crate::bedrock::request_metadata::Metadata;
6use crate::error::RoutingError;
7use async_trait::async_trait;
8use cm_rust::CapabilityTypeName;
9use cm_types::{IterablePath, RelativePath};
10use fidl_fuchsia_component_sandbox as fsandbox;
11use moniker::ExtendedMoniker;
12use router_error::RouterError;
13use sandbox::{
14 Capability, CapabilityBound, Connector, Data, Dict, DirConnector, DirEntry, Request, Routable,
15 Router, RouterResponse,
16};
17use std::fmt::Debug;
18
19#[async_trait]
20pub trait DictExt {
21 fn get_capability(&self, path: &impl IterablePath) -> Option<Capability>;
23
24 fn get_router_or_not_found<T>(
33 &self,
34 path: &impl IterablePath,
35 not_found_error: RoutingError,
36 ) -> Router<T>
37 where
38 T: CapabilityBound,
39 Router<T>: TryFrom<Capability>;
40
41 fn insert_capability(
43 &self,
44 path: &impl IterablePath,
45 capability: Capability,
46 ) -> Result<(), fsandbox::CapabilityStoreError>;
47
48 fn remove_capability(&self, path: &impl IterablePath);
50
51 async fn get_with_request<'a>(
60 &self,
61 moniker: &ExtendedMoniker,
62 path: &'a impl IterablePath,
63 request: Option<Request>,
64 debug: bool,
65 ) -> Result<Option<GenericRouterResponse>, RouterError>;
66}
67
68#[derive(Debug)]
71pub enum GenericRouterResponse {
72 Capability(Capability),
74
75 Unavailable,
77
78 Debug(Data),
80}
81
82impl<T: CapabilityBound> TryFrom<GenericRouterResponse> for RouterResponse<T> {
83 type Error = &'static str;
85
86 fn try_from(r: GenericRouterResponse) -> Result<Self, Self::Error> {
87 let r = match r {
88 GenericRouterResponse::Capability(c) => {
89 let debug_name = c.debug_typename();
90 RouterResponse::<T>::Capability(c.try_into().map_err(|_| debug_name)?)
91 }
92 GenericRouterResponse::Unavailable => RouterResponse::<T>::Unavailable,
93 GenericRouterResponse::Debug(d) => RouterResponse::<T>::Debug(d),
94 };
95 Ok(r)
96 }
97}
98
99#[async_trait]
100impl DictExt for Dict {
101 fn get_capability(&self, path: &impl IterablePath) -> Option<Capability> {
102 let mut segments = path.iter_segments();
103 let Some(mut current_name) = segments.next() else { return Some(self.clone().into()) };
104 let mut current_dict = self.clone();
105 loop {
106 match segments.next() {
107 Some(next_name) => {
108 let sub_dict = current_dict
109 .get(current_name)
110 .ok()
111 .flatten()
112 .and_then(|value| value.to_dictionary())?;
113 current_dict = sub_dict;
114
115 current_name = next_name;
116 }
117 None => return current_dict.get(current_name).ok().flatten(),
118 }
119 }
120 }
121
122 fn get_router_or_not_found<T>(
123 &self,
124 path: &impl IterablePath,
125 not_found_error: RoutingError,
126 ) -> Router<T>
127 where
128 T: CapabilityBound,
129 Router<T>: TryFrom<Capability>,
130 {
131 let mut segments = path.iter_segments();
132 let root = segments.next().expect("path must be nonempty");
133
134 #[derive(Debug)]
135 struct ErrorRouter {
136 not_found_error: RouterError,
137 }
138
139 #[async_trait]
140 impl<T: CapabilityBound> Routable<T> for ErrorRouter {
141 async fn route(
142 &self,
143 _request: Option<Request>,
144 _debug: bool,
145 ) -> Result<RouterResponse<T>, RouterError> {
146 Err(self.not_found_error.clone())
147 }
148 }
149
150 #[derive(Debug)]
154 struct ScopedDictRouter<P: IterablePath + Debug + 'static> {
155 router: Router<Dict>,
156 path: P,
157 not_found_error: RoutingError,
158 }
159
160 #[async_trait]
161 impl<P: IterablePath + Debug + 'static, T: CapabilityBound> Routable<T> for ScopedDictRouter<P> {
162 async fn route(
163 &self,
164 request: Option<Request>,
165 debug: bool,
166 ) -> Result<RouterResponse<T>, RouterError> {
167 let get_init_request = || request_with_dictionary_replacement(request.as_ref());
168
169 let init_request = (get_init_request)()?;
174 match self.router.route(init_request, false).await? {
175 RouterResponse::<Dict>::Capability(dict) => {
176 let moniker: ExtendedMoniker = self.not_found_error.clone().into();
177 let resp =
178 dict.get_with_request(&moniker, &self.path, request, debug).await?;
179 let resp =
180 resp.ok_or_else(|| RouterError::from(self.not_found_error.clone()))?;
181 let resp = resp.try_into().map_err(|debug_name: &'static str| {
182 RoutingError::BedrockWrongCapabilityType {
183 expected: T::debug_typename().into(),
184 actual: debug_name.into(),
185 moniker,
186 }
187 })?;
188 Ok(resp)
189 }
190 RouterResponse::<Dict>::Debug(data) => Ok(RouterResponse::<T>::Debug(data)),
191 RouterResponse::<Dict>::Unavailable => {
192 if !debug {
193 Ok(RouterResponse::<T>::Unavailable)
194 } else {
195 let init_request = (get_init_request)()?;
200 match self.router.route(init_request, true).await? {
201 RouterResponse::<Dict>::Debug(d) => {
202 Ok(RouterResponse::<T>::Debug(d))
203 }
204 _ => {
205 let moniker = self.not_found_error.clone().into();
207 Err(RoutingError::BedrockWrongCapabilityType {
208 expected: "RouterResponse::Debug".into(),
209 actual: "not RouterResponse::Debug".into(),
210 moniker,
211 }
212 .into())
213 }
214 }
215 }
216 }
217 }
218 }
219 }
220
221 if segments.next().is_none() {
222 let Some(router) =
224 self.get(root).ok().flatten().and_then(|cap| Router::<T>::try_from(cap).ok())
225 else {
226 return Router::<T>::new(ErrorRouter { not_found_error: not_found_error.into() });
227 };
228 return router;
229 }
230
231 let Some(cap) = self.get(root).ok().flatten() else {
232 return Router::<T>::new(ErrorRouter { not_found_error: not_found_error.into() });
233 };
234 let router = match cap {
235 Capability::Dictionary(d) => Router::<Dict>::new_ok(d),
236 Capability::DictionaryRouter(r) => r,
237 _ => {
238 return Router::<T>::new(ErrorRouter { not_found_error: not_found_error.into() });
239 }
240 };
241
242 let mut segments = path.iter_segments();
243 let _ = segments.next().unwrap();
244 let path = RelativePath::from(segments.collect::<Vec<_>>());
245
246 Router::<T>::new(ScopedDictRouter { router, path, not_found_error: not_found_error.into() })
247 }
248
249 fn insert_capability(
250 &self,
251 path: &impl IterablePath,
252 capability: Capability,
253 ) -> Result<(), fsandbox::CapabilityStoreError> {
254 let mut segments = path.iter_segments();
255 let mut current_name = segments.next().expect("path must be non-empty");
256 let mut current_dict = self.clone();
257 loop {
258 match segments.next() {
259 Some(next_name) => {
260 let sub_dict = {
261 match current_dict.get(current_name) {
262 Ok(Some(cap)) => cap
263 .to_dictionary()
264 .ok_or(fsandbox::CapabilityStoreError::ItemNotFound)?,
265 Ok(None) => {
266 let dict = Dict::new();
267 current_dict.insert(
268 current_name.into(),
269 Capability::Dictionary(dict.clone()),
270 )?;
271 dict
272 }
273 Err(_) => return Err(fsandbox::CapabilityStoreError::ItemNotFound),
274 }
275 };
276 current_dict = sub_dict;
277
278 current_name = next_name;
279 }
280 None => {
281 return current_dict.insert(current_name.into(), capability);
282 }
283 }
284 }
285 }
286
287 fn remove_capability(&self, path: &impl IterablePath) {
288 let mut segments = path.iter_segments();
289 let mut current_name = segments.next().expect("path must be non-empty");
290 let mut current_dict = self.clone();
291 loop {
292 match segments.next() {
293 Some(next_name) => {
294 let sub_dict = current_dict
295 .get(current_name)
296 .ok()
297 .flatten()
298 .and_then(|value| value.to_dictionary());
299 if sub_dict.is_none() {
300 return;
302 }
303 current_dict = sub_dict.unwrap();
304 current_name = next_name;
305 }
306 None => {
307 current_dict.remove(current_name);
308 return;
309 }
310 }
311 }
312 }
313
314 async fn get_with_request<'a>(
315 &self,
316 moniker: &ExtendedMoniker,
317 path: &'a impl IterablePath,
318 request: Option<Request>,
319 debug: bool,
320 ) -> Result<Option<GenericRouterResponse>, RouterError> {
321 let mut current_dict = self.clone();
322 let num_segments = path.iter_segments().count();
323 for (next_idx, next_name) in path.iter_segments().enumerate() {
324 let capability = current_dict
326 .get(next_name)
327 .map_err(|_| RoutingError::BedrockNotCloneable { moniker: moniker.clone() })?;
328
329 let Some(capability) = capability else {
331 return Ok(None);
332 };
333
334 if next_idx < num_segments - 1 {
335 let dict_request = request_with_dictionary_replacement(request.as_ref())?;
338 match capability {
339 Capability::Dictionary(d) => {
340 current_dict = d;
341 }
342 Capability::DictionaryRouter(r) => match r.route(dict_request, false).await? {
343 RouterResponse::<Dict>::Capability(d) => {
344 current_dict = d;
345 }
346 RouterResponse::<Dict>::Debug(d) => {
347 return Ok(Some(GenericRouterResponse::Debug(d)));
350 }
351 RouterResponse::<Dict>::Unavailable => {
352 if !debug {
353 return Ok(Some(GenericRouterResponse::Unavailable));
354 } else {
355 let dict_request =
361 request_with_dictionary_replacement(request.as_ref())?;
362 match r.route(dict_request, true).await? {
363 RouterResponse::<Dict>::Debug(d) => {
364 return Ok(Some(GenericRouterResponse::Debug(d)));
365 }
366 _ => {
367 return Err(RoutingError::BedrockWrongCapabilityType {
369 expected: "RouterResponse::Debug".into(),
370 actual: "not RouterResponse::Debug".into(),
371 moniker: moniker.clone(),
372 }
373 .into());
374 }
375 }
376 }
377 }
378 },
379 _ => {
380 return Err(RoutingError::BedrockWrongCapabilityType {
381 expected: Dict::debug_typename().into(),
382 actual: capability.debug_typename().into(),
383 moniker: moniker.clone(),
384 }
385 .into());
386 }
387 }
388 } else {
389 let request = request.as_ref().map(|r| r.try_clone()).transpose()?;
395 let capability: Capability = match capability {
396 Capability::DictionaryRouter(r) => match r.route(request, debug).await? {
397 RouterResponse::<Dict>::Capability(c) => c.into(),
398 RouterResponse::<Dict>::Unavailable => {
399 return Ok(Some(GenericRouterResponse::Unavailable));
400 }
401 RouterResponse::<Dict>::Debug(d) => {
402 return Ok(Some(GenericRouterResponse::Debug(d)));
403 }
404 },
405 Capability::ConnectorRouter(r) => match r.route(request, debug).await? {
406 RouterResponse::<Connector>::Capability(c) => c.into(),
407 RouterResponse::<Connector>::Unavailable => {
408 return Ok(Some(GenericRouterResponse::Unavailable));
409 }
410 RouterResponse::<Connector>::Debug(d) => {
411 return Ok(Some(GenericRouterResponse::Debug(d)));
412 }
413 },
414 Capability::DataRouter(r) => match r.route(request, debug).await? {
415 RouterResponse::<Data>::Capability(c) => c.into(),
416 RouterResponse::<Data>::Unavailable => {
417 return Ok(Some(GenericRouterResponse::Unavailable));
418 }
419 RouterResponse::<Data>::Debug(d) => {
420 return Ok(Some(GenericRouterResponse::Debug(d)));
421 }
422 },
423 Capability::DirEntryRouter(r) => match r.route(request, debug).await? {
424 RouterResponse::<DirEntry>::Capability(c) => c.into(),
425 RouterResponse::<DirEntry>::Unavailable => {
426 return Ok(Some(GenericRouterResponse::Unavailable));
427 }
428 RouterResponse::<DirEntry>::Debug(d) => {
429 return Ok(Some(GenericRouterResponse::Debug(d)));
430 }
431 },
432 Capability::DirConnectorRouter(r) => match r.route(request, debug).await? {
433 RouterResponse::<DirConnector>::Capability(c) => c.into(),
434 RouterResponse::<DirConnector>::Unavailable => {
435 return Ok(Some(GenericRouterResponse::Unavailable));
436 }
437 RouterResponse::<DirConnector>::Debug(d) => {
438 return Ok(Some(GenericRouterResponse::Debug(d)));
439 }
440 },
441 other => other,
442 };
443 return Ok(Some(GenericRouterResponse::Capability(capability)));
444 }
445 }
446 unreachable!("get_with_request: All cases are handled in the loop");
447 }
448}
449
450pub(super) fn request_with_dictionary_replacement(
456 request: Option<&Request>,
457) -> Result<Option<Request>, RoutingError> {
458 Ok(request.as_ref().map(|r| r.try_clone()).transpose()?.map(|r| {
459 let _ = r.metadata.set_metadata(CapabilityTypeName::Dictionary);
460 r
461 }))
462}