use super::error::ConductorApiError;
use super::error::ConductorApiResult;
use crate::conductor::error::ConductorResult;
use crate::conductor::ConductorHandle;
use crate::core::ribosome::guest_callback::post_commit::PostCommitArgs;
use crate::core::ribosome::real_ribosome::RealRibosome;
use crate::core::workflow::ZomeCallResult;
use async_trait::async_trait;
use holochain_keystore::MetaLairClient;
use holochain_p2p::HolochainP2pResult;
use holochain_state::conductor::WitnessNonceResult;
use holochain_state::host_fn_workspace::SourceChainWorkspace;
use holochain_types::prelude::*;
use holochain_zome_types::block::Block;
use holochain_zome_types::block::BlockTargetId;
use std::sync::Arc;
use tokio::sync::mpsc::error::SendError;
use tokio::sync::mpsc::OwnedPermit;
#[derive(Clone)]
pub struct CellConductorApi {
conductor_handle: ConductorHandle,
cell_id: CellId,
}
pub type CellConductorHandle = Arc<dyn CellConductorApiT + Send + 'static>;
pub type CellConductorReadHandle = Arc<dyn CellConductorReadHandleT + Send + 'static>;
impl CellConductorApi {
pub fn new(conductor_handle: ConductorHandle, cell_id: CellId) -> Self {
Self {
conductor_handle,
cell_id,
}
}
}
#[async_trait]
impl CellConductorApiT for CellConductorApi {
fn cell_id(&self) -> &CellId {
&self.cell_id
}
fn keystore(&self) -> &MetaLairClient {
self.conductor_handle.keystore()
}
fn get_dna_file(&self, cell_id: &CellId) -> Option<DnaFile> {
self.conductor_handle.get_dna_file(cell_id)
}
fn get_this_ribosome(&self) -> ConductorApiResult<RealRibosome> {
Ok(self.conductor_handle.get_ribosome(&self.cell_id)?)
}
#[cfg_attr(feature = "instrument", tracing::instrument(skip(self)))]
fn get_zome(&self, cell_id: &CellId, zome_name: &ZomeName) -> ConductorApiResult<Zome> {
let dna = self
.get_dna_file(cell_id)
.ok_or_else(|| ConductorApiError::CellMissing(cell_id.clone()))?;
Ok(dna.dna_def().get_zome(zome_name)?)
}
fn get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef> {
self.conductor_handle.get_entry_def(key)
}
fn into_call_zome_handle(self) -> CellConductorReadHandle {
Arc::new(self)
}
async fn post_commit_permit(&self) -> Result<OwnedPermit<PostCommitArgs>, SendError<()>> {
self.conductor_handle.post_commit_permit().await
}
}
#[async_trait]
#[cfg_attr(feature = "test_utils", mockall::automock)]
pub trait CellConductorApiT: Send + Sync {
fn cell_id(&self) -> &CellId;
fn keystore(&self) -> &MetaLairClient;
fn get_dna_file(&self, cell_id: &CellId) -> Option<DnaFile>;
fn get_this_ribosome(&self) -> ConductorApiResult<RealRibosome>;
fn get_zome(&self, cell_id: &CellId, zome_name: &ZomeName) -> ConductorApiResult<Zome>;
fn get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef>;
fn into_call_zome_handle(self) -> CellConductorReadHandle;
async fn post_commit_permit(&self) -> Result<OwnedPermit<PostCommitArgs>, SendError<()>>;
}
#[async_trait]
#[cfg_attr(feature = "test_utils", mockall::automock)]
pub trait CellConductorReadHandleT: Send + Sync {
fn cell_id(&self) -> &CellId;
async fn call_zome(&self, params: ZomeCallParams) -> ConductorApiResult<ZomeCallResult>;
async fn call_zome_with_workspace(
&self,
params: ZomeCallParams,
workspace_lock: SourceChainWorkspace,
) -> ConductorApiResult<ZomeCallResult>;
fn get_zome(&self, cell_id: &CellId, zome_name: &ZomeName) -> ConductorApiResult<Zome>;
fn get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef>;
async fn witness_nonce_from_calling_agent(
&self,
agent: AgentPubKey,
nonce: Nonce256Bits,
expires: Timestamp,
) -> ConductorApiResult<WitnessNonceResult>;
async fn find_cell_with_role_alongside_cell(
&self,
cell_id: &CellId,
role_name: &RoleName,
) -> ConductorResult<Option<CellId>>;
async fn block(&self, input: Block) -> HolochainP2pResult<()>;
async fn is_blocked(&self, input: BlockTargetId, timestamp: Timestamp)
-> ConductorResult<bool>;
async fn find_app_containing_cell(
&self,
cell_id: &CellId,
) -> ConductorResult<Option<InstalledApp>>;
async fn create_clone_cell(
&self,
installed_app_id: &InstalledAppId,
payload: CreateCloneCellPayload,
) -> ConductorResult<ClonedCell>;
async fn disable_clone_cell(
&self,
installed_app_id: &InstalledAppId,
payload: DisableCloneCellPayload,
) -> ConductorResult<()>;
async fn enable_clone_cell(
&self,
installed_app_id: &InstalledAppId,
payload: EnableCloneCellPayload,
) -> ConductorResult<ClonedCell>;
async fn delete_clone_cell(&self, payload: DeleteCloneCellPayload) -> ConductorResult<()>;
#[cfg(feature = "unstable-countersigning")]
async fn accept_countersigning_session(
&self,
cell_id: CellId,
request: PreflightRequest,
) -> ConductorResult<PreflightRequestAcceptance>;
}
#[async_trait]
impl CellConductorReadHandleT for CellConductorApi {
fn cell_id(&self) -> &CellId {
&self.cell_id
}
async fn call_zome(&self, params: ZomeCallParams) -> ConductorApiResult<ZomeCallResult> {
self.conductor_handle.call_zome(params).await
}
async fn call_zome_with_workspace(
&self,
params: ZomeCallParams,
workspace_lock: SourceChainWorkspace,
) -> ConductorApiResult<ZomeCallResult> {
if self.cell_id == params.cell_id {
self.conductor_handle
.call_zome_with_workspace(params, workspace_lock)
.await
} else {
self.conductor_handle.call_zome(params).await
}
}
fn get_zome(&self, cell_id: &CellId, zome_name: &ZomeName) -> ConductorApiResult<Zome> {
CellConductorApiT::get_zome(self, cell_id, zome_name)
}
fn get_entry_def(&self, key: &EntryDefBufferKey) -> Option<EntryDef> {
CellConductorApiT::get_entry_def(self, key)
}
async fn witness_nonce_from_calling_agent(
&self,
agent: AgentPubKey,
nonce: Nonce256Bits,
expires: Timestamp,
) -> ConductorApiResult<WitnessNonceResult> {
Ok(self
.conductor_handle
.witness_nonce_from_calling_agent(agent, nonce, expires)
.await?)
}
async fn find_cell_with_role_alongside_cell(
&self,
cell_id: &CellId,
role_name: &RoleName,
) -> ConductorResult<Option<CellId>> {
self.conductor_handle
.find_cell_with_role_alongside_cell(cell_id, role_name)
.await
}
async fn block(&self, input: Block) -> HolochainP2pResult<()> {
self.conductor_handle.holochain_p2p().block(input).await
}
async fn is_blocked(
&self,
input: BlockTargetId,
timestamp: Timestamp,
) -> ConductorResult<bool> {
self.conductor_handle.is_blocked(input, timestamp).await
}
async fn find_app_containing_cell(
&self,
cell_id: &CellId,
) -> ConductorResult<Option<InstalledApp>> {
self.conductor_handle
.find_app_containing_cell(cell_id)
.await
}
async fn create_clone_cell(
&self,
installed_app_id: &InstalledAppId,
payload: CreateCloneCellPayload,
) -> ConductorResult<ClonedCell> {
self.conductor_handle
.clone()
.create_clone_cell(installed_app_id, payload)
.await
}
async fn disable_clone_cell(
&self,
installed_app_id: &InstalledAppId,
payload: DisableCloneCellPayload,
) -> ConductorResult<()> {
self.conductor_handle
.clone()
.disable_clone_cell(installed_app_id, &payload)
.await
}
async fn enable_clone_cell(
&self,
installed_app_id: &InstalledAppId,
payload: EnableCloneCellPayload,
) -> ConductorResult<ClonedCell> {
self.conductor_handle
.clone()
.enable_clone_cell(installed_app_id, &payload)
.await
}
async fn delete_clone_cell(&self, payload: DeleteCloneCellPayload) -> ConductorResult<()> {
self.conductor_handle
.clone()
.delete_clone_cell(&payload)
.await
}
#[cfg(feature = "unstable-countersigning")]
async fn accept_countersigning_session(
&self,
cell_id: CellId,
request: PreflightRequest,
) -> ConductorResult<PreflightRequestAcceptance> {
self.conductor_handle
.accept_countersigning_session(cell_id, request)
.await
}
}