use crate::{
constants::Format,
error::CarbonadoError,
stream::{
io::{
AsyncPipelineSink, AsyncPipelineSource, BoundedCopyTruncation, async_copy_all,
async_copy_bounded, async_reject_trailing,
},
spool::SeekableSpool,
stream_decode,
},
};
#[cfg(all(feature = "async", not(target_arch = "wasm32")))]
pub async fn stream_decode_async<R, W>(
master_key: &[u8],
hash: &[u8],
mut input: R,
padding: u32,
format: u8,
encoded_body_len: Option<u64>,
output: &mut W,
) -> Result<u64, CarbonadoError>
where
R: AsyncPipelineSource + Unpin,
W: AsyncPipelineSink + Unpin,
{
let fmt = Format::from(format);
let truncation = if fmt.contains(Format::Fec) && !fmt.contains(Format::Verification) {
BoundedCopyTruncation::FecBody
} else {
BoundedCopyTruncation::EncodedBody
};
let mut encoded_spool = SeekableSpool::new()?;
async_copy_bounded(&mut input, &mut encoded_spool, encoded_body_len, truncation).await?;
if let Some(declared) = encoded_body_len {
async_reject_trailing(&mut input, declared).await?;
}
encoded_spool.rewind()?;
let (nbytes, mut plaintext_spool) =
run_sync_stream_decode(master_key, hash, encoded_spool, padding, format).await?;
async_copy_all(&mut plaintext_spool, output).await?;
Ok(nbytes)
}
#[cfg(all(feature = "async", target_arch = "wasm32"))]
pub async fn stream_decode_async<R, W>(
_master_key: &[u8],
_hash: &[u8],
_input: R,
_padding: u32,
_format: u8,
_encoded_body_len: Option<u64>,
_output: &mut W,
) -> Result<u64, CarbonadoError>
where
R: AsyncPipelineSource + Unpin,
W: AsyncPipelineSink + Unpin,
{
Err(CarbonadoError::NotImplemented)
}
#[cfg(all(feature = "async", not(target_arch = "wasm32")))]
async fn run_sync_stream_decode(
master_key: &[u8],
hash: &[u8],
encoded_spool: SeekableSpool,
padding: u32,
format: u8,
) -> Result<(u64, SeekableSpool), CarbonadoError> {
#[cfg(feature = "async-tokio")]
{
let master_key: [u8; 32] = master_key
.try_into()
.map_err(|_| CarbonadoError::InvalidKeyLength)?;
let hash_len = hash.len();
let hash: [u8; 32] = hash
.try_into()
.map_err(|_| CarbonadoError::HashDecodeError(32, hash_len))?;
tokio::task::spawn_blocking(move || {
let mut plaintext_spool = SeekableSpool::new()?;
let nbytes = stream_decode(
&master_key,
&hash,
encoded_spool,
padding,
format,
None,
&mut plaintext_spool,
)?;
plaintext_spool.rewind()?;
Ok((nbytes, plaintext_spool))
})
.await
.map_err(|e| {
CarbonadoError::InternalStateError(format!("spawn_blocking join failed: {e}"))
})?
}
#[cfg(not(feature = "async-tokio"))]
{
let mut plaintext_spool = SeekableSpool::new()?;
let nbytes = stream_decode(
master_key,
hash,
encoded_spool,
padding,
format,
None,
&mut plaintext_spool,
)?;
plaintext_spool.rewind()?;
Ok((nbytes, plaintext_spool))
}
}