Skip to main content

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