static files for posts
This commit is contained in:
parent
982a642d17
commit
3895837b7a
6 changed files with 658 additions and 350 deletions
945
Cargo.lock
generated
945
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,8 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { version = "0.5.7", features = ["http2"] }
|
axum = { version = "0.6.12", features = ["http2"] }
|
||||||
|
cached = "0.42.0"
|
||||||
color-eyre = "0.6.1"
|
color-eyre = "0.6.1"
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
hyper = { version = "0.14.19", features = ["full"] }
|
hyper = { version = "0.14.19", features = ["full"] }
|
||||||
|
@ -17,6 +18,6 @@ serde_json = "1.0.85"
|
||||||
tera = "1.17.0"
|
tera = "1.17.0"
|
||||||
tokio = { version = "1.19.2", features = ["full"] }
|
tokio = { version = "1.19.2", features = ["full"] }
|
||||||
tower = { version = "0.4.12", features = ["full"] }
|
tower = { version = "0.4.12", features = ["full"] }
|
||||||
tower-http = { version = "0.3.4", features = ["full"] }
|
tower-http = { version = "0.4.0", features = ["full"] }
|
||||||
tracing = "0.1.35"
|
tracing = "0.1.35"
|
||||||
tracing-subscriber = { version = "0.3.11", features = ["fmt"] }
|
tracing-subscriber = { version = "0.3.11", features = ["fmt"] }
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use axum::{extract::Path, response::Html, Extension};
|
use axum::{extract::Path, response::Html, Extension};
|
||||||
|
use cached::proc_macro::cached;
|
||||||
use pulldown_cmark::{html, Options, Parser};
|
use pulldown_cmark::{html, Options, Parser};
|
||||||
use tracing::log::*;
|
use tracing::log::*;
|
||||||
|
|
||||||
use super::{Error, Result};
|
use super::{Error, Result};
|
||||||
use crate::{handlers::PageContext, State};
|
use crate::{handlers::PageContext, Post, State};
|
||||||
|
|
||||||
pub async fn view(Path(slug): Path<String>, Extension(state): Extension<Arc<State>>) -> Result {
|
pub async fn view(Path(path): Path<String>, Extension(state): Extension<Arc<State>>) -> Result {
|
||||||
let post = state
|
let post = path.trim_end_matches('/');
|
||||||
.posts
|
info!("Requested post: {}", post);
|
||||||
.iter()
|
let res = render_post(&state, post).await.ok_or(Error::NotFound)?;
|
||||||
.find(|p| p.slug == slug)
|
Ok(Html(res.into()))
|
||||||
.ok_or(Error::NotFound)?;
|
}
|
||||||
|
|
||||||
info!("Requested post: {}", slug);
|
#[cached(time = 60, key = "String", convert = r"{ path.to_owned() }")]
|
||||||
|
async fn render_post(state: &State, path: &str) -> Option<String> {
|
||||||
|
let post = state.posts.iter().find(|p| p.slug == path)?;
|
||||||
|
|
||||||
let options = Options::all();
|
let options = Options::all();
|
||||||
let parser = Parser::new_ext(&post.content, options);
|
let parser = Parser::new_ext(&post.content, options);
|
||||||
|
@ -22,22 +25,23 @@ pub async fn view(Path(slug): Path<String>, Extension(state): Extension<Arc<Stat
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
html::push_html(&mut out, parser);
|
html::push_html(&mut out, parser);
|
||||||
|
|
||||||
let ctx =
|
let ctx = tera::Context::from_serialize(PageContext { content: out }).ok()?;
|
||||||
tera::Context::from_serialize(PageContext { content: out }).map_err(|_| Error::NotFound)?;
|
|
||||||
|
|
||||||
let res = state.tera.render("post.html", &ctx).map_err(|e| {
|
let res = match state.tera.render("post.html", &ctx) {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(e) => {
|
||||||
error!("Failed rendering post: {}", e);
|
error!("Failed rendering post: {}", e);
|
||||||
Error::NotFound
|
return None;
|
||||||
})?;
|
}
|
||||||
|
};
|
||||||
Ok(Html(res.into()))
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn index(Extension(state): Extension<Arc<State>>) -> Result {
|
pub async fn index(Extension(state): Extension<Arc<State>>) -> Result {
|
||||||
let mut ctx = tera::Context::new();
|
let mut ctx = tera::Context::new();
|
||||||
ctx.insert("posts", &state.posts);
|
ctx.insert("posts", &state.posts);
|
||||||
let res = state.tera.render("postsindex.html", &ctx).map_err(|e| {
|
let res = state.tera.render("postsindex.html", &ctx).map_err(|e| {
|
||||||
error!("Failed rendering posts index: {}", e);
|
error!("Failed rendering posts index: {:?}", e);
|
||||||
Error::NotFound
|
Error::NotFound
|
||||||
})?;
|
})?;
|
||||||
Ok(Html(res.into()))
|
Ok(Html(res.into()))
|
||||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -4,7 +4,7 @@ use axum::{
|
||||||
handler::Handler,
|
handler::Handler,
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
routing::{get, get_service},
|
routing::{get, get_service},
|
||||||
Extension, Router,
|
Extension, Router, ServiceExt,
|
||||||
};
|
};
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use glob::glob;
|
use glob::glob;
|
||||||
|
@ -22,6 +22,7 @@ pub struct State {
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct Post {
|
pub struct Post {
|
||||||
|
pub name: String,
|
||||||
pub slug: String,
|
pub slug: String,
|
||||||
pub content: String,
|
pub content: String,
|
||||||
}
|
}
|
||||||
|
@ -36,6 +37,7 @@ async fn main() -> Result<()> {
|
||||||
let posts = glob("posts/**/*.md")?
|
let posts = glob("posts/**/*.md")?
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
let path = p.unwrap();
|
let path = p.unwrap();
|
||||||
|
info!("found page: {}", path.display());
|
||||||
|
|
||||||
let filename = path.file_name().unwrap().to_string_lossy();
|
let filename = path.file_name().unwrap().to_string_lossy();
|
||||||
|
|
||||||
|
@ -51,8 +53,8 @@ async fn main() -> Result<()> {
|
||||||
} else {
|
} else {
|
||||||
filename.to_owned()
|
filename.to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
Post {
|
Post {
|
||||||
|
name: slug.clone(),
|
||||||
slug,
|
slug,
|
||||||
content: std::fs::read_to_string(&path).unwrap(),
|
content: std::fs::read_to_string(&path).unwrap(),
|
||||||
}
|
}
|
||||||
|
@ -68,13 +70,9 @@ async fn main() -> Result<()> {
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/", get(handlers::index))
|
.route("/", get(handlers::index))
|
||||||
.route("/posts/", get(handlers::posts::index))
|
.route("/posts/", get(handlers::posts::index))
|
||||||
.route("/posts/:slug/", get(handlers::posts::view))
|
.route("/posts/:path/", get(handlers::posts::view))
|
||||||
.nest(
|
.nest_service("/static", tower_http::services::ServeDir::new("./static"))
|
||||||
"/static",
|
.fallback_service(tower_http::services::ServeDir::new("./"))
|
||||||
get_service(tower_http::services::ServeDir::new("./static"))
|
|
||||||
.handle_error(|_e| async { (StatusCode::NOT_FOUND, "not found") }),
|
|
||||||
)
|
|
||||||
.fallback((|| async { (StatusCode::NOT_FOUND, "not found") }).into_service())
|
|
||||||
.layer(middleware);
|
.layer(middleware);
|
||||||
|
|
||||||
info!("Now listening at http://localhost:8180");
|
info!("Now listening at http://localhost:8180");
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<p>hi hello welcome to my website it's pretty wip right now yeah ok bye</p>
|
<p>hi hello welcome to my website it's pretty wip right now yeah ok bye</p>
|
||||||
<h2>todo</h2>
|
<h2>todo</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>static content</li>
|
<li>static content ✅</li>
|
||||||
<li>sass compilation</li>
|
<li>sass compilation</li>
|
||||||
<li>post metadata (frontmatter)</li>
|
<li>post metadata (frontmatter)</li>
|
||||||
<li>rss/atom/jsonfeed</li>
|
<li>rss/atom/jsonfeed</li>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<p>i occasionally write some stuff i guess</p>
|
<p>i occasionally write some stuff i guess</p>
|
||||||
<ul>
|
<ul>
|
||||||
{% for post in posts %}
|
{% for post in posts %}
|
||||||
<li><a href="/posts/{{post.name}}">{{post.name}}</a></li>
|
<li><a href="/posts/{{post.name}}/">{{post.name}}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock main %}
|
{% endblock main %}
|
Loading…
Reference in a new issue