Skip to main content

settings_privacy/
privacy_controller.rs

1// Copyright 2019 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::privacy_fidl_handler::Publisher;
6use crate::types::PrivacyInfo;
7use anyhow::Error;
8use fuchsia_async as fasync;
9use futures::StreamExt;
10use futures::channel::mpsc::UnboundedReceiver;
11use futures::channel::oneshot::Sender;
12use settings_common::inspect::event::{ResponseType, SettingValuePublisher};
13use settings_storage::UpdateState;
14use settings_storage::device_storage::{DeviceStorage, DeviceStorageCompatible};
15use settings_storage::storage_factory::{NoneT, StorageAccess, StorageFactory};
16use std::rc::Rc;
17
18impl DeviceStorageCompatible for PrivacyInfo {
19    type Loader = NoneT;
20    const KEY: &'static str = "privacy_info";
21}
22
23#[derive(thiserror::Error, Debug)]
24pub(crate) enum PrivacyError {
25    #[error("Write failed for Setup: {0:?}")]
26    WriteFailure(Error),
27}
28
29impl From<&PrivacyError> for ResponseType {
30    fn from(error: &PrivacyError) -> Self {
31        match error {
32            PrivacyError::WriteFailure(..) => ResponseType::StorageFailure,
33        }
34    }
35}
36
37pub(crate) enum Request {
38    Set(Option<bool>, Sender<Result<(), PrivacyError>>),
39}
40
41pub struct PrivacyController {
42    store: Rc<DeviceStorage>,
43    publisher: Option<Publisher>,
44    setting_value_publisher: SettingValuePublisher<PrivacyInfo>,
45}
46
47impl PrivacyController {
48    pub(super) async fn new<F>(
49        storage_factory: Rc<F>,
50        setting_value_publisher: SettingValuePublisher<PrivacyInfo>,
51    ) -> Self
52    where
53        F: StorageFactory<Storage = DeviceStorage>,
54    {
55        PrivacyController {
56            store: storage_factory.get_store().await,
57            publisher: None,
58            setting_value_publisher,
59        }
60    }
61
62    pub(super) fn register_publisher(&mut self, publisher: Publisher) {
63        self.publisher = Some(publisher);
64    }
65
66    fn publish(&self, info: PrivacyInfo) {
67        let _ = self.setting_value_publisher.publish(&info);
68        if let Some(publisher) = self.publisher.as_ref() {
69            publisher.set(info);
70        }
71    }
72
73    pub(super) async fn handle(
74        self,
75        mut request_rx: UnboundedReceiver<Request>,
76    ) -> fasync::Task<()> {
77        fasync::Task::local(async move {
78            while let Some(request) = request_rx.next().await {
79                let Request::Set(user_data_sharing_consent, tx) = request;
80                let res = self.set(user_data_sharing_consent).await.map(|info| {
81                    if let Some(info) = info {
82                        self.publish(info);
83                    }
84                });
85                let _ = tx.send(res);
86            }
87        })
88    }
89
90    async fn set(
91        &self,
92        user_data_sharing_consent: Option<bool>,
93    ) -> Result<Option<PrivacyInfo>, PrivacyError> {
94        let mut info = self.store.get::<PrivacyInfo>().await;
95        if let Some(user_data_sharing_consent) = user_data_sharing_consent {
96            info.user_data_sharing_consent = Some(user_data_sharing_consent);
97        }
98
99        self.store
100            .write(&info)
101            .await
102            .map(|state| (UpdateState::Updated == state).then_some(info))
103            .map_err(PrivacyError::WriteFailure)
104    }
105
106    pub(super) async fn restore(&self) -> PrivacyInfo {
107        self.store.get::<PrivacyInfo>().await
108    }
109}
110
111impl StorageAccess for PrivacyController {
112    type Storage = DeviceStorage;
113    type Data = PrivacyInfo;
114    const STORAGE_KEY: &'static str = PrivacyInfo::KEY;
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120    use futures::channel::mpsc;
121    use settings_test_common::storage::InMemoryStorageFactory;
122
123    #[fuchsia::test(allow_stalls = false)]
124    async fn test_privacy_storage() {
125        let factory = Rc::new(InMemoryStorageFactory::new());
126        let (tx, _) = mpsc::unbounded();
127        let setting_value_publisher = SettingValuePublisher::new(tx);
128
129        factory.initialize::<PrivacyController>().await.expect("can initialize privacy storage");
130
131        let privacy_controller =
132            PrivacyController::new(Rc::clone(&factory), setting_value_publisher).await;
133        let store = factory.get_store().await;
134
135        // Initial stored state has no consent value. Calling set(None) is a no-op.
136        let result = privacy_controller.set(None).await.expect("set successful");
137        assert_eq!(result, None);
138        assert_eq!(store.get::<PrivacyInfo>().await.user_data_sharing_consent, None);
139
140        // Set consent to Some(true).
141        let expected_true = PrivacyInfo { user_data_sharing_consent: Some(true) };
142        let result = privacy_controller
143            .set(Some(true))
144            .await
145            .expect("set successful")
146            .expect("privacy info changed");
147        assert_eq!(result, expected_true);
148        assert_eq!(store.get::<PrivacyInfo>().await, expected_true);
149
150        // Calling set(None) preserves Some(true).
151        let result = privacy_controller.set(None).await.expect("set successful");
152        assert_eq!(result, None);
153        assert_eq!(store.get::<PrivacyInfo>().await, expected_true);
154
155        // Set consent to Some(false).
156        let expected_false = PrivacyInfo { user_data_sharing_consent: Some(false) };
157        let result = privacy_controller
158            .set(Some(false))
159            .await
160            .expect("set successful")
161            .expect("privacy info changed");
162        assert_eq!(result, expected_false);
163        assert_eq!(store.get::<PrivacyInfo>().await, expected_false);
164
165        // Calling set(None) preserves Some(false).
166        let result = privacy_controller.set(None).await.expect("set successful");
167        assert_eq!(result, None);
168        assert_eq!(store.get::<PrivacyInfo>().await, expected_false);
169    }
170}