mirror of
https://github.com/chatmail/core.git
synced 2026-08-18 06:36:29 +03:00
fix: set_draft mutating real messages (race)
The issue has been introduced incf33db3dcb(https://github.com/chatmail/core/pull/2887). This, again, has to do with a race where the draft message is sent in another Future after `get_draft` but before `sql.execute`. Related: -07fa9c35ee(https://github.com/chatmail/core/pull/6052). -df4fd82140(https://github.com/chatmail/core/pull/6061).
This commit is contained in:
65
src/chat.rs
65
src/chat.rs
@@ -831,39 +831,34 @@ SELECT id, rfc724_mid, pre_rfc724_mid, timestamp, ?, 1 FROM msgs WHERE chat_id=?
|
||||
msg.state = MessageState::OutDraft;
|
||||
msg.chat_id = self;
|
||||
|
||||
// if possible, replace existing draft and keep id
|
||||
if !msg.id.is_special()
|
||||
&& let Some(old_draft) = self.get_draft(context).await?
|
||||
&& old_draft.id == msg.id
|
||||
&& old_draft.chat_id == self
|
||||
&& old_draft.state == MessageState::OutDraft
|
||||
{
|
||||
let affected_rows = context
|
||||
.sql.execute(
|
||||
"UPDATE msgs
|
||||
SET timestamp=?1,type=?2,txt=?3,txt_normalized=?4,param=?5,mime_in_reply_to=?6
|
||||
WHERE id=?7
|
||||
AND (type <> ?2
|
||||
OR txt <> ?3
|
||||
OR txt_normalized <> ?4
|
||||
OR param <> ?5
|
||||
OR mime_in_reply_to <> ?6);",
|
||||
(
|
||||
time(),
|
||||
msg.viewtype,
|
||||
&msg.text,
|
||||
normalize_text(&msg.text),
|
||||
msg.param.to_string(),
|
||||
msg.in_reply_to.as_deref().unwrap_or_default(),
|
||||
msg.id,
|
||||
),
|
||||
).await?;
|
||||
return Ok(affected_rows > 0);
|
||||
}
|
||||
|
||||
let row_id = context
|
||||
let (msg_id, changed) = context
|
||||
.sql
|
||||
.transaction(|transaction| {
|
||||
// if possible, replace existing draft and keep id
|
||||
if !msg.id.is_special() && self.has_draft_with_id(transaction, &msg.id)? {
|
||||
let affected_rows = transaction.execute(
|
||||
"UPDATE msgs
|
||||
SET timestamp=?1,type=?2,txt=?3,txt_normalized=?4,param=?5,mime_in_reply_to=?6
|
||||
WHERE id=?7
|
||||
AND (type <> ?2
|
||||
OR txt <> ?3
|
||||
OR txt_normalized <> ?4
|
||||
OR param <> ?5
|
||||
OR mime_in_reply_to <> ?6);",
|
||||
(
|
||||
time(),
|
||||
msg.viewtype,
|
||||
&msg.text,
|
||||
normalize_text(&msg.text),
|
||||
msg.param.to_string(),
|
||||
msg.in_reply_to.as_deref().unwrap_or_default(),
|
||||
msg.id,
|
||||
),
|
||||
)?;
|
||||
let changed = affected_rows > 0;
|
||||
return Ok((msg.id, changed));
|
||||
}
|
||||
|
||||
// Delete existing draft if it exists.
|
||||
transaction.execute(
|
||||
"DELETE FROM msgs WHERE chat_id=? AND state=?",
|
||||
@@ -900,11 +895,13 @@ SELECT id, rfc724_mid, pre_rfc724_mid, timestamp, ?, 1 FROM msgs WHERE chat_id=?
|
||||
),
|
||||
)?;
|
||||
|
||||
Ok(transaction.last_insert_rowid())
|
||||
let msg_id = MsgId::new(transaction.last_insert_rowid().try_into()?);
|
||||
let changed = true;
|
||||
Ok((msg_id, changed))
|
||||
})
|
||||
.await?;
|
||||
msg.id = MsgId::new(row_id.try_into()?);
|
||||
Ok(true)
|
||||
msg.id = msg_id;
|
||||
Ok(changed)
|
||||
}
|
||||
|
||||
/// Returns number of messages in a chat.
|
||||
|
||||
Reference in New Issue
Block a user