mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 01:16:31 +03:00
feat: adapt quota warning to automatic cleanup
This commit is contained in:
98
src/quota.rs
98
src/quota.rs
@@ -6,33 +6,17 @@ use std::time::Duration;
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use async_imap::types::{Quota, QuotaResource};
|
||||
|
||||
use crate::chat::add_device_msg_with_importance;
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::imap::session::Session as ImapSession;
|
||||
use crate::log::warn;
|
||||
use crate::message::Message;
|
||||
use crate::tools::{self, time_elapsed};
|
||||
use crate::{EventType, stock_str};
|
||||
|
||||
/// warn about a nearly full mailbox after this usage percentage is reached.
|
||||
/// quota icon is "yellow".
|
||||
/// quota icon in connectivity is "yellow".
|
||||
pub const QUOTA_WARN_THRESHOLD_PERCENTAGE: u64 = 80;
|
||||
|
||||
/// warning again after this usage percentage is reached,
|
||||
/// quota icon is "red".
|
||||
/// quota icon in connectivity is "red".
|
||||
pub const QUOTA_ERROR_THRESHOLD_PERCENTAGE: u64 = 95;
|
||||
|
||||
/// if quota is below this value (again),
|
||||
/// QuotaExceeding is cleared.
|
||||
///
|
||||
/// This value should be a bit below QUOTA_WARN_THRESHOLD_PERCENTAGE to
|
||||
/// avoid jittering and lots of warnings when quota is exactly at the warning threshold.
|
||||
///
|
||||
/// We do not repeat warnings on a daily base or so as some provider
|
||||
/// providers report bad values and we would then spam the user.
|
||||
pub const QUOTA_ALLCLEAR_PERCENTAGE: u64 = 75;
|
||||
|
||||
/// Server quota information with an update timestamp.
|
||||
#[derive(Debug)]
|
||||
pub struct QuotaInfo {
|
||||
@@ -70,37 +54,6 @@ async fn get_unique_quota_roots_and_usage(
|
||||
Ok(unique_quota_roots)
|
||||
}
|
||||
|
||||
fn get_highest_usage<'t>(
|
||||
unique_quota_roots: &'t BTreeMap<String, Vec<QuotaResource>>,
|
||||
) -> Result<(u64, &'t String, &'t QuotaResource)> {
|
||||
let mut highest: Option<(u64, &'t String, &QuotaResource)> = None;
|
||||
for (name, resources) in unique_quota_roots {
|
||||
for r in resources {
|
||||
let usage_percent = r.get_usage_percentage();
|
||||
match highest {
|
||||
None => {
|
||||
highest = Some((usage_percent, name, r));
|
||||
}
|
||||
Some((up, ..)) => {
|
||||
if up <= usage_percent {
|
||||
highest = Some((usage_percent, name, r));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
highest.context("no quota_resource found, this is unexpected")
|
||||
}
|
||||
|
||||
/// Checks if a quota warning is needed.
|
||||
pub fn needs_quota_warning(curr_percentage: u64, warned_at_percentage: u64) -> bool {
|
||||
(curr_percentage >= QUOTA_WARN_THRESHOLD_PERCENTAGE
|
||||
&& warned_at_percentage < QUOTA_WARN_THRESHOLD_PERCENTAGE)
|
||||
|| (curr_percentage >= QUOTA_ERROR_THRESHOLD_PERCENTAGE
|
||||
&& warned_at_percentage < QUOTA_ERROR_THRESHOLD_PERCENTAGE)
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Returns whether the quota value needs an update. If so, `update_recent_quota()` should be
|
||||
/// called.
|
||||
@@ -134,32 +87,6 @@ impl Context {
|
||||
Err(anyhow!(stock_str::not_supported_by_provider(self)))
|
||||
};
|
||||
|
||||
if let Ok(quota) = "a {
|
||||
match get_highest_usage(quota) {
|
||||
Ok((highest, _, _)) => {
|
||||
if needs_quota_warning(
|
||||
highest,
|
||||
self.get_config_int(Config::QuotaExceeding).await? as u64,
|
||||
) {
|
||||
self.set_config_internal(
|
||||
Config::QuotaExceeding,
|
||||
Some(&highest.to_string()),
|
||||
)
|
||||
.await?;
|
||||
let mut msg = Message::new_text(stock_str::quota_exceeding(self, highest));
|
||||
add_device_msg_with_importance(self, None, Some(&mut msg), true).await?;
|
||||
} else if highest <= QUOTA_ALLCLEAR_PERCENTAGE {
|
||||
self.set_config_internal(Config::QuotaExceeding, None)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Err(err) => warn!(
|
||||
self,
|
||||
"Transport {transport_id}: Cannot get highest quota usage: {err:#}"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
self.quota.write().await.insert(
|
||||
transport_id,
|
||||
QuotaInfo {
|
||||
@@ -179,29 +106,10 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::test_utils::TestContextManager;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_needs_quota_warning() -> Result<()> {
|
||||
assert!(!needs_quota_warning(0, 0));
|
||||
assert!(!needs_quota_warning(10, 0));
|
||||
assert!(!needs_quota_warning(70, 0));
|
||||
assert!(!needs_quota_warning(75, 0));
|
||||
assert!(!needs_quota_warning(79, 0));
|
||||
assert!(needs_quota_warning(80, 0));
|
||||
assert!(needs_quota_warning(81, 0));
|
||||
assert!(!needs_quota_warning(85, 80));
|
||||
assert!(!needs_quota_warning(85, 81));
|
||||
assert!(needs_quota_warning(95, 82));
|
||||
assert!(!needs_quota_warning(97, 95));
|
||||
assert!(!needs_quota_warning(97, 96));
|
||||
assert!(!needs_quota_warning(1000, 96));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[expect(clippy::assertions_on_constants)]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_quota_thresholds() -> anyhow::Result<()> {
|
||||
assert!(QUOTA_ALLCLEAR_PERCENTAGE > 50);
|
||||
assert!(QUOTA_ALLCLEAR_PERCENTAGE < QUOTA_WARN_THRESHOLD_PERCENTAGE);
|
||||
assert!(0 < QUOTA_WARN_THRESHOLD_PERCENTAGE);
|
||||
assert!(QUOTA_WARN_THRESHOLD_PERCENTAGE < QUOTA_ERROR_THRESHOLD_PERCENTAGE);
|
||||
assert!(QUOTA_ERROR_THRESHOLD_PERCENTAGE < 100);
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user