blob: 8d83dabd95c9dd828c6c9755e0d492ccae0b98f5 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::base::SettingType;
use crate::event;
use crate::message::base::MessengerType;
use crate::monitor;
use crate::payload_convert;
use crate::policy::PolicyType;
use crate::service;
use crate::service::message::Receptor;
use crate::service_context::ServiceContext;
use futures::future::BoxFuture;
use std::collections::HashSet;
use std::fmt::Debug;
use std::sync::Arc;
use thiserror::Error;
/// Agent for watching the camera3 status.
pub(crate) mod camera_watcher;
/// Agent for handling media button input.
pub(crate) mod media_buttons;
/// This mod provides a concrete implementation of the agent authority.
pub(crate) mod authority;
/// Agent for rehydrating actions for restore.
pub(crate) mod restore_agent;
/// Agent for managing access to storage.
pub mod storage;
/// Earcons.
pub(crate) mod earcons;
/// Inspect agents.
pub(crate) mod inspect;
#[derive(Error, Debug, Clone, Copy, PartialEq)]
pub enum AgentError {
#[error("Unhandled Lifespan")]
UnhandledLifespan,
#[error("Unexpected Error")]
UnexpectedError,
}
pub(crate) type InvocationResult = Result<(), AgentError>;
/// The scope of an agent's life. Initialization components should
/// only run at the beginning of the service. Service components follow
/// initialization and run for the duration of the service.
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum Lifespan {
Initialization,
Service,
}
/// Struct of information passed to the agent during each invocation.
#[derive(Clone)]
pub struct Invocation {
pub(crate) lifespan: Lifespan,
pub(crate) service_context: Arc<ServiceContext>,
}
impl Debug for Invocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Invocation").field("lifespan", &self.lifespan).finish_non_exhaustive()
}
}
impl PartialEq for Invocation {
fn eq(&self, other: &Self) -> bool {
self.lifespan == other.lifespan
}
}
/// Blueprint defines an interface provided to the authority for constructing
/// a given agent.
pub trait Blueprint {
/// Returns a debug id that can be used during error reporting.
fn debug_id(&self) -> &'static str;
/// Uses the supplied context to create agent.
fn create(&self, context: Context) -> BoxFuture<'static, ()>;
}
pub type BlueprintHandle = Arc<dyn Blueprint + Send + Sync>;
/// TODO(fxbug.dev/68659): Add documentation.
pub struct Context {
pub receptor: Receptor,
publisher: event::Publisher,
pub delegate: service::message::Delegate,
pub(crate) available_components: HashSet<SettingType>,
pub available_policies: HashSet<PolicyType>,
pub resource_monitor_actor: Option<monitor::environment::Actor>,
}
impl Context {
pub(crate) async fn new(
receptor: Receptor,
delegate: service::message::Delegate,
available_components: HashSet<SettingType>,
available_policies: HashSet<PolicyType>,
resource_monitor_actor: Option<monitor::environment::Actor>,
) -> Self {
let publisher = event::Publisher::create(&delegate, MessengerType::Unbound).await;
Self {
receptor,
publisher,
delegate,
available_components,
available_policies,
resource_monitor_actor,
}
}
/// Generates a new `Messenger` on the service `MessageHub`. Only
/// top-level messages can be sent, not received, as the associated
/// `Receptor` is discarded.
async fn create_messenger(
&self,
) -> Result<service::message::Messenger, service::message::MessageError> {
Ok(self.delegate.create(MessengerType::Unbound).await?.0)
}
pub(crate) fn get_publisher(&self) -> event::Publisher {
self.publisher.clone()
}
}
#[macro_export]
macro_rules! blueprint_definition {
($component:literal, $create:expr) => {
pub(crate) mod blueprint {
#[allow(unused_imports)]
use super::*;
use crate::agent::{Blueprint, BlueprintHandle, Context};
use futures::future::BoxFuture;
use std::sync::Arc;
pub(crate) fn create() -> BlueprintHandle {
Arc::new(BlueprintImpl)
}
struct BlueprintImpl;
impl Blueprint for BlueprintImpl {
fn debug_id(&self) -> &'static str {
$component
}
fn create(&self, context: Context) -> BoxFuture<'static, ()> {
Box::pin(async move {
$create(context).await;
})
}
}
}
};
}
#[derive(Clone, Debug, PartialEq)]
pub enum Payload {
Invocation(Invocation),
Complete(InvocationResult),
}
payload_convert!(Agent, Payload);