Files
RustBox/src/routes/quota.rs
T
Mateusz Gruszczyński a643e7e3ab
RustBox CI / rustbox (push) Waiting to run
v0.0.5
2026-10-30 12:06:44 +01:00

104 lines
3.3 KiB
Rust

use std::sync::Arc;
use std::time::Duration;
use axum::response::{IntoResponse, Response};
use axum::{Extension, Json};
use serde::Serialize;
use crate::auth::session::SessionState;
use crate::config::AppConfig;
use crate::db;
use crate::error::AppError;
use crate::imap::client::{ImapClient, ImapCredentials};
#[derive(Serialize)]
struct QuotaResponse {
usage_bytes: Option<u64>,
limit_bytes: Option<u64>,
}
pub async fn get_quota(
Extension(session): Extension<SessionState>,
Extension(config): Extension<Arc<AppConfig>>,
Extension(imap_client): Extension<Arc<dyn ImapClient>>,
) -> Result<Response, AppError> {
let creds = ImapCredentials {
host: session.imap_host.clone(),
port: session.imap_port,
tls: session.imap_tls,
tls_verify: session.imap_tls_verify,
email: session.email.clone(),
password: session.password.clone(),
};
let quota = imap_client.get_quota(&creds).await.unwrap_or(None);
let resp = match quota {
Some(q) => QuotaResponse {
usage_bytes: Some(q.usage_bytes),
limit_bytes: if q.limit_bytes > 0 {
Some(q.limit_bytes)
} else {
None
},
},
None => {
let database = db::pool::UserDb::new(&config.data_dir, &session.user_hash);
if let Some(bytes) = database
.run(db::messages::cached_storage_bytes)
.await
.map_err(AppError::InternalError)?
{
return Ok(Json(QuotaResponse {
usage_bytes: Some(bytes),
limit_bytes: None,
})
.into_response());
}
let data_dir = config.data_dir.clone();
let user_hash = session.user_hash.clone();
let folders: Vec<String> = tokio::task::spawn_blocking(move || {
let conn = db::pool::open_user_db(&data_dir, &user_hash)?;
Ok::<_, String>(
db::folders::get_all_folders(&conn)
.unwrap_or_default()
.into_iter()
.map(|f| f.name)
.collect(),
)
})
.await
.map_err(|e| AppError::InternalError(format!("Task error: {e}")))?
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?;
let total = tokio::time::timeout(
Duration::from_secs(90),
crate::imap::pool::background(async {
let mut sum: u64 = 0;
for folder in &folders {
sum += imap_client.fetch_folder_size(&creds, folder).await?;
}
Ok::<_, crate::imap::error::ImapError>(sum)
}),
)
.await;
let total = match total {
Ok(Ok(total)) => Some(total),
other => {
tracing::warn!(error = ?other, "Quota folder-size fallback failed");
None
}
};
QuotaResponse {
usage_bytes: total,
limit_bytes: None,
}
}
};
Ok(Json(resp).into_response())
}