| // 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(()) |
| } |
| } |