blob: 7e0f54e46fb657ac740156bf6987610bd3574f30 [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::base::{AgentError, Context, Invocation, InvocationResult, Lifespan};
/// The Restore Agent is responsible for signaling to all components to restore
/// external sources to the last known value. It is invoked during startup.
use crate::blueprint_definition;
use crate::internal::agent::Payload;
use crate::internal::event::{restore, Event, Publisher};
use crate::internal::switchboard;
use crate::message::base::{Audience, MessageEvent};
use crate::switchboard::base::{SettingRequest, SettingType, SwitchboardError};
use fuchsia_async as fasync;
use fuchsia_syslog::{fx_log_err, fx_log_info};
use futures::StreamExt;
use std::collections::HashSet;
blueprint_definition!(
crate::agent::base::Descriptor::Component("restore_agent"),
crate::agent::restore_agent::RestoreAgent::create
);
#[derive(Debug)]
pub struct RestoreAgent {
switchboard_messenger: switchboard::message::Messenger,
event_publisher: Publisher,
available_components: HashSet<SettingType>,
}
impl RestoreAgent {
async fn create(mut context: Context) {
let messenger = if let Ok(messenger) = context.create_switchboard_messenger().await {
messenger
} else {
context.get_publisher().send_event(Event::Custom(
"Could not acquire switchboard messenger in RestoreAgent",
));
return;
};
let mut agent = RestoreAgent {
switchboard_messenger: messenger,
event_publisher: context.get_publisher(),
available_components: context.available_components.clone(),
};
fasync::spawn(async move {
while let Some(event) = context.receptor.next().await {
if let MessageEvent::Message(Payload::Invocation(invocation), client) = event {
client.reply(Payload::Complete(agent.handle(invocation).await)).send().ack();
}
}
});
}
async fn handle(&mut self, invocation: Invocation) -> InvocationResult {
match invocation.lifespan {
Lifespan::Initialization => {
for component in self.available_components.clone() {
let mut receptor = self
.switchboard_messenger
.message(
switchboard::Payload::Action(switchboard::Action::Request(
component,
SettingRequest::Restore,
)),
Audience::Address(switchboard::Address::Switchboard),
)
.send();
if let switchboard::Payload::Action(switchboard::Action::Response(response)) =
receptor.next_payload().await.map_err(|_| AgentError::UnexpectedError)?.0
{
match response {
Ok(_) => {
continue;
}
Err(SwitchboardError::UnimplementedRequest {
setting_type,
request: _,
}) => {
self.event_publisher
.send_event(Event::Restore(restore::Event::NoOp(setting_type)));
continue;
}
Err(SwitchboardError::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 {
return Err(AgentError::UnexpectedError);
}
}
}
_ => {
return Err(AgentError::UnhandledLifespan);
}
}
Ok(())
}
}