improved id's, fixed some bugs, changed database structure, improved errors,

added logging, created html trait, organized and formatted code
doctorpavel
Dawid J. Kubis 3 years ago
parent c6088fbb79
commit 407f5e427a

155
Cargo.lock generated

@ -23,25 +23,6 @@ dependencies = [
"winapi", "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]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@ -98,40 +79,6 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 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]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -160,7 +107,7 @@ dependencies = [
"ansi_term", "ansi_term",
"atty", "atty",
"bitflags", "bitflags",
"strsim 0.8.0", "strsim",
"textwrap", "textwrap",
"unicode-width", "unicode-width",
"vec_map", "vec_map",
@ -225,41 +172,6 @@ dependencies = [
"lazy_static", "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]] [[package]]
name = "deflate" name = "deflate"
version = "1.0.0" version = "1.0.0"
@ -275,12 +187,6 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "event-listener"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
[[package]] [[package]]
name = "exr" name = "exr"
version = "1.4.1" version = "1.4.1"
@ -322,12 +228,6 @@ dependencies = [
"spin", "spin",
] ]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "fs2" name = "fs2"
version = "0.4.3" version = "0.4.3"
@ -388,12 +288,6 @@ version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hashbrown"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.3.3" version = "0.3.3"
@ -412,12 +306,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]] [[package]]
name = "image" name = "image"
version = "0.24.1" version = "0.24.1"
@ -485,7 +373,6 @@ name = "kchan"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bincode", "bincode",
"cached",
"image", "image",
"lazy_static", "lazy_static",
"log", "log",
@ -623,12 +510,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "once_cell"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.11.2" version = "0.11.2"
@ -674,12 +555,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "pin-project-lite"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
[[package]] [[package]]
name = "png" name = "png"
version = "0.17.5" version = "0.17.5"
@ -894,12 +769,6 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "structopt" name = "structopt"
version = "0.3.25" version = "0.3.25"
@ -1003,28 +872,6 @@ dependencies = [
"winapi", "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]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.8.0" version = "1.8.0"

@ -15,7 +15,6 @@ lazy_static = "1.4.0"
sled = "0.34.7" sled = "0.34.7"
bincode = "1.3.3" bincode = "1.3.3"
serde = { version = "1.0.136", features = ["derive"] } serde = { version = "1.0.136", features = ["derive"] }
cached = "0.33.0"
log = "0.4.14" log = "0.4.14"
simplelog = "0.11.2" simplelog = "0.11.2"
image = "0.24.1" image = "0.24.1"

@ -26,7 +26,7 @@ pub enum InternalError {
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum HandlingError { pub enum HandlingError {
#[error("client error: {0}")] #[error("client error: {0}")]
ClientError(RequestError), ClientError(#[from] RequestError),
#[error("server error: {0}")] #[error("server error: {0}")]
ServerError(InternalError), ServerError(#[from] InternalError),
} }

@ -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;
}

@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::str::{FromStr, Lines}; use std::str::{FromStr, Lines};
use crate::errors::RequestError; use crate::errors::{HandlingError, RequestError};
const HTTP_VERSION: &'static str = "HTTP/1.1"; const HTTP_VERSION: &'static str = "HTTP/1.1";
@ -97,6 +97,12 @@ impl Response {
} }
} }
impl From<HandlingError> for Response {
fn from(err: HandlingError) -> Self {
todo!();
}
}
impl fmt::Display for Response { impl fmt::Display for Response {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let headers: String = self let headers: String = self

@ -1,8 +1,12 @@
#![feature(int_log)]
mod errors; mod errors;
mod html;
mod http; mod http;
mod post; mod post;
use crate::errors::{HandlingError, InternalError, RequestError}; use crate::errors::{HandlingError, InternalError, RequestError};
use crate::html::{FAQ, INDEX, STYLE};
use crate::http::{Request, Response, Status}; use crate::http::{Request, Response, Status};
use crate::post::{Post, Thread}; use crate::post::{Post, Thread};
@ -13,21 +17,15 @@ use std::path::PathBuf;
use std::str; use std::str;
use std::str::from_utf8; use std::str::from_utf8;
use std::sync::{Arc, Mutex, MutexGuard}; use std::sync::{Arc, Mutex, MutexGuard};
use std::thread::JoinHandle;
use bincode::{deserialize, serialize}; use bincode::{deserialize, serialize};
use cached::proc_macro::cached;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use log::*; use log::*;
use simplelog::*; use simplelog::*;
use structopt::StructOpt; use structopt::StructOpt;
use threadpool::ThreadPool; 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 // represents command line arguments
#[derive(StructOpt, Debug)] #[derive(StructOpt, Debug)]
struct Opt { struct Opt {
@ -51,15 +49,20 @@ lazy_static! {
#[derive(Debug)] #[derive(Debug)]
struct State { struct State {
db: sled::Db, db: sled::Db,
id_counter: u64, id_counter: u32,
// cache here? // cache here?
} }
impl State { impl State {
fn next_id(&mut self) -> u64 { fn next_id(&mut self) -> String {
let id = self.id_counter; let id = self.id_counter;
self.id_counter += 1; // TODO improve this
id // 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<Mutex<State>>) -> Response {
match request.method.as_str() { match request.method.as_str() {
"GET" => match get(&request.uri, state) { "GET" => match get(&request.uri, state) {
Ok(s) => s, 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 // check admin hash
"DELETE" => Response::new(Status::Ok, vec![], "".to_string()), "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<State>) -> Result<Response, HandlingError>
&deserialize::<Thread>( &deserialize::<Thread>(
&state &state
.db .db
.get(&s.as_bytes()) .get(&s[1..])
.map_err(|_| HandlingError::ServerError(InternalError::DatabaseReadError))? .map_err(|_| HandlingError::ServerError(InternalError::DatabaseReadError))?
.ok_or(HandlingError::ClientError(RequestError::NotFound))?, .ok_or(HandlingError::ClientError(RequestError::NotFound))?,
) )
@ -128,29 +134,54 @@ fn get(path: &str, state: MutexGuard<State>) -> Result<Response, HandlingError>
} }
} }
fn post(request: Request, mut state: MutexGuard<State>) -> Response { fn post(request: Request, mut state: MutexGuard<State>) -> Result<Response, HandlingError> {
match request.uri.as_str() { match request.uri.as_str() {
// means we wish to create a new thread // means we wish to create a new thread
"/" => { "/" => {
// first we increment id // TODO fix unwrap
let id = state.next_id();
let content = dbg!(request.form().unwrap()); let content = dbg!(request.form().unwrap());
let id = state.next_id();
let thread = Thread(vec![Post::new( let thread = Thread(vec![Post::new(
id, &id,
None,
String::from(*content.get("content").unwrap()), 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::<Thread>(
&state
.db
.remove(&s[1..])
.map_err(|_| HandlingError::ServerError(InternalError::DatabaseWriteError))?
.ok_or(HandlingError::ClientError(RequestError::NotFound))?,
)
.unwrap();
thread.0.push(post);
state state
.db .db
.insert(id.to_ne_bytes(), serialize(&thread).unwrap()) .insert(&s[1..], serialize(&thread).unwrap())
.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()); let pool = ThreadPool::new(num_cpus::get());
// setup logger // setup logger
TermLogger::init( TermLogger::init(
LevelFilter::Warn, LevelFilter::Info,
Config::default(), Config::default(),
TerminalMode::Mixed, TerminalMode::Mixed,
ColorChoice::Auto, ColorChoice::Auto,
@ -189,10 +220,11 @@ fn main() {
let mut stream = match stream { let mut stream = match stream {
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
eprintln!("failed connection: {}", e); warn!("Failed connection: {}", e);
continue; continue;
} }
}; };
let state = Arc::clone(&state); let state = Arc::clone(&state);
pool.execute(move || { pool.execute(move || {
let ip = stream.peer_addr().unwrap(); let ip = stream.peer_addr().unwrap();
@ -202,6 +234,7 @@ fn main() {
stream.read(&mut buffer).unwrap(); stream.read(&mut buffer).unwrap();
// NOTE possibly problematic when we cosider images
let text = str::from_utf8(&buffer).unwrap().trim_matches(0 as char); let text = str::from_utf8(&buffer).unwrap().trim_matches(0 as char);
// ^-- gets rid of null at the end of buffer // ^-- gets rid of null at the end of buffer

@ -2,15 +2,15 @@ use std::fmt;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)] //#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Image { //pub struct Image {
pub filename: String, // pub filename: String,
pub img: Box<[u8]>, // pub img: Box<[u8]>,
} //}
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Post { pub struct Post {
pub id: u64, pub id: String,
//pub img: Option<Image>, //pub img: Option<Image>,
pub body: String, pub body: String,
} }
@ -30,9 +30,9 @@ impl Thread {
} }
impl Post { impl Post {
pub fn new(id: u64, img: Option<Image>, body: String) -> Self { pub fn new(id: &str, body: String) -> Self {
Self { Self {
id, id: id.to_string(),
//img, //img,
body, body,
} }

Loading…
Cancel
Save