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();
}
|