use crate::Result;
use crate::core::config::{ExtractInput, ExtractInputKind, ExtractionConfig};
use crate::plugins::Plugin;
use crate::types::ExtractedDocument;
use crate::types::internal::InternalDocument;
use async_trait::async_trait;
use std::path::Path;
#[cfg(not(feature = "tokio-runtime"))]
use crate::XbergError;
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
pub trait DocumentExtractor: Plugin {
async fn extract(&self, input: ExtractInput, config: &ExtractionConfig) -> Result<ExtractedDocument>;
fn supported_mime_types(&self) -> &[&str];
fn priority(&self) -> i32 {
50
}
fn can_handle(&self, _path: &Path, _mime_type: &str) -> bool {
true
}
}
#[cfg_attr(alef, alef(skip))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
pub trait InternalDocumentExtractor: Plugin {
async fn extract_content(
&self,
content: &[u8],
mime_type: &str,
config: &ExtractionConfig,
) -> Result<InternalDocument>;
async fn extract_path(&self, path: &Path, mime_type: &str, config: &ExtractionConfig) -> Result<InternalDocument> {
#[cfg(feature = "tokio-runtime")]
{
use crate::core::io;
let bytes = io::open_file_bytes(path)?;
self.extract_content(&bytes, mime_type, config).await
}
#[cfg(not(feature = "tokio-runtime"))]
{
let _ = (path, mime_type, config);
Err(XbergError::Other(
"Path extraction requires the tokio-runtime feature".to_string(),
))
}
}
fn supported_mime_types(&self) -> &[&str];
fn priority(&self) -> i32 {
50
}
fn can_handle(&self, _path: &Path, _mime_type: &str) -> bool {
true
}
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl<T> DocumentExtractor for T
where
T: InternalDocumentExtractor + ?Sized,
{
async fn extract(&self, input: ExtractInput, config: &ExtractionConfig) -> Result<ExtractedDocument> {
let doc = match input.kind {
ExtractInputKind::Bytes => {
let bytes = input.bytes.ok_or_else(|| {
crate::XbergError::validation(
"document extractor input kind 'bytes' requires the 'bytes' field".to_string(),
)
})?;
let mime_type = input.mime_type.as_deref().unwrap_or("application/octet-stream");
InternalDocumentExtractor::extract_content(self, &bytes, mime_type, config).await?
}
ExtractInputKind::Uri => {
let uri = input.uri.ok_or_else(|| {
crate::XbergError::validation(
"document extractor input kind 'uri' requires the 'uri' field".to_string(),
)
})?;
let mime_type = input.mime_type.as_deref().unwrap_or("application/octet-stream");
InternalDocumentExtractor::extract_path(self, Path::new(&uri), mime_type, config).await?
}
};
Ok(crate::extraction::derive::derive_extraction_result(
doc,
config.include_document_structure,
config.output_format.clone(),
))
}
fn supported_mime_types(&self) -> &[&str] {
InternalDocumentExtractor::supported_mime_types(self)
}
fn priority(&self) -> i32 {
InternalDocumentExtractor::priority(self)
}
fn can_handle(&self, path: &Path, mime_type: &str) -> bool {
InternalDocumentExtractor::can_handle(self, path, mime_type)
}
}