diff --git a/src/ban.rs b/src/ban.rs index af60436..c455ccd 100644 --- a/src/ban.rs +++ b/src/ban.rs @@ -8,7 +8,7 @@ pub struct Item { } pub struct Ban { - index: HashMap>, + index: HashMap>>, timeout: Duration, } @@ -20,7 +20,7 @@ impl Ban { } } - pub fn get(&self, key: &Id20) -> Option<&DateTime> { + pub fn get(&self, key: &Id20) -> Option<&Option>> { self.index.get(key) } @@ -31,8 +31,10 @@ impl Ban { /// * return removed `Item` details pub fn update(&mut self, time: DateTime) -> Vec { let mut b = Vec::with_capacity(self.index.len()); - self.index.retain(|i, &mut expires| { - if time > expires { + self.index.retain(|i, &mut e| { + if let Some(expires) = e + && time > expires + { b.push(Item { expires, info_hash: i.as_string(), @@ -45,13 +47,23 @@ impl Ban { b } - /// * return expiration time - pub fn add(&mut self, key: Id20) -> DateTime { - let t = self - .index - .values() - .max() - .map_or(Local::now(), |t| *t + self.timeout); + /// Add torrent to the ban list + /// + /// If the `is_permanent` option is `true` - ban permanently, + /// or **automatically** count optimal ban time based on the current index max time and timeout offset value. + /// + /// * return expiration time or `None` if the ban is permanent + pub fn add(&mut self, key: Id20, is_permanent: bool) -> Option> { + let t = if is_permanent { + None + } else { + Some( + self.index + .values() + .max() + .map_or(Local::now(), |t| t.unwrap_or(Local::now()) + self.timeout), + ) + }; assert!(self.index.insert(key, t).is_none()); t } diff --git a/src/main.rs b/src/main.rs index 99debe3..87566dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -92,7 +92,13 @@ async fn main() -> Result<()> { continue; } if let Some(t) = ban.get(&i) { - log::debug!("torrent `{h}` is banned until {t}, skip for this queue."); + log::debug!( + "torrent `{h}` banned {}, skip for this queue.", + match t { + Some(v) => format!("until {v}"), + None => "permanently".into(), + } + ); continue; } log::debug!("index `{h}`..."); @@ -184,8 +190,11 @@ async fn main() -> Result<()> { .await { log::info!( - "skip awaiting the completion of preload `{h}` data (`{e}`), ban until {}.", - ban.add(i) + "skip awaiting the completion of preload `{h}` data (`{e}`), ban {}.", + match ban.add(i, false) { + Some(t) => format!("until {t}"), + None => "permanently".into(), // @TODO feature, do not unwrap + } ); session .delete(librqbit::api::TorrentIdOrHash::Id(id), false) @@ -207,13 +216,19 @@ async fn main() -> Result<()> { } Ok(_) => panic!(), Err(e) => log::warn!( - "failed to resolve torrent `{h}`: `{e}`, ban until {}.", - ban.add(i) + "failed to resolve torrent `{h}`: `{e}`, ban {}.", + match ban.add(i, false) { + Some(t) => format!("until {t}"), + None => "permanently".into(), // @TODO feature, do not unwrap + } ), }, Err(e) => log::info!( - "skip awaiting the completion of adding torrent `{h}` data (`{e}`), ban until {}.", - ban.add(i) + "skip awaiting the completion of adding torrent `{h}` data (`{e}`), ban {}.", + match ban.add(i, false) { + Some(t) => format!("until {t}"), + None => "permanently".into(), // @TODO feature, do not unwrap + } ), } }