Skip to content

Commit

Permalink
fix: replace old draft with a new one atomically
Browse files Browse the repository at this point in the history
This prevents creation of multiple drafts per chat.
  • Loading branch information
link2xt committed Oct 16, 2024
1 parent 4efd0d1 commit 03042a4
Showing 1 changed file with 57 additions and 17 deletions.
74 changes: 57 additions & 17 deletions src/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -944,12 +944,18 @@ impl ChatId {
}
}

// insert new draft
self.maybe_delete_draft(context).await?;
let row_id = context
.sql
.insert(
"INSERT INTO msgs (
.transaction(|transaction| {
// Delete existing draft if it exists.
transaction.execute(
"DELETE FROM msgs WHERE chat_id=? AND state=?",
(self, MessageState::OutDraft),
)?;

// Insert new draft.
transaction.execute(
"INSERT INTO msgs (
chat_id,
from_id,
timestamp,
Expand All @@ -961,19 +967,22 @@ impl ChatId {
hidden,
mime_in_reply_to)
VALUES (?,?,?,?,?,?,?,?,?,?);",
(
self,
ContactId::SELF,
time(),
msg.viewtype,
MessageState::OutDraft,
&msg.text,
message::normalize_text(&msg.text),
msg.param.to_string(),
1,
msg.in_reply_to.as_deref().unwrap_or_default(),
),
)
(
self,
ContactId::SELF,
time(),
msg.viewtype,
MessageState::OutDraft,
&msg.text,
message::normalize_text(&msg.text),
msg.param.to_string(),
1,
msg.in_reply_to.as_deref().unwrap_or_default(),
),
)?;

Ok(transaction.last_insert_rowid())
})
.await?;
msg.id = MsgId::new(row_id.try_into()?);
Ok(true)
Expand Down Expand Up @@ -4854,6 +4863,37 @@ mod tests {
Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_only_one_draft_per_chat() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "abc").await?;

let msgs: Vec<message::Message> = (1..=1000)
.map(|i| {
let mut msg = Message::new(Viewtype::Text);
msg.set_text(i.to_string());
return msg;
})
.collect();
let mut tasks = Vec::new();
for mut msg in msgs {
let ctx = t.clone();
let task = tokio::spawn(async move {
let ctx = ctx;
chat_id.set_draft(&ctx, Some(&mut msg)).await
});
tasks.push(task);
}
futures::future::join_all(tasks.into_iter()).await;

assert!(chat_id.get_draft(&t).await?.is_some());

chat_id.set_draft(&t, None).await?;
assert!(chat_id.get_draft(&t).await?.is_none());

Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_change_quotes_on_reused_message_object() -> Result<()> {
let t = TestContext::new_alice().await;
Expand Down

0 comments on commit 03042a4

Please sign in to comment.