1use crate::bedrock::request_metadata::Metadata;
6use crate::capability_source::CapabilitySource;
7use crate::error::RoutingError;
8use async_trait::async_trait;
9use cm_rust::CapabilityTypeName;
10use cm_types::{IterablePath, RelativePath};
11use fidl_fuchsia_component_sandbox as fsandbox;
12use moniker::ExtendedMoniker;
13use router_error::RouterError;
14use sandbox::{
15 Capability, CapabilityBound, Connector, Data, Dict, DirConnector, DirEntry, Request, Routable,
16 Router, RouterResponse, WeakInstanceToken,
17};
18use std::fmt::Debug;
19
20#[async_trait]
21pub trait DictExt {
22 fn get_capability(&self, path: &impl IterablePath) -> Option<Capability>;
24
25 fn get_router_or_not_found<T>(
34 &self,
35 path: &impl IterablePath,
36 not_found_error: RoutingError,
37 ) -> Router<T>
38 where
39 T: CapabilityBound,
40 Router<T>: TryFrom<Capability>;
41
42 fn insert_capability(
44 &self,
45 path: &impl IterablePath,
46 capability: Capability,
47 ) -> Result<(), fsandbox::CapabilityStoreError>;
48
49 fn remove_capability(&self, path: &impl IterablePath) -> Option<Capability>;
51
52 async fn get_with_request<'a>(
61 &self,
62 moniker: &ExtendedMoniker,
63 path: &'a impl IterablePath,
64 request: Option<Request>,
65 debug: bool,
66 target: WeakInstanceToken,
67 ) -> Result<Option<GenericRouterResponse>, RouterError>;
68}
69
70#[derive(Debug)]
73pub enum GenericRouterResponse {
74 Capability(Capability),
76
77 Unavailable,
79
80 Debug(Data),
82}
83
84impl<T: CapabilityBound> TryFrom<GenericRouterResponse> for RouterResponse<T> {
85 type Error = &'static str;
87
88 fn try_from(r: GenericRouterResponse) -> Result<Self, Self::Error> {
89 let r = match r {
90 GenericRouterResponse::Capability(c) => {
91 let debug_name = c.debug_typename();
92 RouterResponse::<T>::Capability(c.try_into().map_err(|_| debug_name)?)
93 }
94 GenericRouterResponse::Unavailable => RouterResponse::<T>::Unavailable,
95 GenericRouterResponse::Debug(d) => RouterResponse::<T>::Debug(d),
96 };
97 Ok(r)
98 }
99}
100
101#[async_trait]
102impl DictExt for Dict {
103 fn get_capability(&self, path: &impl IterablePath) -> Option<Capability> {
104 let mut segments = path.iter_segments();
105 let Some(mut current_name) = segments.next() else { return Some(self.clone().into()) };
106 let mut current_dict = self.clone();
107 loop {
108 match segments.next() {
109 Some(next_name) => {
110 let sub_dict = current_dict
111 .get(current_name)
112 .ok()
113 .flatten()
114 .and_then(|value| value.to_dictionary())?;
115 current_dict = sub_dict;
116
117 current_name = next_name;
118 }
119 None => return current_dict.get(current_name).ok().flatten(),
120 }
121 }
122 }
123
124 fn get_router_or_not_found<T>(
125 &self,
126 path: &impl IterablePath,
127 not_found_error: RoutingError,
128 ) -> Router<T>
129 where
130 T: CapabilityBound,
131 Router<T>: TryFrom<Capability>,
132 {
133 let mut segments = path.iter_segments();
134 let root = segments.next().expect("path must be nonempty");
135
136 #[derive(Debug)]
137 struct ErrorRouter {
138 not_found_error: RouterError,
139 }
140
141 #[async_trait]
142 impl<T: CapabilityBound> Routable<T> for ErrorRouter {
143 async fn route(
144 &self,
145 _request: Option<Request>,
146 _debug: bool,
147 _target: WeakInstanceToken,
148 ) -> Result<RouterResponse<T>, RouterError> {
149 Err(self.not_found_error.clone())
150 }
151 }
152
153 #[derive(Debug)]
157 struct ScopedDictRouter<P: IterablePath + Debug + 'static> {
158 router: Router<Dict>,
159 path: P,
160 not_found_error: RoutingError,
161 }
162
163 #[async_trait]
164 impl<P: IterablePath + Debug + 'static, T: CapabilityBound> Routable<T> for ScopedDictRouter<P> {
165 async fn route(
166 &self,
167 request: Option<Request>,
168 debug: bool,
169 target: WeakInstanceToken,
170 ) -> Result<RouterResponse<T>, RouterError> {
171 let get_init_request = || request_with_dictionary_replacement(request.as_ref());
172
173 let init_request = (get_init_request)()?;
178 match self.router.route(init_request, false, target.clone()).await? {
179 RouterResponse::<Dict>::Capability(dict) => {
180 let moniker: ExtendedMoniker = self.not_found_error.clone().into();
181 let resp = dict
182 .get_with_request(&moniker, &self.path, request, debug, target)
183 .await?;
184 let resp =
185 resp.ok_or_else(|| RouterError::from(self.not_found_error.clone()))?;
186 let resp = resp.try_into().map_err(|debug_name: &'static str| {
187 RoutingError::BedrockWrongCapabilityType {
188 expected: T::debug_typename().into(),
189 actual: debug_name.into(),
190 moniker,
191 }
192 })?;
193 Ok(resp)
194 }
195 RouterResponse::<Dict>::Debug(data) => Ok(RouterResponse::<T>::Debug(data)),
196 RouterResponse::<Dict>::Unavailable => {
197 if !debug {
198 Ok(RouterResponse::<T>::Unavailable)
199 } else {
200 let init_request = (get_init_request)()?;
205 match self.router.route(init_request, true, target).await? {
206 RouterResponse::<Dict>::Debug(d) => {
207 Ok(RouterResponse::<T>::Debug(d))
208 }
209 _ => {
210 let moniker = self.not_found_error.clone().into();
212 Err(RoutingError::BedrockWrongCapabilityType {
213 expected: "RouterResponse::Debug".into(),
214 actual: "not RouterResponse::Debug".into(),
215 moniker,
216 }
217 .into())
218 }
219 }
220 }
221 }
222 }
223 }
224 }
225
226 if segments.next().is_none() {
227 let Some(router) =
229 self.get(root).ok().flatten().and_then(|cap| Router::<T>::try_from(cap).ok())
230 else {
231 return Router::<T>::new(ErrorRouter { not_found_error: not_found_error.into() });
232 };
233 return router;
234 }
235
236 let Some(cap) = self.get(root).ok().flatten() else {
237 return Router::<T>::new(ErrorRouter { not_found_error: not_found_error.into() });
238 };
239 let router = match cap {
240 Capability::Dictionary(d) => Router::<Dict>::new_ok(d),
241 Capability::DictionaryRouter(r) => r,
242 _ => {
243 return Router::<T>::new(ErrorRouter { not_found_error: not_found_error.into() });
244 }
245 };
246
247 let mut segments = path.iter_segments();
248 let _ = segments.next().unwrap();
249 let path = RelativePath::from(segments.collect::<Vec<_>>());
250
251 Router::<T>::new(ScopedDictRouter { router, path, not_found_error: not_found_error.into() })
252 }
253
254 fn insert_capability(
255 &self,
256 path: &impl IterablePath,
257 capability: Capability,
258 ) -> Result<(), fsandbox::CapabilityStoreError> {
259 let mut segments = path.iter_segments();
260 let mut current_name = segments.next().expect("path must be non-empty");
261 let mut current_dict = self.clone();
262 loop {
263 match segments.next() {
264 Some(next_name) => {
265 let sub_dict = {
266 match current_dict.get(current_name) {
267 Ok(Some(Capability::Dictionary(dict))) => dict,
268 Ok(Some(Capability::DictionaryRouter(preexisting_router))) => {
269 let mut path = vec![next_name];
270 while let Some(name) = segments.next() {
271 path.push(name);
272 }
273 let path = RelativePath::from(path);
274 let new_router = Router::new(AdditiveDictionaryRouter {
275 preexisting_router,
276 path,
277 capability,
278 });
279
280 current_dict.remove(current_name).unwrap();
282 current_dict.insert(current_name.into(), new_router.into())?;
283
284 return Ok(());
285 }
286 Ok(None) => {
287 let dict = Dict::new();
288 current_dict.insert(
289 current_name.into(),
290 Capability::Dictionary(dict.clone()),
291 )?;
292 dict
293 }
294 _ => return Err(fsandbox::CapabilityStoreError::ItemNotFound),
295 }
296 };
297 current_dict = sub_dict;
298
299 current_name = next_name;
300 }
301 None => {
302 return current_dict.insert(current_name.into(), capability);
303 }
304 }
305 }
306 }
307
308 fn remove_capability(&self, path: &impl IterablePath) -> Option<Capability> {
309 let mut segments = path.iter_segments();
310 let mut current_name = segments.next().expect("path must be non-empty");
311 let mut current_dict = self.clone();
312 loop {
313 match segments.next() {
314 Some(next_name) => {
315 let sub_dict = current_dict
316 .get(current_name)
317 .ok()
318 .flatten()
319 .and_then(|value| value.to_dictionary());
320 if sub_dict.is_none() {
321 return None;
323 }
324 current_dict = sub_dict.unwrap();
325 current_name = next_name;
326 }
327 None => {
328 return current_dict.remove(current_name);
329 }
330 }
331 }
332 }
333
334 async fn get_with_request<'a>(
335 &self,
336 moniker: &ExtendedMoniker,
337 path: &'a impl IterablePath,
338 request: Option<Request>,
339 debug: bool,
340 target: WeakInstanceToken,
341 ) -> Result<Option<GenericRouterResponse>, RouterError> {
342 let mut current_dict = self.clone();
343 let num_segments = path.iter_segments().count();
344 for (next_idx, next_name) in path.iter_segments().enumerate() {
345 let capability = current_dict
347 .get(next_name)
348 .map_err(|_| RoutingError::BedrockNotCloneable { moniker: moniker.clone() })?;
349
350 let Some(capability) = capability else {
352 return Ok(None);
353 };
354
355 if next_idx < num_segments - 1 {
356 let dict_request = request_with_dictionary_replacement(request.as_ref())?;
359 match capability {
360 Capability::Dictionary(d) => {
361 current_dict = d;
362 }
363 Capability::DictionaryRouter(r) => {
364 match r.route(dict_request, false, target.clone()).await? {
365 RouterResponse::<Dict>::Capability(d) => {
366 current_dict = d;
367 }
368 RouterResponse::<Dict>::Debug(d) => {
369 return Ok(Some(GenericRouterResponse::Debug(d)));
372 }
373 RouterResponse::<Dict>::Unavailable => {
374 if !debug {
375 return Ok(Some(GenericRouterResponse::Unavailable));
376 } else {
377 let dict_request =
383 request_with_dictionary_replacement(request.as_ref())?;
384 match r.route(dict_request, true, target).await? {
385 RouterResponse::<Dict>::Debug(d) => {
386 return Ok(Some(GenericRouterResponse::Debug(d)));
387 }
388 _ => {
389 return Err(RoutingError::BedrockWrongCapabilityType {
391 expected: "RouterResponse::Debug".into(),
392 actual: "not RouterResponse::Debug".into(),
393 moniker: moniker.clone(),
394 }
395 .into());
396 }
397 }
398 }
399 }
400 }
401 }
402 _ => {
403 return Err(RoutingError::BedrockWrongCapabilityType {
404 expected: Dict::debug_typename().into(),
405 actual: capability.debug_typename().into(),
406 moniker: moniker.clone(),
407 }
408 .into());
409 }
410 }
411 } else {
412 let request = request.as_ref().map(|r| r.try_clone()).transpose()?;
418 let capability: Capability = match capability {
419 Capability::DictionaryRouter(r) => {
420 match r.route(request, debug, target).await? {
421 RouterResponse::<Dict>::Capability(c) => c.into(),
422 RouterResponse::<Dict>::Unavailable => {
423 return Ok(Some(GenericRouterResponse::Unavailable));
424 }
425 RouterResponse::<Dict>::Debug(d) => {
426 return Ok(Some(GenericRouterResponse::Debug(d)));
427 }
428 }
429 }
430 Capability::ConnectorRouter(r) => {
431 match r.route(request, debug, target).await? {
432 RouterResponse::<Connector>::Capability(c) => c.into(),
433 RouterResponse::<Connector>::Unavailable => {
434 return Ok(Some(GenericRouterResponse::Unavailable));
435 }
436 RouterResponse::<Connector>::Debug(d) => {
437 return Ok(Some(GenericRouterResponse::Debug(d)));
438 }
439 }
440 }
441 Capability::DataRouter(r) => match r.route(request, debug, target).await? {
442 RouterResponse::<Data>::Capability(c) => c.into(),
443 RouterResponse::<Data>::Unavailable => {
444 return Ok(Some(GenericRouterResponse::Unavailable));
445 }
446 RouterResponse::<Data>::Debug(d) => {
447 return Ok(Some(GenericRouterResponse::Debug(d)));
448 }
449 },
450 Capability::DirEntryRouter(r) => match r.route(request, debug, target).await? {
451 RouterResponse::<DirEntry>::Capability(c) => c.into(),
452 RouterResponse::<DirEntry>::Unavailable => {
453 return Ok(Some(GenericRouterResponse::Unavailable));
454 }
455 RouterResponse::<DirEntry>::Debug(d) => {
456 return Ok(Some(GenericRouterResponse::Debug(d)));
457 }
458 },
459 Capability::DirConnectorRouter(r) => {
460 match r.route(request, debug, target).await? {
461 RouterResponse::<DirConnector>::Capability(c) => c.into(),
462 RouterResponse::<DirConnector>::Unavailable => {
463 return Ok(Some(GenericRouterResponse::Unavailable));
464 }
465 RouterResponse::<DirConnector>::Debug(d) => {
466 return Ok(Some(GenericRouterResponse::Debug(d)));
467 }
468 }
469 }
470 _other if debug => {
471 let remoted_at_moniker = match moniker {
477 ExtendedMoniker::ComponentInstance(m) => m.clone(),
478 ExtendedMoniker::ComponentManager => {
482 panic!("component manager generated a non-router capability")
483 }
484 };
485 return Ok(Some(GenericRouterResponse::Debug(
486 CapabilitySource::RemotedAt(remoted_at_moniker)
487 .try_into()
488 .expect("failed to serialize capability source"),
489 )));
490 }
491 other => other,
492 };
493 return Ok(Some(GenericRouterResponse::Capability(capability)));
494 }
495 }
496 unreachable!("get_with_request: All cases are handled in the loop");
497 }
498}
499
500pub(super) fn request_with_dictionary_replacement(
506 request: Option<&Request>,
507) -> Result<Option<Request>, RoutingError> {
508 Ok(request.as_ref().map(|r| r.try_clone()).transpose()?.map(|r| {
509 let _ = r.metadata.set_metadata(CapabilityTypeName::Dictionary);
510 r
511 }))
512}
513
514struct AdditiveDictionaryRouter {
515 preexisting_router: Router<Dict>,
516 path: RelativePath,
517 capability: Capability,
518}
519
520#[async_trait]
521impl Routable<Dict> for AdditiveDictionaryRouter {
522 async fn route(
523 &self,
524 request: Option<Request>,
525 debug: bool,
526 target: WeakInstanceToken,
527 ) -> Result<RouterResponse<Dict>, RouterError> {
528 let dictionary = match self.preexisting_router.route(request, debug, target).await {
529 Ok(RouterResponse::<Dict>::Capability(dictionary)) => {
530 dictionary.shallow_copy().unwrap()
531 }
532 other_response => return other_response,
533 };
534 let _ = dictionary.insert_capability(&self.path, self.capability.try_clone().unwrap());
535 Ok(RouterResponse::Capability(dictionary))
536 }
537}