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