diff --git a/src/server/connection.rs b/src/server/connection.rs index f4bcf48..893d446 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -39,7 +39,9 @@ impl Connection { "[{}] < [{}] request `{q}`...", self.address.server, self.address.client )); - self.session.request.add(&self.address.client, &q); + if let Some(ref i) = self.session.request { + i.add(&self.address.client, &q) + } self.session .clone() .public @@ -74,14 +76,14 @@ impl Connection { &if is_root { self.session.template.welcome( Some(s), - Some(self.session.request.count()), - Some(self.session.request.total(None)), + self.session.request.as_ref().map(|i| i.count()), + self.session.request.as_ref().map(|i| i.total(None)), ) } else { self.session.template.index( Some(s), - Some(self.session.request.count()), - Some(self.session.request.total(Some(q))), + self.session.request.as_ref().map(|i| i.count()), + self.session.request.as_ref().map(|i| i.total(Some(q))), ) } } diff --git a/src/session.rs b/src/session.rs index 4fd5271..7690491 100644 --- a/src/session.rs +++ b/src/session.rs @@ -11,7 +11,7 @@ pub struct Session { pub access_log: AccessLog, pub debug: Debug, pub public: Public, - pub request: Request, + pub request: Option, pub template: Template, } @@ -22,13 +22,15 @@ impl Session { access_log: AccessLog::init(config)?, debug: Debug::init(config)?, public: Public::init(config)?, - request: Request::init( - // do not int request collector if its features not in use - template.welcome.contains("{hosts}") - || template.welcome.contains("{hits}") - || template.index.contains("{hosts}") - || template.index.contains("{hits}"), - ), + request: if template.welcome.contains("{hosts}") + || template.welcome.contains("{hits}") + || template.index.contains("{hosts}") + || template.index.contains("{hits}") + { + Some(Request::new()) + } else { + None // do not int request collector if its features not in use + }, template, }) } diff --git a/src/session/request.rs b/src/session/request.rs index 7afc84b..a5a029f 100644 --- a/src/session/request.rs +++ b/src/session/request.rs @@ -9,95 +9,81 @@ use std::{ /// Collect peer requests for stats and visitors count pub struct Request { - index: Option>>>, + index: RwLock>>, // prevent log file overflow by recording error events once is_max_peers_reported: RwLock, is_max_peer_queries_reported: RwLock, } impl Request { - pub fn init(is_enabled: bool) -> Self { + pub fn new() -> Self { Self { - index: if is_enabled { - Some(RwLock::new(HashMap::with_capacity(100))) - } else { - None - }, + index: RwLock::new(HashMap::with_capacity(100)), is_max_peers_reported: RwLock::new(false), is_max_peer_queries_reported: RwLock::new(false), } } pub fn add(&self, peer: &SocketAddr, query: &str) { - if let Some(ref this) = self.index { - let mut index = this.write().unwrap(); + let mut index = self.index.write().unwrap(); - // Critical limits to forcefully free one memory slot(s) for the new record - // * the query len is already limited by the read buffer (1024 bytes * LIMIT) - // * make it optional @TODO - const INDEX_MAX_PEERS: usize = 1000; - const INDEX_MAX_PEER_QUERIES: usize = 1000; + // Critical limits to forcefully free one memory slot(s) for the new record + // * the query len is already limited by the read buffer (1024 bytes * LIMIT) + // * make it optional @TODO + const INDEX_MAX_PEERS: usize = 1000; + const INDEX_MAX_PEER_QUERIES: usize = 1000; - if index.len() >= INDEX_MAX_PEERS { - let mut r = self.is_max_peers_reported.write().unwrap(); + if index.len() >= INDEX_MAX_PEERS { + let mut r = self.is_max_peers_reported.write().unwrap(); + if !*r { + *r = true; + eprintln!("Max peers index limit ({INDEX_MAX_PEERS}) reached"); + } + let k = *index.keys().next().unwrap(); + index.remove(&k); // * there is no difference which one key to free for the HashMap + } + for queries in index.values_mut() { + if queries.len() >= INDEX_MAX_PEER_QUERIES { + let mut r = self.is_max_peer_queries_reported.write().unwrap(); if !*r { *r = true; - eprintln!("Max peers index limit ({INDEX_MAX_PEERS}) reached"); + eprintln!("Max queries limit ({INDEX_MAX_PEER_QUERIES}) reached for `{peer}`"); } - let k = *index.keys().next().unwrap(); - index.remove(&k); // * there is no difference which one key to free for the HashMap + queries.truncate(INDEX_MAX_PEER_QUERIES - 1) // free last slot for one query } - for queries in index.values_mut() { - if queries.len() >= INDEX_MAX_PEER_QUERIES { - let mut r = self.is_max_peer_queries_reported.write().unwrap(); - if !*r { - *r = true; - eprintln!( - "Max queries limit ({INDEX_MAX_PEER_QUERIES}) reached for `{peer}`" - ); - } - queries.truncate(INDEX_MAX_PEER_QUERIES - 1) // free last slot for one query - } - } - - // Cleanup deprecated records - // * this is expensive for each request, use schedule instead @TODO - let d = chrono::Local::now().date_naive(); - for queries in index.values_mut() { - queries.retain(|q| q.time.date_naive() == d) - } - index.retain(|_, q| !q.is_empty()); - - // handle new record - index - .entry(peer.ip()) - .and_modify(|c| c.push(Query::new(query))) - .or_insert(vec![Query::new(query)]); } + + // Cleanup deprecated records + // * this is expensive for each request, use schedule instead @TODO + let d = chrono::Local::now().date_naive(); + for queries in index.values_mut() { + queries.retain(|q| q.time.date_naive() == d) + } + index.retain(|_, q| !q.is_empty()); + + // handle new record + index + .entry(peer.ip()) + .and_modify(|c| c.push(Query::new(query))) + .or_insert(vec![Query::new(query)]); } pub fn count(&self) -> usize { - if let Some(ref i) = self.index { - i.read().unwrap().len() - } else { - 0 - } + self.index.read().unwrap().len() } pub fn total(&self, query_prefix: Option<&str>) -> usize { let mut t = 0; - if let Some(ref i) = self.index { - for queries in i.read().unwrap().values() { - match query_prefix { - Some(p) => { - for q in queries { - if q.value.starts_with(p) { - t += 1 - } + for queries in self.index.read().unwrap().values() { + match query_prefix { + Some(p) => { + for q in queries { + if q.value.starts_with(p) { + t += 1 } } - None => t += queries.len(), } + None => t += queries.len(), } } t