initial commit
This commit is contained in:
commit
1e7f8bc24d
6 changed files with 2953 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
2835
Cargo.lock
generated
Normal file
2835
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
16
Cargo.toml
Normal file
16
Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "kdl"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.102"
|
||||
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"
|
||||
tempfile = "3.26.0"
|
||||
tokio = { version = "1.49.0", features = ["fs", "rt", "tracing"] }
|
||||
tower-http = { version = "0.6.8", features = ["fs", "trace"] }
|
||||
tracing = "0.1.44"
|
||||
1
kindle.html
Normal file
1
kindle.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<body><div>Hello banana</div><div>It is 2026-02-26 16:33:19.778042362 UTC</div></body>
|
||||
BIN
kindle.png
Normal file
BIN
kindle.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 216 KiB |
100
src/main.rs
Normal file
100
src/main.rs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
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 std::io::{Cursor, Write};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppError(anyhow::Error);
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
(
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Something went wrong: {}", self.0),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
impl<E> From<E> for AppError
|
||||
where
|
||||
E: Into<anyhow::Error>,
|
||||
{
|
||||
fn from(err: E) -> Self {
|
||||
Self(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
async fn gen_png() -> Result<impl axum::response::IntoResponse, AppError> {
|
||||
let now = chrono::prelude::Utc::now().to_string();
|
||||
let markup = html! {
|
||||
body {
|
||||
div { "Hello banana" }
|
||||
div { (format!("It is {}", now)) }
|
||||
}
|
||||
};
|
||||
|
||||
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()?;
|
||||
let view = tab
|
||||
.navigate_to(&format!("file://{}", tempfile.path().to_string_lossy()))?
|
||||
.wait_for_element("body")?
|
||||
.get_box_model()?
|
||||
.margin_viewport();
|
||||
let png_data = tab.capture_screenshot(
|
||||
headless_chrome::protocol::cdp::Page::CaptureScreenshotFormatOption::Png,
|
||||
None,
|
||||
Some(view),
|
||||
true,
|
||||
)?;
|
||||
|
||||
let png = PngDecoder::new(Cursor::new(png_data))?;
|
||||
let color = DynamicImage::from_decoder(png)?;
|
||||
let gray = color.into_luma8();
|
||||
|
||||
let mut bytes = Vec::new();
|
||||
let png_encoder = PngEncoder::new(&mut bytes);
|
||||
gray.write_with_encoder(png_encoder)?;
|
||||
|
||||
Ok((
|
||||
axum::response::AppendHeaders([(axum::http::header::CONTENT_TYPE, "image/png")]),
|
||||
bytes,
|
||||
))
|
||||
}
|
||||
async fn serve(port: &u32) -> Result<(), AppError> {
|
||||
let app = Router::new()
|
||||
.route("/kindle.png", get(gen_png))
|
||||
//.nest_service("/kindle.png", gen_png()?)
|
||||
.layer(tower_http::trace::TraceLayer::new_for_http());
|
||||
|
||||
let listener = TcpListener::bind(format!("0.0.0.0:{}", port)).await?;
|
||||
println!("Starting axum on 0.0.0.0:{}...", port);
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> Result<(), AppError> {
|
||||
serve(&7777).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue