#![feature(iter_intersperse)] use axum::{ extract::State, http::{ // header, StatusCode, Uri, }, response::{Html, IntoResponse}, routing::{get, get_service}, Json, Router, }; // use image::ImageFormat; // use mysql::prelude::*; use mysql::*; // use plotters::prelude::*; // use std::io::{BufWriter, Cursor}; use std::sync::Arc; mod math; mod my_structs; use my_structs::MyError; use my_structs::Purchase; mod plotting; // use crate::plotting::Plotter; use std::{thread, time}; use tower_http::services::ServeDir; use shared::structs::Nutrition; #[derive(Clone)] struct AppState { sql_pool: Pool, } fn get_sql_pool(url: &str) -> Pool { loop { let sql_pool_attempt = Pool::new(url); match sql_pool_attempt { Ok(sql_pool) => return sql_pool, Err(e) => { println!("Cannot connect to SQL database. Retrying. {:?}", e); thread::sleep(time::Duration::from_millis(1000)); } } } } #[tokio::main] async fn main() { //Initialize state let sql_pool = get_sql_pool("mysql://calories_user:I96xkFy0UFPbB0JCP6X6@db.knyffen.dk:3306/Food"); let shared_state = Arc::new(AppState { sql_pool }); // build our application with a single route let app = Router::new() .route("/get_rows", get(get_rows)) .route("/html_demo", get(html_demo)) .route("/html_plotter", get(html_plotter)) .route("/image.png", get(png_image)) .route("/image.svg", get(svg_image)) .route("/calorie_intake.svg", get(svg_calorie_intake)) .route("/calorie_intake", get(calorie_intake)) .route("/wasm_test", get(wasm_test)) .route("/camera_test", get(camera_test)) .route("/get_product_options", get(get_product_options)) .nest_service("/pkg", get_service(ServeDir::new("../browser/pkg"))) .nest_service("/css", get_service(ServeDir::new("../css"))) .nest_service("/js", get_service(ServeDir::new("../javascript"))) .with_state(shared_state) .fallback(not_found); // run our app with hyper, listening globally on port 3000 let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, app).await.unwrap(); } async fn not_found(uri: Uri) -> (StatusCode, String) { (StatusCode::NOT_FOUND, format!("404 not found: {uri}")) } async fn get_rows(State(state): State>) -> Result { let nutrition_val_promise = Nutrition::get_nutrition_hashmap(state.sql_pool.clone()); let purchases_val_promise = Purchase::get_purchase_rows(state.sql_pool.clone()); let nutrition_val = nutrition_val_promise.await?; let purchases_val = purchases_val_promise.await?; println!("Serving: get_rows"); // Ok("See print logs instead".to_string()) Ok(format!("{:#?} {:#?}", nutrition_val, purchases_val)) } #[axum::debug_handler] async fn get_product_options( State(state): State>, ) -> Result>, MyError> { println!("Serving: get_product_options"); let nutrition_val_promise = Nutrition::get_nutrition_rows(state.sql_pool.clone()); let nutrition_val = nutrition_val_promise.await?; Ok(Json(nutrition_val)) } async fn html_demo(State(_state): State>) -> Html { println!("Serving: html_demo"); Html("

This is HTML

".to_string()) } async fn svg_image(State(_state): State>) -> impl IntoResponse { println!("Serving: svg_image"); let fun = plotting::SVGPlotter::examplefun(); plotting::SVGPlotter::plot(640, 480, fun) } async fn svg_calorie_intake( State(state): State>, ) -> Result { println!("Serving: svg_calorie_intake"); let nutrition_val_promise = Nutrition::get_nutrition_hashmap(state.sql_pool.clone()); let purchases_val_promise = Purchase::get_purchase_rows(state.sql_pool.clone()); let nutrition_val = nutrition_val_promise.await?; let purchases_val = purchases_val_promise.await?; let plotfun = math::plot_calories_per_day(nutrition_val, purchases_val); Ok(plotting::SVGPlotter::plot(640, 480, plotfun)) } async fn png_image(State(_state): State>) -> impl IntoResponse { println!("Serving: png_image"); let fun = plotting::BitMapPlotter::examplefun(); plotting::BitMapPlotter::plot(640, 480, fun, plotting::BitMapOutputFormat::PNG) } async fn html_plotter(State(_state): State>) -> Html { println!("Serving: html_plotter"); Html("".to_string()) } async fn calorie_intake(State(_state): State>) -> Html { println!("Serving: calorie_intake"); Html("".to_string()) } fn construct_js(path: &str) -> Result { // let javascript = std::fs::read_to_string(format!("../javascript/{}", path))?; // let module = format!( // " // // ", // javascript // ); // Ok(module) Ok(format!( "", path )) } fn construct_css(path: &str) -> Result { Ok(format!("", path)) } fn construct_tmpl(path: &str) -> Result { Ok(std::fs::read_to_string(format!("../templates/{}", path))?) } fn construct_html( js_paths: Vec<&str>, css_paths: Vec<&str>, tmpl_paths: Vec<&str>, ) -> Result { let js_modules: Vec = js_paths .into_iter() .map(construct_js) .collect::, MyError>>()?; let css_styling: Vec = css_paths .into_iter() .map(construct_css) .collect::, MyError>>()?; let tmpl_snippets: Vec = tmpl_paths .into_iter() .map(construct_tmpl) .collect::, MyError>>()?; let html = format!( " {} {} {} ", js_modules.join(""), css_styling.join(""), tmpl_snippets.join("") ); Ok(html) } fn get_template(path: &str) -> Result { Ok(std::fs::read_to_string(format!("../templates/{}", path))?) } async fn wasm_test(State(_state): State>) -> Result, MyError> { println!("Serving: wasm_test"); let content = get_template("view_calories.html")?; Ok(Html(content)) } async fn camera_test(State(_state): State>) -> Result, MyError> { println!("Serving: camera_test"); let html = construct_html( vec!["camera.js"], vec!["camera_test.css"], vec!["camera_test.html"], )?; Ok(Html(html)) }