mirror of
https://github.com/Xevion/time-banner.git
synced 2025-12-15 06:13:31 -06:00
Switch to relative time, path parsing, SVG templating
This commit is contained in:
99
src/main.rs
99
src/main.rs
@@ -1,16 +1,18 @@
|
||||
mod config;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use axum::{http::StatusCode, response::IntoResponse, Router, routing::{get}};
|
||||
use axum::body::{Full};
|
||||
use axum::extract::ConnectInfo;
|
||||
use axum::extract::{ConnectInfo, Path};
|
||||
use axum::http::{header, HeaderMap};
|
||||
use axum::response::Response;
|
||||
use dotenvy::dotenv;
|
||||
use lazy_static::lazy_static;
|
||||
use config::Configuration;
|
||||
use tera::{Tera, Context};
|
||||
use timeago::Formatter;
|
||||
|
||||
mod svg;
|
||||
|
||||
@@ -46,7 +48,7 @@ async fn main() {
|
||||
.with_max_level(config.log_level())
|
||||
.init();
|
||||
|
||||
let app = Router::new().route("/", 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::<SocketAddr>())
|
||||
@@ -54,21 +56,51 @@ async fn main() {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// basic handler that responds with a static string
|
||||
async fn root_handler(connect_info: ConnectInfo<SocketAddr>, headers: HeaderMap) -> impl IntoResponse {
|
||||
let renderer = svg::Renderer::new();
|
||||
fn convert_epoch(epoch: u64) -> SystemTime {
|
||||
SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(epoch)
|
||||
}
|
||||
|
||||
let mut context = Context::new();
|
||||
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::<u64>();
|
||||
if epoch_int.is_err() {
|
||||
return Err("Epoch is not a valid integer.".to_string());
|
||||
}
|
||||
|
||||
let mut ip_repr: Option<String> = headers.get("X-Forwarded-For").and_then(|hv| Some(String::from(hv.to_str().unwrap())));
|
||||
if ip_repr.is_none() {
|
||||
let connect_ip = connect_info.ip().to_string();
|
||||
ip_repr = Some(connect_ip.to_string());
|
||||
return Ok((convert_epoch(epoch_int.unwrap()), split_path.1.parse().unwrap()));
|
||||
}
|
||||
|
||||
context.insert("text", &ip_repr.unwrap());
|
||||
let data = TEMPLATES.render("basic.svg", &context);
|
||||
let epoch_int = path.parse::<u64>();
|
||||
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<String>) -> 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)
|
||||
@@ -78,20 +110,35 @@ async fn root_handler(connect_info: ConnectInfo<SocketAddr>, headers: HeaderMap)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let raw_image = renderer.render(data.unwrap().into_bytes());
|
||||
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();
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
Response::builder()
|
||||
.status(StatusCode::OK)
|
||||
.header(header::CONTENT_TYPE, "image/x-png")
|
||||
.body(Full::from(raw_image.unwrap()))
|
||||
.unwrap()
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
<svg width="256" height="32" xmlns="http://www.w3.org/2000/svg" font-family="Arial" font-size="28">
|
||||
<text x="10" y="28">{{ text }}</text>
|
||||
<svg width="{{ width }}" height="{{ height }}" xmlns="http://www.w3.org/2000/svg" font-family="Roboto Mono" font-size="27">
|
||||
<text x="8" y="27">{{ text }}</text>
|
||||
<style>
|
||||
text
|
||||
</style>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 148 B After Width: | Height: | Size: 209 B |
Reference in New Issue
Block a user