Skip to main content

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 crate::night_mode_controller::{NightModeController, NightModeError, Request};
6use crate::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::StreamExt;
14use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
15use futures::channel::oneshot;
16use settings_common::inspect::event::{
17    HangingGetObserver, RequestType, ResponseType, UsagePublisher,
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 = HangingGetObserver<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, observer: SubscriberObject) -> bool {
51        let (usage_responder, responder) = observer.into_parts();
52        usage_responder.respond(format!("{info:?}"), ResponseType::OkSome);
53        if let Err(e) = responder.send(&NightModeSettings::from(*info)) {
54            log::warn!("Failed to respond to watch request: {e:?}");
55            return false;
56        }
57        true
58    }
59
60    pub fn handle_stream(&mut self, mut stream: NightModeRequestStream) {
61        let request_handler = RequestHandler {
62            subscriber: self.hanging_get.new_subscriber(),
63            controller_tx: self.controller_tx.clone(),
64            usage_publisher: self.usage_publisher.clone(),
65        };
66        fasync::Task::local(async move {
67            while let Some(Ok(request)) = stream.next().await {
68                request_handler.handle_request(request).await;
69            }
70        })
71        .detach();
72    }
73}
74
75#[derive(Debug)]
76enum HandlerError {
77    AlreadySubscribed,
78    ControllerStopped,
79    Controller(NightModeError),
80}
81
82impl From<&HandlerError> for ResponseType {
83    fn from(error: &HandlerError) -> Self {
84        match error {
85            HandlerError::AlreadySubscribed => ResponseType::AlreadySubscribed,
86            HandlerError::ControllerStopped => ResponseType::UnexpectedError,
87            HandlerError::Controller(e) => ResponseType::from(e),
88        }
89    }
90}
91
92struct RequestHandler {
93    subscriber: Subscriber,
94    controller_tx: UnboundedSender<Request>,
95    usage_publisher: UsagePublisher<NightModeInfo>,
96}
97
98impl RequestHandler {
99    async fn handle_request(&self, request: NightModeRequest) {
100        match request {
101            NightModeRequest::Watch { responder } => {
102                let usage_res = self.usage_publisher.request("Watch".to_string(), RequestType::Get);
103                let observer = HangingGetObserver::new(usage_res, responder);
104                if let Err(observer) = self.subscriber.register2(observer) {
105                    let e = HandlerError::AlreadySubscribed;
106                    let (usage_res, responder) = observer.into_parts();
107                    usage_res.respond(format!("Err({e:?})"), ResponseType::from(&e));
108                    drop(responder);
109                }
110            }
111            NightModeRequest::Set { settings, responder } => {
112                let usage_res = self
113                    .usage_publisher
114                    .request(format!("Set{{settings:{settings:?}}}"), RequestType::Set);
115                if let Err(e) = self.set(settings).await {
116                    usage_res.respond(format!("Err({e:?}"), ResponseType::from(&e));
117                    let _ = responder.send(Err(SettingsError::Failed));
118                } else {
119                    usage_res.respond("Ok(())".to_string(), ResponseType::OkNone);
120                    let _ = responder.send(Ok(()));
121                }
122            }
123        }
124    }
125
126    async fn set(&self, settings: NightModeSettings) -> Result<(), HandlerError> {
127        let (set_tx, set_rx) = oneshot::channel();
128        self.controller_tx
129            .unbounded_send(Request::Set(settings.night_mode_enabled, set_tx))
130            .map_err(|_| HandlerError::ControllerStopped)?;
131        set_rx
132            .await
133            .map_err(|_| HandlerError::ControllerStopped)
134            .and_then(|res| res.map_err(HandlerError::Controller))
135    }
136}