|
|
|
@ -5,20 +5,23 @@ use crate::http::{Request, Response, Status};
|
|
|
|
|
use crate::post::{Post, Thread};
|
|
|
|
|
|
|
|
|
|
use std::io::{Read, Write};
|
|
|
|
|
use std::net::{TcpListener, TcpStream};
|
|
|
|
|
use std::net::{TcpListener, TcpStream, SocketAddr};
|
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
use std::str;
|
|
|
|
|
use std::str::from_utf8;
|
|
|
|
|
use std::sync::{Arc, Mutex, MutexGuard};
|
|
|
|
|
|
|
|
|
|
use bincode::{deserialize, serialize};
|
|
|
|
|
use cached::proc_macro::cached;
|
|
|
|
|
use lazy_static::lazy_static;
|
|
|
|
|
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");
|
|
|
|
|
|
|
|
|
|
// represents command line arguments
|
|
|
|
|
#[derive(StructOpt, Debug)]
|
|
|
|
|
struct Opt {
|
|
|
|
|
#[structopt(short, long, default_value = "8000")]
|
|
|
|
@ -41,43 +44,80 @@ lazy_static! {
|
|
|
|
|
static ref OPT: Opt = Opt::from_args();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO cache
|
|
|
|
|
//#[derive(Debug)]
|
|
|
|
|
//struct Cache<'a>(&'a str);
|
|
|
|
|
|
|
|
|
|
fn handle(request: Request, database: Arc<Mutex<sled::Db>>) -> String {
|
|
|
|
|
/// top level handling of requests
|
|
|
|
|
fn handle(request: Request, database: Arc<Mutex<sled::Db>>, ip: SocketAddr) -> Response {
|
|
|
|
|
let database = database.lock().unwrap();
|
|
|
|
|
|
|
|
|
|
match request.method.as_str() {
|
|
|
|
|
"GET" => get(&request.uri, database),
|
|
|
|
|
"POST" => "HTTP/1.1 200 OK".to_string(),
|
|
|
|
|
"POST" => {
|
|
|
|
|
println!("{:?}", request);
|
|
|
|
|
Response::new(Status::Ok, vec![], "".to_string())
|
|
|
|
|
},
|
|
|
|
|
// check admin hash
|
|
|
|
|
"DELETE" => "HTTP/1.1 200 OK".to_string(),
|
|
|
|
|
_ => "".to_string(),
|
|
|
|
|
"DELETE" => Response::new(Status::Ok, vec![], "".to_string()),
|
|
|
|
|
_ => Response::new(Status::Ok, vec![], "".to_string()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get(path: &str, database: MutexGuard<sled::Db>) -> String {
|
|
|
|
|
/// get "/" returns head of every thread
|
|
|
|
|
/// or returns posts from thread with id in uri
|
|
|
|
|
fn get(path: &str, database: MutexGuard<sled::Db>) -> Response {
|
|
|
|
|
match path {
|
|
|
|
|
// list threads in this case
|
|
|
|
|
"/" => {
|
|
|
|
|
let content = INDEX.to_string().replace(
|
|
|
|
|
"{}",
|
|
|
|
|
&*database
|
|
|
|
|
let content = content(
|
|
|
|
|
"index",
|
|
|
|
|
&database
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|x| x.unwrap())
|
|
|
|
|
.map(|x| (x.0, deserialize::<Thread>(&x.1).unwrap()))
|
|
|
|
|
.map(|x| x.1.head(from_utf8(&x.0).unwrap()))
|
|
|
|
|
.map(|x| x.1.head())
|
|
|
|
|
.fold(String::from(""), |a, b| format!("{}{}", a, b)),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Response::new(Status::Ok, vec![], content).to_string()
|
|
|
|
|
Response::new(Status::Ok, vec![], content)
|
|
|
|
|
}
|
|
|
|
|
// list specific thread here
|
|
|
|
|
s => "".to_string(),
|
|
|
|
|
// FIXME unwrap hell
|
|
|
|
|
s => {
|
|
|
|
|
let content = content(
|
|
|
|
|
s,
|
|
|
|
|
&deserialize::<Thread>(&database.get(&s.as_bytes()).unwrap().unwrap())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.to_string()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Response::new(Status::Ok, vec![], content)
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn post(path: &str, database: MutexGuard<sled::Db>) -> Response {
|
|
|
|
|
match path {
|
|
|
|
|
|
|
|
|
|
// means we wish to create a new thread
|
|
|
|
|
"/" => {
|
|
|
|
|
// first we generate unique id
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// means we wish to post in specific thread
|
|
|
|
|
s => {
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn delete(path: &str, database: Arc<Mutex<sled::Db>>) -> Response {
|
|
|
|
|
todo!();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn content(name: &str, main: &str) -> String {
|
|
|
|
|
INDEX
|
|
|
|
|
.replace("{name}", &name)
|
|
|
|
|
.replace("{}", &main)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
// TODO do this without unwrap
|
|
|
|
|
// bind listener to local adress and port
|
|
|
|
@ -94,7 +134,7 @@ fn main() {
|
|
|
|
|
let mut stream = stream.unwrap();
|
|
|
|
|
let database = Arc::clone(&db);
|
|
|
|
|
pool.execute(move || {
|
|
|
|
|
let ip = stream.peer_addr();
|
|
|
|
|
let ip = stream.peer_addr().unwrap();
|
|
|
|
|
// TODO check if valid ip before reading request
|
|
|
|
|
let mut buffer = [0; 1 << 10]; // 2 to the power of 10
|
|
|
|
|
// how do I implement images with this?
|
|
|
|
@ -107,7 +147,7 @@ fn main() {
|
|
|
|
|
|
|
|
|
|
// handle request
|
|
|
|
|
// add database and cache here
|
|
|
|
|
stream.write(handle(request, database).as_bytes()).unwrap();
|
|
|
|
|
stream.write(handle(request, database, ip).to_string().as_bytes()).unwrap();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|