use axum::extract::Multipart; use axum::http::StatusCode; use axum::response::IntoResponse; use axum::{extract::State, response::Response, routing::post, Router}; use image::ImageReader; use std::io::Cursor; use crate::display::EInkPanel; use std::sync::{Arc, Mutex}; pub enum ImageFormFields { DitherType, ImageFile, } #[derive(Clone)] pub struct Context { display: Arc>>, } impl Context { #[must_use] pub fn new(w: Box) -> Self { Self { display: Arc::new(Mutex::new(w)), } } } // Make our own error that wraps `anyhow::Error`. struct AppError(anyhow::Error); // Tell axum how to convert `AppError` into a response. impl IntoResponse for AppError { fn into_response(self) -> Response { ( StatusCode::INTERNAL_SERVER_ERROR, format!("Something went wrong: {}", self.0), ) .into_response() } } // This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into // `Result<_, AppError>`. That way you don't need to do that manually. impl From for AppError where E: Into, { fn from(err: E) -> Self { Self(err.into()) } } /// API routes for axum /// Start with the basics: Send an image, crop it, dither, and upload. /// we defer the upload to a separate task. pub fn router() -> Router { Router::new().route("/setimage", post(set_image)) } async fn set_image( State(ctx): State, mut parts: Multipart, ) -> Result { while let Some(field) = parts.next_field().await? { let name = field.name().expect("fields always have names").to_string(); let data = field.bytes().await?; println!("Length of `{}` is {} bytes", name, data.len()); if &name == "image" { let reader = ImageReader::new(Cursor::new(data)) .with_guessed_format() .expect("Cursor io never fails"); println!("Guessed format: {:?}", reader.format()); let _image = reader.decode()?; } } Ok(()) }