mirror of
https://github.com/chatmail/core.git
synced 2026-05-16 21:36:30 +03:00
Merge pull request #1417 from deltachat/dynamic-imap-delete-job-generation
Dynamic imap delete job generation
This commit is contained in:
193
src/job.rs
193
src/job.rs
@@ -75,7 +75,19 @@ impl Default for Thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)]
|
#[derive(
|
||||||
|
Debug,
|
||||||
|
Display,
|
||||||
|
Copy,
|
||||||
|
Clone,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
PartialOrd,
|
||||||
|
FromPrimitive,
|
||||||
|
ToPrimitive,
|
||||||
|
FromSql,
|
||||||
|
ToSql,
|
||||||
|
)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
@@ -150,30 +162,68 @@ impl fmt::Display for Job {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Job {
|
impl Job {
|
||||||
/// Deletes the job from the database.
|
fn new(action: Action, foreign_id: u32, param: Params, delay_seconds: i64) -> Self {
|
||||||
fn delete(&self, context: &Context) -> bool {
|
let timestamp = time();
|
||||||
context
|
|
||||||
.sql
|
Self {
|
||||||
.execute("DELETE FROM jobs WHERE id=?;", params![self.job_id as i32])
|
job_id: 0,
|
||||||
.is_ok()
|
action,
|
||||||
|
foreign_id,
|
||||||
|
desired_timestamp: timestamp + delay_seconds,
|
||||||
|
added_timestamp: timestamp,
|
||||||
|
tries: 0,
|
||||||
|
param,
|
||||||
|
pending_error: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the job already stored in the database.
|
/// Deletes the job from the database.
|
||||||
|
fn delete(&self, context: &Context) -> bool {
|
||||||
|
if self.job_id != 0 {
|
||||||
|
context
|
||||||
|
.sql
|
||||||
|
.execute("DELETE FROM jobs WHERE id=?;", params![self.job_id as i32])
|
||||||
|
.is_ok()
|
||||||
|
} else {
|
||||||
|
// Already deleted.
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Saves the job to the database, creating a new entry if necessary.
|
||||||
///
|
///
|
||||||
/// To add a new job, use [job_add].
|
/// The Job is consumed by this method.
|
||||||
fn update(&self, context: &Context) -> bool {
|
fn save(self, context: &Context) -> bool {
|
||||||
sql::execute(
|
let thread: Thread = self.action.into();
|
||||||
context,
|
|
||||||
&context.sql,
|
if self.job_id != 0 {
|
||||||
"UPDATE jobs SET desired_timestamp=?, tries=?, param=? WHERE id=?;",
|
sql::execute(
|
||||||
params![
|
context,
|
||||||
self.desired_timestamp,
|
&context.sql,
|
||||||
self.tries as i64,
|
"UPDATE jobs SET desired_timestamp=?, tries=?, param=? WHERE id=?;",
|
||||||
self.param.to_string(),
|
params![
|
||||||
self.job_id as i32,
|
self.desired_timestamp,
|
||||||
],
|
self.tries as i64,
|
||||||
)
|
self.param.to_string(),
|
||||||
.is_ok()
|
self.job_id as i32,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
|
} else {
|
||||||
|
sql::execute(
|
||||||
|
context,
|
||||||
|
&context.sql,
|
||||||
|
"INSERT INTO jobs (added_timestamp, thread, action, foreign_id, param, desired_timestamp) VALUES (?,?,?,?,?,?);",
|
||||||
|
params![
|
||||||
|
self.added_timestamp,
|
||||||
|
thread,
|
||||||
|
self.action,
|
||||||
|
self.foreign_id,
|
||||||
|
self.param.to_string(),
|
||||||
|
self.desired_timestamp
|
||||||
|
]
|
||||||
|
).is_ok()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn smtp_send<F>(
|
fn smtp_send<F>(
|
||||||
@@ -943,39 +993,34 @@ pub fn job_send_msg(context: &Context, msg_id: MsgId) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_imap_deletion_jobs(context: &Context) -> sql::Result<()> {
|
fn load_imap_deletion_msgid(context: &Context) -> sql::Result<Option<MsgId>> {
|
||||||
if let Some(delete_server_after) = context.get_config_delete_server_after() {
|
if let Some(delete_server_after) = context.get_config_delete_server_after() {
|
||||||
let threshold_timestamp = time() - delete_server_after;
|
let threshold_timestamp = time() - delete_server_after;
|
||||||
|
|
||||||
// Select all expired messages which don't have a
|
context.sql.query_row_optional(
|
||||||
// corresponding message deletion job yet.
|
|
||||||
let msg_ids = context.sql.query_map(
|
|
||||||
"SELECT id FROM msgs \
|
"SELECT id FROM msgs \
|
||||||
WHERE timestamp < ? \
|
WHERE timestamp < ? \
|
||||||
AND server_uid != 0 \
|
AND server_uid != 0",
|
||||||
AND NOT EXISTS (SELECT 1 FROM jobs WHERE foreign_id = msgs.id \
|
params![threshold_timestamp],
|
||||||
AND action = ?)",
|
|
||||||
params![threshold_timestamp, Action::DeleteMsgOnImap],
|
|
||||||
|row| row.get::<_, MsgId>(0),
|
|row| row.get::<_, MsgId>(0),
|
||||||
|ids| {
|
)
|
||||||
ids.collect::<std::result::Result<Vec<_>, _>>()
|
} else {
|
||||||
.map_err(Into::into)
|
Ok(None)
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Schedule IMAP deletion for expired messages.
|
|
||||||
for msg_id in msg_ids {
|
|
||||||
job_add(
|
|
||||||
context,
|
|
||||||
Action::DeleteMsgOnImap,
|
|
||||||
msg_id.to_u32() as i32,
|
|
||||||
Params::new(),
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
fn load_imap_deletion_job(context: &Context) -> sql::Result<Option<Job>> {
|
||||||
|
let res = if let Some(msg_id) = load_imap_deletion_msgid(context)? {
|
||||||
|
Some(Job::new(
|
||||||
|
Action::DeleteMsgOnImap,
|
||||||
|
msg_id.to_u32(),
|
||||||
|
Params::new(),
|
||||||
|
0,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn perform_inbox_jobs(context: &Context) {
|
pub fn perform_inbox_jobs(context: &Context) {
|
||||||
@@ -985,9 +1030,6 @@ pub fn perform_inbox_jobs(context: &Context) {
|
|||||||
*context.probe_imap_network.write().unwrap() = false;
|
*context.probe_imap_network.write().unwrap() = false;
|
||||||
*context.perform_inbox_jobs_needed.write().unwrap() = false;
|
*context.perform_inbox_jobs_needed.write().unwrap() = false;
|
||||||
|
|
||||||
if let Err(err) = add_imap_deletion_jobs(context) {
|
|
||||||
warn!(context, "Can't add IMAP message deletion jobs: {}", err);
|
|
||||||
}
|
|
||||||
job_perform(context, Thread::Imap, probe_imap_network);
|
job_perform(context, Thread::Imap, probe_imap_network);
|
||||||
info!(context, "dc_perform_inbox_jobs ended.",);
|
info!(context, "dc_perform_inbox_jobs ended.",);
|
||||||
}
|
}
|
||||||
@@ -1059,7 +1101,6 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
|||||||
job.tries = tries;
|
job.tries = tries;
|
||||||
let time_offset = get_backoff_time_offset(tries);
|
let time_offset = get_backoff_time_offset(tries);
|
||||||
job.desired_timestamp = time() + time_offset;
|
job.desired_timestamp = time() + time_offset;
|
||||||
job.update(context);
|
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
"{}-job #{} not succeeded on try #{}, retry in {} seconds.",
|
"{}-job #{} not succeeded on try #{}, retry in {} seconds.",
|
||||||
@@ -1068,6 +1109,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
|||||||
tries,
|
tries,
|
||||||
time_offset
|
time_offset
|
||||||
);
|
);
|
||||||
|
job.save(context);
|
||||||
if thread == Thread::Smtp && tries < JOB_RETRIES - 1 {
|
if thread == Thread::Smtp && tries < JOB_RETRIES - 1 {
|
||||||
context
|
context
|
||||||
.smtp_state
|
.smtp_state
|
||||||
@@ -1225,27 +1267,16 @@ pub fn job_add(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let timestamp = time();
|
let job = Job::new(action, foreign_id as u32, param, delay_seconds);
|
||||||
let thread: Thread = action.into();
|
job.save(context);
|
||||||
|
|
||||||
sql::execute(
|
if delay_seconds == 0 {
|
||||||
context,
|
let thread: Thread = action.into();
|
||||||
&context.sql,
|
match thread {
|
||||||
"INSERT INTO jobs (added_timestamp, thread, action, foreign_id, param, desired_timestamp) VALUES (?,?,?,?,?,?);",
|
Thread::Imap => interrupt_inbox_idle(context),
|
||||||
params![
|
Thread::Smtp => interrupt_smtp_idle(context),
|
||||||
timestamp,
|
Thread::Unknown => {}
|
||||||
thread,
|
}
|
||||||
action,
|
|
||||||
foreign_id,
|
|
||||||
param.to_string(),
|
|
||||||
(timestamp + delay_seconds as i64)
|
|
||||||
]
|
|
||||||
).ok();
|
|
||||||
|
|
||||||
match thread {
|
|
||||||
Thread::Imap => interrupt_inbox_idle(context),
|
|
||||||
Thread::Smtp => interrupt_smtp_idle(context),
|
|
||||||
Thread::Unknown => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1289,7 +1320,7 @@ fn load_next_job(context: &Context, thread: Thread, probe_network: bool) -> Opti
|
|||||||
params_probe
|
params_probe
|
||||||
};
|
};
|
||||||
|
|
||||||
context
|
let job = context
|
||||||
.sql
|
.sql
|
||||||
.query_map(
|
.query_map(
|
||||||
query,
|
query,
|
||||||
@@ -1318,7 +1349,23 @@ fn load_next_job(context: &Context, thread: Thread, probe_network: bool) -> Opti
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
if thread == Thread::Imap {
|
||||||
|
if let Some(job) = job {
|
||||||
|
if job.action < Action::DeleteMsgOnImap {
|
||||||
|
load_imap_deletion_job(context)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.or(Some(job))
|
||||||
|
} else {
|
||||||
|
Some(job)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
load_imap_deletion_job(context).unwrap_or_default()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
job
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user