summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdam T. Carpenter <atc@53hor.net>2024-09-07 21:18:54 -0400
committerAdam T. Carpenter <atc@53hor.net>2024-09-07 21:18:54 -0400
commitae00627e7c99fd21ce4ad8ec0692445f00a349b2 (patch)
tree9af9c980db9075fbc0e520443201d684a0a03832 /src
parent4ae354f108acaef8c78b778124d4638904bd7c69 (diff)
downloadcarpentertutoring-ae00627e7c99fd21ce4ad8ec0692445f00a349b2.tar.xz
carpentertutoring-ae00627e7c99fd21ce4ad8ec0692445f00a349b2.zip
feat: basic markdown post to html page loading
Diffstat (limited to 'src')
-rw-r--r--src/main.rs136
1 files changed, 136 insertions, 0 deletions
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<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();
+}