diff --git a/Cargo.lock b/Cargo.lock index f3c0a50..28739af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,25 +23,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "async-mutex" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-rwlock" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261803dcc39ba9e72760ba6e16d0199b1eef9fc44e81bffabbebb9f5aea3906c" -dependencies = [ - "async-mutex", - "event-listener", -] - [[package]] name = "atty" version = "0.2.14" @@ -98,40 +79,6 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" -[[package]] -name = "cached" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66c8f6ae13abbdc12268879b8070a441777b69157fb7653b4c7da7f2610c25d" -dependencies = [ - "async-mutex", - "async-rwlock", - "cached_proc_macro", - "cached_proc_macro_types", - "hashbrown", - "once_cell", - "thiserror", - "tokio", -] - -[[package]] -name = "cached_proc_macro" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc8de7b947777686ee8f3c11f4c3e58c296d6bc598d9b2286a80a9404a538ff8" -dependencies = [ - "cached_proc_macro_types", - "darling", - "quote", - "syn", -] - -[[package]] -name = "cached_proc_macro_types" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" - [[package]] name = "cfg-if" version = "1.0.0" @@ -160,7 +107,7 @@ dependencies = [ "ansi_term", "atty", "bitflags", - "strsim 0.8.0", + "strsim", "textwrap", "unicode-width", "vec_map", @@ -225,41 +172,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "darling" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" -dependencies = [ - "darling_core", - "quote", - "syn", -] - [[package]] name = "deflate" version = "1.0.0" @@ -275,12 +187,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -[[package]] -name = "event-listener" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" - [[package]] name = "exr" version = "1.4.1" @@ -322,12 +228,6 @@ dependencies = [ "spin", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "fs2" version = "0.4.3" @@ -388,12 +288,6 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" -[[package]] -name = "hashbrown" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" - [[package]] name = "heck" version = "0.3.3" @@ -412,12 +306,6 @@ dependencies = [ "libc", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "image" version = "0.24.1" @@ -485,7 +373,6 @@ name = "kchan" version = "0.1.0" dependencies = [ "bincode", - "cached", "image", "lazy_static", "log", @@ -623,12 +510,6 @@ dependencies = [ "libc", ] -[[package]] -name = "once_cell" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" - [[package]] name = "parking_lot" version = "0.11.2" @@ -674,12 +555,6 @@ dependencies = [ "syn", ] -[[package]] -name = "pin-project-lite" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" - [[package]] name = "png" version = "0.17.5" @@ -894,12 +769,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "structopt" version = "0.3.25" @@ -1003,28 +872,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "tokio" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" -dependencies = [ - "num_cpus", - "pin-project-lite", - "tokio-macros", -] - -[[package]] -name = "tokio-macros" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "unicode-segmentation" version = "1.8.0" diff --git a/Cargo.toml b/Cargo.toml index d717c81..8718005 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ lazy_static = "1.4.0" sled = "0.34.7" bincode = "1.3.3" serde = { version = "1.0.136", features = ["derive"] } -cached = "0.33.0" log = "0.4.14" simplelog = "0.11.2" image = "0.24.1" diff --git a/src/errors.rs b/src/errors.rs index f6e6aec..3d3b1f8 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -26,7 +26,7 @@ pub enum InternalError { #[derive(Debug, Error)] pub enum HandlingError { #[error("client error: {0}")] - ClientError(RequestError), + ClientError(#[from] RequestError), #[error("server error: {0}")] - ServerError(InternalError), + ServerError(#[from] InternalError), } diff --git a/src/html.rs b/src/html.rs new file mode 100644 index 0000000..8d33506 --- /dev/null +++ b/src/html.rs @@ -0,0 +1,9 @@ +// statically linked index and favicon +pub const INDEX: &'static str = include_str!("www/index.html"); +//pub const FAVICON: &'static [u8] = include_bytes!("www/favicon.ico"); +pub const STYLE: &'static str = include_str!("www/style.css"); +pub const FAQ: &'static str = include_str!("www/faq.html"); + +pub trait Htmlizable { + fn to_html(&self) -> String; +} diff --git a/src/http.rs b/src/http.rs index ac0e07b..4380ee6 100644 --- a/src/http.rs +++ b/src/http.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::fmt; use std::str::{FromStr, Lines}; -use crate::errors::RequestError; +use crate::errors::{HandlingError, RequestError}; const HTTP_VERSION: &'static str = "HTTP/1.1"; @@ -97,6 +97,12 @@ impl Response { } } +impl From for Response { + fn from(err: HandlingError) -> Self { + todo!(); + } +} + impl fmt::Display for Response { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let headers: String = self diff --git a/src/main.rs b/src/main.rs index 0d36a8f..977f6aa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,12 @@ +#![feature(int_log)] + mod errors; +mod html; mod http; mod post; use crate::errors::{HandlingError, InternalError, RequestError}; +use crate::html::{FAQ, INDEX, STYLE}; use crate::http::{Request, Response, Status}; use crate::post::{Post, Thread}; @@ -13,21 +17,15 @@ use std::path::PathBuf; use std::str; use std::str::from_utf8; use std::sync::{Arc, Mutex, MutexGuard}; +use std::thread::JoinHandle; use bincode::{deserialize, serialize}; -use cached::proc_macro::cached; use lazy_static::lazy_static; use log::*; use simplelog::*; use structopt::StructOpt; 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)] struct Opt { @@ -51,15 +49,20 @@ lazy_static! { #[derive(Debug)] struct State { db: sled::Db, - id_counter: u64, + id_counter: u32, // cache here? } impl State { - fn next_id(&mut self) -> u64 { + fn next_id(&mut self) -> String { let id = self.id_counter; - self.id_counter += 1; - id + // TODO improve this + // means the highest possible id is 999_999_999, then it loops back to zero + // NOTE this could technically be used to limit the storage required, + // might possibly be a good feature + self.id_counter = (self.id_counter + 1) % 1_000_000_000; + let width = u32::MAX.log10() as usize; // happens to be 9 in this case + format!("{id:0width$}") } } @@ -74,12 +77,15 @@ fn handle(request: &str, state: Arc>) -> Response { match request.method.as_str() { "GET" => match get(&request.uri, state) { Ok(s) => s, - Err(e) => Response::new(Status::NotFound, vec![], e.to_string()), + Err(e) => Response::new(Status::NotFound, vec![], dbg!(e).to_string()), + }, + "POST" => match post(request, state) { + Ok(s) => s, + Err(e) => Response::new(Status::Ok, vec![], "".to_string()), }, - "POST" => post(request, state), // check admin hash "DELETE" => Response::new(Status::Ok, vec![], "".to_string()), - _ => Response::new(Status::Ok, vec![], "".to_string()), + _ => Response::new(Status::Ok, vec![], RequestError::BadRequest.to_string()), } } @@ -115,7 +121,7 @@ fn get(path: &str, state: MutexGuard) -> Result &deserialize::( &state .db - .get(&s.as_bytes()) + .get(&s[1..]) .map_err(|_| HandlingError::ServerError(InternalError::DatabaseReadError))? .ok_or(HandlingError::ClientError(RequestError::NotFound))?, ) @@ -128,29 +134,54 @@ fn get(path: &str, state: MutexGuard) -> Result } } -fn post(request: Request, mut state: MutexGuard) -> Response { +fn post(request: Request, mut state: MutexGuard) -> Result { match request.uri.as_str() { // means we wish to create a new thread "/" => { - // first we increment id - let id = state.next_id(); + // TODO fix unwrap let content = dbg!(request.form().unwrap()); + let id = state.next_id(); let thread = Thread(vec![Post::new( - id, - None, + &id, String::from(*content.get("content").unwrap()), )]); + state.db.insert(&id, serialize(&thread).unwrap()).unwrap(); + + info!("Created new thread, id: {}", id); + + // TODO add redirect + Ok(Response::new(Status::Ok, vec![], String::from(""))) + } + + // means we wish to post in specific thread + s => { + // first we increment id + let id = state.next_id(); + let content = dbg!(request.form().unwrap()); + let post = Post::new(&id, String::from(*content.get("content").unwrap())); + + let mut thread = deserialize::( + &state + .db + .remove(&s[1..]) + .map_err(|_| HandlingError::ServerError(InternalError::DatabaseWriteError))? + .ok_or(HandlingError::ClientError(RequestError::NotFound))?, + ) + .unwrap(); + + thread.0.push(post); + state .db - .insert(id.to_ne_bytes(), serialize(&thread).unwrap()) + .insert(&s[1..], serialize(&thread).unwrap()) .unwrap(); + // make this less weird + info!("Added new post to thread {}", s); - Response::new(Status::Ok, vec![], String::from("")) + // TODO add redirect + Ok(Response::new(Status::Ok, vec![], String::from(""))) } - - // means we wish to post in specific thread - s => Response::new(Status::Ok, vec![], String::from("")), } } @@ -171,7 +202,7 @@ fn main() { let pool = ThreadPool::new(num_cpus::get()); // setup logger TermLogger::init( - LevelFilter::Warn, + LevelFilter::Info, Config::default(), TerminalMode::Mixed, ColorChoice::Auto, @@ -189,10 +220,11 @@ fn main() { let mut stream = match stream { Ok(s) => s, Err(e) => { - eprintln!("failed connection: {}", e); + warn!("Failed connection: {}", e); continue; } }; + let state = Arc::clone(&state); pool.execute(move || { let ip = stream.peer_addr().unwrap(); @@ -202,6 +234,7 @@ fn main() { stream.read(&mut buffer).unwrap(); + // NOTE possibly problematic when we cosider images let text = str::from_utf8(&buffer).unwrap().trim_matches(0 as char); // ^-- gets rid of null at the end of buffer diff --git a/src/post.rs b/src/post.rs index ff1313c..8a046ac 100644 --- a/src/post.rs +++ b/src/post.rs @@ -2,15 +2,15 @@ use std::fmt; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Image { - pub filename: String, - pub img: Box<[u8]>, -} +//#[derive(Debug, Clone, Serialize, Deserialize)] +//pub struct Image { +// pub filename: String, +// pub img: Box<[u8]>, +//} #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Post { - pub id: u64, + pub id: String, //pub img: Option, pub body: String, } @@ -30,9 +30,9 @@ impl Thread { } impl Post { - pub fn new(id: u64, img: Option, body: String) -> Self { + pub fn new(id: &str, body: String) -> Self { Self { - id, + id: id.to_string(), //img, body, }