settings/night_mode/
night_mode_fidl_handler.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
5use super::night_mode_controller::{NightModeController, NightModeError, Request};
6use crate::night_mode::types::NightModeInfo;
7use async_utils::hanging_get::server;
8use fidl_fuchsia_settings::{
9    Error as SettingsError, NightModeRequest, NightModeRequestStream, NightModeSettings,
10    NightModeWatchResponder,
11};
12use fuchsia_async as fasync;
13use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
14use futures::channel::oneshot;
15use futures::StreamExt;
16use settings_common::inspect::event::{
17    RequestType, ResponseType, UsagePublisher, UsageResponsePublisher,
18};
19
20impl From<NightModeInfo> for NightModeSettings {
21    fn from(info: NightModeInfo) -> Self {
22        NightModeSettings { night_mode_enabled: info.night_mode_enabled, ..Default::default() }
23    }
24}
25
26pub(super) type SubscriberObject = (UsageResponsePublisher<NightModeInfo>, NightModeWatchResponder);
27type HangingGetFn = fn(&NightModeInfo, SubscriberObject) -> bool;
28pub(super) type HangingGet = server::HangingGet<NightModeInfo, SubscriberObject, HangingGetFn>;
29pub(super) type Publisher = server::Publisher<NightModeInfo, SubscriberObject, HangingGetFn>;
30pub(super) type Subscriber = server::Subscriber<NightModeInfo, SubscriberObject, HangingGetFn>;
31
32pub struct NightModeFidlHandler {
33    hanging_get: HangingGet,
34    controller_tx: UnboundedSender<Request>,
35    usage_publisher: UsagePublisher<NightModeInfo>,
36}
37
38impl NightModeFidlHandler {
39    pub(crate) fn new(
40        night_mode_controller: &mut NightModeController,
41        usage_publisher: UsagePublisher<NightModeInfo>,
42        initial_value: NightModeInfo,
43    ) -> (Self, UnboundedReceiver<Request>) {
44        let hanging_get = HangingGet::new(initial_value, Self::hanging_get);
45        night_mode_controller.register_publisher(hanging_get.new_publisher());
46        let (controller_tx, controller_rx) = mpsc::unbounded();
47        (Self { hanging_get, controller_tx, usage_publisher }, controller_rx)
48    }
49
50    fn hanging_get(info: &NightModeInfo, (usage_responder, responder): SubscriberObject) -> bool {
51        usage_responder.respond(format!("{info:?}"), ResponseType::OkSome);
52        if let Err(e) = responder.send(&NightModeSettings::from(*info)) {
53            log::warn!("Failed to respond to watch request: {e:?}");
54            return false;
55        }
56        true
57    }
58
59    pub fn handle_stream(&mut self, mut stream: NightModeRequestStream) {
60        let request_handler = RequestHandler {
61            subscriber: self.hanging_get.new_subscriber(),
62            controller_tx: self.controller_tx.clone(),
63            usage_publisher: self.usage_publisher.clone(),
64        };
65        fasync::Task::local(async move {
66            while let Some(Ok(request)) = stream.next().await {
67                request_handler.handle_request(request).await;
68            }
69        })
70        .detach();
71    }
72}
73
74#[derive(Debug)]
75enum HandlerError {
76    AlreadySubscribed,
77    ControllerStopped,
78    Controller(NightModeError),
79}
80
81impl From<&HandlerError> for ResponseType {
82    fn from(error: &HandlerError) -> Self {
83        match error {
84            HandlerError::AlreadySubscribed => ResponseType::AlreadySubscribed,
85            HandlerError::ControllerStopped => ResponseType::UnexpectedError,
86            HandlerError::Controller(e) => ResponseType::from(e),
87        }
88    }
89}
90
91struct RequestHandler {
92    subscriber: Subscriber,
93    controller_tx: UnboundedSender<Request>,
94    usage_publisher: UsagePublisher<NightModeInfo>,
95}
96
97impl RequestHandler {
98    async fn handle_request(&self, request: NightModeRequest) {
99        match request {
100            NightModeRequest::Watch { responder } => {
101                let usage_res = self.usage_publisher.request("Watch".to_string(), RequestType::Get);
102                if let Err((usage_res, responder)) =
103                    self.subscriber.register2((usage_res, responder))
104                {
105                    let e = HandlerError::AlreadySubscribed;
106                    usage_res.respond(format!("Err({e:?})"), ResponseType::from(&e));
107                    drop(responder);
108                }
109            }
110            NightModeRequest::Set { settings, responder } => {
111                let usage_res = self
112                    .usage_publisher
113                    .request(format!("Set{{settings:{settings:?}}}"), RequestType::Set);
114                if let Err(e) = self.set(settings).await {
115                    usage_res.respond(format!("Err({e:?}"), ResponseType::from(&e));
116                    let _ = responder.send(Err(SettingsError::Failed));
117                } else {
118                    usage_res.respond("Ok(())".to_string(), ResponseType::OkNone);
119                    let _ = responder.send(Ok(()));
120                }
121            }
122        }
123    }
124
125    async fn set(&self, settings: NightModeSettings) -> Result<(), HandlerError> {
126        let (set_tx, set_rx) = oneshot::channel();
127        self.controller_tx
128            .unbounded_send(Request::Set(settings.night_mode_enabled, set_tx))
129            .map_err(|_| HandlerError::ControllerStopped)?;
130        set_rx
131            .await
132            .map_err(|_| HandlerError::ControllerStopped)
133            .and_then(|res| res.map_err(HandlerError::Controller))
134    }
135}