| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use { |
| anyhow::{format_err, Error}, |
| fidl_fuchsia_factory::{ |
| AlphaFactoryStoreProviderRequest, AlphaFactoryStoreProviderRequestStream, |
| CastCredentialsFactoryStoreProviderRequest, |
| CastCredentialsFactoryStoreProviderRequestStream, MiscFactoryStoreProviderRequest, |
| MiscFactoryStoreProviderRequestStream, PlayReadyFactoryStoreProviderRequest, |
| PlayReadyFactoryStoreProviderRequestStream, WeaveFactoryStoreProviderRequest, |
| WeaveFactoryStoreProviderRequestStream, WidevineFactoryStoreProviderRequest, |
| WidevineFactoryStoreProviderRequestStream, |
| }, |
| fidl_fuchsia_io::{DirectoryMarker, DirectoryProxy, MODE_TYPE_DIRECTORY, OPEN_RIGHT_READABLE}, |
| fuchsia_async as fasync, |
| fuchsia_component::server::ServiceFs, |
| fuchsia_syslog::{self as syslog, macros::*}, |
| fuchsia_vfs_pseudo_fs::{ |
| directory::entry::DirectoryEntry, file::simple::read_only_str, tree_builder::TreeBuilder, |
| }, |
| futures::{lock::Mutex, prelude::*}, |
| serde_json::from_reader, |
| std::{collections::HashMap, fs::File, iter, str::FromStr, sync::Arc}, |
| structopt::StructOpt, |
| }; |
| |
| type LockedDirectoryProxy = Arc<Mutex<DirectoryProxy>>; |
| |
| enum IncomingServices { |
| AlphaFactoryStoreProvider(AlphaFactoryStoreProviderRequestStream), |
| CastCredentialsFactoryStoreProvider(CastCredentialsFactoryStoreProviderRequestStream), |
| MiscFactoryStoreProvider(MiscFactoryStoreProviderRequestStream), |
| PlayReadyFactoryStoreProvider(PlayReadyFactoryStoreProviderRequestStream), |
| WeaveFactoryStoreProvider(WeaveFactoryStoreProviderRequestStream), |
| WidevineFactoryStoreProvider(WidevineFactoryStoreProviderRequestStream), |
| } |
| |
| fn start_test_dir(config_path: &str) -> Result<DirectoryProxy, Error> { |
| let files: HashMap<String, String> = match File::open(&config_path) { |
| Ok(file) => from_reader(file)?, |
| Err(err) => { |
| fx_log_warn!("publishing empty directory for {} due to error: {:?}", &config_path, err); |
| HashMap::new() |
| } |
| }; |
| |
| fx_log_info!("Files from {}: {:?}", &config_path, files); |
| |
| let mut tree = TreeBuilder::empty_dir(); |
| |
| for (name, contents) in files.into_iter() { |
| tree.add_entry( |
| &name.split("/").collect::<Vec<&str>>(), |
| read_only_str(move || Ok(contents.to_string())), |
| ) |
| .unwrap(); |
| } |
| |
| let mut test_dir = tree.build(); |
| |
| let (test_dir_proxy, test_dir_service) = fidl::endpoints::create_proxy::<DirectoryMarker>()?; |
| test_dir.open( |
| OPEN_RIGHT_READABLE, |
| MODE_TYPE_DIRECTORY, |
| &mut iter::empty(), |
| test_dir_service.into_channel().into(), |
| ); |
| |
| fasync::Task::spawn(async move { |
| let _ = test_dir.await; |
| }) |
| .detach(); |
| |
| Ok(test_dir_proxy) |
| } |
| |
| async fn run_server(req: IncomingServices, dir_mtx: LockedDirectoryProxy) -> Result<(), Error> { |
| match req { |
| IncomingServices::AlphaFactoryStoreProvider(mut stream) => { |
| while let Some(request) = stream.try_next().await? { |
| let AlphaFactoryStoreProviderRequest::GetFactoryStore { dir, control_handle: _ } = |
| request; |
| dir_mtx.lock().await.clone(OPEN_RIGHT_READABLE, dir.into_channel().into())?; |
| } |
| } |
| IncomingServices::CastCredentialsFactoryStoreProvider(mut stream) => { |
| while let Some(request) = stream.try_next().await? { |
| let CastCredentialsFactoryStoreProviderRequest::GetFactoryStore { |
| dir, |
| control_handle: _, |
| } = request; |
| dir_mtx.lock().await.clone(OPEN_RIGHT_READABLE, dir.into_channel().into())?; |
| } |
| } |
| IncomingServices::MiscFactoryStoreProvider(mut stream) => { |
| while let Some(request) = stream.try_next().await? { |
| let MiscFactoryStoreProviderRequest::GetFactoryStore { dir, control_handle: _ } = |
| request; |
| dir_mtx.lock().await.clone(OPEN_RIGHT_READABLE, dir.into_channel().into())?; |
| } |
| } |
| IncomingServices::PlayReadyFactoryStoreProvider(mut stream) => { |
| while let Some(request) = stream.try_next().await? { |
| let PlayReadyFactoryStoreProviderRequest::GetFactoryStore { |
| dir, |
| control_handle: _, |
| } = request; |
| dir_mtx.lock().await.clone(OPEN_RIGHT_READABLE, dir.into_channel().into())?; |
| } |
| } |
| IncomingServices::WeaveFactoryStoreProvider(mut stream) => { |
| while let Some(request) = stream.try_next().await? { |
| let WeaveFactoryStoreProviderRequest::GetFactoryStore { dir, control_handle: _ } = |
| request; |
| dir_mtx.lock().await.clone(OPEN_RIGHT_READABLE, dir.into_channel().into())?; |
| } |
| } |
| IncomingServices::WidevineFactoryStoreProvider(mut stream) => { |
| while let Some(request) = stream.try_next().await? { |
| let WidevineFactoryStoreProviderRequest::GetFactoryStore { dir, control_handle: _ } = |
| request; |
| dir_mtx.lock().await.clone(OPEN_RIGHT_READABLE, dir.into_channel().into())?; |
| } |
| } |
| } |
| Ok(()) |
| } |
| |
| #[derive(Debug, StructOpt)] |
| enum Provider { |
| Alpha, |
| Cast, |
| Misc, |
| Playready, |
| Weave, |
| Widevine, |
| } |
| impl FromStr for Provider { |
| type Err = Error; |
| |
| fn from_str(s: &str) -> Result<Self, Self::Err> { |
| let formatted_str = s.trim().to_lowercase(); |
| match formatted_str.as_ref() { |
| "alpha" => Ok(Provider::Alpha), |
| "cast" => Ok(Provider::Cast), |
| "misc" => Ok(Provider::Misc), |
| "playready" => Ok(Provider::Playready), |
| "weave" => Ok(Provider::Weave), |
| "widevine" => Ok(Provider::Widevine), |
| _ => Err(format_err!("Could not find '{}' provider", formatted_str)), |
| } |
| } |
| } |
| |
| #[derive(Debug, StructOpt)] |
| struct Flags { |
| /// The factory store provider to fake. |
| #[structopt(short, long)] |
| provider: Provider, |
| |
| /// The path to the config file for the provider. |
| #[structopt(short, long)] |
| config: String, |
| } |
| |
| #[fasync::run_singlethreaded] |
| async fn main() -> Result<(), Error> { |
| syslog::init_with_tags(&["fake_factory_store_providers"])?; |
| let flags = Flags::from_args(); |
| let dir = Arc::new(Mutex::new(start_test_dir(&flags.config)?)); |
| |
| let mut fs = ServiceFs::new_local(); |
| let mut fs_dir = fs.dir("svc"); |
| |
| match flags.provider { |
| Provider::Alpha => fs_dir.add_fidl_service(IncomingServices::AlphaFactoryStoreProvider), |
| Provider::Cast => { |
| fs_dir.add_fidl_service(IncomingServices::CastCredentialsFactoryStoreProvider) |
| } |
| Provider::Misc => fs_dir.add_fidl_service(IncomingServices::MiscFactoryStoreProvider), |
| Provider::Playready => { |
| fs_dir.add_fidl_service(IncomingServices::PlayReadyFactoryStoreProvider) |
| } |
| Provider::Weave => fs_dir.add_fidl_service(IncomingServices::WeaveFactoryStoreProvider), |
| Provider::Widevine => { |
| fs_dir.add_fidl_service(IncomingServices::WidevineFactoryStoreProvider) |
| } |
| }; |
| |
| fs.take_and_serve_directory_handle()?; |
| fs.for_each_concurrent(10, |req| { |
| run_server(req, dir.clone()).unwrap_or_else(|e| fx_log_err!("{:?}", e)) |
| }) |
| .await; |
| Ok(()) |
| } |