1pub mod router;
2
3use std::convert::Infallible;
4use rust_embed::RustEmbed;
5use std::{env, str};
6use std::net::SocketAddr;
7use hyper::{Body, Request, Response, Server};
8use hyper::service::{make_service_fn, service_fn};
9use sailfish::TemplateOnce;
10use ::router::Router;
11
12struct PostEntry {
13 title: String,
14 file: String,
15}
16
17#[derive(TemplateOnce)]
18#[template(path = "index.html")]
19struct IndexTemplate {
20 posts: Vec<PostEntry>,
21}
22
23#[derive(TemplateOnce)]
24#[template(path = "post.html")]
25struct PostTemplate {
26 content: String,
27}
28
29#[derive(RustEmbed)]
30#[folder = "content/posts/"]
31struct PostAsset;
32
33
34fn get_file_content(path: &str) -> String {
35 let buffer = PostAsset::get(path)
36 .unwrap()
37 .data
38 .into_owned();
39
40 return String::from_utf8(buffer).unwrap();
41}
42
43fn get_post_entry(path: &String) -> PostEntry {
44 let sub_title = str::replace(path, "_", " ");
45 let title = str::replace(sub_title.as_str(), ".html", "");
46 PostEntry {
47 title: String::from(title),
48 file: String::from(path),
49 }
50}
51
52fn get_post_title() -> Vec<PostEntry> {
53 PostAsset::iter()
54 .map(|e| format!("{}", e))
55 .map(|e| get_post_entry(&e))
56 .collect()
57}
58
59
60async fn not_found() -> Result<Response<Body>, Infallible> {
61 let resp: Response<Body> = Response::builder()
62 .status(404)
63 .body("Not Found".into())
64 .unwrap();
65 Ok(resp)
66}
67
68
69async fn index() -> Result<Response<Body>, Infallible> {
70 let files = get_post_title();
71 let body = IndexTemplate { posts: files }
72 .render_once()
73 .unwrap();
74
75 let resp: Response<Body> = Response::builder()
76 .status(200)
77 .header("posts-type", "text/html")
78 .body(body.into())
79 .unwrap();
80
81 Ok(resp)
82}
83
84
85async fn post(path: &String) -> Result<Response<Body>, Infallible> {
86 let body = PostTemplate { content: get_file_content(path) }
87 .render_once()
88 .unwrap();
89
90 let resp: Response<Body> = Response::builder()
91 .status(200)
92 .header("posts-type", "text/html")
93 .body(body.into())
94 .unwrap();
95
96 Ok(resp)
97}
98
99async fn request(req: Request<Body>) -> Result<Response<Body>, Infallible> {
100 let path = req.uri().path();
101
102 match Router::new(path) {
103 Router::Index => index().await,
104 Router::Post { page } => post(&page).await,
105 Router::NotFound => not_found().await
106 }
107}
108
109
110#[tokio::main]
111async fn main() {
112 let port = env::var("PORT").unwrap_or("3000".into()).parse::<u16>().unwrap_or(3000);
113 let addr = SocketAddr::from(([0, 0, 0, 0], port));
114
115 let make_svc = make_service_fn(|_conn| async {
116 Ok::<_, Infallible>(service_fn(request))
117 });
118
119 let server = Server::bind(&addr).serve(make_svc);
120
121 if let Err(e) = server.await {
122 eprintln!("server error: {}", e);
123 }
124}