blob: a907b3c575a8be89f260b49db7bba7d3a3ac23f5 [file] [log] [blame]
// Copyright 2020 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::agent::storage::device_storage::DeviceStorageAccess;
use crate::agent::Payload;
use crate::agent::{AgentError, Context, Invocation, InvocationResult, Lifespan};
use crate::base::SettingType;
use crate::blueprint_definition;
use crate::event::{restore, Event, Publisher};
use crate::handler::base::{Error, Payload as HandlerPayload, Request};
use crate::message::base::Audience;
use crate::policy::{Payload as PolicyPayload, PolicyType, Request as PolicyRequest};
use crate::service;
use fuchsia_async as fasync;
use fuchsia_syslog::{fx_log_err, fx_log_info};
use std::collections::HashSet;
blueprint_definition!("restore_agent", crate::agent::restore_agent::RestoreAgent::create);
/// The Restore Agent is responsible for signaling to all components to restore
/// external sources to the last known value. It is invoked during startup.
#[derive(Debug)]
pub(crate) struct RestoreAgent {
messenger: service::message::Messenger,
event_publisher: Publisher,
available_components: HashSet<SettingType>,
available_policies: HashSet<PolicyType>,
}
impl DeviceStorageAccess for RestoreAgent {
const STORAGE_KEYS: &'static [&'static str] = &[];
}
impl RestoreAgent {
async fn create(context: Context) {
let mut agent = RestoreAgent {
messenger: context.create_messenger().await.expect("should acquire messenger"),
event_publisher: context.get_publisher(),
available_components: context.available_components,
available_policies: context.available_policies,
};
let mut receptor = context.receptor;
fasync::Task::spawn(async move {
while let Ok((Payload::Invocation(invocation), client)) =
receptor.next_of::<Payload>().await
{
client.reply(Payload::Complete(agent.handle(invocation).await).into()).send().ack();
}
})
.detach();
}
async fn handle(&mut self, invocation: Invocation) -> InvocationResult {
match invocation.lifespan {
Lifespan::Initialization => {
for component in &self.available_components {
let mut receptor = self
.messenger
.message(
HandlerPayload::Request(Request::Restore).into(),
Audience::Address(service::Address::Handler(*component)),
)
.send();
let response = receptor
.next_of::<HandlerPayload>()
.await
.map_err(|e| {
fx_log_err!("Received error when getting payload: {:?}", e);
AgentError::UnexpectedError
})?
.0;
if let HandlerPayload::Response(response) = response {
match response {
Ok(_) => {
continue;
}
Err(Error::UnimplementedRequest(setting_type, _)) => {
self.event_publisher
.send_event(Event::Restore(restore::Event::NoOp(setting_type)));
continue;
}
Err(Error::UnhandledType(setting_type)) => {
fx_log_info!(
"setting not available for restore: {:?}",
setting_type
);
continue;
}
_ => {
fx_log_err!("error during restore for {:?}", component);
return Err(AgentError::UnexpectedError);
}
}
} else {
fx_log_err!("Error because of response: {:?}", response);
return Err(AgentError::UnexpectedError);
}
}
for policy in &self.available_policies {
let mut receptor = self
.messenger
.message(
PolicyPayload::Request(PolicyRequest::Restore).into(),
Audience::Address(service::Address::PolicyHandler(*policy)),
)
.send();
let response = receptor
.next_of::<PolicyPayload>()
.await
.map_err(|e| {
fx_log_err!("Received error while getting policy payload: {:?}", e);
AgentError::UnexpectedError
})?
.0;
if let PolicyPayload::Response(response) = response {
match response {
Ok(_) => {
continue;
}
_ => {
fx_log_err!("error during policy restore for {:?}", policy);
return Err(AgentError::UnexpectedError);
}
}
} else {
fx_log_err!("Error because of policy response: {:?}", response);
return Err(AgentError::UnexpectedError);
}
}
}
_ => {
return Err(AgentError::UnhandledLifespan);
}
}
Ok(())
}
}