#[cfg(feature = "async-transport")]
pub mod async_transport_chirho;
#[cfg(feature = "async-transport")]
pub use async_transport_chirho::{
AsyncTransportChirho, AsyncTransportTraitChirho,
DownloadProgressChirho, ProgressCallbackChirho, CancellationTokenChirho,
};
use std::path::Path;
#[cfg(feature = "http-transport")]
use std::fs::File;
#[cfg(feature = "http-transport")]
use std::io::Write;
use crate::error_chirho::{ErrorChirho, ResultChirho};
pub trait TransportChirho {
fn download_chirho(&self, url_chirho: &str, dest_chirho: &Path) -> ResultChirho<()>;
fn fetch_chirho(&self, url_chirho: &str) -> ResultChirho<Vec<u8>>;
fn fetch_text_chirho(&self, url_chirho: &str) -> ResultChirho<String> {
let bytes_chirho = self.fetch_chirho(url_chirho)?;
String::from_utf8(bytes_chirho)
.map_err(|e_chirho| ErrorChirho::generic_chirho(format!("Invalid UTF-8: {}", e_chirho)))
}
fn is_accessible_chirho(&self, url_chirho: &str) -> bool;
}
#[cfg(feature = "http-transport")]
pub struct HttpTransportChirho {
client_chirho: reqwest::blocking::Client,
}
#[cfg(feature = "http-transport")]
impl HttpTransportChirho {
pub fn new_chirho() -> ResultChirho<Self> {
let client_chirho = reqwest::blocking::Client::builder()
.user_agent("rsword-chirho/0.1 (SWORD module library)")
.timeout(std::time::Duration::from_secs(60))
.build()
.map_err(|e_chirho| ErrorChirho::network_chirho(format!("Failed to create HTTP client: {}", e_chirho)))?;
Ok(Self { client_chirho })
}
}
#[cfg(feature = "http-transport")]
impl TransportChirho for HttpTransportChirho {
fn download_chirho(&self, url_chirho: &str, dest_chirho: &Path) -> ResultChirho<()> {
let response_chirho = self.client_chirho.get(url_chirho)
.send()
.map_err(|e_chirho| ErrorChirho::network_chirho(format!("Download failed: {}", e_chirho)))?;
if !response_chirho.status().is_success() {
return Err(ErrorChirho::network_chirho(format!(
"HTTP error: {}",
response_chirho.status()
)));
}
let bytes_chirho = response_chirho.bytes()
.map_err(|e_chirho| ErrorChirho::network_chirho(format!("Failed to read response: {}", e_chirho)))?;
if let Some(parent_chirho) = dest_chirho.parent() {
std::fs::create_dir_all(parent_chirho)?;
}
let mut file_chirho = File::create(dest_chirho)?;
file_chirho.write_all(&bytes_chirho)?;
Ok(())
}
fn fetch_chirho(&self, url_chirho: &str) -> ResultChirho<Vec<u8>> {
let response_chirho = self.client_chirho.get(url_chirho)
.send()
.map_err(|e_chirho| ErrorChirho::network_chirho(format!("Fetch failed: {}", e_chirho)))?;
if !response_chirho.status().is_success() {
return Err(ErrorChirho::network_chirho(format!(
"HTTP error: {}",
response_chirho.status()
)));
}
response_chirho.bytes()
.map(|b_chirho| b_chirho.to_vec())
.map_err(|e_chirho| ErrorChirho::network_chirho(format!("Failed to read response: {}", e_chirho)))
}
fn is_accessible_chirho(&self, url_chirho: &str) -> bool {
self.client_chirho.head(url_chirho)
.send()
.map(|r_chirho| r_chirho.status().is_success())
.unwrap_or(false)
}
}
#[cfg(not(feature = "http-transport"))]
pub struct HttpTransportChirho;
#[cfg(not(feature = "http-transport"))]
impl HttpTransportChirho {
pub fn new_chirho() -> Self {
Self
}
}
#[cfg(not(feature = "http-transport"))]
impl TransportChirho for HttpTransportChirho {
fn download_chirho(&self, _url_chirho: &str, _dest_chirho: &Path) -> ResultChirho<()> {
Err(ErrorChirho::network_chirho("HTTP transport not compiled (enable http-transport feature)"))
}
fn fetch_chirho(&self, _url_chirho: &str) -> ResultChirho<Vec<u8>> {
Err(ErrorChirho::network_chirho("HTTP transport not compiled (enable http-transport feature)"))
}
fn is_accessible_chirho(&self, _url_chirho: &str) -> bool {
false
}
}
#[cfg(feature = "native")]
pub struct UreqTransportChirho {
agent_chirho: ureq::Agent,
}
#[cfg(feature = "native")]
impl UreqTransportChirho {
pub fn new_chirho() -> Self {
let agent_chirho = ureq::Agent::new_with_defaults();
Self { agent_chirho }
}
}
#[cfg(feature = "native")]
impl TransportChirho for UreqTransportChirho {
fn download_chirho(&self, url_chirho: &str, dest_chirho: &Path) -> ResultChirho<()> {
if let Some(parent_chirho) = dest_chirho.parent() {
std::fs::create_dir_all(parent_chirho)?;
}
let response_chirho = self.agent_chirho.get(url_chirho)
.call()
.map_err(|e_chirho| ErrorChirho::network_chirho(format!("HTTP request failed: {}", e_chirho)))?;
let status_chirho = response_chirho.status().as_u16();
if !(200..300).contains(&status_chirho) {
return Err(ErrorChirho::network_chirho(format!("HTTP error: {}", status_chirho)));
}
let bytes_chirho = response_chirho.into_body()
.read_to_vec()
.map_err(|e_chirho| ErrorChirho::network_chirho(format!("Failed to read response: {}", e_chirho)))?;
std::fs::write(dest_chirho, &bytes_chirho)?;
Ok(())
}
fn fetch_chirho(&self, url_chirho: &str) -> ResultChirho<Vec<u8>> {
let response_chirho = self.agent_chirho.get(url_chirho)
.call()
.map_err(|e_chirho| ErrorChirho::network_chirho(format!("HTTP request failed: {}", e_chirho)))?;
let status_chirho = response_chirho.status().as_u16();
if !(200..300).contains(&status_chirho) {
return Err(ErrorChirho::network_chirho(format!("HTTP error: {}", status_chirho)));
}
let bytes_chirho = response_chirho.into_body()
.read_to_vec()
.map_err(|e_chirho| ErrorChirho::network_chirho(format!("Failed to read response: {}", e_chirho)))?;
Ok(bytes_chirho)
}
fn is_accessible_chirho(&self, url_chirho: &str) -> bool {
self.agent_chirho.head(url_chirho)
.call()
.map(|r_chirho| {
let status_chirho = r_chirho.status().as_u16();
(200..300).contains(&status_chirho)
})
.unwrap_or(false)
}
}
#[cfg(feature = "native")]
pub type SystemTransportChirho = UreqTransportChirho;
#[cfg(not(feature = "native"))]
pub struct StubTransportChirho;
#[cfg(not(feature = "native"))]
impl TransportChirho for StubTransportChirho {
fn download_chirho(&self, _url_chirho: &str, _dest_chirho: &Path) -> ResultChirho<()> {
Err(ErrorChirho::network_chirho("Network transport not available in WASM"))
}
fn fetch_chirho(&self, _url_chirho: &str) -> ResultChirho<Vec<u8>> {
Err(ErrorChirho::network_chirho("Network transport not available in WASM"))
}
fn is_accessible_chirho(&self, _url_chirho: &str) -> bool {
false
}
}
#[cfg(not(feature = "native"))]
pub type SystemTransportChirho = StubTransportChirho;
#[cfg(test)]
mod tests_chirho {
use super::*;
#[test]
#[cfg(feature = "native")]
fn test_system_transport_new_chirho() {
let _transport_chirho = SystemTransportChirho::new_chirho();
}
#[cfg(all(feature = "native", not(feature = "http-transport")))]
#[test]
fn test_http_transport_stub_chirho() {
let transport_chirho = HttpTransportChirho::new_chirho();
assert!(!transport_chirho.is_accessible_chirho("https://example.com"));
}
}