From a814f60f320098079d333ec344c5d9e8c6854882 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Mon, 25 Aug 2025 18:42:54 -0300 Subject: [PATCH] feat: add stream_item_content method for async content streaming Co-authored-by: aider (openai/andrew/openrouter/qwen/qwen3-coder) --- src/services/async_item_service.rs | 51 ++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/services/async_item_service.rs b/src/services/async_item_service.rs index aec0fe5..4daa2a5 100644 --- a/src/services/async_item_service.rs +++ b/src/services/async_item_service.rs @@ -51,6 +51,57 @@ impl AsyncItemService { .unwrap() } + pub async fn stream_item_content( + &self, + item_id: i64, + allow_binary: bool, + offset: u64, + length: u64, + ) -> Result<(impl tokio_stream::Stream>, String), CoreError> { + let item_with_content = self.get_item_content(item_id).await?; + let metadata = item_with_content.item_with_meta.meta_as_map(); + + // Check if content is binary when allow_binary is false + if !allow_binary { + let is_content_binary = if let Some(binary_val) = metadata.get("binary") { + binary_val == "true" + } else { + // If binary metadata not available, check the actual content + is_binary(&item_with_content.content) + }; + + if is_content_binary { + return Err(CoreError::InvalidInput("Binary content not allowed".to_string())); + } + } + + let mime_type = metadata + .get("mime_type") + .map(|s| s.to_string()) + .unwrap_or_else(|| "application/octet-stream".to_string()); + + // Open the file for streaming + let file_path = self.data_path.join(format!("{}.dat", item_id)); + let file = tokio::fs::File::open(&file_path).await?; + let mut buffered_file = tokio::io::BufReader::new(file); + + // Seek to the requested offset if needed + if offset > 0 { + buffered_file.seek(std::io::SeekFrom::Start(offset)).await?; + } + + // Create a reader stream with optional length limit + let stream = if length > 0 { + // Limit the stream to the specified length + ReaderStream::new(buffered_file.take(length)) + } else { + // Stream the entire file from the offset + ReaderStream::new(buffered_file) + }; + + Ok((stream, mime_type)) + } + pub async fn find_item( &self, ids: Vec,