From ae00627e7c99fd21ce4ad8ec0692445f00a349b2 Mon Sep 17 00:00:00 2001 From: "Adam T. Carpenter" Date: Sat, 7 Sep 2024 21:18:54 -0400 Subject: feat: basic markdown post to html page loading --- src/main.rs | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/main.rs (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..43b6fa6 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,136 @@ +use axum::response::Html; +use axum::extract::State; +use std::sync::Arc; +use askama_axum::Template; +use axum::{routing::get, Router}; +use std::borrow::Cow; +use std::ffi::OsString; +use std::fmt; +use std::fs; +use std::io::*; +use std::path::Path; +use std::path::PathBuf; + +trait Post<'a>: fmt::Debug { + fn dump(&self); + fn display_name(&'a self) -> &'a str; + fn get_content(&self) -> Cow; +} + +#[derive(Debug)] +struct MockPost; + +impl<'a> Post<'a> for MockPost { + fn dump(&self) { + println!("Post content goes here."); + } + + fn display_name(&'a self) -> &'a str { + "" + } + + fn get_content(&self) -> Cow { + Cow::Borrowed("") + } +} + +struct MdFilePost { + path: PathBuf, + name: OsString, +} + +impl MdFilePost { + fn new(path: &Path) -> Self { + Self { + path: path.to_path_buf(), + name: path.file_stem().unwrap_or_default().to_owned(), + } + } +} + +impl<'a> Post<'a> for MdFilePost { + fn dump(&self) { + println!("{}: {}", &self.display_name(), &self.get_content()); + } + + fn display_name(&'a self) -> &'a str { + self.name.to_str().unwrap() + } + + fn get_content(&self) -> Cow { + let mut file = std::fs::File::open(&self.path).unwrap(); + let mut markdown = String::new(); + file.read_to_string(&mut markdown).unwrap(); + Cow::Owned(markdown) + } +} + +impl fmt::Debug for MdFilePost { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "MdFilePost '{}'", self.display_name()) + } +} + +trait Posts { + fn get_posts(&self) -> impl Iterator; +} + +struct FsDirPosts { + path: PathBuf, +} + +impl FsDirPosts { + fn new(path: &str) -> Self { + Self { + path: PathBuf::from(path), + } + } +} + +impl Posts for FsDirPosts { + fn get_posts(&self) -> impl Iterator { + let dirs = fs::read_dir(&self.path).unwrap(); + dirs.flatten().map(|d| MdFilePost::new(&d.path())) + } +} + +trait Page<'a>: Template { + fn from_post(post: &impl Post<'a>) -> Self; +} + +#[derive(Template)] +#[template(path = "post.html")] +struct MdPage { + article: String, +} + +impl<'a> Page<'a> for MdPage { + fn from_post(post: &impl Post<'a>) -> Self { + Self { + article: post.get_content().into_owned(), + } + } +} + +fn test_get_posts(posts: &impl Posts) { + for post in posts.get_posts() { + let page = MdPage::from_post(&post); + println!("{}", page.render().unwrap()); + } +} + +async fn handler(State(posts): State>) -> Html { + let post = posts.get_posts().next().unwrap(); + let page = MdPage::from_post(&post); + Html(page.render().unwrap()) +} + +#[tokio::main] +async fn main() { + let repo = Arc::new(FsDirPosts::new(&format!("/data/ct/{}", "blog"))); + + let app = Router::new().route("/posts", get(handler)).with_state(repo); + + let listener = tokio::net::TcpListener::bind("0.0.0.0:8000").await.unwrap(); + axum::serve(listener, app).await.unwrap(); +} -- cgit v1.2.3