//! Bluetooth testing root facade service use bt_facade_proto::rootservice::*; use bt_facade_proto::rootservice_grpc::{create_root_facade, RootFacade}; use bt_hal::facade::HciHalFacadeService; use bt_hci::controller_facade::ControllerFacadeService; use bt_hci::facade::HciFacadeService; use bt_main::Stack; use futures::executor::block_on; use grpcio::*; use std::sync::Arc; use tokio::runtime::Runtime; use tokio::sync::mpsc::{channel, Sender}; use tokio::sync::oneshot; /// Bluetooth testing root facade service #[derive(Clone)] pub struct RootFacadeService { rt: Arc, manager: FacadeServiceManager, } impl RootFacadeService { /// Create a new instance of the root facade service pub fn create( rt: Arc, grpc_port: u16, rootcanal_port: Option, snoop_path: Option, ) -> grpcio::Service { create_root_facade(Self { rt: rt.clone(), manager: FacadeServiceManager::create(rt, grpc_port, rootcanal_port, snoop_path), }) } } impl RootFacade for RootFacadeService { fn start_stack( &mut self, _ctx: RpcContext<'_>, req: StartStackRequest, sink: UnarySink, ) { self.rt.block_on(self.manager.start(req)).unwrap(); sink.success(StartStackResponse::default()); } fn stop_stack( &mut self, _ctx: RpcContext<'_>, _req: StopStackRequest, sink: UnarySink, ) { self.rt.block_on(self.manager.stop()).unwrap(); sink.success(StopStackResponse::default()); } } #[derive(Debug)] enum LifecycleCommand { Start { req: StartStackRequest, done: oneshot::Sender<()> }, Stop { done: oneshot::Sender<()> }, } #[derive(Clone)] struct FacadeServiceManager { lifecycle_tx: Sender, } struct FacadeServer { server: Server, stack: Stack, } impl FacadeServer { async fn start(stack: Stack, req: StartStackRequest, grpc_port: u16) -> Self { let mut services = Vec::new(); match req.get_module_under_test() { BluetoothModule::HAL => { services.push(stack.get_grpc::().await); } BluetoothModule::HCI => { services.push(stack.get_grpc::().await); } BluetoothModule::HCI_INTERFACES => { services.push(stack.get_grpc::().await); services.push(stack.get_grpc::().await); } _ => unimplemented!(), } let env = Arc::new(Environment::new(2)); let mut builder = ServerBuilder::new(env).bind("0.0.0.0", grpc_port); for service in services { builder = builder.register_service(service); } let mut server = builder.build().unwrap(); server.start(); Self { server, stack } } async fn stop(&mut self) { self.server.shutdown().await.unwrap(); self.stack.stop().await; } } /// Result type type Result = std::result::Result>; impl FacadeServiceManager { fn create( rt: Arc, grpc_port: u16, rootcanal_port: Option, snoop_path: Option, ) -> Self { let (tx, mut rx) = channel::(1); let local_rt = rt.clone(); rt.spawn(async move { let mut server: Option = None; while let Some(cmd) = rx.recv().await { match cmd { LifecycleCommand::Start { req, done } => { let stack = Stack::new(local_rt.clone()).await; stack.set_rootcanal_port(rootcanal_port).await; stack.configure_snoop(snoop_path.clone()).await; server = Some(FacadeServer::start(stack, req, grpc_port).await); done.send(()).unwrap(); } LifecycleCommand::Stop { done } => { if let Some(s) = &mut server { block_on(s.stop()); server = None; } done.send(()).unwrap(); } } } }); Self { lifecycle_tx: tx } } async fn start(&self, req: StartStackRequest) -> Result<()> { let (tx, rx) = oneshot::channel(); self.lifecycle_tx.send(LifecycleCommand::Start { req, done: tx }).await?; rx.await?; Ok(()) } async fn stop(&self) -> Result<()> { let (tx, rx) = oneshot::channel(); self.lifecycle_tx.send(LifecycleCommand::Stop { done: tx }).await?; rx.await?; Ok(()) } }