simplified Thread representation

doctorpavel
Dawid J. Kubis 3 years ago
parent 31a8bf78cb
commit d8761eee20

155
Cargo.lock generated

@ -11,6 +11,25 @@ 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"
@ -49,6 +68,40 @@ 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"
@ -64,7 +117,7 @@ dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"strsim 0.8.0",
"textwrap",
"unicode-width",
"vec_map",
@ -102,6 +155,53 @@ 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 = "event-listener"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
[[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"
@ -132,6 +232,12 @@ dependencies = [
"wasi",
]
[[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"
@ -150,6 +256,12 @@ dependencies = [
"libc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "instant"
version = "0.1.12"
@ -164,6 +276,7 @@ name = "kchan"
version = "0.1.0"
dependencies = [
"bincode",
"cached",
"lazy_static",
"num_cpus",
"rand",
@ -223,6 +336,12 @@ 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"
@ -248,6 +367,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "pin-project-lite"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
[[package]]
name = "ppv-lite86"
version = "0.2.15"
@ -399,6 +524,12 @@ 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"
@ -472,6 +603,28 @@ dependencies = [
"num_cpus",
]
[[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"

@ -15,3 +15,4 @@ lazy_static = "1.4.0"
sled = "0.34.7"
bincode = "1.3.3"
serde = { version = "1.0.136", features = ["derive"] }
cached = "0.33.0"

@ -1,9 +1,8 @@
use std::fmt;
use std::str::FromStr;
use std::str::{FromStr, Lines};
const HTTP_VERSION: &str = "HTTP/1.1";
const HTTP_VERSION: &'static str = "HTTP/1.1";
// TODO use &str
#[derive(Debug)]
pub struct Request {
pub method: String,
@ -26,7 +25,7 @@ pub enum Status {
}
impl Status {
pub fn get_message(&self) -> &'static str {
pub fn message(&self) -> &'static str {
match self {
Self::Ok => "OK",
Self::NotFound => "NOT FOUND",
@ -34,16 +33,15 @@ impl Status {
}
}
// TODO implement this with display and enums
// TODO proper errors
impl FromStr for Request {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut iter = dbg!(s).lines();
let mut first = iter.nth(0).unwrap().split_whitespace();
let method = first.next().unwrap().to_string();
let uri = first.next().unwrap().to_string();
let mut iter = s.lines();
let mut first = iter.next().unwrap().split_whitespace();
let method = first.next().unwrap();
let uri = first.next().unwrap();
let mut headers: Vec<(String, String)> = vec![];
for line in &mut iter {
@ -56,10 +54,10 @@ impl FromStr for Request {
let body: String = iter.fold(String::new(), |a, b| format!("{}{}", a, b));
Ok(Self {
method,
uri,
headers,
body,
method: method.to_string(),
uri: uri.to_string(),
headers: headers,
body: body.to_string(),
})
}
}
@ -87,7 +85,7 @@ impl fmt::Display for Response {
"{} {} {}\n{}\n\n{}",
HTTP_VERSION,
self.status as i32,
self.status.get_message(),
self.status.message(),
headers,
self.body,
)

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

@ -2,47 +2,83 @@ 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 Post {
pub id: u64,
pub ip: [u8; 4],
pub date: String,
pub img: Option<Image>,
pub body: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Thread(Vec<Post>);
impl Thread {
pub fn head(&self) -> String {
let first = self.0[0];
format!(
"<article><div><span class=\"info\">{}</span></div>{}</article>",
first.id,
first.to_string(),
)
}
}
impl Post {
fn new(id: u64, ip: [u8; 4], date: String, img: Option<Image>, body: String) -> Self {
Self {
id,
ip,
date,
img,
body,
}
}
}
impl fmt::Display for Post {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"<article><div><span class=\"info\">{} {}</span></div><p>{}</p></article>",
self.id, self.date, self.body,
"<article>\
<img src=\"{}\" alt=\"img\">\
<div>\
<div class=\"meta\">\
<div>\
{}&nbsp;\
<strong>{}</strong>&nbsp;\
</div>\
<nav>\
<a href=\"#\">open</a>\
<a href=\"#\">quote</a>\
<a href=\"#\">reply</a>\
</nav>\
</div>\
<div class=\"image-info\">{}</div>\
{}\
</div>\
</article>",
self.id, self.date, self.id,
if let Some(s) = self.img {s.filename} else {"".to_string()},
self.body,
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Thread {
pub topic: String,
pub posts: Vec<Post>,
}
impl fmt::Display for Thread {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let posts: String = self
.posts
.0
.iter()
.fold(String::from(""), |a, b| format!("{}{}", a, b));
write!(f, "{}", posts)
}
}
impl Thread {
pub fn head(&self, id: &str) -> String {
format!(
"<article><div><span class=\"info\">{} {}</span></div>{}</article>",
id,
self.topic,
self.posts[0].to_string(),
)
}
}

@ -18,44 +18,7 @@
</header>
<main>
<div class="wrap">
<article>
<img src="placeholder.jpg" alt="img">
<div>
<div class="meta">
<div>
{ post_datetime }&nbsp;
<strong>{ post_id }</strong>&nbsp;
</div>
<nav>
<a href="#">open</a>
<a href="#">quote</a>
<a href="#">reply</a>
</nav>
</div>
<div class="image-info">{ image_filename }</div>
<div class="title">{ post_title }</div>
{ post_content }
</div>
</article>
<article>
<img src="placeholder.jpg" alt="img">
<div>
<div class="meta">
<div>
{ post_datetime }&nbsp;
<strong>{ post_id }</strong>&nbsp;
</div>
<nav>
<a href="#">open</a>
<a href="#">quote</a>
<a href="#">reply</a>
</nav>
</div>
<div class="image-info">{ image_filename }</div>
<div class="title">{ post_title }</div>
{ post_content }
</div>
</article>
{}
</div>
</main>
</head>

Loading…
Cancel
Save