blob: b1f744fbb4df7cbcf5dd7c148c169a8ef1dbb827 [file] [log] [blame]
// Copyright 2023 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::{bail, Context, Result};
use fidl_fuchsia_hwinfo::{
BoardInfo, BoardRequest, BoardRequestStream, DeviceInfo, DeviceRequest, DeviceRequestStream,
ProductInfo, ProductRequest, ProductRequestStream,
};
use fidl_fuchsia_hwinfo_mock::{SetterRequest, SetterRequestStream};
use fuchsia_async as fasync;
use fuchsia_component::server::ServiceFs;
use fuchsia_inspect::{component, health::Reporter};
use futures::prelude::*;
use lazy_static::lazy_static;
use std::sync::{Arc, Mutex};
enum IncomingRequest {
Product(ProductRequestStream),
Board(BoardRequestStream),
Device(DeviceRequestStream),
Setter(SetterRequestStream),
}
struct ReturnValues {
board: BoardInfo,
product: ProductInfo,
device: DeviceInfo,
}
lazy_static! {
static ref RETURN_VALUES: Arc<Mutex<Option<ReturnValues>>> = Arc::new(Mutex::new(None));
}
#[fuchsia::main(logging = true)]
async fn main() -> Result<()> {
let mut service_fs = ServiceFs::new_local();
// Initialize inspect
component::health().set_starting_up();
service_fs.dir("svc").add_fidl_service(IncomingRequest::Product);
service_fs.dir("svc").add_fidl_service(IncomingRequest::Board);
service_fs.dir("svc").add_fidl_service(IncomingRequest::Device);
service_fs.dir("svc").add_fidl_service(IncomingRequest::Setter);
service_fs.take_and_serve_directory_handle().context("failed to serve outgoing namespace")?;
component::health().set_ok();
tracing::debug!("Initialized.");
let _inspect_server_task = inspect_runtime::publish(
component::inspector(),
inspect_runtime::PublishOptions::default(),
);
service_fs
.for_each_concurrent(None, |request: IncomingRequest| async move {
match request {
IncomingRequest::Product(stream) => fasync::Task::spawn(async move {
if let Err(e) = handle_product(stream).await {
tracing::error!("Product handling failed: {:?}", e);
}
})
.detach(),
IncomingRequest::Board(stream) => fasync::Task::spawn(async move {
if let Err(e) = handle_board(stream).await {
tracing::error!("Board handling failed: {:?}", e);
}
})
.detach(),
IncomingRequest::Device(stream) => fasync::Task::spawn(async move {
if let Err(e) = handle_device(stream).await {
tracing::error!("Device handling failed: {:?}", e);
}
})
.detach(),
IncomingRequest::Setter(stream) => {
fasync::Task::spawn(handle_setter(stream)).detach()
}
}
// match on `request` and handle each protocol.
})
.await;
Ok(())
}
async fn handle_product(mut stream: ProductRequestStream) -> Result<()> {
while let Some(Ok(req)) = stream.next().await {
match req {
ProductRequest::GetInfo { responder } => {
let locked = RETURN_VALUES.lock().unwrap();
if locked.is_none() {
bail!("Return values have not been set in mock.");
}
responder.send(&locked.as_ref().unwrap().product)?;
}
}
}
Ok(())
}
async fn handle_board(mut stream: BoardRequestStream) -> Result<()> {
while let Some(Ok(req)) = stream.next().await {
match req {
BoardRequest::GetInfo { responder } => {
let locked = RETURN_VALUES.lock().unwrap();
if locked.is_none() {
bail!("Return values have not been set in mock.");
}
responder.send(&locked.as_ref().unwrap().board)?;
}
}
}
Ok(())
}
async fn handle_device(mut stream: DeviceRequestStream) -> Result<()> {
while let Some(Ok(req)) = stream.next().await {
match req {
DeviceRequest::GetInfo { responder } => {
let locked = RETURN_VALUES.lock().unwrap();
if locked.is_none() {
bail!("Return values have not been set in mock.");
}
responder.send(&locked.as_ref().unwrap().device)?;
}
}
}
Ok(())
}
async fn handle_setter(mut stream: SetterRequestStream) {
while let Some(Ok(req)) = stream.next().await {
match req {
SetterRequest::SetResponses { device, product, board, responder } => {
let mut locked = RETURN_VALUES.lock().unwrap();
*locked = Some(ReturnValues { board, product, device });
responder.send().ok();
}
}
}
}