settings_light/
lib.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5pub 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;