From dbd35db901dfe768d8542b3fcfcd3f302f0e728d Mon Sep 17 00:00:00 2001 From: Pedro Campelo Date: Wed, 8 Nov 2023 10:51:18 -0300 Subject: [PATCH 01/10] feature: added generate_pdf_from_html string alternative --- simple_pdf_generator/src/lib.rs | 167 ++++++++++++++++++++++++++++++-- 1 file changed, 159 insertions(+), 8 deletions(-) diff --git a/simple_pdf_generator/src/lib.rs b/simple_pdf_generator/src/lib.rs index cd18fe1..2162637 100644 --- a/simple_pdf_generator/src/lib.rs +++ b/simple_pdf_generator/src/lib.rs @@ -153,17 +153,11 @@ pub fn set_no_sandbox(val: bool) { NO_SANDBOX.store(val, Ordering::Relaxed); } -pub async fn generate_pdf( - template: Template, +pub async fn generate_pdf_from_html( + html: String, assets: &[Asset], print_options: &PrintOptions, ) -> Result, SimplePdfGeneratorError> { - let html = tokio::fs::read_to_string(template.html_path.clone()) - .await - .map_err(|e| { - SimplePdfGeneratorError::IoError(format!("Cannot read the html file: {}", e)) - })?; - let mut xpath_texts: Vec = Vec::new(); let html = TOKENS_AND_IMAGES_REGEX .replace_all(&html, |caps: ®ex::Captures| { @@ -310,6 +304,163 @@ pub async fn generate_pdf( .map_err(|e| SimplePdfGeneratorError::PdfError(format!("Cannot create the pdf: {}", e))) } +pub async fn generate_pdf( + template: Template, + assets: &[Asset], + print_options: &PrintOptions, +) -> Result, SimplePdfGeneratorError> { + let html = tokio::fs::read_to_string(template.html_path.clone()) + .await + .map_err(|e| { + SimplePdfGeneratorError::IoError(format!("Cannot read the html file: {}", e)) + })?; + + let mut xpath_texts: Vec = Vec::new(); + let html = TOKENS_AND_IMAGES_REGEX + .replace_all(&html, |caps: ®ex::Captures| { + let prop_name = caps.name("prop_name").map(|prop_name| prop_name.as_str()); + let img_src = caps.name("img_src").map(|img_src| img_src.as_str()); + let mut result = String::new(); + + if let Some(prop_name) = prop_name { + if let Some(property) = template.properties.get(prop_name) { + if property.is_none { + xpath_texts.push(format!("text() = '{}'", prop_name)); + result = prop_name.to_string(); + } else { + result = html_escape::encode_text(&property.val).to_string() + } + } + } else if let Some(img_src) = img_src { + if img_src.starts_with("data:image") { + result = img_src.to_string(); + } else { + let mime_type = mime_guess::from_path(img_src).first_raw(); + if let Some(mime_type) = mime_type { + let mut img_src_path = Path::new(img_src).to_owned(); + if img_src_path.is_relative() { + img_src_path = template + .html_path + .parent() + .unwrap_or_else(|| Path::new("")) + .join(img_src_path) + .canonicalize() + .unwrap_or_else(|_| PathBuf::new()); + } + + let img_data = fs::read(img_src_path).unwrap_or(Vec::new()); + let image_base64 = general_purpose::STANDARD.encode(img_data); + let new_src = format!("data:{};base64,{}", mime_type, image_base64); + + result = caps.get(0).unwrap().as_str().replace(img_src, &new_src); + } else { + result = img_src.to_string(); + } + } + } + + result + }) + .to_string(); + + let browser = get_browser().await; + let browser_instance = browser + .as_ref() + .ok_or(SimplePdfGeneratorError::BrowserError( + "Cannot create the browser".to_string(), + ))?; + let page = browser_instance + .browser + .new_page("about:blank") + .await + .map_err(|e| { + SimplePdfGeneratorError::BrowserError(format!("Cannot create the page: {}", e)) + })?; + page.set_content(html).await.map_err(|e| { + SimplePdfGeneratorError::BrowserError(format!("Cannot set the content: {}", e)) + })?; + + let mut asset_content_futures = Vec::new(); + for asset in assets { + asset_content_futures.push(tokio::fs::read_to_string(asset.path.clone())); + } + + let asset_contents = try_join_all(asset_content_futures) + .await + .map_err(|e| SimplePdfGeneratorError::IoError(format!("Cannot read the asset: {}", e)))?; + let mut inject_futures_css = Vec::new(); + let mut inject_futures_js = Vec::new(); + for (index, asset_content) in asset_contents.into_iter().enumerate() { + match assets[index].r#type { + AssetType::Style => { + inject_futures_css.push(inject_css(&page, asset_content)); + } + AssetType::Script => { + inject_futures_js.push(inject_js(&page, asset_content)); + } + } + } + try_join_all(inject_futures_css).await.map_err(|e| { + SimplePdfGeneratorError::BrowserError(format!("Cannot inject the css: {}", e)) + })?; + try_join_all(inject_futures_js).await.map_err(|e| { + SimplePdfGeneratorError::BrowserError(format!("Cannot inject the js: {}", e)) + })?; + + if !template.tables.is_empty() { + let table_generator_js: &'static str = include_str!("../assets/js/table-generator.js"); + + let mut tables_data = "tablesData = {".to_string(); + for (table_name, mut table_data) in template.tables { + if table_data.is_empty() { + table_data = "[]".to_string(); + xpath_texts.push(format!("@items = '{}'", table_name)); + } + + tables_data.push_str(&format!("{}:{},", table_name, table_data)); + } + tables_data.push('}'); + + let table_generator_js = + table_generator_js.replacen("tablesData", &html_escape::encode_text(&tables_data), 1); + _ = page.evaluate(table_generator_js).await.map_err(|e| { + SimplePdfGeneratorError::BrowserError(format!("Cannot evaluate the js: {}", e)) + })?; + } + + if !xpath_texts.is_empty() { + let xpath_expression = format!( + "//*[not(self::script or self::style or self::title) and ({})]", + xpath_texts.join(" or ") + ); + let js_script = format!( + " + () => {{ + const xpathExpression = `{}`; + const result = document.evaluate(xpathExpression, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); + + for (let i = 0; i < result.snapshotLength; i++) {{ + const targetElement = result.snapshotItem(i); + targetElement.style.display = 'none'; + }} + }} + ", + xpath_expression + ); + + _ = page.evaluate(js_script).await.map_err(|e| { + SimplePdfGeneratorError::BrowserError(format!( + "Cannot evaluate the xPath script: {}", + e + )) + })?; + } + + page.pdf(print_options.into()) + .await + .map_err(|e| SimplePdfGeneratorError::PdfError(format!("Cannot create the pdf: {}", e))) +} + async fn inject_js(page: &Page, js: String) -> Result { let script = format!( "() => {{ From 826c93c0061b1ea2a5a8d83886fd5112907431c9 Mon Sep 17 00:00:00 2001 From: Pedro Campelo Date: Wed, 8 Nov 2023 10:59:38 -0300 Subject: [PATCH 02/10] feature: added generate_pdf_from_html to derive package --- simple_pdf_generator_derive/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/simple_pdf_generator_derive/src/lib.rs b/simple_pdf_generator_derive/src/lib.rs index b213bb4..bf6f995 100644 --- a/simple_pdf_generator_derive/src/lib.rs +++ b/simple_pdf_generator_derive/src/lib.rs @@ -84,6 +84,16 @@ pub fn pdf_template_property(input: TokenStream) -> TokenStream { simple_pdf_generator::generate_pdf(template, assets, print_options).await } + + pub async fn generate_pdf_from_html(&self, + html_string: String, + assets: &[simple_pdf_generator::Asset], + print_options: &simple_pdf_generator::PrintOptions, + ) -> std::result::Result, simple_pdf_generator::SimplePdfGeneratorError> { + #(#inspect_struct_fields)* + + simple_pdf_generator::generate_pdf_from_html(html_string, assets, print_options).await + } } }; From 919549dc2d08e8fbf4dcb1ab914a88dc484c96fd Mon Sep 17 00:00:00 2001 From: Pedro Campelo Date: Wed, 8 Nov 2023 11:42:10 -0300 Subject: [PATCH 03/10] fix: removed template need in generate_pdf_from_html file --- simple_pdf_generator/src/lib.rs | 41 +------------------------- simple_pdf_generator_derive/src/lib.rs | 2 -- 2 files changed, 1 insertion(+), 42 deletions(-) diff --git a/simple_pdf_generator/src/lib.rs b/simple_pdf_generator/src/lib.rs index 2162637..fca46a9 100644 --- a/simple_pdf_generator/src/lib.rs +++ b/simple_pdf_generator/src/lib.rs @@ -165,31 +165,13 @@ pub async fn generate_pdf_from_html( let img_src = caps.name("img_src").map(|img_src| img_src.as_str()); let mut result = String::new(); - if let Some(prop_name) = prop_name { - if let Some(property) = template.properties.get(prop_name) { - if property.is_none { - xpath_texts.push(format!("text() = '{}'", prop_name)); - result = prop_name.to_string(); - } else { - result = html_escape::encode_text(&property.val).to_string() - } - } - } else if let Some(img_src) = img_src { + if let Some(img_src) = img_src { if img_src.starts_with("data:image") { result = img_src.to_string(); } else { let mime_type = mime_guess::from_path(img_src).first_raw(); if let Some(mime_type) = mime_type { let mut img_src_path = Path::new(img_src).to_owned(); - if img_src_path.is_relative() { - img_src_path = template - .html_path - .parent() - .unwrap_or_else(|| Path::new("")) - .join(img_src_path) - .canonicalize() - .unwrap_or_else(|_| PathBuf::new()); - } let img_data = fs::read(img_src_path).unwrap_or(Vec::new()); let image_base64 = general_purpose::STANDARD.encode(img_data); @@ -250,27 +232,6 @@ pub async fn generate_pdf_from_html( SimplePdfGeneratorError::BrowserError(format!("Cannot inject the js: {}", e)) })?; - if !template.tables.is_empty() { - let table_generator_js: &'static str = include_str!("../assets/js/table-generator.js"); - - let mut tables_data = "tablesData = {".to_string(); - for (table_name, mut table_data) in template.tables { - if table_data.is_empty() { - table_data = "[]".to_string(); - xpath_texts.push(format!("@items = '{}'", table_name)); - } - - tables_data.push_str(&format!("{}:{},", table_name, table_data)); - } - tables_data.push('}'); - - let table_generator_js = - table_generator_js.replacen("tablesData", &html_escape::encode_text(&tables_data), 1); - _ = page.evaluate(table_generator_js).await.map_err(|e| { - SimplePdfGeneratorError::BrowserError(format!("Cannot evaluate the js: {}", e)) - })?; - } - if !xpath_texts.is_empty() { let xpath_expression = format!( "//*[not(self::script or self::style or self::title) and ({})]", diff --git a/simple_pdf_generator_derive/src/lib.rs b/simple_pdf_generator_derive/src/lib.rs index bf6f995..d942b6b 100644 --- a/simple_pdf_generator_derive/src/lib.rs +++ b/simple_pdf_generator_derive/src/lib.rs @@ -90,8 +90,6 @@ pub fn pdf_template_property(input: TokenStream) -> TokenStream { assets: &[simple_pdf_generator::Asset], print_options: &simple_pdf_generator::PrintOptions, ) -> std::result::Result, simple_pdf_generator::SimplePdfGeneratorError> { - #(#inspect_struct_fields)* - simple_pdf_generator::generate_pdf_from_html(html_string, assets, print_options).await } } From 795eb0d2aad966916a4a4e0d6462ae5893c1fbd0 Mon Sep 17 00:00:00 2001 From: Pedro Campelo Date: Thu, 9 Nov 2023 18:42:24 -0300 Subject: [PATCH 04/10] fix: returned template validation due to template variables not being replaced --- simple_pdf_generator/Cargo.toml | 4 +-- simple_pdf_generator/src/lib.rs | 59 +++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/simple_pdf_generator/Cargo.toml b/simple_pdf_generator/Cargo.toml index f38c5d6..eb26160 100644 --- a/simple_pdf_generator/Cargo.toml +++ b/simple_pdf_generator/Cargo.toml @@ -13,9 +13,7 @@ repository = "https://github.com/Massimiliano-solutiontech/simple_pdf_generator" edition = "2021" [dependencies] -chromiumoxide = { version = "0.5.1", features = [ - "tokio-runtime", -], default-features = false } +chromiumoxide = { version = "0.5.1", features = ["tokio-runtime", "fetcher"], default-features = false } base64 = "0.21.3" futures = "0.3.28" html-escape = "0.2.13" diff --git a/simple_pdf_generator/src/lib.rs b/simple_pdf_generator/src/lib.rs index fca46a9..1c46223 100644 --- a/simple_pdf_generator/src/lib.rs +++ b/simple_pdf_generator/src/lib.rs @@ -158,6 +158,7 @@ pub async fn generate_pdf_from_html( assets: &[Asset], print_options: &PrintOptions, ) -> Result, SimplePdfGeneratorError> { + let template = Template::default(); let mut xpath_texts: Vec = Vec::new(); let html = TOKENS_AND_IMAGES_REGEX .replace_all(&html, |caps: ®ex::Captures| { @@ -165,28 +166,44 @@ pub async fn generate_pdf_from_html( let img_src = caps.name("img_src").map(|img_src| img_src.as_str()); let mut result = String::new(); - if let Some(img_src) = img_src { - if img_src.starts_with("data:image") { - result = img_src.to_string(); - } else { - let mime_type = mime_guess::from_path(img_src).first_raw(); - if let Some(mime_type) = mime_type { - let mut img_src_path = Path::new(img_src).to_owned(); - - let img_data = fs::read(img_src_path).unwrap_or(Vec::new()); - let image_base64 = general_purpose::STANDARD.encode(img_data); - let new_src = format!("data:{};base64,{}", mime_type, image_base64); - - result = caps.get(0).unwrap().as_str().replace(img_src, &new_src); - } else { - result = img_src.to_string(); - } - } - } + if let Some(prop_name) = prop_name { + if let Some(property) = template.properties.get(prop_name) { + if property.is_none { + xpath_texts.push(format!("text() = '{}'", prop_name)); + result = prop_name.to_string(); + } else { + result = html_escape::encode_text(&property.val).to_string() + } + } + } else if let Some(img_src) = img_src { + if img_src.starts_with("data:image") { + result = img_src.to_string(); + } else { + let mime_type = mime_guess::from_path(img_src).first_raw(); + if let Some(mime_type) = mime_type { + let mut img_src_path = Path::new(img_src).to_owned(); + if img_src_path.is_relative() { + img_src_path = template + .html_path + .parent() + .unwrap_or_else(|| Path::new("")) + .join(img_src_path) + .canonicalize() + .unwrap_or_else(|_| PathBuf::new()); + } - result - }) - .to_string(); + let img_data = fs::read(img_src_path).unwrap_or(Vec::new()); + let image_base64 = general_purpose::STANDARD.encode(img_data); + let new_src = format!("data:{};base64,{}", mime_type, image_base64); + result = caps.get(0).unwrap().as_str().replace(img_src, &new_src); + } else { + result = img_src.to_string(); + } + } + } + result + }) + .to_string(); let browser = get_browser().await; let browser_instance = browser From 870c7b1d887c5ee296875a5dfc37d98a15917f1c Mon Sep 17 00:00:00 2001 From: Pedro Campelo Date: Thu, 9 Nov 2023 19:19:49 -0300 Subject: [PATCH 05/10] feature: implemented new derivation to enable inspect_struct_fields macro in PdfTemplate --- simple_pdf_generator_derive/src/lib.rs | 109 ++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/simple_pdf_generator_derive/src/lib.rs b/simple_pdf_generator_derive/src/lib.rs index d942b6b..d61ca52 100644 --- a/simple_pdf_generator_derive/src/lib.rs +++ b/simple_pdf_generator_derive/src/lib.rs @@ -84,13 +84,120 @@ pub fn pdf_template_property(input: TokenStream) -> TokenStream { simple_pdf_generator::generate_pdf(template, assets, print_options).await } + } + }; + + let utility_methods = quote! { + fn stringify_object(obj: &T) -> String { + let mut result = String::new(); + + let serialized = serde_json::to_value(obj).unwrap(); + if let serde_json::Value::Object(map) = &serialized { + result.push('{'); + for (key, value) in map { + result.push_str(&format!("{}:{},", key, value)); + } + result.push('}'); + } else if let serde_json::Value::Array(array) = serialized { + result.push('['); + for value in array { + result.push_str(&format!("{},", value)); + } + result.push(']'); + } + + result + } + }; + + quote! { + #impl_methods + #utility_methods + } + .into() +} + +#[proc_macro_derive(PdfTemplateForHtml, attributes(PdfTableData))] +pub fn pdf_template_property_for_html_string(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let struct_name = &input.ident; + + let struct_fields = match input.data { + Data::Struct(ref data) => &data.fields, + _ => panic!("PdfTemplate can only be derived for structs"), + }; + + let inspect_struct_fields = struct_fields.iter().map(|field| { + let field_name = &field.ident; + let field_ty = &field.ty; + + let is_tabledata = field + .attrs + .iter() + .any(|attr| attr.path().is_ident("PdfTableData")); + + if is_tabledata { + quote! { + template.tables.insert( + stringify!(#field_name).to_string(), + stringify_object(&self.#field_name), + ); + } + } else { + let property = match field_ty { + syn::Type::Path(type_path) => { + let type_name = type_path.path.segments.first().unwrap().ident.to_string(); + if type_name == "Option" { + quote! { + simple_pdf_generator::Property { + val: match &self.#field_name { + std::option::Option::Some(value) => value.to_string(), + std::option::Option::None => String::new(), + }, + is_none: self.#field_name.is_none(), + is_tabledata: false, + } + } + } else { + quote! { + simple_pdf_generator::Property { + val: self.#field_name.to_string(), + is_none: false, + is_tabledata: false, + } + } + } + } + _ => quote! { + simple_pdf_generator::Property { + val: self.#field_name.to_string(), + is_none: false, + is_tabledata: false, + } + }, + }; + quote! { + template.properties.insert( + stringify!(#field_name).to_string(), + #property, + ); + } + } + }); + + let impl_methods = quote! { + impl #struct_name { pub async fn generate_pdf_from_html(&self, html_string: String, + attributes: assets: &[simple_pdf_generator::Asset], print_options: &simple_pdf_generator::PrintOptions, ) -> std::result::Result, simple_pdf_generator::SimplePdfGeneratorError> { - simple_pdf_generator::generate_pdf_from_html(html_string, assets, print_options).await + let mut template = simple_pdf_generator::Template::default(); + + #(#inspect_struct_fields)* + simple_pdf_generator::generate_pdf_from_html(html_string, template, assets, print_options).await } } }; From bdca22224d09a03692d41ee973a9ee3a420ee264 Mon Sep 17 00:00:00 2001 From: Pedro Campelo Date: Thu, 9 Nov 2023 19:27:16 -0300 Subject: [PATCH 06/10] fix: made small alterations to derive --- README.md | 2 +- simple_pdf_generator_derive/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 920a0b0..242bfe9 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Simple PDF Generator: ## Quick Start -In order to have a template you must create struct with `PdfTemplate` derive: +In order to have a template you must create struct with `PdfTemplate` or `PdfTemplateForHtml` derive: ```rust use simple_pdf_generator::{Asset, AssetType}; diff --git a/simple_pdf_generator_derive/src/lib.rs b/simple_pdf_generator_derive/src/lib.rs index d61ca52..0111ccc 100644 --- a/simple_pdf_generator_derive/src/lib.rs +++ b/simple_pdf_generator_derive/src/lib.rs @@ -124,7 +124,7 @@ pub fn pdf_template_property_for_html_string(input: TokenStream) -> TokenStream let struct_fields = match input.data { Data::Struct(ref data) => &data.fields, - _ => panic!("PdfTemplate can only be derived for structs"), + _ => panic!("PdfTemplateForHtml can only be derived for structs"), }; let inspect_struct_fields = struct_fields.iter().map(|field| { From 2bcace16e5286225ce32cdafa0bebb7642923f7e Mon Sep 17 00:00:00 2001 From: Pedro Campelo Date: Fri, 10 Nov 2023 10:15:27 -0300 Subject: [PATCH 07/10] fix: corrected derive macro for PdfTemplateForHtml --- simple_pdf_generator/src/lib.rs | 2 +- simple_pdf_generator_derive/src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/simple_pdf_generator/src/lib.rs b/simple_pdf_generator/src/lib.rs index 1c46223..33181ce 100644 --- a/simple_pdf_generator/src/lib.rs +++ b/simple_pdf_generator/src/lib.rs @@ -155,10 +155,10 @@ pub fn set_no_sandbox(val: bool) { pub async fn generate_pdf_from_html( html: String, + template: Template, assets: &[Asset], print_options: &PrintOptions, ) -> Result, SimplePdfGeneratorError> { - let template = Template::default(); let mut xpath_texts: Vec = Vec::new(); let html = TOKENS_AND_IMAGES_REGEX .replace_all(&html, |caps: ®ex::Captures| { diff --git a/simple_pdf_generator_derive/src/lib.rs b/simple_pdf_generator_derive/src/lib.rs index 0111ccc..4b85af0 100644 --- a/simple_pdf_generator_derive/src/lib.rs +++ b/simple_pdf_generator_derive/src/lib.rs @@ -190,7 +190,6 @@ pub fn pdf_template_property_for_html_string(input: TokenStream) -> TokenStream impl #struct_name { pub async fn generate_pdf_from_html(&self, html_string: String, - attributes: assets: &[simple_pdf_generator::Asset], print_options: &simple_pdf_generator::PrintOptions, ) -> std::result::Result, simple_pdf_generator::SimplePdfGeneratorError> { From 937b3fc5b5fbaaabd8072dc3a22b79f94bd64ca3 Mon Sep 17 00:00:00 2001 From: Pedro Campelo Date: Mon, 13 Nov 2023 20:52:37 -0300 Subject: [PATCH 08/10] feature: removed option for seting --no-sandbox in ChromiumInstance that was not being used, now all browsers are disabling sandbox for performance --- simple_pdf_generator/src/lib.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/simple_pdf_generator/src/lib.rs b/simple_pdf_generator/src/lib.rs index 33181ce..0ab77ad 100644 --- a/simple_pdf_generator/src/lib.rs +++ b/simple_pdf_generator/src/lib.rs @@ -114,13 +114,11 @@ struct ChromiumInstance { impl ChromiumInstance { async fn new() -> Self { - let options = BrowserConfig::builder(); - let options = if NO_SANDBOX.load(Ordering::Relaxed) { - options.no_sandbox() - } else { - options - }; - let options = options.build().expect("Invalid browser options."); + let options = + BrowserConfig::builder() + .no_sandbox() + .build() + .expect("Invalid browser options."); let (browser, mut handler) = Browser::launch(options) .await @@ -147,11 +145,7 @@ static BROWSER: Lazy>> = Lazy::new(|| RwLock::ne static TOKENS_AND_IMAGES_REGEX: Lazy = Lazy::new(|| { Regex::new(r#"(?:%%(?P.*)%%)|(?:]*\ssrc="(?P.*?)"[^>]*>)"#).unwrap() }); -static NO_SANDBOX: AtomicBool = AtomicBool::new(false); -pub fn set_no_sandbox(val: bool) { - NO_SANDBOX.store(val, Ordering::Relaxed); -} pub async fn generate_pdf_from_html( html: String, From 3caf785ece3bfc3f5464dbb84f7b9f813da0e732 Mon Sep 17 00:00:00 2001 From: Pedro Campelo Date: Mon, 13 Nov 2023 20:54:18 -0300 Subject: [PATCH 09/10] fix: removed unused dependency in lib.rs --- simple_pdf_generator/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/simple_pdf_generator/src/lib.rs b/simple_pdf_generator/src/lib.rs index 0ab77ad..aa6a798 100644 --- a/simple_pdf_generator/src/lib.rs +++ b/simple_pdf_generator/src/lib.rs @@ -2,7 +2,6 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::fs; use std::path::{Path, PathBuf}; -use std::sync::atomic::{AtomicBool, Ordering}; use base64::engine::general_purpose; use base64::Engine; From af657797f6ecf1ba8f3ac1e62e1327b161b76ab8 Mon Sep 17 00:00:00 2001 From: Pedro Campelo Date: Tue, 26 Dec 2023 19:51:11 -0300 Subject: [PATCH 10/10] fix: altered requests by @max --- simple_pdf_generator/Cargo.toml | 2 +- simple_pdf_generator/src/lib.rs | 38 ++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/simple_pdf_generator/Cargo.toml b/simple_pdf_generator/Cargo.toml index eb26160..b580669 100644 --- a/simple_pdf_generator/Cargo.toml +++ b/simple_pdf_generator/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/Massimiliano-solutiontech/simple_pdf_generator" edition = "2021" [dependencies] -chromiumoxide = { version = "0.5.1", features = ["tokio-runtime", "fetcher"], default-features = false } +chromiumoxide = { version = "0.5.1", features = ["tokio-runtime"], default-features = false } base64 = "0.21.3" futures = "0.3.28" html-escape = "0.2.13" diff --git a/simple_pdf_generator/src/lib.rs b/simple_pdf_generator/src/lib.rs index aa6a798..9104fe7 100644 --- a/simple_pdf_generator/src/lib.rs +++ b/simple_pdf_generator/src/lib.rs @@ -113,11 +113,13 @@ struct ChromiumInstance { impl ChromiumInstance { async fn new() -> Self { - let options = - BrowserConfig::builder() - .no_sandbox() - .build() - .expect("Invalid browser options."); + let options = BrowserConfig::builder(); + let options = if NO_SANDBOX.load(Ordering::Relaxed) { + options.no_sandbox() + } else { + options + }; + let options = options.build().expect("Invalid browser options."); let (browser, mut handler) = Browser::launch(options) .await @@ -145,6 +147,11 @@ static TOKENS_AND_IMAGES_REGEX: Lazy = Lazy::new(|| { Regex::new(r#"(?:%%(?P.*)%%)|(?:]*\ssrc="(?P.*?)"[^>]*>)"#).unwrap() }); +static NO_SANDBOX: AtomicBool = AtomicBool::new(false); + +pub fn set_no_sandbox(val: bool) { + NO_SANDBOX.store(val, Ordering::Relaxed); +} pub async fn generate_pdf_from_html( html: String, @@ -242,6 +249,27 @@ pub async fn generate_pdf_from_html( SimplePdfGeneratorError::BrowserError(format!("Cannot inject the js: {}", e)) })?; + if !template.tables.is_empty() { + let table_generator_js: &'static str = include_str!("../assets/js/table-generator.js"); + + let mut tables_data = "tablesData = {".to_string(); + for (table_name, mut table_data) in template.tables { + if table_data.is_empty() { + table_data = "[]".to_string(); + xpath_texts.push(format!("@items = '{}'", table_name)); + } + + tables_data.push_str(&format!("{}:{},", table_name, table_data)); + } + tables_data.push('}'); + + let table_generator_js = + table_generator_js.replacen("tablesData", &html_escape::encode_text(&tables_data), 1); + _ = page.evaluate(table_generator_js).await.map_err(|e| { + SimplePdfGeneratorError::BrowserError(format!("Cannot evaluate the js: {}", e)) + })?; + } + if !xpath_texts.is_empty() { let xpath_expression = format!( "//*[not(self::script or self::style or self::title) and ({})]",