1use crate::bedrock::dict_ext::DictExt;
6use crate::bedrock::request_metadata;
7use crate::component_instance::ComponentInstanceInterface;
8use crate::{RouterResponse, RoutingError};
9use cm_rust::{Availability, FidlIntoNative};
10use router_error::Explain;
11use runtime_capabilities::Data;
12use std::sync::Arc;
13use zx_status as zx;
14
15pub fn get_use_config_from_key<'a>(
17 key: &str,
18 decl: &'a cm_rust::ComponentDecl,
19) -> Option<&'a cm_rust::UseConfigurationDecl> {
20 decl.uses.iter().find_map(|use_| match use_ {
21 cm_rust::UseDecl::Config(c) => (c.target_name == key).then_some(c),
22 _ => None,
23 })
24}
25
26pub async fn route_config_value<C>(
30 use_config: &cm_rust::UseConfigurationDecl,
31 component: &Arc<C>,
32) -> Result<Option<cm_rust::ConfigValue>, router_error::RouterError>
33where
34 C: ComponentInstanceInterface + 'static,
35{
36 let component_sandbox =
37 component.component_sandbox().await.map_err(|e| RoutingError::from(e))?;
38 let capability =
39 match component_sandbox.program_input.config().get_capability(&use_config.target_name) {
40 Some(c) => c,
41 None => {
42 return Err(RoutingError::BedrockNotPresentInDictionary {
43 name: use_config.target_name.to_string(),
44 moniker: component.moniker().clone().into(),
45 }
46 .into());
47 }
48 };
49 let runtime_capabilities::Capability::DataRouter(router) = capability else {
50 return Err(RoutingError::BedrockWrongCapabilityType {
51 actual: format!("{:?}", capability),
52 expected: "Router".to_string(),
53 moniker: component.moniker().clone().into(),
54 }
55 .into());
56 };
57 let request = runtime_capabilities::Request {
58 metadata: request_metadata::config_metadata(use_config.availability),
59 };
60 let data = match router.route(Some(request), false, component.as_weak().into()).await {
61 Ok(RouterResponse::<Data>::Capability(d)) => d,
62 Ok(RouterResponse::<Data>::Unavailable) => return Ok(use_config.default.clone()),
63 Ok(RouterResponse::<Data>::Debug(_)) => {
64 return Err(RoutingError::RouteUnexpectedDebug {
65 type_name: cm_rust::CapabilityTypeName::Config,
66 moniker: component.moniker().clone().into(),
67 }
68 .into());
69 }
70 Err(e)
71 if use_config.availability == Availability::Transitional
72 && e.as_zx_status() == zx::Status::NOT_FOUND =>
73 {
74 return Ok(use_config.default.clone());
75 }
76 Err(e) => return Err(e),
77 };
78 let Data::Bytes(bytes) = data else {
79 return Err(RoutingError::BedrockWrongCapabilityType {
80 actual: format!("{:?}", data),
81 expected: "Data::bytes".to_string(),
82 moniker: component.moniker().clone().into(),
83 }
84 .into());
85 };
86 let config_value: fidl_fuchsia_component_decl::ConfigValue = match fidl::unpersist(&bytes) {
87 Ok(v) => v,
88 Err(_) => {
89 return Err(RoutingError::BedrockWrongCapabilityType {
90 actual: "{unknown}".into(),
91 expected: "fuchsia.component.decl.ConfigValue".into(),
92 moniker: component.moniker().clone().into(),
93 }
94 .into());
95 }
96 };
97
98 Ok(Some(config_value.fidl_into_native()))
99}