1use crate::common_utils::common::{read_json_from_vmo, write_json_to_vmo};
6use crate::server::constants::CONCURRENT_REQ_LIMIT;
7use crate::server::Facade;
8use anyhow::Error;
9use async_trait::async_trait;
10use fidl_fuchsia_testing_sl4f::{
11 FacadeIteratorRequest, FacadeProviderRequest, FacadeProviderRequestStream,
12};
13use futures::stream::{StreamExt, TryStreamExt};
14use log::{error, info, warn};
15use serde_json::Value;
16use std::sync::Arc;
17
18#[async_trait(?Send)]
20pub trait FacadeProvider {
21 fn get_facade(&self, name: &str) -> Option<Arc<dyn Facade>>;
25
26 fn get_facades(&self) -> Box<dyn Iterator<Item = &Arc<dyn Facade>> + '_>;
28
29 fn get_facade_names(&self) -> Vec<String>;
31
32 async fn get_facades_impl(&self, request: FacadeProviderRequest) {
37 let iterator = match request {
38 FacadeProviderRequest::GetFacades { iterator, control_handle: _ } => iterator,
39 _ => panic!(
40 "get_facade_impl() must only be called with a FacadeProviderRequest::GetFacades."
41 ),
42 };
43
44 let get_facades_fut = async {
46 let mut iterator = iterator.into_stream();
47 if let Some(FacadeIteratorRequest::GetNext { responder }) = iterator.try_next().await? {
48 responder.send(&self.get_facade_names())?;
51 if let Some(FacadeIteratorRequest::GetNext { responder }) =
52 iterator.try_next().await?
53 {
54 responder.send(&[])?; }
56 }
57 Ok::<(), Error>(())
58 };
59 if let Err(error) = get_facades_fut.await {
60 error!(error:%; "Failed to handle GetFacades()");
61 }
62 }
63
64 async fn execute_impl(&self, request: FacadeProviderRequest) {
68 let (facade, command, params_blob, responder) = match request {
69 FacadeProviderRequest::Execute { facade, command, params_blob, responder } => {
70 (facade, command, params_blob, responder)
71 }
72 _ => {
73 panic!("execute_impl() must only be called with a FacadeProviderRequest::Execute.")
74 }
75 };
76
77 let facade = if let Some(f) = self.get_facade(&facade) {
79 f
80 } else {
81 let err_str = format!("Could not find facade: {}", facade);
82 error!("{}", err_str);
83 if let Err(send_error) = responder.send(None, Some(&err_str)) {
84 error!("Failed to send response with: {}", send_error);
85 }
86 return;
87 };
88
89 let params = match read_json_from_vmo(¶ms_blob) {
91 Ok(value) => value,
92 Err(error) => {
93 if let Err(send_error) =
94 responder.send(None, Some(&format!("Failed to extract params: {}", error)))
95 {
96 error!(error:% = send_error; "Failed to send response");
97 }
98 return;
99 }
100 };
101
102 let result = match facade.handle_request(command, params).await {
104 Ok(Value::Null) => {
105 if let Err(error) = responder.send(None, None) {
106 error!(error:%; "Failed to send response");
107 }
108 return;
109 }
110 Ok(result) => result,
111 Err(error) => {
112 if let Err(error) = responder.send(None, Some(&error.to_string())) {
113 error!(error:%; "Failed to send response");
114 }
115 return;
116 }
117 };
118
119 if let Err(send_error) = match write_json_to_vmo(¶ms_blob, &result) {
121 Ok(()) => responder.send(Some(params_blob), None),
122 Err(error) => responder.send(None, Some(&format!("Failed to write result: {}", error))),
123 } {
124 error!(error:% = send_error; "Failed to send response");
125 }
126 }
127
128 fn cleanup_impl(&self) {
130 for facade in self.get_facades() {
131 facade.cleanup();
132 }
133 }
134
135 fn print_impl(&self) {
137 for facade in self.get_facades() {
138 facade.print();
139 }
140 }
141
142 async fn handle_request(&self, request: FacadeProviderRequest) {
146 match request {
147 FacadeProviderRequest::GetFacades { iterator, control_handle } => {
148 self.get_facades_impl(FacadeProviderRequest::GetFacades {
149 iterator,
150 control_handle,
151 })
152 .await;
153 }
154 FacadeProviderRequest::Execute { facade, command, params_blob, responder } => {
155 info!("Received command {}.{}", facade, command);
156 self.execute_impl(FacadeProviderRequest::Execute {
157 facade,
158 command,
159 params_blob,
160 responder,
161 })
162 .await;
163 }
164 FacadeProviderRequest::Cleanup { responder } => {
165 self.cleanup_impl();
166 if let Err(error) = responder.send() {
167 warn!(error:%; "Failed to notify completion of Cleanup()");
168 }
169 }
170 FacadeProviderRequest::Print { responder } => {
171 self.print_impl();
172 if let Err(error) = responder.send() {
173 error!(error:%; "Failed to notify completion of Print()");
174 }
175 }
176 }
177 }
178
179 async fn run_facade_provider(&self, stream: FacadeProviderRequestStream) {
189 stream
190 .for_each_concurrent(CONCURRENT_REQ_LIMIT, |request| {
191 self.handle_request(request.unwrap())
192 })
193 .await;
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use anyhow::format_err;
201 use fidl_fuchsia_testing_sl4f::FacadeProviderMarker;
202 use fuchsia_async as fasync;
203 use serde_json::json;
204 use std::cell::RefCell;
205 use std::collections::HashMap;
206 use std::pin::pin;
207 use std::task::Poll;
208
209 #[derive(Debug)]
212 struct TestFacade {
213 state: RefCell<bool>,
215 }
216
217 impl TestFacade {
218 pub fn new() -> TestFacade {
219 TestFacade { state: RefCell::new(false) }
220 }
221 }
222
223 #[async_trait(?Send)]
224 impl Facade for TestFacade {
225 async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
226 match method.as_str() {
227 "set" => {
228 if let Value::Bool(new_state) = args {
229 *self.state.borrow_mut() = new_state;
230 return Ok(json!(null));
231 }
232 panic!("Received invalid args");
233 }
234 "get" => {
235 if let Value::Null = args {
236 return Ok(json!(*self.state.borrow()));
237 }
238 panic!("Received invalid args");
239 }
240 _ => return Err(format_err!("Invalid TestFacade method {}", method)),
241 }
242 }
243
244 fn cleanup(&self) {
245 *self.state.borrow_mut() = false;
246 }
247
248 fn print(&self) {}
249 }
250
251 struct TestFacadeProvider {
254 facades: HashMap<String, Arc<dyn Facade>>,
255 }
256
257 impl TestFacadeProvider {
258 pub fn new() -> TestFacadeProvider {
259 let mut facades: HashMap<String, Arc<dyn Facade>> = HashMap::new();
260 facades
261 .insert("test_facade".to_string(), Arc::new(TestFacade::new()) as Arc<dyn Facade>);
262 TestFacadeProvider { facades }
263 }
264 }
265
266 #[async_trait(?Send)]
267 impl FacadeProvider for TestFacadeProvider {
268 fn get_facade(&self, name: &str) -> Option<Arc<dyn Facade>> {
269 self.facades.get(name).map(Arc::clone)
270 }
271
272 fn get_facades(&self) -> Box<dyn Iterator<Item = &Arc<dyn Facade>> + '_> {
273 Box::new(self.facades.values())
274 }
275
276 fn get_facade_names(&self) -> Vec<String> {
277 self.facades.keys().cloned().collect()
278 }
279 }
280
281 #[test]
293 fn test_facade_provider() -> Result<(), Error> {
294 let mut executor = fasync::TestExecutor::new();
295
296 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<FacadeProviderMarker>();
297 let server_fut = async {
298 let sl4f = TestFacadeProvider::new();
300 sl4f.run_facade_provider(stream).await;
301 };
302 let client_fut = async {
303 let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, 0)?;
305 write_json_to_vmo(&vmo, &json!(null))?;
306 if let (Some(vmo), None) = proxy.execute("test_facade", "get", vmo).await? {
307 assert_eq!(false, read_json_from_vmo(&vmo)?.as_bool().unwrap());
308 } else {
309 panic!("Failed to get initial state.");
310 }
311
312 let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, 0)?;
314 write_json_to_vmo(&vmo, &json!(true))?;
315 if let (None, None) = proxy.execute("test_facade", "set", vmo).await? {
316 } else {
317 panic!("Failed to set new state.");
318 }
319
320 let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, 0)?;
322 write_json_to_vmo(&vmo, &json!(null))?;
323 if let (Some(vmo), None) = proxy.execute("test_facade", "get", vmo).await? {
324 assert_eq!(true, read_json_from_vmo(&vmo)?.as_bool().unwrap());
325 } else {
326 panic!("Failed to get new state.");
327 }
328
329 proxy.cleanup().await?;
331
332 let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, 0)?;
334 write_json_to_vmo(&vmo, &json!(null))?;
335 if let (Some(vmo), None) = proxy.execute("test_facade", "get", vmo).await? {
336 assert_eq!(false, read_json_from_vmo(&vmo)?.as_bool().unwrap());
337 } else {
338 panic!("Failed to get initial state.");
339 }
340
341 drop(proxy);
343 Ok::<(), Error>(())
344 };
345 let mut combined_fut = pin!(async {
346 let (_, res) = futures::join!(server_fut, client_fut);
347 res.unwrap();
348 });
349
350 assert_eq!(Poll::Ready(()), executor.run_until_stalled(&mut combined_fut));
351
352 Ok(())
353 }
354}