aboutsummaryrefslogtreecommitdiff
path: root/backend/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'backend/src/main.rs')
-rw-r--r--backend/src/main.rs160
1 files changed, 160 insertions, 0 deletions
diff --git a/backend/src/main.rs b/backend/src/main.rs
new file mode 100644
index 0000000..0474f89
--- /dev/null
+++ b/backend/src/main.rs
@@ -0,0 +1,160 @@
+mod config;
+mod monolith;
+mod render;
+
+use std::env;
+use std::collections::hash_map::{HashMap, RandomState};
+
+enum CGIStatusCode {
+ S200,
+ C400,
+ C404,
+ C405
+}
+
+type CGIHTTPHeaders = Vec<(String, String)>;
+
+struct CGIResponse {
+ status: CGIStatusCode,
+ headers: CGIHTTPHeaders,
+ body: String
+}
+
+fn cgi_handle_request(conf: &config::Config) -> Result<CGIResponse, CGIResponse> {
+ let headers = vec![
+ (String::from("Allow"), String::from("GET")),
+ (String::from("Content-type"), String::from("text/html"))
+ ];
+ let mkerr = |status| CGIResponse {
+ status,
+ headers: headers.clone(),
+ body: String::from("")
+ };
+ let request_method = env::var("REQUEST_METHOD").map_err(|_| mkerr(CGIStatusCode::C400))?;
+ if request_method != "GET" {
+ return Err(mkerr(CGIStatusCode::C405));
+ }
+ let query: HashMap<_, _, RandomState> =
+ if let Ok(query_string) = env::var("QUERY_STRING") {
+ if query_string.len() > 0 {
+ HashMap::from_iter(query_string.split('&').map(|qi| {
+ let (k, v) = config::split_at_first(qi, "=");
+ (String::from(k), String::from(v))
+ }))
+ } else { HashMap::from([(String::from("page"), String::from("1"))]) }
+ } else { HashMap::from([(String::from("page"), String::from("1"))]) };
+ let m = monolith::Monolith::new(String::from("posts.monolith"));
+ if let Some(ps) = query.get("page") {
+ let p = usize::from_str_radix(&ps, 10).map_err(|_| mkerr(CGIStatusCode::C400))?.checked_sub(1).ok_or(mkerr(CGIStatusCode::C404))?;
+ let ps = m.get_page_posts(p).ok_or(mkerr(CGIStatusCode::C404))?;
+ let r = render::Renderer::load("./template");
+ return Ok(CGIResponse {
+ status: CGIStatusCode::S200,
+ headers,
+ body: r.render_page(ps, p, m.get_page_count(), conf)
+ });
+ } else if let Some(ds) = query.get("post") {
+ let d = i64::from_str_radix(&ds, 10).map_err(|_| mkerr(CGIStatusCode::C400))?;
+ let p = m.get_post_2(d).ok_or(mkerr(CGIStatusCode::C404))?;
+ let r = render::Renderer::load("./template");
+ return Ok(CGIResponse {
+ status: CGIStatusCode::S200,
+ headers,
+ body: r.render_single_post(p, conf)
+ });
+ }
+ Err(mkerr(CGIStatusCode::C400))
+}
+
+fn cgimain(conf: config::Config) -> Result<(), &'static str> {
+ let r = match cgi_handle_request(&conf) {
+ Ok(r) => r,
+ Err(r) => r
+ };
+ let (status, status_str) = match r.status {
+ CGIStatusCode::S200 => (200, "OK"),
+ CGIStatusCode::C400 => (400, "Bad Request"),
+ CGIStatusCode::C404 => (404, "Not Found"),
+ CGIStatusCode::C405 => (405, "Method Not Allowed")
+ };
+ print!("Status: {} {}\r\n", status, status_str);
+ r.headers.iter().for_each(|(f, v)| print!("{}: {}\r\n", f, v));
+ print!("\r\n");
+ if status < 400 {
+ print!("{}", r.body);
+ } else {
+ let rdr = render::Renderer::load("./template");
+ print!("{}", rdr.render_error(status, String::from(status_str), &conf));
+ }
+ Ok(())
+}
+
+fn dbgmain(conf: config::Config) -> Result<(), &'static str> {
+ eprintln!("in debug mode");
+ eprintln!("notekins version {}", conf.get("VERSION_STRING"));
+ let mut m = monolith::Monolith::new(String::from("posts.monolith"));
+ let mut args = env::args();
+ args.next();
+ if let Some(dbgop) = args.next() {
+ match dbgop.as_str() {
+ "get_post" => {
+ let tss = args.next().ok_or("missing timestamp")?;
+ let ts = i64::from_str_radix(&tss, 10).map_err(|_| "invalid timestamp")?;
+ m.load_index();
+ let p = m.get_post(ts).ok_or("post not found")?;
+ monolith::test_print_post(&p);
+ Ok(())
+ },
+ "get_post2" => {
+ let tss = args.next().ok_or("missing timestamp")?;
+ let ts = i64::from_str_radix(&tss, 10).map_err(|_| "invalid timestamp")?;
+ let p = m.get_post_2(ts).ok_or("post not found")?;
+ monolith::test_print_post(&p);
+ Ok(())
+ },
+ "get_page" => {
+ let pgs = args.next().ok_or("missing page")?;
+ let pg = usize::from_str_radix(&pgs, 10).map_err(|_| "invalid page")?;
+ let ps = m.get_page_posts(pg).ok_or("page out of range")?;
+ for p in ps {
+ monolith::test_print_post(&p);
+ }
+ Ok(())
+ },
+ "render_page" => {
+ let pgs = args.next().ok_or("missing page")?;
+ let pg = usize::from_str_radix(&pgs, 10).map_err(|_| "invalid page")?;
+ let ps = m.get_page_posts(pg).ok_or("page out of range")?;
+ let r = render::Renderer::load("./template");
+ println!("{}", r.render_page(ps, pg, m.get_page_count(), &conf));
+ Ok(())
+ },
+ "render_post" => {
+ let tss = args.next().ok_or("missing timestamp")?;
+ let ts = i64::from_str_radix(&tss, 10).map_err(|_| "invalid timestamp")?;
+ let p = m.get_post_2(ts).ok_or("post not found")?;
+ let r = render::Renderer::load("./template");
+ println!("{}", r.render_single_post(p, &conf));
+ Ok(())
+ },
+ _ => Err("unsupported debug option")
+ }
+ } else {
+ m.load_index();
+ let dates = m.get_all_dates();
+ for d in dates {
+ let p = m.get_post(d);
+ println!("{:?}", p)
+ }
+ Ok(())
+ }
+}
+
+fn main() -> Result<(), &'static str> {
+ let conf = config::Config::parse_config("notekins.conf");
+ if let Ok(_) = env::var("SERVER_SOFTWARE") {
+ cgimain(conf)
+ } else {
+ dbgmain(conf)
+ }
+}