Skip to main content

routing/
config.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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
15/// Get a specific configuration use declaration from the structured config key value.
16pub 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
26/// Routes the config value referenced in `use_config` from `component`. Returns the default value
27/// if the capability is not available (i.e. routed from void), or if `use_config` has transitional
28/// availability and routing fails with an error that maps to `NOT_FOUND`.
29pub 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}