From 545e9bdabe19811210de5479e00e3eca0cef1c80 Mon Sep 17 00:00:00 2001 From: Compositr Date: Fri, 1 Nov 2024 22:51:12 +1100 Subject: [PATCH] feat: sending out svgs --- src/icons.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 40 +++++++++++++++++------------------ 2 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 src/icons.rs diff --git a/src/icons.rs b/src/icons.rs new file mode 100644 index 0000000..399bcea --- /dev/null +++ b/src/icons.rs @@ -0,0 +1,59 @@ +use std::{env, ffi::OsString, fs}; + +const ICON_FILE_EXTENSION: &'static str = ".svg"; +pub const ICON_FILE_EXTENSION_LEN: usize = ICON_FILE_EXTENSION.len(); + +pub struct Icons { + icons_dir_path: String, + icon_filenames: Vec, +} + +impl Icons { + /// Build the Icons (handler) struct + /// + /// Returns a result with the Icons struct or an error message + pub fn build() -> Result { + let icons_dir_arg = env::args() + .nth(1) + .unwrap_or(String::from("vendor/lucide/icons")); + + let icon_dir = match fs::read_dir(&icons_dir_arg) { + Ok(dir) => dir, + Err(_) => return Err("Failed to read icon directory"), + }; + + let icon_filenames: Vec<_> = icon_dir + .map(|entry| entry.unwrap().file_name()) + .filter(|entry| entry.to_str().unwrap_or("").ends_with(".svg")) + .collect(); + + Ok(Icons { + icons_dir_path: icons_dir_arg, + icon_filenames, + }) + } + + pub fn has_filename(&self, icon: &str) -> bool { + self.icon_filenames.contains(&OsString::from(icon)) + } + + pub fn has_iconname(&self, icon: &str) -> bool { + self.icon_filenames + .iter() + .find(|&i| match i.to_str() { + Some(i) => &i[..i.len() - ICON_FILE_EXTENSION_LEN] == icon, + None => false, + }) + .is_some() + } + + pub fn icons_len(&self) -> usize { + self.icon_filenames.len() + } + + pub fn get_icon(&self, icon: &str) -> Option> { + let icon_path = format!("{}/{}.svg", self.icons_dir_path, icon); + println!("Reading icon: {}", icon_path); + fs::read(icon_path).ok() + } +} diff --git a/src/main.rs b/src/main.rs index 44abac4..e09c37b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,29 +1,15 @@ -use std::{env, ffi::OsString, fs, net::TcpListener, process}; +use std::{ffi::OsString, fs, net::TcpListener, process}; use ctrlc; -use http::responses::{Response, Body}; +use http::responses::{Body, Response}; mod handlers; mod http; +mod icons; fn main() { println!("luciders starting..."); - let icons_dir_arg = env::args_os() - .nth(1) - .unwrap_or(OsString::from("vendor/lucide/icons")); - - println!("Using icons from: {:?}", icons_dir_arg); - - let icon_filenames: Vec<_> = fs::read_dir(icons_dir_arg) - .unwrap_or_else(|_| fatal("Failed to read icons directory! Does the path exist?")) - .map(|entry| entry.unwrap_or_else(|_| fatal("Failed to read icon entry"))) - .map(|entry| entry.file_name()) - .filter(|entry| entry.to_str().unwrap_or("").ends_with(".svg")) - .collect(); - - println!("Found {} icons", icon_filenames.len()); - let listener = TcpListener::bind("[::]:7878").unwrap_or_else(|_| fatal("Failed to bind to address")); @@ -33,6 +19,11 @@ fn main() { }) .unwrap_or_else(|_| fatal("Failed to set termination signal handler")); + let icons = match icons::Icons::build() { + Ok(icons) => icons, + Err(e) => fatal(e), + }; + let mut handlers = handlers::Handlers::new(); handlers.add_handler("/", |req| { @@ -43,21 +34,28 @@ fn main() { Response::new(req, 200, Body::Static("OK - luciders is running")) }); - handlers.add_handler("/icons/[icon].png", move |req| { + handlers.add_handler("/icons/[icon].svg", move |req| { if req.method != "GET" { return Response::new(req, 405, Body::Static("Method Not Allowed")); } - let icon_name = match req.url.get_path_segment(1) { + let icon_filename = match req.url.get_path_segment(1) { Some(icon) => icon, None => return Response::new(req, 404, Body::Static("Icon Not Found")), }; - if !icon_filenames.contains(&OsString::from(&icon_name[..icon_name.len() - 4])) { + let icon_name = &icon_filename[..icon_filename.len() - icons::ICON_FILE_EXTENSION_LEN]; + + if !icons.has_iconname(icon_name) { return Response::new(req, 404, Body::Static("Icon Not Found")); } - return Response::new(req, 200, Body::Static("Icon Not Found")); + let icon = match icons.get_icon(icon_name) { + Some(icon) => icon, + None => return Response::new(req, 500, Body::Static("Failed to read icon")), + }; + + return Response::new(req, 200, Body::Bytes(icon, "image/svg+xml")); }); handlers.bind(listener);