summaryrefslogblamecommitdiff
path: root/src/main.rs
blob: 43b6fa66d67aa4eefd3922a3d698088d1f714c9a (plain) (tree)







































































































































                                                                                
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<str>;
}

#[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<str> {
        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<str> {
        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<Item = impl Post>;
}

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<Item = impl Post> {
        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<Arc<impl Posts>>) -> Html<String> {
    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();
}