diff --git a/src/main.rs b/src/main.rs index fcfb6fd..7a06180 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,39 +1,14 @@ use std::net::SocketAddr; -use std::time::SystemTime; -use axum::{http::StatusCode, response::IntoResponse, Router, routing::get}; -use axum::body::Full; -use axum::extract::{Path}; -use axum::http::{header}; -use axum::response::Response; +use axum::{Router, routing::get}; use dotenvy::dotenv; -use lazy_static::lazy_static; -use tera::{Context, Tera}; -use timeago::Formatter; - use config::Configuration; +use crate::routes::root_handler; mod config; - mod svg; mod abbr; - -lazy_static! { - pub static ref TEMPLATES: Tera = { - let mut _tera = match Tera::new("templates/**/*.svg") { - Ok(t) => { - let names: Vec<&str> = t.get_template_names().collect(); - println!("{} templates found ([{}]).", names.len(), names.join(", ")); - t - }, - Err(e) => { - println!("Parsing error(s): {}", e); - ::std::process::exit(1); - } - }; - _tera - }; -} +mod routes; #[tokio::main] @@ -50,97 +25,11 @@ async fn main() { .with_max_level(config.log_level()) .init(); - let app = Router::new().route("/:path", get(root_handler)); + let app = Router::new() + .route("/:path", get(root_handler)); let addr = SocketAddr::from((config.socket_addr(), config.port)); axum::Server::bind(&addr) .serve(app.into_make_service_with_connect_info::()) .await .unwrap(); -} - -fn convert_epoch(epoch: u64) -> SystemTime { - SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(epoch) -} - -fn parse_path(path: String) -> Result<(SystemTime, String), String> { - if path.contains(".") { - let split_path = path.split_once(".").unwrap(); - let epoch_int = split_path.0.parse::(); - if epoch_int.is_err() { - return Err("Epoch is not a valid integer.".to_string()); - } - - return Ok((convert_epoch(epoch_int.unwrap()), split_path.1.parse().unwrap())); - } - - let epoch_int = path.parse::(); - if epoch_int.is_err() { - return Err("Epoch is not a valid integer.".to_string()); - } - - Ok( - (convert_epoch(epoch_int.unwrap()), String::from("svg")) - ) -} - -// basic handler that responds with a static string -async fn root_handler(Path(path): Path) -> impl IntoResponse { - let renderer = svg::Renderer::new(); - let mut context = Context::new(); - let f = Formatter::new(); - - let parse_result = parse_path(path); - if parse_result.is_err() { - return Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Full::from(parse_result.err().unwrap())) - .unwrap(); - } - let (epoch, extension) = parse_result.unwrap(); - - context.insert("text", &f.convert(epoch.elapsed().ok().unwrap())); - context.insert("width", "512"); - context.insert("height", "34"); - - let data = TEMPLATES.render("basic.svg", &context); - if data.is_err() { - return Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Full::from( - format!("Template Could Not Be Rendered :: {}", data.err().unwrap()) - )) - .unwrap(); - } - - match extension.as_str() { - "svg" => { - Response::builder() - .header(header::CONTENT_TYPE, "image/svg+xml") - .body(Full::from(data.unwrap())) - .unwrap() - } - "png" => { - let raw_image = renderer.render(data.unwrap().into_bytes()); - if raw_image.is_err() { - return Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Full::from( - format!("Internal Server Error :: {}", raw_image.err().unwrap()) - )) - .unwrap(); - } - - Response::builder() - .status(StatusCode::OK) - .header(header::CONTENT_TYPE, "image/x-png") - .body(Full::from(raw_image.unwrap())) - .unwrap() - } - _ => { - Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Full::from("Unsupported extension.")) - .unwrap() - } - } } \ No newline at end of file diff --git a/src/routes.rs b/src/routes.rs new file mode 100644 index 0000000..058922d --- /dev/null +++ b/src/routes.rs @@ -0,0 +1,116 @@ +use std::time::SystemTime; + +use axum::{http::StatusCode, response::IntoResponse}; +use axum::body::Full; +use axum::extract::{Path}; +use axum::http::{header}; +use axum::response::Response; +use lazy_static::lazy_static; +use tera::{Context, Tera}; +use timeago::Formatter; + +use crate::svg::Renderer; + +lazy_static! { + static ref TEMPLATES: Tera = { + let mut _tera = match Tera::new("templates/**/*.svg") { + Ok(t) => { + let names: Vec<&str> = t.get_template_names().collect(); + println!("{} templates found ([{}]).", names.len(), names.join(", ")); + t + }, + Err(e) => { + println!("Parsing error(s): {}", e); + ::std::process::exit(1); + } + }; + _tera + }; +} + +fn convert_epoch(epoch: u64) -> SystemTime { + SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(epoch) +} + +fn parse_path(path: String) -> Result<(SystemTime, String), String> { + if path.contains(".") { + let split_path = path.split_once(".").unwrap(); + let epoch_int = split_path.0.parse::(); + if epoch_int.is_err() { + return Err("Epoch is not a valid integer.".to_string()); + } + + return Ok((convert_epoch(epoch_int.unwrap()), split_path.1.parse().unwrap())); + } + + let epoch_int = path.parse::(); + if epoch_int.is_err() { + return Err("Epoch is not a valid integer.".to_string()); + } + + Ok( + (convert_epoch(epoch_int.unwrap()), String::from("svg")) + ) +} + +// basic handler that responds with a static string +pub async fn root_handler(Path(path): Path) -> impl IntoResponse { + let renderer = Renderer::new(); + let mut context = Context::new(); + let f = Formatter::new(); + + let parse_result = parse_path(path); + if parse_result.is_err() { + return Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Full::from(parse_result.err().unwrap())) + .unwrap(); + } + let (epoch, extension) = parse_result.unwrap(); + + context.insert("text", &f.convert(epoch.elapsed().ok().unwrap())); + context.insert("width", "512"); + context.insert("height", "34"); + + let data = TEMPLATES.render("basic.svg", &context); + if data.is_err() { + return Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(Full::from( + format!("Template Could Not Be Rendered :: {}", data.err().unwrap()) + )) + .unwrap(); + } + + match extension.as_str() { + "svg" => { + Response::builder() + .header(header::CONTENT_TYPE, "image/svg+xml") + .body(Full::from(data.unwrap())) + .unwrap() + } + "png" => { + let raw_image = renderer.render(data.unwrap().into_bytes()); + if raw_image.is_err() { + return Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(Full::from( + format!("Internal Server Error :: {}", raw_image.err().unwrap()) + )) + .unwrap(); + } + + Response::builder() + .status(StatusCode::OK) + .header(header::CONTENT_TYPE, "image/x-png") + .body(Full::from(raw_image.unwrap())) + .unwrap() + } + _ => { + Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Full::from("Unsupported extension.")) + .unwrap() + } + } +} \ No newline at end of file