Skip to content

Commit

Permalink
feat: handle incoming edit messages
Browse files Browse the repository at this point in the history
  • Loading branch information
boxdot committed Dec 22, 2023
1 parent 0b08486 commit aeef4e3
Show file tree
Hide file tree
Showing 16 changed files with 305 additions and 45 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions migrations/002_edits.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- messages with added field `edit` and foreign key on `channels`
ALTER TABLE messages
ADD COLUMN edit INTEGER; -- reference to edited message

CREATE INDEX idx_messages_quote
ON messages (quote);

CREATE INDEX idx_messages_edit
ON messages (edit);
11 changes: 8 additions & 3 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,9 @@ impl App {
});
return Ok(());
}
(metadata, ContentBody::SynchronizeMessage(sync_message)) => {
return self.handle_sync_message(metadata, sync_message);
}
(
Metadata {
sender:
Expand Down Expand Up @@ -796,7 +799,7 @@ impl App {
}

unhandled => {
trace!(?unhandled, "skipping unhandled message");
info!(?unhandled, "skipping unhandled message");
return Ok(());
}
};
Expand Down Expand Up @@ -1155,7 +1158,7 @@ impl App {
}
}

async fn ensure_contact_channel_exists(&mut self, uuid: Uuid, name: &str) -> usize {
pub(crate) async fn ensure_contact_channel_exists(&mut self, uuid: Uuid, name: &str) -> usize {
if let Some(channel_idx) = self
.channels
.items
Expand Down Expand Up @@ -1205,7 +1208,7 @@ impl App {
self.touch_channel(channel_idx);
}

fn touch_channel(&mut self, channel_idx: usize) {
pub(crate) fn touch_channel(&mut self, channel_idx: usize) {
if self.channels.state.selected() != Some(channel_idx) {
let channel_id = self.channels.items[channel_idx];
let mut channel = self
Expand Down Expand Up @@ -1520,6 +1523,8 @@ mod tests {
receipt: Default::default(),
body_ranges: Default::default(),
send_failed: Default::default(),
edit: Default::default(),
edited: Default::default(),
},
);

Expand Down
27 changes: 27 additions & 0 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,29 @@ pub struct Message {
pub(crate) body_ranges: Vec<BodyRange>,
#[serde(skip)]
pub(crate) send_failed: Option<String>,
/// Arrived at of edited message
#[serde(default)]
pub(crate) edit: Option<u64>,
#[serde(skip)]
pub(crate) edited: bool,
}

impl Message {
pub(crate) fn text(from_id: Uuid, arrived_at: u64, message: String) -> Self {
Self {
from_id,
message: Some(message),
arrived_at,
quote: Default::default(),
attachments: Default::default(),
reactions: Default::default(),
receipt: Default::default(),
body_ranges: Default::default(),
send_failed: Default::default(),
edit: Default::default(),
edited: Default::default(),
}
}
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -269,6 +292,8 @@ impl Message {
receipt: Receipt::Sent,
body_ranges: body_ranges.into_iter().collect(),
send_failed: Default::default(),
edit: Default::default(),
edited: Default::default(),
}
}

Expand All @@ -287,6 +312,8 @@ impl Message {
.filter_map(BodyRange::from_proto)
.collect(),
send_failed: Default::default(),
edit: Default::default(),
edited: Default::default(),
})
}

Expand Down
127 changes: 127 additions & 0 deletions src/handlers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use anyhow::Context;
use presage::libsignal_service::content::Metadata;
use presage::proto::sync_message::Sent;
use presage::proto::{DataMessage, EditMessage, SyncMessage};
use tracing::{info, warn};
use uuid::Uuid;

use crate::app::App;
use crate::data::{ChannelId, Message};
use crate::storage::MessageId;

impl App {
pub(super) fn handle_sync_message(
&mut self,
metadata: Metadata,
sync_message: SyncMessage,
) -> anyhow::Result<()> {
info!("###### {sync_message:?}");

let Some(channel_id) = sync_message.channel_id() else {
warn!("dropping a sync message not attached to a channel");
return Ok(());
};

// edit message
if let Some(Sent {
edit_message:
Some(EditMessage {
target_sent_timestamp: Some(target_sent_timestamp),
data_message:
Some(DataMessage {
body: Some(body),
timestamp: Some(arrived_at),
..
}),
}),
..
}) = sync_message.sent
{
let from_id = metadata.sender.uuid;
let edited = self
.storage
.message(MessageId::new(channel_id, target_sent_timestamp))
.context("no message to edit")?;

// get original message
let mut original = if let Some(edit) = edited.edit {
self.storage
.message(MessageId::new(channel_id, edit))
.context("no original edited message")?
.into_owned()
} else {
// original message => first edit
let original = edited.into_owned();

// preserve body of the original message; it is replaced below
let mut preserved = original.clone();
preserved.arrived_at = original.arrived_at + 1;
preserved.edit = Some(original.arrived_at);
self.storage.store_message(channel_id, preserved);

original
};

self.storage.store_message(
channel_id,
Message {
edit: Some(original.arrived_at),
..Message::text(from_id, arrived_at, body.clone())
},
);

// override the body of the original message
original.message = Some(body);
self.storage.store_message(channel_id, original);

let channel_idx = self
.channels
.items
.iter()
.position(|id| id == &channel_id)
.context("editing message in non-existent channel")?;
self.touch_channel(channel_idx);
}

Ok(())
}
}

trait MessageExt {
fn sender_id(&self) -> Option<Uuid>;

/// Get a channel id a message
fn channel_id(&self) -> Option<ChannelId>;
}

impl MessageExt for SyncMessage {
fn sender_id(&self) -> Option<Uuid> {
todo!()
}

fn channel_id(&self) -> Option<ChannelId> {
// only sent sync message are attached to a conversation
let sent = self.sent.as_ref()?;
if let Some(uuid) = sent
.destination_service_id
.as_ref()
.and_then(|id| id.parse().ok())
{
Some(ChannelId::User(uuid))
} else {
let group_v2 = sent
.message
.as_ref()
.and_then(|message| message.group_v2.as_ref())
.or_else(|| {
sent.edit_message
.as_ref()?
.data_message
.as_ref()?
.group_v2
.as_ref()
})?;
ChannelId::from_master_key_bytes(group_v2.master_key.as_deref()?).ok()
}
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod data;
pub mod dev;
pub(crate) mod emoji;
pub mod event;
mod handlers;
pub mod input;
pub mod receipt;
pub mod shortcuts;
Expand Down
2 changes: 2 additions & 0 deletions src/signal/impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ impl SignalManager for PresageManager {
receipt: Receipt::Sent,
body_ranges: Default::default(),
send_failed: Default::default(),
edit: Default::default(),
edited: Default::default(),
};
(message, response)
}
Expand Down
2 changes: 2 additions & 0 deletions src/signal/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ impl SignalManager for SignalManagerMock {
receipt: Receipt::Sent,
body_ranges: Default::default(),
send_failed: Default::default(),
edit: Default::default(),
edited: Default::default(),
};
self.sent_messages.borrow_mut().push(message.clone());
let (tx, rx) = oneshot::channel();
Expand Down
6 changes: 6 additions & 0 deletions src/storage/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,8 @@ mod tests {
receipt: Default::default(),
body_ranges: Default::default(),
send_failed: Default::default(),
edit: Default::default(),
edited: Default::default(),
}],
unread_messages: 1,
typing: Some(TypingSet::SingleTyping(false)),
Expand All @@ -355,6 +357,8 @@ mod tests {
receipt: Default::default(),
body_ranges: Default::default(),
send_failed: Default::default(),
edit: Default::default(),
edited: Default::default(),
}],
unread_messages: 2,
typing: Some(TypingSet::GroupTyping(Default::default())),
Expand Down Expand Up @@ -504,6 +508,8 @@ mod tests {
receipt: Default::default(),
body_ranges: Default::default(),
send_failed: Default::default(),
edit: Default::default(),
edited: Default::default(),
},
);

Expand Down
Loading

0 comments on commit aeef4e3

Please sign in to comment.