use crate::callback::{c_callback, with_libstorage_lock, CallbackFuture};
use crate::error::{Result, StorageError};
use crate::ffi::{storage_download_chunk, string_to_c_string};
use crate::node::lifecycle::StorageNode;
use std::sync::{Arc, Mutex};
pub async fn download_chunk(node: &StorageNode, cid: &str) -> Result<Vec<u8>> {
if cid.is_empty() {
return Err(StorageError::invalid_parameter(
"cid",
"CID cannot be empty",
));
}
let chunk_data = Arc::new(Mutex::new(Vec::<u8>::new()));
let chunk_data_clone = chunk_data.clone();
let future = CallbackFuture::new();
let context_ptr = future.context_ptr();
future.context.set_progress_callback(move |_len, chunk| {
if let Some(chunk_bytes) = chunk {
let mut data = chunk_data_clone.lock().unwrap();
data.clear();
data.extend_from_slice(chunk_bytes);
}
});
let result = with_libstorage_lock(|| unsafe {
let ctx = node.ctx();
let c_cid = string_to_c_string(cid);
storage_download_chunk(
ctx as *mut _,
c_cid.as_ptr(),
Some(c_callback),
context_ptr.as_ptr(),
)
});
if result != 0 {
return Err(StorageError::download_error("Failed to download chunk"));
}
future.await?;
let data = chunk_data.lock().unwrap().clone();
Ok(data)
}
pub async fn download_chunks(node: &StorageNode, cids: Vec<String>) -> Result<Vec<Vec<u8>>> {
let node = node.clone();
let futures: Vec<_> = cids
.into_iter()
.enumerate()
.map(|(index, cid)| {
let node = node.clone();
async move { download_chunk(&node, &cid).await.map_err(|e| (index, e)) }
})
.collect();
let results = futures::future::join_all(futures).await;
let mut chunks = Vec::with_capacity(results.len());
for result in results {
match result {
Ok(chunk) => chunks.push(chunk),
Err((index, e)) => {
return Err(StorageError::download_error(format!(
"Failed to download chunk {}: {}",
index, e
)));
}
}
}
Ok(chunks)
}
pub async fn download_chunk_with_progress<F>(
node: &StorageNode,
cid: &str,
progress_callback: F,
) -> Result<()>
where
F: Fn(&[u8]) + Send + Sync + 'static,
{
if cid.is_empty() {
return Err(StorageError::invalid_parameter(
"cid",
"CID cannot be empty",
));
}
let future = CallbackFuture::new();
let progress_callback_clone = Arc::new(progress_callback);
let context_ptr = future.context_ptr();
future.context.set_progress_callback(move |_len, chunk| {
if let Some(chunk_bytes) = chunk {
progress_callback_clone(chunk_bytes);
}
});
let result = with_libstorage_lock(|| unsafe {
let ctx = node.ctx();
let c_cid = string_to_c_string(cid);
storage_download_chunk(
ctx as *mut _,
c_cid.as_ptr(),
Some(c_callback),
context_ptr.as_ptr(),
)
});
if result != 0 {
return Err(StorageError::download_error("Failed to download chunk"));
}
future.await?;
Ok(())
}