Add Quota to Connectivity View (#2612)

* add imap::get_quota_roots()

* schedule quote-checking job on getting connectivity-html

* get quota and debug print it

* basic quota output

* update quota at most once per minute, emit event on changes

* use more meaningful names

* add some comments, move update_recent_quota() to quota.rs

* show root name only if there are several roots

* make clippy happy, some refactorings

* allow only one update-quota job per time

* add now supported QUOTA to standards.md
This commit is contained in:
bjoern
2021-08-20 10:40:24 +02:00
committed by GitHub
parent 53cd633e8d
commit 5399c9151d
10 changed files with 283 additions and 11 deletions

View File

@@ -3,9 +3,14 @@ use std::{ops::Deref, sync::Arc};
use async_std::sync::{Mutex, RwLockReadGuard};
use crate::dc_tools::time;
use crate::events::EventType;
use crate::quota::{
QUOTA_ERROR_THRESHOLD_PERCENTAGE, QUOTA_MAX_AGE_SECONDS, QUOTA_WARN_THRESHOLD_PERCENTAGE,
};
use crate::{config::Config, scheduler::Scheduler};
use crate::{context::Context, log::LogExt};
use humansize::{file_size_opts, FileSize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumProperty, PartialOrd, Ord)]
pub enum Connectivity {
@@ -403,6 +408,81 @@ impl Context {
ret += &*escaper::encode_minimal(&detailed.to_string_smtp(self));
ret += "</li></ul>";
ret += "<h3>Quota</h3><ul>";
let quota = self.quota.read().await;
if let Some(quota) = &*quota {
match &quota.recent {
Ok(quota) => {
let roots_cnt = quota.len();
for (root_name, resources) in quota {
use async_imap::types::QuotaResourceName::*;
for resource in resources {
ret += "<li>";
let usage_percent = resource.get_usage_percentage();
if usage_percent >= QUOTA_ERROR_THRESHOLD_PERCENTAGE {
ret += "<span class=\"red dot\"></span> ";
} else if usage_percent >= QUOTA_WARN_THRESHOLD_PERCENTAGE {
ret += "<span class=\"yellow dot\"></span> ";
} else {
ret += "<span class=\"green dot\"></span> ";
}
// root name is empty eg. for gmail and redundant eg. for riseup.
// therefore, use it only if there are really several roots.
if roots_cnt > 1 && !root_name.is_empty() {
ret +=
&format!("<b>{}:</b> ", &*escaper::encode_minimal(root_name));
} else {
info!(self, "connectivity: root name hidden: \"{}\"", root_name);
}
ret += &match &resource.name {
Atom(resource_name) => {
format!(
"<b>{}:</b> {} of {} used",
&*escaper::encode_minimal(resource_name),
resource.usage.to_string(),
resource.limit.to_string(),
)
}
Message => {
format!(
"<b>Messages:</b> {} of {} used",
resource.usage.to_string(),
resource.limit.to_string(),
)
}
Storage => {
let usage = (resource.usage * 1024)
.file_size(file_size_opts::BINARY)
.unwrap_or_default();
let limit = (resource.limit * 1024)
.file_size(file_size_opts::BINARY)
.unwrap_or_default();
format!("<b>Storage:</b> {} of {} used", usage, limit)
}
};
ret += &format!(" ({}%)", usage_percent);
ret += "</li>";
}
}
}
Err(e) => {
ret += format!("<li>{}</li>", e).as_str();
}
}
if quota.modified + QUOTA_MAX_AGE_SECONDS < time() {
self.schedule_quota_update().await;
}
} else {
ret += "<li>One moment...</li>";
self.schedule_quota_update().await;
}
ret += "</ul>";
ret += "</body></html>\n";
ret
}