use crate::core::ribosome::error::RibosomeError;
use crate::core::ribosome::host_fn::cascade_from_call_context;
use crate::core::ribosome::CallContext;
use crate::core::ribosome::HostFnAccess;
use crate::core::ribosome::RibosomeT;
use holochain_cascade::error::CascadeResult;
use holochain_types::prelude::*;
use holochain_wasmer_host::prelude::*;
use std::sync::Arc;
use wasmer::RuntimeError;
#[allow(clippy::extra_unused_lifetimes)]
pub fn delete_link<'a>(
_ribosome: Arc<impl RibosomeT>,
call_context: Arc<CallContext>,
input: DeleteLinkInput,
) -> Result<ActionHash, RuntimeError> {
match HostFnAccess::from(&call_context.host_context()) {
HostFnAccess {
write_workspace: Permission::Allow,
..
} => {
let DeleteLinkInput {
address,
chain_top_ordering,
get_options,
} = input;
let call_context_2 = call_context.clone();
let address_2 = address.clone();
let maybe_add_link: Option<SignedActionHashed> =
tokio_helper::block_forever_on(async move {
CascadeResult::Ok(
cascade_from_call_context(&call_context_2)
.dht_get(address_2.into(), get_options)
.await?
.map(|el| el.into_inner().0),
)
})
.map_err(|cascade_error| -> RuntimeError {
wasm_error!(WasmErrorInner::Host(cascade_error.to_string())).into()
})?;
let base_address = match maybe_add_link {
Some(add_link_signed_action_hash) => {
match add_link_signed_action_hash.action() {
Action::CreateLink(link_add_action) => {
Ok(link_add_action.base_address.clone())
}
_ => Err(RibosomeError::RecordDeps(address.clone().into())),
}
}
None => Err(RibosomeError::RecordDeps(address.clone().into())),
}
.map_err(|ribosome_error| -> RuntimeError {
wasm_error!(WasmErrorInner::Host(ribosome_error.to_string())).into()
})?;
let source_chain = call_context
.host_context
.workspace_write()
.source_chain()
.as_ref()
.expect("Must have source chain if write_workspace access is given");
tokio_helper::block_forever_on(async move {
let action_builder = builder::DeleteLink {
link_add_address: address,
base_address,
};
let action_hash = source_chain
.put(action_builder, None, chain_top_ordering)
.await
.map_err(|source_chain_error| -> RuntimeError {
wasm_error!(WasmErrorInner::Host(source_chain_error.to_string())).into()
})?;
Ok(action_hash)
})
}
_ => Err(wasm_error!(WasmErrorInner::Host(
RibosomeError::HostFnPermissions(
call_context.zome.zome_name().clone(),
call_context.function_name().clone(),
"delete_link".into(),
)
.to_string(),
))
.into()),
}
}
#[cfg(test)]
#[cfg(feature = "slow_tests")]
pub mod slow_tests {
use crate::test_utils::RibosomeTestFixture;
use hdk::prelude::*;
use holo_hash::ActionHash;
use holochain_wasm_test_utils::TestWasm;
#[tokio::test(flavor = "multi_thread")]
async fn ribosome_delete_link_add_remove() {
holochain_trace::test_run();
let RibosomeTestFixture {
conductor, alice, ..
} = RibosomeTestFixture::new(TestWasm::Link).await;
let links: Vec<Vec<Link>> = conductor.call(&alice, "get_links", ()).await;
assert!(links.is_empty());
let mut link_actions: Vec<ActionHash> = Vec::new();
for _ in 0..2 {
link_actions.push(conductor.call(&alice, "create_link", ()).await)
}
let links: Vec<Link> = conductor.call(&alice, "get_links", ()).await;
assert!(links.len() == 2);
let _: ActionHash = conductor
.call(&alice, "delete_link", link_actions[0].clone())
.await;
let links: Vec<Link> = conductor.call(&alice, "get_links", ()).await;
assert!(links.len() == 1);
let _: ActionHash = conductor
.call(&alice, "delete_link", link_actions[1].clone())
.await;
let links: Vec<Link> = conductor.call(&alice, "get_links", ()).await;
assert!(links.is_empty());
let _h: ActionHash = conductor.call(&alice, "create_link", ()).await;
let _h: ActionHash = conductor.call(&alice, "create_link", ()).await;
let links: Vec<Link> = conductor.call(&alice, "get_links", ()).await;
assert!(links.len() == 2);
let _: () = conductor.call(&alice, "delete_all_links", ()).await;
let links: Vec<Link> = conductor.call(&alice, "get_links", ()).await;
assert!(links.is_empty());
}
}