Compare commits

...
Author SHA1 Message Date
4ce93a30ae Update Rust crate ed25519-dalek to v3
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
2026-08-08 03:00:54 +02:00
326ebf3b37
[Fix] Replies 2026-08-08 02:09:38 +02:00
6 changed files with 292 additions and 199 deletions

366
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -407,6 +407,12 @@ impl ClientConnection {
return;
}
if cv.is_type(CommunicationType::MessageGet) {
self.send_message(&message_handlers::handle_message_get(&cv))
.await;
return;
}
if cv.is_type(CommunicationType::GetChats) {
self.send_message(&message_handlers::handle_get_chats(&cv))
.await;

View file

@ -102,11 +102,11 @@ pub fn handle_message_delete(cv: &CommunicationValue) -> CommunicationValue {
}
}
fn stored_message_value(
fn stored_message_fields(
message: &chat_files::StoredMessage,
storage_owner: i64,
partner_id: i64,
) -> DataValue {
) -> Vec<(DataType, DataValue)> {
let mut fields = vec![
(
DataType::MessageId,
@ -162,7 +162,15 @@ fn stored_message_value(
.collect();
fields.push((DataType::Reactions, DataValue::Array(reactions)));
}
typed_container(fields)
fields
}
fn stored_message_value(
message: &chat_files::StoredMessage,
storage_owner: i64,
partner_id: i64,
) -> DataValue {
typed_container(stored_message_fields(message, storage_owner, partner_id))
}
pub fn handle_get_chat_secret(cv: &CommunicationValue) -> CommunicationValue {
@ -520,6 +528,28 @@ pub fn handle_messages_get(cv: &CommunicationValue) -> CommunicationValue {
.add_typed_default(DataType::Messages, DataValue::Array(msg_array))
}
pub fn handle_message_get(cv: &CommunicationValue) -> CommunicationValue {
let Some(send_time) = data_i64(cv, DataType::SendTime) else {
return error_response(cv, CommunicationType::ErrorInvalidData);
};
let partner_id = data_i64(cv, DataType::ChatPartnerId);
let owner = cv.get_sender() as i64;
let message = match chat_files::get_message(owner, send_time, partner_id) {
Ok(Some(message)) => message,
Ok(None) => return error_response(cv, CommunicationType::ErrorNotFound),
Err(_) => return error_response(cv, CommunicationType::ErrorInvalidData),
};
let mut response = CommunicationValue::new(CommunicationType::MessageGet)
.with_id(cv.get_id())
.with_receiver(cv.get_sender());
for (data_type, value) in stored_message_fields(&message, owner, message.external_user) {
response = response.add_typed_default(data_type, value);
}
response
}
pub fn handle_get_chats(cv: &CommunicationValue) -> CommunicationValue {
let user_id = cv.get_sender();
let users = chats_util::get_users(user_id as i64);

View file

@ -644,6 +644,62 @@ pub fn get_messages(
}
}
pub fn get_message(
storage_owner: i64,
message_time: i64,
external_user: Option<i64>,
) -> Result<Option<StoredMessage>, StorageError> {
db::with_db(|conn| {
let mut stmt = conn.prepare(
r#"
SELECT id, message_time, content, sent_by_self, message_state, height,
reply_to, edited_count, external_user
FROM messages
WHERE storage_owner = ?1
AND message_time = ?2
AND deleted_by_external = 0
AND (?3 IS NULL OR external_user = ?3)
ORDER BY id DESC
"#,
)?;
let rows = stmt.query_map(params![storage_owner, message_time, external_user], |row| {
Ok(StoredMessage {
id: row.get(0)?,
message_time: row.get(1)?,
content: row.get(2)?,
sent_by_self: row.get::<_, i64>(3)? != 0,
message_state: row.get(4)?,
height: row.get(5).unwrap_or(0),
reply_to: row.get(6).ok().flatten(),
edited: row.get::<_, i64>(7).unwrap_or(0) > 0,
external_user: row.get(8)?,
reactions: Vec::new(),
})
})?;
let messages: Vec<StoredMessage> = rows.collect::<Result<_, _>>()?;
if messages.is_empty() {
return Ok(None);
}
if external_user.is_none()
&& messages
.iter()
.map(|message| message.external_user)
.collect::<std::collections::HashSet<_>>()
.len()
> 1
{
return Ok(None);
}
let mut message = messages.into_iter().next().expect("checked non-empty");
let reaction_map = load_reactions(conn, &[message.id]);
message.reactions = reaction_map.get(&message.id).cloned().unwrap_or_default();
Ok(Some(message))
})
}
pub fn get_messages_by_ids(storage_owner: i64, ids: &[i64]) -> Vec<StoredMessage> {
if ids.is_empty() {
return Vec::new();

View file

@ -30,5 +30,5 @@ serde = "1.0.228"
tempfile = "3.27.0"
anyhow = "1.0.102"
semver = "1.0.28"
ed25519-dalek = "2.2.0"
ed25519-dalek = "3.0.0"
serde_json = "1.0"

View file

@ -884,6 +884,7 @@ impl OmikronConnection {
dispatch!(MessageReactionLive, handle_message_reaction_live);
dispatch!(MessageDeleteLive, handle_message_delete_live);
dispatch!(MessageOtherIota, handle_message_other_iota);
dispatch!(MessageGet, handle_message_get);
dispatch!(MessagesGet, handle_messages_get);
dispatch!(GetChats, handle_get_chats);
dispatch!(AddConversation, handle_add_conversation);
@ -1447,6 +1448,24 @@ impl OmikronConnection {
let height = cv.get_data(DataType::Height).as_number().unwrap_or(0) as i64;
let reply_to = cv.get_data(DataType::ReplyId).as_number().map(|n| n as i64);
if let Some(reply_to) = reply_to {
match chat_files::get_message(sender_id as i64, reply_to, Some(receiver_id)) {
Ok(Some(_)) => {}
Ok(None) => {
let _ = self
.send_message(&error_response(cv, CommunicationType::ErrorNotFound))
.await;
return;
}
Err(_) => {
let _ = self
.send_message(&error_response(cv, CommunicationType::ErrorInvalidData))
.await;
return;
}
}
}
let is_local = iota_storage::users::user_manager::get_user(receiver_id).is_some();
if is_local {
@ -1701,6 +1720,12 @@ impl OmikronConnection {
.await;
}
async fn handle_message_get(self: Arc<Self>, cv: &CommunicationValue) {
let _ = self
.send_message(&message_handlers::handle_message_get(cv))
.await;
}
async fn handle_get_chats(self: Arc<Self>, cv: &CommunicationValue) {
let _ = self
.send_message(&message_handlers::handle_get_chats(cv))