From 7de8132386600e4dcdc511092e71898261860b8d Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 29 Jul 2024 12:58:18 +1200 Subject: [PATCH] Implement fetching of local filesystem resources --- examples/markdown.rs | 20 +++++++++++--- packages/dom/src/util.rs | 57 +++++++++++++++++++++++++++++++++------- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/examples/markdown.rs b/examples/markdown.rs index 87c64294..b100705c 100644 --- a/examples/markdown.rs +++ b/examples/markdown.rs @@ -1,14 +1,26 @@ //! Render the readme.md using the gpu renderer +use std::path::Path; + use comrak::{markdown_to_html, ExtensionOptionsBuilder, Options, RenderOptionsBuilder}; use dioxus_blitz::Config; fn main() { - let contents = std::env::args() + let (base_url, contents) = std::env::args() .skip(1) .next() - .map(|path| std::fs::read_to_string(path).unwrap()) - .unwrap_or(include_str!("../README.md").to_string()); + .map(|path| { + let base_path = std::path::absolute(Path::new(&path)).unwrap(); + let base_path = base_path.parent().unwrap().to_string_lossy(); + let base_url = format!("file://{}/", base_path); + let contents = std::fs::read_to_string(path).unwrap(); + (base_url, contents) + }) + .unwrap_or({ + let base_url = "https://raw.githubusercontent.com/DioxusLabs/blitz/main/".to_string(); + let contents = include_str!("../README.md").to_string(); + (base_url, contents) + }); let stylesheet = include_str!("./assets/github-markdown-light.css"); let body_html = markdown_to_html( @@ -52,7 +64,7 @@ fn main() { &html, Config { stylesheets: vec![String::from(stylesheet)], - base_url: Some("https://raw.githubusercontent.com/DioxusLabs/blitz/main/".to_string()), + base_url: Some(base_url), }, ); } diff --git a/packages/dom/src/util.rs b/packages/dom/src/util.rs index 2e113520..60e87306 100644 --- a/packages/dom/src/util.rs +++ b/packages/dom/src/util.rs @@ -11,13 +11,42 @@ const FILE_SIZE_LIMIT: u64 = 1_000_000_000; // 1GB static FONT_DB: OnceLock> = OnceLock::new(); -pub(crate) fn fetch_blob(url: &str) -> Result, Box> { +pub(crate) enum FetchErr { + UrlParse(url::ParseError), + Ureq(Box), + FileIo(std::io::Error), +} +impl From for FetchErr { + fn from(value: url::ParseError) -> Self { + Self::UrlParse(value) + } +} +impl From> for FetchErr { + fn from(value: Box) -> Self { + Self::Ureq(value) + } +} +impl From for FetchErr { + fn from(value: std::io::Error) -> Self { + Self::FileIo(value) + } +} + +pub(crate) fn fetch_blob(url: &str) -> Result, FetchErr> { + // Handle data URIs if url.starts_with("data:") { let data_url = data_url::DataUrl::process(url).unwrap(); let decoded = data_url.decode_to_vec().expect("Invalid data url"); return Ok(decoded.0); } + // Handle file:// URLs + let parsed_url = Url::parse(url)?; + if parsed_url.scheme() == "file" { + let file_content = std::fs::read(parsed_url.path())?; + return Ok(file_content); + } + let resp = ureq::get(url) .set("User-Agent", USER_AGENT) .call() @@ -37,7 +66,7 @@ pub(crate) fn fetch_blob(url: &str) -> Result, Box> { Ok(bytes) } -pub(crate) fn fetch_string(url: &str) -> Result> { +pub(crate) fn fetch_string(url: &str) -> Result { fetch_blob(url).map(|vec| String::from_utf8(vec).expect("Invalid UTF8")) } @@ -55,23 +84,30 @@ pub(crate) enum ImageOrSvg { #[allow(unused)] pub(crate) enum ImageFetchErr { - FetchErr(Box), - ImageError(image::error::ImageError), - SvgError(usvg::Error), + UrlParse(url::ParseError), + Ureq(Box), + FileIo(std::io::Error), + ImageParse(image::error::ImageError), + SvgParse(usvg::Error), } -impl From> for ImageFetchErr { - fn from(value: Box) -> Self { - Self::FetchErr(value) + +impl From for ImageFetchErr { + fn from(value: FetchErr) -> Self { + match value { + FetchErr::UrlParse(err) => Self::UrlParse(err), + FetchErr::Ureq(err) => Self::Ureq(err), + FetchErr::FileIo(err) => Self::FileIo(err), + } } } impl From for ImageFetchErr { fn from(value: image::error::ImageError) -> Self { - Self::ImageError(value) + Self::ImageParse(value) } } impl From for ImageFetchErr { fn from(value: usvg::Error) -> Self { - Self::SvgError(value) + Self::SvgParse(value) } } @@ -172,6 +208,7 @@ pub fn walk_tree(indent: usize, node: &Node) { use peniko::Color as PenikoColor; use style::color::AbsoluteColor; +use url::Url; pub trait ToPenikoColor { fn as_peniko(&self) -> PenikoColor;