|
|
@ -20,6 +20,8 @@ use threadpool::ThreadPool;
|
|
|
|
// statically linked index and favicon
|
|
|
|
// statically linked index and favicon
|
|
|
|
const INDEX: &'static str = include_str!("www/index.html");
|
|
|
|
const INDEX: &'static str = include_str!("www/index.html");
|
|
|
|
const FAVICON: &'static [u8] = include_bytes!("www/favicon.ico");
|
|
|
|
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)]
|
|
|
@ -44,15 +46,29 @@ lazy_static! {
|
|
|
|
static ref OPT: Opt = Opt::from_args();
|
|
|
|
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
|
|
|
|
/// top level handling of requests
|
|
|
|
fn handle(request: Request, database: Arc<Mutex<sled::Db>>, ip: SocketAddr) -> Response {
|
|
|
|
fn handle(request: Request, state: Arc<Mutex<State>>) -> Response {
|
|
|
|
let database = database.lock().unwrap();
|
|
|
|
let state = state.lock().unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
match request.method.as_str() {
|
|
|
|
match request.method.as_str() {
|
|
|
|
"GET" => get(&request.uri, database),
|
|
|
|
"GET" => get(&request.uri, state),
|
|
|
|
"POST" => {
|
|
|
|
"POST" => {
|
|
|
|
println!("{:?}", request);
|
|
|
|
post(request, state)
|
|
|
|
Response::new(Status::Ok, vec![], "".to_string())
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
// check admin hash
|
|
|
|
// check admin hash
|
|
|
|
"DELETE" => Response::new(Status::Ok, vec![], "".to_string()),
|
|
|
|
"DELETE" => Response::new(Status::Ok, vec![], "".to_string()),
|
|
|
@ -62,13 +78,14 @@ fn handle(request: Request, database: Arc<Mutex<sled::Db>>, ip: SocketAddr) -> R
|
|
|
|
|
|
|
|
|
|
|
|
/// get "/" returns head of every thread
|
|
|
|
/// get "/" returns head of every thread
|
|
|
|
/// or returns posts from thread with id in uri
|
|
|
|
/// or returns posts from thread with id in uri
|
|
|
|
fn get(path: &str, database: MutexGuard<sled::Db>) -> Response {
|
|
|
|
fn get(path: &str, state: MutexGuard<State>) -> Response {
|
|
|
|
match path {
|
|
|
|
match path {
|
|
|
|
// list threads in this case
|
|
|
|
// list threads in this case
|
|
|
|
"/" => {
|
|
|
|
"/" => {
|
|
|
|
let content = content(
|
|
|
|
let content = content(
|
|
|
|
"index",
|
|
|
|
"index",
|
|
|
|
&database
|
|
|
|
&state
|
|
|
|
|
|
|
|
.db
|
|
|
|
.iter()
|
|
|
|
.iter()
|
|
|
|
.map(|x| x.unwrap())
|
|
|
|
.map(|x| x.unwrap())
|
|
|
|
.map(|x| (x.0, deserialize::<Thread>(&x.1).unwrap()))
|
|
|
|
.map(|x| (x.0, deserialize::<Thread>(&x.1).unwrap()))
|
|
|
@ -78,12 +95,18 @@ fn get(path: &str, database: MutexGuard<sled::Db>) -> Response {
|
|
|
|
|
|
|
|
|
|
|
|
Response::new(Status::Ok, vec![], content)
|
|
|
|
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
|
|
|
|
// list specific thread here
|
|
|
|
// FIXME unwrap hell
|
|
|
|
// FIXME unwrap hell
|
|
|
|
s => {
|
|
|
|
s => {
|
|
|
|
let content = content(
|
|
|
|
let content = content(
|
|
|
|
s,
|
|
|
|
s,
|
|
|
|
&deserialize::<Thread>(&database.get(&s.as_bytes()).unwrap().unwrap())
|
|
|
|
&deserialize::<Thread>(&state.db.get(&s.as_bytes()).unwrap().unwrap())
|
|
|
|
.unwrap()
|
|
|
|
.unwrap()
|
|
|
|
.to_string()
|
|
|
|
.to_string()
|
|
|
|
);
|
|
|
|
);
|
|
|
@ -93,17 +116,30 @@ fn get(path: &str, database: MutexGuard<sled::Db>) -> Response {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn post(path: &str, database: MutexGuard<sled::Db>) -> Response {
|
|
|
|
fn post(request: Request, mut state: MutexGuard<State>) -> Response {
|
|
|
|
match path {
|
|
|
|
match request.uri.as_str() {
|
|
|
|
|
|
|
|
|
|
|
|
// means we wish to create a new thread
|
|
|
|
// 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
|
|
|
|
// means we wish to post in specific thread
|
|
|
|
s => {
|
|
|
|
s => {
|
|
|
|
|
|
|
|
Response::new(Status::Ok, vec![], String::from(""))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -112,6 +148,7 @@ fn delete(path: &str, database: Arc<Mutex<sled::Db>>) -> Response {
|
|
|
|
todo!();
|
|
|
|
todo!();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn content(name: &str, main: &str) -> String {
|
|
|
|
fn content(name: &str, main: &str) -> String {
|
|
|
|
INDEX
|
|
|
|
INDEX
|
|
|
|
.replace("{name}", &name)
|
|
|
|
.replace("{name}", &name)
|
|
|
@ -125,17 +162,21 @@ fn main() {
|
|
|
|
// create threadpool for incoming requests
|
|
|
|
// create threadpool for incoming requests
|
|
|
|
let pool = ThreadPool::new(num_cpus::get());
|
|
|
|
let pool = ThreadPool::new(num_cpus::get());
|
|
|
|
// open database
|
|
|
|
// 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
|
|
|
|
// TODO setup cache
|
|
|
|
//let cache = Arc::new(Cache(""));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// wait for requests
|
|
|
|
// wait for requests
|
|
|
|
for stream in listener.incoming() {
|
|
|
|
for stream in listener.incoming() {
|
|
|
|
let mut stream = stream.unwrap();
|
|
|
|
let mut stream = stream.unwrap();
|
|
|
|
let database = Arc::clone(&db);
|
|
|
|
let state = Arc::clone(&state);
|
|
|
|
pool.execute(move || {
|
|
|
|
pool.execute(move || {
|
|
|
|
let ip = stream.peer_addr().unwrap();
|
|
|
|
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
|
|
|
|
let mut buffer = [0; 1 << 10]; // 2 to the power of 10
|
|
|
|
// how do I implement images with this?
|
|
|
|
// how do I implement images with this?
|
|
|
|
|
|
|
|
|
|
|
@ -146,8 +187,7 @@ fn main() {
|
|
|
|
let request: Request = text.parse().unwrap();
|
|
|
|
let request: Request = text.parse().unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
// handle request
|
|
|
|
// handle request
|
|
|
|
// add database and cache here
|
|
|
|
stream.write(handle(request, state).to_string().as_bytes()).unwrap();
|
|
|
|
stream.write(handle(request, database, ip).to_string().as_bytes()).unwrap();
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|