split webview and png render

This commit is contained in:
Robert Perce 2026-02-26 21:07:48 -06:00
parent 1e7f8bc24d
commit efc2605a4f
5 changed files with 34 additions and 23 deletions

2
Cargo.lock generated
View file

@ -1191,6 +1191,8 @@ version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8156733e27020ea5c684db5beac5d1d611e1272ab17901a49466294b84fc217e"
dependencies = [
"axum-core",
"http",
"itoa",
"maud_macros",
]

View file

@ -9,7 +9,7 @@ axum = { version = "0.8.8", features = ["macros"] }
chrono = "0.4.44"
headless_chrome = "1.0.21"
image = { version = "0.25.9", features = ["png"] }
maud = "0.27.0"
maud = { version = "0.27.0", features = ["axum"] }
tempfile = "3.26.0"
tokio = { version = "1.49.0", features = ["fs", "rt", "tracing"] }
tower-http = { version = "0.6.8", features = ["fs", "trace"] }

View file

@ -1 +0,0 @@
<body><div>Hello banana</div><div>It is 2026-02-26 16:33:19.778042362 UTC</div></body>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

View file

@ -1,9 +1,10 @@
use axum::extract::State;
use axum::Router;
use axum::response::{IntoResponse, Response};
use axum::routing::get;
use image::DynamicImage;
use image::codecs::png::{PngDecoder, PngEncoder};
use maud::html;
use maud::{Markup,html};
use std::io::{Cursor, Write};
use tokio::net::TcpListener;
@ -28,34 +29,38 @@ where
}
}
#[derive(Clone)]
struct AppState {
browser: Option<headless_chrome::Browser>,
}
#[axum::debug_handler]
async fn gen_png() -> Result<impl axum::response::IntoResponse, AppError> {
async fn dashboard() -> Result<Markup, AppError> {
let now = chrono::prelude::Utc::now().to_string();
let markup = html! {
body {
div { "Hello banana" }
div { (format!("It is {}", now)) }
style {
"body {
width: 600px;
height: 800px;
border: 1px solid black;
margin: auto;
}"
}
}
};
Ok(markup)
}
let mut tempfile = tempfile::Builder::new()
.suffix(".html")
.rand_bytes(5)
.tempfile()?;
tempfile
.write_all(markup.into_string().as_bytes())
.expect("unable to write");
tempfile.as_file().sync_all()?;
let launch = headless_chrome::browser::LaunchOptions::default_builder()
.window_size(Some((600, 939)))
.build()?;
let browser = headless_chrome::Browser::new(launch)?;
let tab = browser.new_tab()?;
async fn gen_png(State(state): State<AppState>) -> Result<impl axum::response::IntoResponse, AppError> {
if state.browser.is_none() {
return Err(AppError(anyhow::Error::msg("no headless chrome")));
}
let tab = state.browser.expect("chrome not available").new_tab()?;
let view = tab
.navigate_to(&format!("file://{}", tempfile.path().to_string_lossy()))?
.navigate_to("http://localhost:7777/")?
.wait_for_element("body")?
.get_box_model()?
.margin_viewport();
@ -80,10 +85,15 @@ async fn gen_png() -> Result<impl axum::response::IntoResponse, AppError> {
))
}
async fn serve(port: &u32) -> Result<(), AppError> {
let launch = headless_chrome::browser::LaunchOptions::default_builder()
.window_size(Some((600, 939)))
.build()?;
let browser = headless_chrome::Browser::new(launch).ok();
let app = Router::new()
.route("/", get(dashboard))
.route("/kindle.png", get(gen_png))
//.nest_service("/kindle.png", gen_png()?)
.layer(tower_http::trace::TraceLayer::new_for_http());
.with_state(AppState{browser});
let listener = TcpListener::bind(format!("0.0.0.0:{}", port)).await?;
println!("Starting axum on 0.0.0.0:{}...", port);