use crate::core::ribosome::host_fn::cascade_from_call_context;
use crate::core::ribosome::CallContext;
use crate::core::ribosome::HostFnAccess;
use crate::core::ribosome::RibosomeError;
use crate::core::ribosome::RibosomeT;
use futures::StreamExt;
use holochain_types::prelude::*;
use holochain_wasmer_host::prelude::*;
use std::sync::Arc;
use wasmer::RuntimeError;
#[cfg_attr(feature = "instrument", tracing::instrument(skip(_ribosome, call_context), fields(?call_context.zome, function = ?call_context.function_name)))]
pub fn get(
_ribosome: Arc<impl RibosomeT>,
call_context: Arc<CallContext>,
inputs: Vec<GetInput>,
) -> Result<Vec<Option<Record>>, RuntimeError> {
let num_requests = inputs.len();
tracing::debug!("Starting with {} requests.", num_requests);
match HostFnAccess::from(&call_context.host_context()) {
HostFnAccess {
read_workspace: Permission::Allow,
..
} => {
let results: Vec<Result<Option<Record>, _>> =
tokio_helper::block_forever_on(async move {
futures::stream::iter(inputs.into_iter().map(|input| async {
let GetInput {
any_dht_hash,
get_options,
} = input;
cascade_from_call_context(&call_context)
.dht_get(any_dht_hash, get_options)
.await
}))
.buffered(10)
.collect()
.await
});
let results: Result<Vec<_>, RuntimeError> = results
.into_iter()
.map(|result| match result {
Ok(v) => Ok(v),
Err(cascade_error) => {
Err(wasm_error!(WasmErrorInner::Host(cascade_error.to_string())).into())
}
})
.collect();
let results = results?;
tracing::debug!(
"Ending with {} out of {} results and {} total responses.",
results.iter().filter(|r| r.is_some()).count(),
num_requests,
results.len(),
);
Ok(results)
}
_ => Err(wasm_error!(WasmErrorInner::Host(
RibosomeError::HostFnPermissions(
call_context.zome.zome_name().clone(),
call_context.function_name().clone(),
"get".into(),
)
.to_string(),
))
.into()),
}
}
#[cfg(test)]
#[cfg(feature = "slow_tests")]
pub mod slow_tests {
use crate::sweettest::{SweetConductorBatch, SweetConductorConfig, SweetDnaFile};
use holo_hash::ActionHash;
use holochain_wasm_test_utils::TestWasm;
use holochain_zome_types::record::Record;
#[tokio::test(flavor = "multi_thread")]
async fn get_action_entry_local_only() {
holochain_trace::test_run();
let config = SweetConductorConfig::rendezvous(false).tune_network_config(|nc| {
nc.disable_publish = true;
nc.disable_gossip = true;
});
let mut conductors = SweetConductorBatch::from_config_rendezvous(2, config).await;
let (dna_file, _, _) = SweetDnaFile::unique_from_test_wasms(vec![TestWasm::Create]).await;
let apps = conductors.setup_app("test", &[dna_file]).await.unwrap();
let zome_alice = apps[0].cells()[0].zome(TestWasm::Create.coordinator_zome_name());
let entry_action_hash: ActionHash =
conductors[0].call(&zome_alice, "create_entry", ()).await;
let local_record_by_action_hash: Option<Record> = conductors[0]
.call(&zome_alice, "get_post", entry_action_hash.clone())
.await;
assert!(local_record_by_action_hash.is_some());
conductors.exchange_peer_info().await;
let zome_bob = apps[1].cells()[0].zome(TestWasm::Create.coordinator_zome_name());
let local_record_by_action_hash: Option<Record> = conductors[1]
.call(&zome_bob, "get_post", entry_action_hash)
.await;
assert!(local_record_by_action_hash.is_none());
let zome_bob = apps[1].cells()[0].zome(TestWasm::Create.coordinator_zome_name());
let local_record_by_entry_hash: Option<Record> =
conductors[1].call(&zome_bob, "get_entry", ()).await;
assert!(local_record_by_entry_hash.is_none());
}
}