settings/
agent.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::base::SettingType;
6use crate::message::base::MessengerType;
7use crate::service::message::Receptor;
8use crate::service_context::ServiceContext;
9use crate::{event, payload_convert, service};
10
11use futures::future::LocalBoxFuture;
12use std::collections::HashSet;
13use std::fmt::Debug;
14use std::rc::Rc;
15use thiserror::Error;
16
17/// Agent for watching the camera3 status.
18pub(crate) mod camera_watcher;
19
20/// Agent for handling media button input.
21pub(crate) mod media_buttons;
22
23/// This mod provides a concrete implementation of the agent authority.
24pub(crate) mod authority;
25
26/// Agent for rehydrating actions for restore.
27pub(crate) mod restore_agent;
28
29/// Earcons.
30pub(crate) mod earcons;
31
32/// Inspect agents.
33pub(crate) mod inspect;
34
35#[derive(Error, Debug, Clone, Copy, PartialEq)]
36pub enum AgentError {
37    #[error("Unhandled Lifespan")]
38    UnhandledLifespan,
39    #[error("Unexpected Error")]
40    UnexpectedError,
41}
42
43pub(crate) type InvocationResult = Result<(), AgentError>;
44
45/// The scope of an agent's life. Initialization components should
46/// only run at the beginning of the service. Service components follow
47/// initialization and run for the duration of the service.
48#[derive(Clone, Copy, Debug, PartialEq)]
49pub(crate) enum Lifespan {
50    Initialization,
51    Service,
52}
53
54/// Struct of information passed to the agent during each invocation.
55#[derive(Clone)]
56pub struct Invocation {
57    pub(crate) lifespan: Lifespan,
58    pub(crate) service_context: Rc<ServiceContext>,
59}
60
61impl Debug for Invocation {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        f.debug_struct("Invocation").field("lifespan", &self.lifespan).finish_non_exhaustive()
64    }
65}
66
67impl PartialEq for Invocation {
68    fn eq(&self, other: &Self) -> bool {
69        self.lifespan == other.lifespan
70    }
71}
72
73pub type AgentFuture = LocalBoxFuture<'static, ()>;
74
75/// Supported types of [Agent] creation functions.
76pub enum CreationFunc {
77    /// A simple wrapper around a static creation function.
78    ///
79    /// Example usage:
80    /// ```no_run
81    /// async fn create(c: Context) { }
82    /// let f = CreationFunc::Static(|c| Box::Pin(example::create(c));
83    /// ```
84    Static(fn(Context) -> AgentFuture),
85    /// Used for more complicate creation functions that need to capture state.
86    ///
87    /// Example usage:
88    /// ```no_run
89    /// let shared = Rc::new(Mutex::new(0u));
90    /// let f = CreationFunc::Dynamic(Rc::new(move |c| -> AgentFuture {
91    ///     let shared = Rc::clone(&shared);
92    ///     Box::pin(async move {
93    ///         *shared.lock().await = 42;
94    ///     })
95    /// }));
96    /// ```
97    Dynamic(Rc<dyn Fn(Context) -> AgentFuture>),
98}
99
100/// AgentCreator provides a simple wrapper for an async Agent creation function.
101pub struct AgentCreator {
102    pub debug_id: &'static str,
103    pub create: CreationFunc,
104}
105
106impl AgentCreator {
107    pub(crate) fn create(&self, context: Context) -> AgentFuture {
108        match &self.create {
109            CreationFunc::Static(f) => (f)(context),
110            CreationFunc::Dynamic(f) => (f)(context),
111        }
112    }
113}
114
115/// Agent Context contains necessary parts to create an agent.
116pub struct Context {
117    /// The receivor end to receive messages.
118    pub receptor: Receptor,
119
120    /// Publishers are used to publish events.
121    publisher: event::Publisher,
122
123    /// Delegates are used to create new messengers.
124    pub delegate: service::message::Delegate,
125
126    /// Indicates available Settings interfaces.
127    pub(crate) available_components: HashSet<SettingType>,
128}
129
130impl Context {
131    pub(crate) async fn new(
132        receptor: Receptor,
133        delegate: service::message::Delegate,
134        available_components: HashSet<SettingType>,
135    ) -> Self {
136        let publisher = event::Publisher::create(&delegate, MessengerType::Unbound).await;
137        Self { receptor, publisher, delegate, available_components }
138    }
139
140    /// Generates a new `Messenger` on the service `MessageHub`. Only
141    /// top-level messages can be sent, not received, as the associated
142    /// `Receptor` is discarded.
143    async fn create_messenger(
144        &self,
145    ) -> Result<service::message::Messenger, service::message::MessageError> {
146        Ok(self.delegate.create(MessengerType::Unbound).await?.0)
147    }
148
149    pub(crate) fn get_publisher(&self) -> event::Publisher {
150        self.publisher.clone()
151    }
152}
153
154#[derive(Clone, Debug, PartialEq)]
155pub enum Payload {
156    Invocation(Invocation),
157    Complete(InvocationResult),
158}
159
160payload_convert!(Agent, Payload);