Don't put the complete site info into a mutex, use atomic ints where possible
This commit is contained in:
parent
999290b1df
commit
58d02c86e2
110
src/main.rs
110
src/main.rs
@ -5,7 +5,10 @@ use std::{
|
|||||||
io::{BufReader, Error, ErrorKind, Result, prelude::*},
|
io::{BufReader, Error, ErrorKind, Result, prelude::*},
|
||||||
net::{TcpListener, TcpStream},
|
net::{TcpListener, TcpStream},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::{Arc, Mutex},
|
sync::{
|
||||||
|
Arc, Mutex,
|
||||||
|
atomic::{AtomicUsize, Ordering},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use data_stream::{
|
use data_stream::{
|
||||||
@ -79,18 +82,21 @@ struct Comment {
|
|||||||
text: Box<str>,
|
text: Box<str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default)]
|
||||||
struct SiteInfo {
|
struct SiteInfo {
|
||||||
comments: Vec<Comment>,
|
comments: Mutex<Vec<Comment>>,
|
||||||
visits: usize,
|
visits: AtomicUsize,
|
||||||
up: usize,
|
up: AtomicUsize,
|
||||||
down: usize,
|
down: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SizeSettings> ToStream<S> for SiteInfo {
|
impl<S: SizeSettings> ToStream<S> for SiteInfo {
|
||||||
fn to_stream<W: Write>(&self, stream: &mut W) -> Result<()> {
|
fn to_stream<W: Write>(&self, stream: &mut W) -> Result<()> {
|
||||||
S::size_to_stream(self.comments.len(), stream)?;
|
let Ok(comments) = self.comments.lock() else {
|
||||||
for Comment { name, text } in &self.comments {
|
return Err(std::io::ErrorKind::ResourceBusy.into());
|
||||||
|
};
|
||||||
|
S::size_to_stream(comments.len(), stream)?;
|
||||||
|
for Comment { name, text } in comments.iter() {
|
||||||
let name_bytes = name.as_bytes();
|
let name_bytes = name.as_bytes();
|
||||||
S::size_to_stream(name_bytes.len(), stream)?;
|
S::size_to_stream(name_bytes.len(), stream)?;
|
||||||
stream.write_all(name_bytes)?;
|
stream.write_all(name_bytes)?;
|
||||||
@ -100,9 +106,9 @@ impl<S: SizeSettings> ToStream<S> for SiteInfo {
|
|||||||
stream.write_all(text_bytes)?;
|
stream.write_all(text_bytes)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
S::size_to_stream(self.visits, stream)?;
|
S::size_to_stream(self.visits.load(Ordering::Acquire), stream)?;
|
||||||
S::size_to_stream(self.up, stream)?;
|
S::size_to_stream(self.up.load(Ordering::Acquire), stream)?;
|
||||||
S::size_to_stream(self.down, stream)?;
|
S::size_to_stream(self.down.load(Ordering::Acquire), stream)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -111,25 +117,27 @@ impl<S: SizeSettings> ToStream<S> for SiteInfo {
|
|||||||
impl<S: SizeSettings> FromStream<S> for SiteInfo {
|
impl<S: SizeSettings> FromStream<S> for SiteInfo {
|
||||||
fn from_stream<R: Read>(stream: &mut R) -> Result<Self> {
|
fn from_stream<R: Read>(stream: &mut R) -> Result<Self> {
|
||||||
let size = S::size_from_stream(stream)?;
|
let size = S::size_from_stream(stream)?;
|
||||||
let comments = (0..size)
|
let comments = Mutex::new(
|
||||||
.map(|_| {
|
(0..size)
|
||||||
let name_bytes = <Vec<_> as FromStream<S>>::from_stream(stream)?;
|
.map(|_| {
|
||||||
let name = std::str::from_utf8(&name_bytes)
|
let name_bytes = <Vec<_> as FromStream<S>>::from_stream(stream)?;
|
||||||
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?
|
let name = std::str::from_utf8(&name_bytes)
|
||||||
.into();
|
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?
|
||||||
|
.into();
|
||||||
|
|
||||||
let text_bytes = <Vec<_> as FromStream<S>>::from_stream(stream)?;
|
let text_bytes = <Vec<_> as FromStream<S>>::from_stream(stream)?;
|
||||||
let text = std::str::from_utf8(&text_bytes)
|
let text = std::str::from_utf8(&text_bytes)
|
||||||
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?
|
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
Ok(Comment { name, text })
|
Ok(Comment { name, text })
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?,
|
||||||
|
);
|
||||||
|
|
||||||
let visits = S::size_from_stream(stream)?;
|
let visits = S::size_from_stream(stream)?.into();
|
||||||
let up = S::size_from_stream(stream)?;
|
let up = S::size_from_stream(stream)?.into();
|
||||||
let down = S::size_from_stream(stream)?;
|
let down = S::size_from_stream(stream)?.into();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
comments,
|
comments,
|
||||||
@ -142,7 +150,7 @@ impl<S: SizeSettings> FromStream<S> for SiteInfo {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Context {
|
struct Context {
|
||||||
infos: HashMap<Box<str>, Arc<Mutex<SiteInfo>>>,
|
infos: HashMap<Box<str>, Arc<SiteInfo>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_connection(
|
fn handle_connection(
|
||||||
@ -345,13 +353,13 @@ fn handle_connection(
|
|||||||
match context.infos.entry(relative_path.clone().into_boxed_str()) {
|
match context.infos.entry(relative_path.clone().into_boxed_str()) {
|
||||||
Occupied(o) => o.get().clone(),
|
Occupied(o) => o.get().clone(),
|
||||||
Vacant(v) => v
|
Vacant(v) => v
|
||||||
.insert(Arc::new(Mutex::new(
|
.insert(Arc::new(
|
||||||
File::open(&data_path)
|
File::open(&data_path)
|
||||||
.map(|mut file| {
|
.map(|mut file| {
|
||||||
from_stream::<PortableSettings, _, _>(&mut file).unwrap_or_default()
|
from_stream::<PortableSettings, _, _>(&mut file).unwrap_or_default()
|
||||||
})
|
})
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
)))
|
))
|
||||||
.clone(),
|
.clone(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -408,7 +416,7 @@ struct DocumentPaths<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_relative_connection(
|
fn handle_relative_connection(
|
||||||
info: Arc<Mutex<SiteInfo>>,
|
info: Arc<SiteInfo>,
|
||||||
mut stream: TcpStream,
|
mut stream: TcpStream,
|
||||||
body: &str,
|
body: &str,
|
||||||
relative_path: &str,
|
relative_path: &str,
|
||||||
@ -464,26 +472,30 @@ fn handle_relative_connection(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let info = if let Ok(mut info) = info.lock() {
|
let comments = {
|
||||||
|
let Ok(mut comments) = info.comments.lock() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
if let (Some(name), Some(text)) = (name, text) {
|
if let (Some(name), Some(text)) = (name, text) {
|
||||||
info.comments.push(Comment { name, text });
|
comments.push(Comment { name, text });
|
||||||
}
|
}
|
||||||
if up {
|
comments.clone()
|
||||||
info.up += 1;
|
};
|
||||||
}
|
let up = if up {
|
||||||
if down {
|
info.up.fetch_add(1, Ordering::Relaxed)
|
||||||
info.down += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.visits += 1;
|
|
||||||
|
|
||||||
info.clone()
|
|
||||||
} else {
|
} else {
|
||||||
return;
|
info.up.load(Ordering::Relaxed)
|
||||||
|
};
|
||||||
|
let down = if down {
|
||||||
|
info.down.fetch_add(1, Ordering::Relaxed)
|
||||||
|
} else {
|
||||||
|
info.down.load(Ordering::Relaxed)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let visits = info.visits.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
if let Ok(mut file) = File::create(file_paths.data) {
|
if let Ok(mut file) = File::create(file_paths.data) {
|
||||||
if to_stream::<PortableSettings, _, _>(&info, &mut file).is_err() {
|
if to_stream::<PortableSettings, _, _>(&*info, &mut file).is_err() {
|
||||||
eprintln!("Error saving data!");
|
eprintln!("Error saving data!");
|
||||||
eprintln!();
|
eprintln!();
|
||||||
}
|
}
|
||||||
@ -507,11 +519,7 @@ fn handle_relative_connection(
|
|||||||
let _ = writeln!(stream, "<a href=\"/{parent_path}\"><< Back</a>");
|
let _ = writeln!(stream, "<a href=\"/{parent_path}\"><< Back</a>");
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = writeln!(
|
let _ = writeln!(stream, "<p>👁️{visits} 💖️{up} 💔️{down}</p>");
|
||||||
stream,
|
|
||||||
"<p>👁️{} 💖️{} 💔️{}</p>",
|
|
||||||
info.visits, info.up, info.down
|
|
||||||
);
|
|
||||||
|
|
||||||
section(&mut stream);
|
section(&mut stream);
|
||||||
|
|
||||||
@ -688,7 +696,7 @@ fn handle_relative_connection(
|
|||||||
};
|
};
|
||||||
let _ = stream.write_all(html.into_string().as_bytes());
|
let _ = stream.write_all(html.into_string().as_bytes());
|
||||||
|
|
||||||
for Comment { name, text } in &info.comments {
|
for Comment { name, text } in comments {
|
||||||
let html = html! {
|
let html = html! {
|
||||||
fieldset {
|
fieldset {
|
||||||
legend { (name) }
|
legend { (name) }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user