routing/bedrock/
with_availability.rs1use crate::bedrock::request_metadata::Metadata;
6use crate::error::RoutingError;
7use async_trait::async_trait;
8use cm_types::Availability;
9use fidl_fuchsia_component_sandbox as fsandbox;
10use moniker::ExtendedMoniker;
11use router_error::RouterError;
12use sandbox::{CapabilityBound, Request, Routable, Router, RouterResponse};
13
14struct AvailabilityRouter<T: CapabilityBound> {
15 router: Router<T>,
16 availability: Availability,
17 moniker: ExtendedMoniker,
18}
19
20#[async_trait]
21impl<T: CapabilityBound> Routable<T> for AvailabilityRouter<T> {
22 async fn route(
23 &self,
24 request: Option<Request>,
25 debug: bool,
26 ) -> Result<RouterResponse<T>, RouterError> {
27 let request = request.ok_or_else(|| RouterError::InvalidArgs)?;
28 let AvailabilityRouter { router, availability, moniker } = self;
29 let request_availability =
32 request.metadata.get_metadata().ok_or(fsandbox::RouterError::InvalidArgs).inspect_err(
33 |e| {
34 log::error!(
35 "request {:?} did not have availability metadata: {e:?}",
36 request.target
37 )
38 },
39 )?;
40 match crate::availability::advance(moniker, request_availability, *availability) {
41 Ok(updated) => {
42 request.metadata.set_metadata(updated);
43 router.route(Some(request), debug).await
45 }
46 Err(e) => Err(RoutingError::from(e).into()),
47 }
48 }
49}
50
51pub trait WithAvailability {
52 fn with_availability(
55 self,
56 moniker: impl Into<ExtendedMoniker>,
57 availability: Availability,
58 ) -> Self;
59}
60
61impl<T: CapabilityBound> WithAvailability for Router<T> {
62 fn with_availability(
63 self,
64 moniker: impl Into<ExtendedMoniker>,
65 availability: Availability,
66 ) -> Self {
67 Router::<T>::new(AvailabilityRouter { availability, router: self, moniker: moniker.into() })
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use assert_matches::assert_matches;
75 use router_error::{DowncastErrorForTest, RouterError};
76 use sandbox::{Data, Dict, WeakInstanceToken};
77 use std::sync::Arc;
78
79 #[derive(Debug)]
80 struct FakeComponentToken {}
81
82 impl FakeComponentToken {
83 fn new() -> WeakInstanceToken {
84 WeakInstanceToken { inner: Arc::new(FakeComponentToken {}) }
85 }
86 }
87
88 impl sandbox::WeakInstanceTokenAny for FakeComponentToken {
89 fn as_any(&self) -> &dyn std::any::Any {
90 self
91 }
92 }
93
94 #[fuchsia::test]
95 async fn availability_good() {
96 let source = Data::String("hello".to_string());
97 let base = Router::<Data>::new_ok(source);
98 let proxy =
99 base.with_availability(ExtendedMoniker::ComponentManager, Availability::Optional);
100 let metadata = Dict::new();
101 metadata.set_metadata(Availability::Optional);
102 let capability = proxy
103 .route(Some(Request { target: FakeComponentToken::new(), metadata }), false)
104 .await
105 .unwrap();
106 let capability = match capability {
107 RouterResponse::<Data>::Capability(d) => d,
108 c => panic!("Bad enum {:#?}", c),
109 };
110 assert_eq!(capability, Data::String("hello".to_string()));
111 }
112
113 #[fuchsia::test]
114 async fn availability_bad() {
115 let source = Data::String("hello".to_string());
116 let base = Router::<Data>::new_ok(source);
117 let proxy =
118 base.with_availability(ExtendedMoniker::ComponentManager, Availability::Optional);
119 let metadata = Dict::new();
120 metadata.set_metadata(Availability::Required);
121 let error = proxy
122 .route(Some(Request { target: FakeComponentToken::new(), metadata }), false)
123 .await
124 .unwrap_err();
125 assert_matches!(
126 error,
127 RouterError::NotFound(err)
128 if matches!(
129 err.downcast_for_test::<RoutingError>(),
130 RoutingError::AvailabilityRoutingError(
131 crate::error::AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager}
132 )
133 )
134 );
135 }
136}