Static site generator + my presonnal website written in rust for some reason.
1use std::{error::Error, fs::{self, read_dir, DirBuilder, File}, io::Write, path::Path}; 2 3use ascii::AsciiString; 4use tiny_http::{Response, Server}; 5 6 7mod handlers; 8mod structs; 9pub mod blog_entries; 10pub mod rand_quote; 11 12 13 14fn main() { 15 let output_path = "output"; 16 match DirBuilder::new() 17 .recursive(true) 18 .create(output_path) { 19 Ok(_) => (), 20 Err(_) => (), 21 } 22 23 match copy_dir_all("assets", format!("{output_path}/assets")) { 24 Ok(_) => (), 25 Err(err) => println!("Couldnt copy assets directory, err: {err}"), 26 } 27 28 29 30 fs::write(format!("{output_path}/index.html"), handlers::index().as_bytes()).expect("Couldnt write index file"); 31 fs::write(format!("{output_path}/about.html"), handlers::about().as_bytes()).expect("Couldnt write about file"); 32 fs::write(format!("{output_path}/404.html"), handlers::not_found().as_bytes()).expect("Couldnt write 404 file"); 33 34 match DirBuilder::new() 35 .create(format!("{output_path}/blog")) { 36 Ok(_) => (), 37 Err(_) => (), 38 } 39 40 41 let post_dir_iter = match read_dir("posts/") { 42 Ok(iter) => iter, 43 Err(err) => panic!("could ls files, err {err}") 44 }; 45 46 for entry in post_dir_iter { 47 if let Ok(entry) = entry { 48 49 let filename = entry.file_name().into_string().unwrap().split(".").collect::<Vec<_>>()[0].to_string(); 50 51 fs::write(format!("{output_path}/blog/{filename}.html"), handlers::blog(filename).as_bytes()).expect("Couldnt write blog entry"); 52 }; 53 54 } 55 56} 57fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> { 58 std::fs::create_dir_all(&dst)?; 59 for entry in std::fs::read_dir(src)? { 60 let entry = entry?; 61 let ty = entry.file_type()?; 62 if ty.is_dir() { 63 copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; 64 } else { 65 std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; 66 } 67 } 68 Ok(()) 69} 70 71fn old_main() { 72 73 // let app: axum::Router = Router::new() 74 // .route("/", get(handlers::index)) 75 // .route("/about", get(handlers::about)) 76 // .route("/blog",get(handlers::index)) 77 // .route("/blog/:blog_path",get(handlers::blog)) 78 // .route_service("/robots.txt", ServeFile::new("assets/robots.txt")) 79 // .fallback(get(handlers::not_found)) 80 // .nest_service("/assets", ServeDir::new("assets")); 81 // 82 // 83 // let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await.unwrap(); 84 // axum::serve(listener, app).await.unwrap(); 85 // 86 //----- 87 // let server = Arc::new(Server::http("127.0.0.1:3001").unwrap()); 88 // println!("started server on port 3001"); 89 // 90 // let mut handles = Vec::new(); 91 // 92 // for thread_num in 0..6 { 93 // println!("starting thread {}",thread_num); 94 // let server = server.clone(); 95 // handles.push(thread::spawn(move || server_thread(server))); 96 // 97 // } 98 // for h in handles { 99 // h.join().unwrap(); 100 // } 101 // ------------ 102 let server = Server::http("127.0.0.1:3000").unwrap(); 103 println!("started server on port 3001"); 104 server_thread(server); 105 106} 107 108fn server_thread(server: Server) { 109 for request in server.incoming_requests() { 110 println!("received request; method: {}, url: {}", 111 request.method(),request.url()); 112 113 match request.url() { 114 "" | "/" => { 115 let response = Response::from_string(handlers::index()); 116 let response = response.with_header(tiny_http::Header { 117 field: "Content-Type".parse().unwrap(), 118 value: AsciiString::from_ascii("text/html;charset=utf8").unwrap(), 119 }); 120 121 let _ = request.respond(response); 122 123 } 124 "/about" => { 125 let response = Response::from_string(handlers::about()); 126 let response = response.with_header(tiny_http::Header { 127 field: "Content-Type".parse().unwrap(), 128 value: AsciiString::from_ascii("text/html;charset=utf8").unwrap(), 129 }); 130 131 let _ = request.respond(response); 132 133 } 134 asset_url @ _ if asset_url.starts_with("/assets/") => { 135 println!("getting asset : {}",asset_url); 136 if let Some(asset) = get_asset(&asset_url){ 137 let _ = request.respond(asset); 138 } 139 140 } 141 blog_url @ _ if blog_url.starts_with("/blog/") => { 142 143 144 let response = Response::from_string(handlers::blog(blog_url[6..].to_string())); 145 let response = response.with_header(tiny_http::Header { 146 field: "Content-Type".parse().unwrap(), 147 value: AsciiString::from_ascii("text/html;charset=utf8").unwrap(), 148 }); 149 150 let _ = request.respond(response); 151 152 } 153 &_ => { 154 155 let response = Response::from_string(handlers::not_found()); 156 let response = response.with_header(tiny_http::Header { 157 field: "Content-Type".parse().unwrap(), 158 value: AsciiString::from_ascii("text/html;charset=utf8").unwrap(), 159 }); 160 161 let _ = request.respond(response); 162 } 163 } 164 } 165} 166 167 168 169fn get_asset(asset:&str)-> Option<Response<File>>{ 170 171 match Path::new(&asset[1..]).exists() { 172 true => { 173 println!("found asset"); 174 Some(Response::from_file(File::open(&asset[1..]).unwrap())) 175 } 176 false => None, 177 } 178 179} 180 181 182 183 184 185 186 187 188 189