This commit is contained in:
rustmailer
2026-05-07 11:56:08 +08:00
parent 2802c7ea07
commit 7eacfbfb20
27 changed files with 465 additions and 353 deletions
+1 -38
View File
@@ -17,11 +17,11 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use crate::{
raise_error, utc_now,
{
database::{async_find_impl, delete_impl, manager::DB_MANAGER, update_impl, upsert_impl},
error::{code::ErrorCode, BichonResult},
},
raise_error, utc_now,
};
use native_db::*;
use native_model::{native_model, Model};
@@ -91,7 +91,6 @@ pub struct DownloadState {
pub history: Vec<DownloadSession>,
pub last_trigger_at: i64,
pub last_finished_at: Option<i64>,
pub global_errors: Vec<AccountError>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
@@ -122,7 +121,6 @@ impl DownloadState {
}),
history: Default::default(),
last_finished_at: Default::default(),
global_errors: Default::default(),
};
upsert_impl(DB_MANAGER.envelope_db(), state).await
}
@@ -305,39 +303,4 @@ impl DownloadState {
})
.await
}
pub async fn append_global_error_message(account_id: u64, error: String) -> BichonResult<()> {
Self::update_state(account_id, move |current| {
let mut updated = current.clone();
updated.append_global_error_log(error);
Ok(updated)
})
.await
}
fn append_global_error_log(&mut self, error: String) {
let new_error = AccountError {
error,
at: utc_now!(),
};
self.global_errors.push(new_error);
let to_remove = self.global_errors.len().saturating_sub(30);
if to_remove > 0 {
self.global_errors.drain(0..to_remove);
}
}
pub async fn clear_global_errors(account_id: u64) -> BichonResult<()> {
Self::update_state(account_id, move |current| {
let mut updated = current.clone();
updated.clear_global_error_log();
Ok(updated)
})
.await
}
fn clear_global_error_log(&mut self) {
self.global_errors.clear();
}
}
+18
View File
@@ -1,3 +1,21 @@
//
// Copyright (c) 2025-2026 rustmailer.com (https://rustmailer.com)
//
// This file is part of the Bichon Email Archiving Project
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
+3 -4
View File
@@ -21,8 +21,8 @@ use crate::account::state::DownloadState;
use crate::cache::imap::download::process_imap_download;
use crate::common::periodic::{PeriodicTask, TaskHandle};
use crate::oauth2::token::OAuth2AccessToken;
use crate::{account::migration::AccountModel, error::BichonResult};
use crate::utc_now;
use crate::{account::migration::AccountModel, error::BichonResult};
use std::collections::HashMap;
use std::sync::atomic::{AtomicI64, Ordering};
use std::{sync::LazyLock, time::Duration};
@@ -83,7 +83,7 @@ impl AccountSyncTask {
}
}
if let Err(e) = process_imap_download(&account, internal_token).await {
DownloadState::append_global_error_message(
DownloadState::append_session_error(
account.id,
format!("error in account download task: {:#?}", e),
)
@@ -140,8 +140,7 @@ impl AccountSyncTask {
account_id
);
token.cancel();
if let Err(_) = tokio::time::timeout(Duration::from_secs(5), handler.stop()).await
{
if let Err(_) = tokio::time::timeout(Duration::from_secs(5), handler.stop()).await {
error!(
"Shutdown: Account {} download task forced timeout.",
account_id