diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/http.rs b/src/http.rs index 81b38c5..8b75b3f 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::fmt; use std::str::{FromStr, Lines}; @@ -33,11 +34,25 @@ impl Status { } } +impl Request { + pub fn form(&self) -> HashMap<&str, &str> { + let mut hashmap = HashMap::new(); + self.body.split("&") + .map(|x| x.split("=")) + .for_each( + |mut x| {hashmap.insert(x.next().unwrap(), x.next().unwrap());} + // fix unwrap hell + ); + hashmap + } +} + // TODO proper errors impl FromStr for Request { type Err = String; fn from_str(s: &str) -> Result { + dbg!(&s); let mut iter = s.lines(); let mut first = iter.next().unwrap().split_whitespace(); let method = first.next().unwrap(); @@ -91,3 +106,4 @@ impl fmt::Display for Response { ) } } + diff --git a/src/main.rs b/src/main.rs index bcd4460..4947e62 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,8 @@ use threadpool::ThreadPool; // statically linked index and favicon const INDEX: &'static str = include_str!("www/index.html"); const FAVICON: &'static [u8] = include_bytes!("www/favicon.ico"); +const STYLE: &'static str = include_str!("www/style.css"); +const FAQ: &'static str = include_str!("www/faq.html"); // represents command line arguments #[derive(StructOpt, Debug)] @@ -44,15 +46,29 @@ lazy_static! { static ref OPT: Opt = Opt::from_args(); } +#[derive(Debug)] +struct State { + db: sled::Db, + id_counter: u64, + // cache here? +} + +impl State { + fn next_id(&mut self) -> u64 { + let id = self.id_counter; + self.id_counter += 1; + id + } +} + /// top level handling of requests -fn handle(request: Request, database: Arc>, ip: SocketAddr) -> Response { - let database = database.lock().unwrap(); +fn handle(request: Request, state: Arc>) -> Response { + let state = state.lock().unwrap(); match request.method.as_str() { - "GET" => get(&request.uri, database), + "GET" => get(&request.uri, state), "POST" => { - println!("{:?}", request); - Response::new(Status::Ok, vec![], "".to_string()) + post(request, state) }, // check admin hash "DELETE" => Response::new(Status::Ok, vec![], "".to_string()), @@ -62,13 +78,14 @@ fn handle(request: Request, database: Arc>, ip: SocketAddr) -> R /// get "/" returns head of every thread /// or returns posts from thread with id in uri -fn get(path: &str, database: MutexGuard) -> Response { +fn get(path: &str, state: MutexGuard) -> Response { match path { // list threads in this case "/" => { let content = content( "index", - &database + &state + .db .iter() .map(|x| x.unwrap()) .map(|x| (x.0, deserialize::(&x.1).unwrap())) @@ -78,12 +95,18 @@ fn get(path: &str, database: MutexGuard) -> Response { Response::new(Status::Ok, vec![], content) } + // TODO /css /faq /favicon.ico + + "/css" => Response::new(Status::Ok, vec![], String::from(STYLE)), + + "/faq" => Response::new(Status::Ok, vec![], String::from(FAQ)), + // list specific thread here // FIXME unwrap hell s => { let content = content( s, - &deserialize::(&database.get(&s.as_bytes()).unwrap().unwrap()) + &deserialize::(&state.db.get(&s.as_bytes()).unwrap().unwrap()) .unwrap() .to_string() ); @@ -93,17 +116,30 @@ fn get(path: &str, database: MutexGuard) -> Response { } } -fn post(path: &str, database: MutexGuard) -> Response { - match path { +fn post(request: Request, mut state: MutexGuard) -> Response { + match request.uri.as_str() { // means we wish to create a new thread "/" => { - // first we generate unique id + // first we increment id + let id = state.next_id(); + let content = dbg!(request.form()); + let thread = Thread(vec![ + Post::new(id, None, String::from(*content.get(":D").unwrap())) + ]); + + state.db.insert( + id.to_ne_bytes(), + serialize(&thread) + .unwrap() + ); + + Response::new(Status::Ok, vec![], String::from("")) }, // means we wish to post in specific thread s => { - + Response::new(Status::Ok, vec![], String::from("")) }, } } @@ -112,6 +148,7 @@ fn delete(path: &str, database: Arc>) -> Response { todo!(); } +#[inline] fn content(name: &str, main: &str) -> String { INDEX .replace("{name}", &name) @@ -125,17 +162,21 @@ fn main() { // create threadpool for incoming requests let pool = ThreadPool::new(num_cpus::get()); // open database - let db = Arc::new(Mutex::new(sled::open(&OPT.database).unwrap())); + let state = Arc::new(Mutex::new( + State { + db: sled::open(&OPT.database).unwrap(), + id_counter: 0 + } + )); // TODO setup cache - //let cache = Arc::new(Cache("")); // wait for requests for stream in listener.incoming() { let mut stream = stream.unwrap(); - let database = Arc::clone(&db); + let state = Arc::clone(&state); pool.execute(move || { let ip = stream.peer_addr().unwrap(); - // TODO check if valid ip before reading request + // TODO check if allowed ip before reading request let mut buffer = [0; 1 << 10]; // 2 to the power of 10 // how do I implement images with this? @@ -146,8 +187,7 @@ fn main() { let request: Request = text.parse().unwrap(); // handle request - // add database and cache here - stream.write(handle(request, database, ip).to_string().as_bytes()).unwrap(); + stream.write(handle(request, state).to_string().as_bytes()).unwrap(); }); } } diff --git a/src/post.rs b/src/post.rs index 01dc290..f70dac3 100644 --- a/src/post.rs +++ b/src/post.rs @@ -11,18 +11,18 @@ pub struct Image { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Post { pub id: u64, - pub ip: [u8; 4], - pub date: String, pub img: Option, pub body: String, } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Thread(Vec); +pub struct Thread( + pub Vec +); impl Thread { pub fn head(&self) -> String { - let first = self.0[0]; + let first = &self.0[0]; format!( "
{}
{}
", first.id, @@ -32,11 +32,9 @@ impl Thread { } impl Post { - fn new(id: u64, ip: [u8; 4], date: String, img: Option, body: String) -> Self { + pub fn new(id: u64, img: Option, body: String) -> Self { Self { id, - ip, - date, img, body, } @@ -65,8 +63,8 @@ impl fmt::Display for Post { {}\ \ ", - self.id, self.date, self.id, - if let Some(s) = self.img {s.filename} else {"".to_string()}, + self.id, "", self.id, + if let Some(s) = &self.img {&s.filename} else {""}, self.body, ) } diff --git a/src/www/index.html b/src/www/index.html index 0510b7c..4c4b799 100644 --- a/src/www/index.html +++ b/src/www/index.html @@ -3,7 +3,7 @@ kchan - {name} - +
@@ -17,6 +17,14 @@
+
+

Create new thread

+
+ + +
+
+
{}