1pub mod light_controller;
6pub mod light_fidl_handler;
7pub mod light_hardware_configuration;
8pub mod types;
9
10pub use light_hardware_configuration::build_light_default_settings;
11
12use self::light_controller::LightError;
13use self::light_fidl_handler::LightFidlHandler;
14use self::light_hardware_configuration::LightHardwareConfiguration;
15
16use anyhow::{anyhow, Context, Result};
17use fuchsia_async as fasync;
18use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
19use futures::channel::oneshot;
20use futures::StreamExt;
21use settings_common::config::default_settings::DefaultSetting;
22use settings_common::inspect::event::{
23 ExternalEventPublisher, RequestType, ResponseType, SettingValuePublisher, UsagePublisher,
24};
25use settings_common::service_context::ServiceContext;
26use settings_storage::fidl_storage::FidlStorage;
27use settings_storage::storage_factory::StorageFactory;
28use std::rc::Rc;
29use types::LightInfo;
30
31pub struct SetupResult {
32 pub light_fidl_handler: LightFidlHandler,
33 pub media_buttons_event_tx: UnboundedSender<settings_media_buttons::Event>,
34 pub task: fuchsia_async::Task<()>,
35}
36
37pub async fn setup_light_api<F>(
38 service_context: Rc<ServiceContext>,
39 light_configuration: &mut DefaultSetting<LightHardwareConfiguration, &'static str>,
40 storage_factory: Rc<F>,
41 setting_value_publisher: SettingValuePublisher<LightInfo>,
42 usage_publisher: UsagePublisher<LightInfo>,
43 external_publisher: ExternalEventPublisher,
44) -> Result<SetupResult>
45where
46 F: StorageFactory<Storage = FidlStorage>,
47{
48 use light_controller::LightController;
49
50 let mut light_controller = LightController::new(
51 service_context,
52 light_configuration,
53 storage_factory,
54 setting_value_publisher.clone(),
55 external_publisher,
56 )
57 .await
58 .context("failed to construct light controller")?;
59 let initial_value = light_controller
60 .restore()
61 .await
62 .map_err(|e| anyhow!("failed to restore initial value: {e:?}"))?;
63 let _ = setting_value_publisher.publish(&initial_value);
64
65 let (light_fidl_handler, request_rx) =
66 LightFidlHandler::new(&mut light_controller, usage_publisher.clone(), initial_value);
67 let (media_buttons_event_tx, media_buttons_event_rx) = mpsc::unbounded();
68 let inner_mb_event_rx = event_request_logger(media_buttons_event_rx, usage_publisher);
69 let task = light_controller
70 .handle(inner_mb_event_rx, request_rx)
71 .await
72 .map_err(|e| anyhow!("failed to start light controller task: {e:?}"))?;
73 Ok(SetupResult { light_fidl_handler, media_buttons_event_tx, task })
74}
75
76type ResultSender = oneshot::Sender<Result<Option<()>, LightError>>;
77
78fn event_request_logger(
79 mut media_buttons_event_rx: UnboundedReceiver<settings_media_buttons::Event>,
80 usage_publisher: UsagePublisher<LightInfo>,
81) -> UnboundedReceiver<(settings_media_buttons::Event, ResultSender)> {
82 let (inner_mb_event_tx, inner_mb_event_rx) = mpsc::unbounded();
83 fasync::Task::local(async move {
84 while let Some(event) = media_buttons_event_rx.next().await {
85 let usage_responder =
86 usage_publisher.request(format!("{event:?}"), RequestType::MediaButtons);
87 let (tx, rx) = oneshot::channel::<Result<Option<()>, LightError>>();
88 let _ = inner_mb_event_tx.unbounded_send((event, tx));
89 if let Ok(res) = rx.await {
90 usage_responder.respond(
91 format!("{res:?}"),
92 res.map(|res| {
93 if res.is_some() {
94 ResponseType::OkSome
95 } else {
96 ResponseType::OkNone
97 }
98 })
99 .unwrap_or_else(|e| ResponseType::from(&e)),
100 );
101 } else {
102 usage_responder
103 .respond("Err(ControllerDied)".to_string(), ResponseType::UnexpectedError);
104 }
105 }
106 })
107 .detach();
108 inner_mb_event_rx
109}
110
111#[cfg(test)]
112mod test_fakes;