use config::Config; use std::{path::PathBuf, sync::Arc}; use tokio::sync::RwLock; use blog::{Blog, RenderedBlog}; use warp::{ http::HeaderValue, hyper::{ header::{CONTENT_TYPE, EXPIRES}, Body, }, path::FullPath, reply, Filter, }; mod blog; mod config; mod date; mod favicon; mod image; mod load; mod misc; mod parser; mod path; mod post; mod resp; mod style; mod util; async fn handle_request( req: FullPath, blog: Arc<RwLock<RenderedBlog>>, ) -> Result<impl warp::Reply, warp::Rejection> { let blog = blog.read().await; let (status, content) = blog.get(req.as_str()); let mut reply = reply::Response::new(Body::from(content.data)); let headers = reply.headers_mut(); headers.insert(CONTENT_TYPE, HeaderValue::from_static(content.content_type)); if let Some(expires) = content.expiry.header_value() { // TODO log a metric (statsd) if this fails) if let Ok(hv) = HeaderValue::from_str(&expires) { headers.insert(EXPIRES, hv); } } *reply.status_mut() = status; Ok(reply) } #[tokio::main] async fn main() { let config = Config::load().unwrap(); let blog: RenderedBlog = Blog::new( config.name, config.description, &PathBuf::from(config.path), config.logo, ) .unwrap() .try_into() .unwrap(); let blog = Arc::new(RwLock::new(blog)); let blog_filter = warp::any().map(move || blog.clone()); warp::serve( warp::filters::path::full() .and(blog_filter.clone()) .and_then(handle_request), ) .run(([0, 0, 0, 0], 3030)) .await; }