blob: 9d43fe31cd16885d753dc8c6f5090b6aacd19ffa [file] [log] [blame]
// Copyright 2021 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::model::{
actions::{Action, ActionKey},
component::instance::{InstanceState, UnresolvedInstanceState},
component::ComponentInstance,
error::{ActionError, DiscoverActionError},
hooks::{Event, EventPayload},
structured_dict::ComponentInput,
},
async_trait::async_trait,
std::sync::Arc,
};
/// Dispatches a `Discovered` event for a component instance. This action should be registered
/// when a component instance is created.
pub struct DiscoverAction {
/// A struct holding the capabilities made available to this component by its parent.
component_input: ComponentInput,
}
impl DiscoverAction {
pub fn new(component_input: ComponentInput) -> Self {
Self { component_input }
}
}
#[async_trait]
impl Action for DiscoverAction {
async fn handle(self, component: &Arc<ComponentInstance>) -> Result<(), ActionError> {
do_discover(component, self.component_input).await.map_err(Into::into)
}
fn key(&self) -> ActionKey {
ActionKey::Discover
}
}
async fn do_discover(
component: &Arc<ComponentInstance>,
component_input: ComponentInput,
) -> Result<(), DiscoverActionError> {
let is_discovered = {
let state = component.lock_state().await;
match *state {
InstanceState::New => false,
InstanceState::Unresolved(_)
| InstanceState::Resolved(_)
| InstanceState::Started(_, _)
| InstanceState::Shutdown(_, _) => true,
InstanceState::Destroyed => {
return Err(DiscoverActionError::InstanceDestroyed {
moniker: component.moniker.clone(),
});
}
}
};
if is_discovered {
return Ok(());
}
let event = Event::new(&component, EventPayload::Discovered);
component.hooks.dispatch(&event).await;
{
let mut state = component.lock_state().await;
assert!(
matches!(*state, InstanceState::New | InstanceState::Destroyed),
"Component in unexpected state after discover"
);
match *state {
InstanceState::Shutdown(_, _) | InstanceState::Destroyed => {
// Nothing to do.
}
InstanceState::Unresolved(_)
| InstanceState::Resolved(_)
| InstanceState::Started(_, _) => {
panic!(
"Component was marked {:?} during Discover action, which shouldn't be possible",
*state
);
}
InstanceState::New => {
state.set(InstanceState::Unresolved(UnresolvedInstanceState::new(component_input)));
}
}
}
Ok(())
}