settings_common/inspect/
event.rs

1// Copyright 2025 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::listener_logger::ListenerInspectLogger;
6use crate::service_context::ExternalServiceEvent;
7use anyhow::{anyhow, Error};
8use futures::channel::mpsc::UnboundedSender;
9use std::cell::Cell;
10use std::marker::PhantomData;
11use std::rc::Rc;
12
13#[derive(Clone)]
14pub enum Direction {
15    Request(String),
16    Response(String, ResponseType),
17}
18
19#[derive(Clone)]
20pub struct UsageEvent {
21    pub setting: &'static str,
22    pub request_type: RequestType,
23    pub direction: Direction,
24    pub id: u64,
25}
26
27pub trait Nameable {
28    const NAME: &str;
29}
30
31#[derive(Clone)]
32pub struct UsagePublisher<T> {
33    id_gen: Rc<Cell<u64>>,
34    inspect_tx: UnboundedSender<UsageEvent>,
35    listener_logger: Rc<ListenerInspectLogger>,
36    _phantom: PhantomData<T>,
37}
38
39impl<T> UsagePublisher<T> {
40    pub fn new(
41        inspect_tx: UnboundedSender<UsageEvent>,
42        listener_logger: Rc<ListenerInspectLogger>,
43    ) -> Self {
44        Self { id_gen: Rc::new(Cell::new(0)), inspect_tx, listener_logger, _phantom: PhantomData }
45    }
46}
47
48impl<T> UsagePublisher<T>
49where
50    T: Nameable,
51{
52    pub fn request(&self, request: String, request_type: RequestType) -> UsageResponsePublisher<T> {
53        let id = self.id_gen.get();
54        self.id_gen.set(id.wrapping_add(1));
55        let _ = self.inspect_tx.unbounded_send(UsageEvent {
56            setting: T::NAME,
57            request_type,
58            direction: Direction::Request(request),
59            id,
60        });
61        if let RequestType::Get = request_type {
62            self.listener_logger.add_listener(T::NAME.into());
63        }
64
65        UsageResponsePublisher {
66            id,
67            request_type,
68            inspect_tx: self.inspect_tx.clone(),
69            listener_logger: Rc::clone(&self.listener_logger),
70            sent: false,
71            _phantom: PhantomData,
72        }
73    }
74}
75
76#[derive(Clone)]
77pub struct UsageResponsePublisher<T> {
78    id: u64,
79    request_type: RequestType,
80    inspect_tx: UnboundedSender<UsageEvent>,
81    listener_logger: Rc<ListenerInspectLogger>,
82    sent: bool,
83    _phantom: PhantomData<T>,
84}
85
86impl<T> UsageResponsePublisher<T>
87where
88    T: Nameable,
89{
90    pub fn respond(mut self, response: String, response_type: ResponseType) {
91        let _ = self.inspect_tx.unbounded_send(UsageEvent {
92            setting: T::NAME,
93            request_type: self.request_type,
94            direction: Direction::Response(response, response_type),
95            id: self.id,
96        });
97        if let RequestType::Get = self.request_type {
98            self.listener_logger.remove_listener(T::NAME.into());
99        }
100        self.sent = true;
101    }
102}
103
104impl<T> Drop for UsageResponsePublisher<T> {
105    fn drop(&mut self) {
106        if !self.sent {
107            log::error!("UsageResponsePublisher dropped without sending response");
108        }
109    }
110}
111
112#[derive(Copy, Clone, Debug)]
113pub enum RequestType {
114    Get,
115    Set,
116    Camera,
117    MediaButtons,
118}
119
120#[derive(Debug, Copy, Clone)]
121/// Response type to a request to a setting. Used for accumulating response type
122/// counts for inspect. This should be updated to have a matching error for each
123/// of the controller error variants.
124pub enum ResponseType {
125    OkSome,
126    OkNone,
127    UnimplementedRequest,
128    StorageFailure,
129    InitFailure,
130    RestoreFailure,
131    InvalidArgument,
132    IncompatibleArguments,
133    ExternalFailure,
134    UnhandledType,
135    DeliveryError,
136    UnexpectedError,
137    UndeliverableError,
138    UnsupportedError,
139    CommunicationError,
140    IrrecoverableError,
141    TimeoutError,
142    AlreadySubscribed,
143}
144
145#[derive(Copy, Clone, Debug)]
146pub struct MediaButtons {
147    pub mic_mute: Option<bool>,
148    pub camera_disable: Option<bool>,
149}
150
151#[derive(Clone)]
152pub struct SettingValuePublisher<T> {
153    tx: UnboundedSender<(&'static str, String)>,
154    _phantom: PhantomData<T>,
155}
156
157impl<T> SettingValuePublisher<T> {
158    pub fn new(tx: UnboundedSender<(&'static str, String)>) -> Self {
159        Self { tx, _phantom: PhantomData }
160    }
161}
162
163impl<T> SettingValuePublisher<T>
164where
165    T: Nameable + std::fmt::Debug,
166{
167    pub fn publish(&self, value: &T) -> Result<(), Error> {
168        self.tx
169            .unbounded_send((T::NAME, format!("{value:?}")))
170            .map_err(|e| anyhow!("Unable to send setting_value update: {e:?}"))
171    }
172}
173
174#[derive(Clone)]
175pub struct ExternalEventPublisher {
176    tx: UnboundedSender<ExternalServiceEvent>,
177}
178
179impl ExternalEventPublisher {
180    pub fn new(tx: UnboundedSender<ExternalServiceEvent>) -> Self {
181        Self { tx }
182    }
183
184    pub fn publish(&self, event: ExternalServiceEvent) -> Result<(), Error> {
185        self.tx
186            .unbounded_send(event)
187            .map_err(|e| anyhow!("Unable to send external event update: {e:?}"))
188    }
189}