use std::path::{Path, PathBuf};
use super::error::FetchError;
use crate::error::Result;
use super::{FetchResult, SchemaFetcher};
pub struct FileFetcher {
base_dir: Option<PathBuf>,
}
impl FileFetcher {
pub fn new() -> Self {
Self { base_dir: None }
}
pub fn with_base_dir(base_dir: impl AsRef<Path>) -> Self {
Self {
base_dir: Some(base_dir.as_ref().to_path_buf()),
}
}
pub fn base_dir(mut self, base_dir: impl AsRef<Path>) -> Self {
self.base_dir = Some(base_dir.as_ref().to_path_buf());
self
}
fn resolve_path(&self, url: &str) -> Option<PathBuf> {
if let Some(path) = url.strip_prefix("file://") {
return Some(PathBuf::from(path));
}
let path = Path::new(url);
if path.is_absolute() {
return Some(path.to_path_buf());
}
if let Some(ref base) = self.base_dir {
let resolved = base.join(url);
if resolved.exists() {
return Some(resolved);
}
}
if path.exists() {
return Some(path.to_path_buf());
}
None
}
}
impl Default for FileFetcher {
fn default() -> Self {
Self::new()
}
}
impl SchemaFetcher for FileFetcher {
fn fetch(&self, url: &str) -> Result<FetchResult> {
let path = self
.resolve_path(url)
.ok_or_else(|| FetchError::RequestFailed {
url: url.to_string(),
message: "Cannot resolve file path".to_string(),
})?;
let content = std::fs::read(&path).map_err(|e| FetchError::RequestFailed {
url: url.to_string(),
message: e.to_string(),
})?;
let final_url = format!("file://{}", path.display());
Ok(FetchResult {
content,
final_url,
redirected: false,
})
}
}