blob: 609d951d2da3b5d73cd2e3c0f37d3ee764dcd511 [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::{
capability::{CapabilityProvider, CapabilitySource},
model::{
component::{ComponentInstance, WeakComponentInstance},
error::ModelError,
hooks::{Event, EventPayload, EventType, Hook, HooksRegistration},
model::Model,
routing::service::CollectionServiceDirectoryProvider,
},
},
async_trait::async_trait,
cm_rust::CapabilityTypeName,
moniker::{AbsoluteMoniker, ExtendedMoniker},
routing::capability_source::{AggregateCapability, AggregateCapabilityProvider},
std::sync::{Arc, Weak},
};
/// Creates `CapabilityProvider`s for capabilities routed from collections.
#[derive(Clone)]
pub struct CollectionCapabilityHost {
model: Weak<Model>,
}
impl CollectionCapabilityHost {
pub fn new(model: Weak<Model>) -> Self {
Self { model }
}
pub fn hooks(self: &Arc<Self>) -> Vec<HooksRegistration> {
vec![HooksRegistration::new(
"CollectionCapabilityHost",
vec![EventType::CapabilityRouted],
Arc::downgrade(self) as Weak<dyn Hook>,
)]
}
async fn on_collection_capability_routed_async(
self: Arc<Self>,
source: WeakComponentInstance,
target_moniker: AbsoluteMoniker,
aggregate_capability_provider: Box<dyn AggregateCapabilityProvider<ComponentInstance>>,
capability: &AggregateCapability,
capability_provider: Option<Box<dyn CapabilityProvider>>,
) -> Result<Option<Box<dyn CapabilityProvider>>, ModelError> {
// If some other capability has already been installed, then there's nothing to do here.
if capability_provider.is_none() && capability.type_name() == CapabilityTypeName::Service {
let model = self.model.upgrade().ok_or(ModelError::ModelNotAvailable)?;
let target = WeakComponentInstance::new(&model.look_up(&target_moniker).await?);
Ok(Some(Box::new(
CollectionServiceDirectoryProvider::create(
target,
&source.upgrade()?,
aggregate_capability_provider,
)
.await?,
)))
} else {
Ok(capability_provider)
}
}
}
#[async_trait]
impl Hook for CollectionCapabilityHost {
async fn on(self: Arc<Self>, event: &Event) -> Result<(), ModelError> {
if let Ok(EventPayload::CapabilityRouted {
source:
CapabilitySource::Collection {
component,
capability,
capability_provider: aggregate_capability_provider,
..
},
capability_provider,
}) = &event.result
{
let target_moniker = match &event.target_moniker {
ExtendedMoniker::ComponentManager => {
Err(ModelError::UnexpectedComponentManagerMoniker)
}
ExtendedMoniker::ComponentInstance(moniker) => Ok(moniker),
}?;
let mut capability_provider = capability_provider.lock().await;
*capability_provider = self
.on_collection_capability_routed_async(
component.clone(),
target_moniker.clone(),
aggregate_capability_provider.clone_boxed(),
&capability,
capability_provider.take(),
)
.await?;
}
Ok(())
}
}