[Fix] Connection Management
This commit is contained in:
parent
9e9e3597da
commit
3f2ac18333
122 changed files with 19970 additions and 5263 deletions
|
|
@ -50,7 +50,9 @@ impl MessageState {
|
|||
pub struct StoredMessage {
|
||||
pub id: i64,
|
||||
pub external_user: i64,
|
||||
pub external_principal: Option<iota_identity::PrincipalHandle>,
|
||||
pub relay_signer_id: Option<i64>,
|
||||
pub relay_signer_principal: Option<iota_identity::PrincipalHandle>,
|
||||
pub relay_message_id: Option<String>,
|
||||
pub message_time: i64,
|
||||
pub authored_at: Option<i64>,
|
||||
|
|
@ -74,11 +76,13 @@ pub struct StoredMessage {
|
|||
|
||||
pub struct NewMessage<'a> {
|
||||
pub relay_signer_id: i64,
|
||||
pub relay_signer_principal: iota_identity::PrincipalHandle,
|
||||
pub relay_message_id: &'a str,
|
||||
pub authored_at: i64,
|
||||
pub send_time: i64,
|
||||
pub storage_owner: i64,
|
||||
pub external_user: i64,
|
||||
pub external_principal: iota_identity::PrincipalHandle,
|
||||
pub sent_by_self: bool,
|
||||
pub content: &'a str,
|
||||
pub height: i64,
|
||||
|
|
@ -109,6 +113,26 @@ pub fn edit_message(
|
|||
update_message_content(
|
||||
storage_owner,
|
||||
external_user,
|
||||
None,
|
||||
message_time,
|
||||
editor_id,
|
||||
new_content,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn edit_message_for_principal(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: iota_identity::PrincipalHandle,
|
||||
message_time: i64,
|
||||
editor_id: i64,
|
||||
new_content: &str,
|
||||
) -> Result<(), StorageError> {
|
||||
update_message_content(
|
||||
storage_owner,
|
||||
external_user,
|
||||
Some(external_principal),
|
||||
message_time,
|
||||
editor_id,
|
||||
new_content,
|
||||
|
|
@ -133,6 +157,31 @@ pub fn apply_remote_edit(
|
|||
update_message_content(
|
||||
storage_owner,
|
||||
external_user,
|
||||
None,
|
||||
message_time,
|
||||
editor_id,
|
||||
new_content,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn apply_remote_edit_for_principal(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: iota_identity::PrincipalHandle,
|
||||
message_time: i64,
|
||||
editor_id: i64,
|
||||
new_content: &str,
|
||||
) -> Result<(), StorageError> {
|
||||
if editor_id != external_user {
|
||||
return Err(StorageError::Other(
|
||||
"Remote editor does not match chat partner".into(),
|
||||
));
|
||||
}
|
||||
update_message_content(
|
||||
storage_owner,
|
||||
external_user,
|
||||
Some(external_principal),
|
||||
message_time,
|
||||
editor_id,
|
||||
new_content,
|
||||
|
|
@ -143,6 +192,7 @@ pub fn apply_remote_edit(
|
|||
fn update_message_content(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: Option<iota_identity::PrincipalHandle>,
|
||||
message_time: i64,
|
||||
editor_id: i64,
|
||||
new_content: &str,
|
||||
|
|
@ -153,10 +203,20 @@ fn update_message_content(
|
|||
r#"
|
||||
SELECT id, content, sent_by_self, history_deleted
|
||||
FROM messages
|
||||
WHERE storage_owner = ?1 AND external_user = ?2 AND message_time = ?3
|
||||
WHERE storage_owner = ?1
|
||||
AND message_time = ?3
|
||||
AND (
|
||||
(?4 IS NULL AND external_user = ?2)
|
||||
OR external_principal = ?4
|
||||
)
|
||||
ORDER BY id DESC LIMIT 1
|
||||
"#,
|
||||
params![storage_owner, external_user, message_time],
|
||||
params![
|
||||
storage_owner,
|
||||
external_user,
|
||||
message_time,
|
||||
external_principal.map(|principal| principal.0)
|
||||
],
|
||||
|row| {
|
||||
Ok((
|
||||
row.get::<_, i64>(0)?,
|
||||
|
|
@ -221,16 +281,35 @@ pub fn hard_delete_message(
|
|||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
message_time: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
hard_delete_message_with_principal(storage_owner, external_user, None, message_time)
|
||||
}
|
||||
|
||||
fn hard_delete_message_with_principal(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: Option<iota_identity::PrincipalHandle>,
|
||||
message_time: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
db::with_db(|conn| {
|
||||
let msg_id = conn
|
||||
.query_row(
|
||||
r#"
|
||||
SELECT id, history_deleted FROM messages
|
||||
WHERE storage_owner = ?1 AND external_user = ?2 AND message_time = ?3
|
||||
WHERE storage_owner = ?1
|
||||
AND message_time = ?3
|
||||
AND (
|
||||
(?4 IS NULL AND external_user = ?2)
|
||||
OR external_principal = ?4
|
||||
)
|
||||
ORDER BY id DESC LIMIT 1
|
||||
"#,
|
||||
params![storage_owner, external_user, message_time],
|
||||
params![
|
||||
storage_owner,
|
||||
external_user,
|
||||
message_time,
|
||||
external_principal.map(|principal| principal.0)
|
||||
],
|
||||
|row| row.get::<_, i64>(0),
|
||||
)
|
||||
.optional()?;
|
||||
|
|
@ -277,14 +356,14 @@ pub fn remove_message_history_in_tx(
|
|||
storage_owner: i64,
|
||||
message_id: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
let message: Option<(i64, i64)> = tx
|
||||
let message: Option<(i64, Option<i64>, i64)> = tx
|
||||
.query_row(
|
||||
"SELECT external_user, history_deleted FROM messages WHERE id = ?1 AND storage_owner = ?2",
|
||||
"SELECT external_user, external_principal, history_deleted FROM messages WHERE id = ?1 AND storage_owner = ?2",
|
||||
params![message_id, storage_owner],
|
||||
|row| Ok((row.get(0)?, row.get(1)?)),
|
||||
|row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)),
|
||||
)
|
||||
.optional()?;
|
||||
let Some((external_user, history_deleted)) = message else {
|
||||
let Some((external_user, external_principal, history_deleted)) = message else {
|
||||
return Ok(());
|
||||
};
|
||||
if history_deleted != 0 {
|
||||
|
|
@ -295,7 +374,7 @@ pub fn remove_message_history_in_tx(
|
|||
[message_id],
|
||||
)?;
|
||||
tx.execute("DELETE FROM reactions WHERE message_id = ?1", [message_id])?;
|
||||
tx.execute("DELETE FROM message_receipts WHERE storage_owner = ?1 AND EXISTS (SELECT 1 FROM messages WHERE id = ?2 AND relay_signer_id = message_receipts.target_signer_id AND relay_message_id = message_receipts.target_message_id)", params![storage_owner, message_id])?;
|
||||
tx.execute("DELETE FROM message_receipts WHERE storage_owner = ?1 AND EXISTS (SELECT 1 FROM messages WHERE id = ?2 AND relay_signer_principal = message_receipts.target_signer_principal AND relay_message_id = message_receipts.target_message_id)", params![storage_owner, message_id])?;
|
||||
tx.execute("UPDATE messages SET content = '', history_deleted = 1, history_deleted_at = ?2, expires_at = NULL, client_received_at = NULL, client_received_recorded_at = NULL, read_at = NULL, read_recorded_at = NULL WHERE id = ?1", params![message_id, sync::now_millis()])?;
|
||||
sync::record_event(
|
||||
tx,
|
||||
|
|
@ -304,7 +383,12 @@ pub fn remove_message_history_in_tx(
|
|||
message_id,
|
||||
Operation::Delete,
|
||||
)?;
|
||||
update_contact_last_message_in_tx(tx, storage_owner, external_user)?;
|
||||
update_contact_last_message_in_tx(
|
||||
tx,
|
||||
storage_owner,
|
||||
external_user,
|
||||
external_principal.map(iota_identity::PrincipalHandle),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -312,8 +396,12 @@ fn update_contact_last_message_in_tx(
|
|||
tx: &Transaction<'_>,
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: Option<iota_identity::PrincipalHandle>,
|
||||
) -> Result<(), StorageError> {
|
||||
tx.execute("UPDATE contacts SET last_message_at = (SELECT MAX(COALESCE(destination_iota_received_at, origin_iota_received_at, authored_at, message_time)) FROM messages WHERE storage_owner = ?1 AND external_user = ?2 AND deleted_by_external = 0 AND history_deleted = 0) WHERE storage_owner = ?1 AND user_id = ?2", params![storage_owner, external_user])?;
|
||||
tx.execute(
|
||||
"UPDATE contacts SET last_message_at = (SELECT MAX(COALESCE(destination_iota_received_at, origin_iota_received_at, authored_at, message_time)) FROM messages WHERE storage_owner = ?1 AND ((?3 IS NULL AND external_user = ?2) OR external_principal = ?3) AND deleted_by_external = 0 AND history_deleted = 0) WHERE storage_owner = ?1 AND ((?3 IS NULL AND user_id = ?2) OR principal_handle = ?3)",
|
||||
params![storage_owner, external_user, external_principal.map(|principal| principal.0)],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -322,15 +410,17 @@ pub fn purge_message_in_tx(
|
|||
storage_owner: i64,
|
||||
message_id: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
let (external_user, relay_signer_id, relay_message_id) = tx.query_row(
|
||||
"SELECT external_user, relay_signer_id, relay_message_id FROM messages WHERE id = ?1 AND storage_owner = ?2",
|
||||
let (external_user, external_principal, relay_signer_principal, relay_message_id) = tx.query_row(
|
||||
"SELECT external_user, external_principal, relay_signer_principal, relay_message_id FROM messages WHERE id = ?1 AND storage_owner = ?2",
|
||||
params![message_id, storage_owner],
|
||||
|row| Ok((row.get::<_, i64>(0)?, row.get::<_, Option<i64>>(1)?, row.get::<_, Option<String>>(2)?)),
|
||||
|row| Ok((row.get::<_, i64>(0)?, row.get::<_, Option<i64>>(1)?, row.get::<_, Option<i64>>(2)?, row.get::<_, Option<String>>(3)?)),
|
||||
)?;
|
||||
if let (Some(relay_signer_id), Some(relay_message_id)) = (relay_signer_id, relay_message_id) {
|
||||
if let (Some(relay_signer_principal), Some(relay_message_id)) =
|
||||
(relay_signer_principal, relay_message_id)
|
||||
{
|
||||
tx.execute(
|
||||
"DELETE FROM message_receipts WHERE storage_owner = ?1 AND target_signer_id = ?2 AND target_message_id = ?3",
|
||||
params![storage_owner, relay_signer_id, relay_message_id],
|
||||
"DELETE FROM message_receipts WHERE storage_owner = ?1 AND target_signer_principal = ?2 AND target_message_id = ?3",
|
||||
params![storage_owner, relay_signer_principal, relay_message_id],
|
||||
)?;
|
||||
}
|
||||
tx.execute(
|
||||
|
|
@ -346,7 +436,12 @@ pub fn purge_message_in_tx(
|
|||
message_id,
|
||||
Operation::Delete,
|
||||
)?;
|
||||
update_contact_last_message_in_tx(tx, storage_owner, external_user)?;
|
||||
update_contact_last_message_in_tx(
|
||||
tx,
|
||||
storage_owner,
|
||||
external_user,
|
||||
external_principal.map(iota_identity::PrincipalHandle),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -356,8 +451,50 @@ pub fn delete_message(
|
|||
external_user: i64,
|
||||
message_time: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
match ensure_message_direction(storage_owner, external_user, message_time, true) {
|
||||
Ok(()) => hard_delete_message(storage_owner, external_user, message_time),
|
||||
delete_message_with_principal(storage_owner, external_user, None, message_time, true)
|
||||
}
|
||||
|
||||
pub fn delete_message_for_principal(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: iota_identity::PrincipalHandle,
|
||||
message_time: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
delete_message_with_principal(
|
||||
storage_owner,
|
||||
external_user,
|
||||
Some(external_principal),
|
||||
message_time,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
fn delete_message_with_principal(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: Option<iota_identity::PrincipalHandle>,
|
||||
message_time: i64,
|
||||
sent_by_self: bool,
|
||||
) -> Result<(), StorageError> {
|
||||
match ensure_message_direction(
|
||||
storage_owner,
|
||||
external_user,
|
||||
external_principal,
|
||||
message_time,
|
||||
sent_by_self,
|
||||
) {
|
||||
Ok(()) if sent_by_self => hard_delete_message_with_principal(
|
||||
storage_owner,
|
||||
external_user,
|
||||
external_principal,
|
||||
message_time,
|
||||
),
|
||||
Ok(()) => flag_deleted_by_external_with_principal(
|
||||
storage_owner,
|
||||
external_user,
|
||||
external_principal,
|
||||
message_time,
|
||||
),
|
||||
Err(StorageError::Db(rusqlite::Error::QueryReturnedNoRows)) => Ok(()),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
|
|
@ -375,16 +512,34 @@ pub fn apply_remote_delete(
|
|||
"Remote sender does not match chat partner".into(),
|
||||
));
|
||||
}
|
||||
match ensure_message_direction(storage_owner, external_user, message_time, false) {
|
||||
Ok(()) => flag_deleted_by_external(storage_owner, external_user, message_time),
|
||||
Err(StorageError::Db(rusqlite::Error::QueryReturnedNoRows)) => Ok(()),
|
||||
Err(error) => Err(error),
|
||||
delete_message_with_principal(storage_owner, external_user, None, message_time, false)
|
||||
}
|
||||
|
||||
pub fn apply_remote_delete_for_principal(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: iota_identity::PrincipalHandle,
|
||||
message_time: i64,
|
||||
sender_id: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
if sender_id != external_user {
|
||||
return Err(StorageError::Other(
|
||||
"Remote sender does not match chat partner".into(),
|
||||
));
|
||||
}
|
||||
delete_message_with_principal(
|
||||
storage_owner,
|
||||
external_user,
|
||||
Some(external_principal),
|
||||
message_time,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
fn ensure_message_direction(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: Option<iota_identity::PrincipalHandle>,
|
||||
message_time: i64,
|
||||
expected_sent_by_self: bool,
|
||||
) -> Result<(), StorageError> {
|
||||
|
|
@ -392,10 +547,20 @@ fn ensure_message_direction(
|
|||
let sent_by_self: i64 = conn.query_row(
|
||||
r#"
|
||||
SELECT sent_by_self FROM messages
|
||||
WHERE storage_owner = ?1 AND external_user = ?2 AND message_time = ?3
|
||||
WHERE storage_owner = ?1
|
||||
AND message_time = ?3
|
||||
AND (
|
||||
(?4 IS NULL AND external_user = ?2)
|
||||
OR external_principal = ?4
|
||||
)
|
||||
ORDER BY id DESC LIMIT 1
|
||||
"#,
|
||||
params![storage_owner, external_user, message_time],
|
||||
params![
|
||||
storage_owner,
|
||||
external_user,
|
||||
message_time,
|
||||
external_principal.map(|principal| principal.0)
|
||||
],
|
||||
|row| row.get(0),
|
||||
)?;
|
||||
if (sent_by_self != 0) != expected_sent_by_self {
|
||||
|
|
@ -415,6 +580,15 @@ pub fn flag_deleted_by_external(
|
|||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
message_time: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
flag_deleted_by_external_with_principal(storage_owner, external_user, None, message_time)
|
||||
}
|
||||
|
||||
fn flag_deleted_by_external_with_principal(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: Option<iota_identity::PrincipalHandle>,
|
||||
message_time: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
db::with_db(|conn| {
|
||||
let tx = conn.unchecked_transaction()?;
|
||||
|
|
@ -422,14 +596,28 @@ pub fn flag_deleted_by_external(
|
|||
r#"
|
||||
UPDATE messages
|
||||
SET deleted_by_external = 1
|
||||
WHERE storage_owner = ?1 AND external_user = ?2 AND message_time = ?3
|
||||
WHERE storage_owner = ?1
|
||||
AND message_time = ?3
|
||||
AND (
|
||||
(?4 IS NULL AND external_user = ?2)
|
||||
OR external_principal = ?4
|
||||
)
|
||||
"#,
|
||||
params![storage_owner, external_user, message_time],
|
||||
params![
|
||||
storage_owner,
|
||||
external_user,
|
||||
message_time,
|
||||
external_principal.map(|principal| principal.0)
|
||||
],
|
||||
)?;
|
||||
if affected == 0 {
|
||||
return Err(StorageError::Other("Message not found".into()));
|
||||
}
|
||||
let msg_id: i64 = tx.query_row("SELECT id FROM messages WHERE storage_owner = ?1 AND external_user = ?2 AND message_time = ?3 ORDER BY id DESC LIMIT 1", params![storage_owner, external_user, message_time], |r| r.get(0))?;
|
||||
let msg_id: i64 = tx.query_row(
|
||||
"SELECT id FROM messages WHERE storage_owner = ?1 AND message_time = ?3 AND ((?4 IS NULL AND external_user = ?2) OR external_principal = ?4) ORDER BY id DESC LIMIT 1",
|
||||
params![storage_owner, external_user, message_time, external_principal.map(|principal| principal.0)],
|
||||
|r| r.get(0),
|
||||
)?;
|
||||
sync::record_event(
|
||||
&tx,
|
||||
storage_owner,
|
||||
|
|
@ -437,7 +625,7 @@ pub fn flag_deleted_by_external(
|
|||
msg_id,
|
||||
Operation::Delete,
|
||||
)?;
|
||||
update_contact_last_message_in_tx(&tx, storage_owner, external_user)?;
|
||||
update_contact_last_message_in_tx(&tx, storage_owner, external_user, external_principal)?;
|
||||
tx.commit()?;
|
||||
Ok(())
|
||||
})
|
||||
|
|
@ -490,15 +678,65 @@ pub fn add_reaction(
|
|||
message_time: i64,
|
||||
user_id: i64,
|
||||
reaction: &str,
|
||||
) -> Result<(), StorageError> {
|
||||
add_reaction_with_principal(
|
||||
storage_owner,
|
||||
external_user,
|
||||
None,
|
||||
message_time,
|
||||
user_id,
|
||||
None,
|
||||
reaction,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn add_reaction_for_principal(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: iota_identity::PrincipalHandle,
|
||||
message_time: i64,
|
||||
user_id: i64,
|
||||
user_principal: iota_identity::PrincipalHandle,
|
||||
reaction: &str,
|
||||
) -> Result<(), StorageError> {
|
||||
add_reaction_with_principal(
|
||||
storage_owner,
|
||||
external_user,
|
||||
Some(external_principal),
|
||||
message_time,
|
||||
user_id,
|
||||
Some(user_principal),
|
||||
reaction,
|
||||
)
|
||||
}
|
||||
|
||||
fn add_reaction_with_principal(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: Option<iota_identity::PrincipalHandle>,
|
||||
message_time: i64,
|
||||
user_id: i64,
|
||||
user_principal: Option<iota_identity::PrincipalHandle>,
|
||||
reaction: &str,
|
||||
) -> Result<(), StorageError> {
|
||||
db::with_immediate_transaction(|tx| {
|
||||
let (msg_id, history_deleted): (i64, i64) = tx.query_row(
|
||||
r#"
|
||||
SELECT id, history_deleted FROM messages
|
||||
WHERE storage_owner = ?1 AND external_user = ?2 AND message_time = ?3
|
||||
WHERE storage_owner = ?1
|
||||
AND message_time = ?3
|
||||
AND (
|
||||
(?4 IS NULL AND external_user = ?2)
|
||||
OR external_principal = ?4
|
||||
)
|
||||
ORDER BY id DESC LIMIT 1
|
||||
"#,
|
||||
params![storage_owner, external_user, message_time],
|
||||
params![
|
||||
storage_owner,
|
||||
external_user,
|
||||
message_time,
|
||||
external_principal.map(|principal| principal.0)
|
||||
],
|
||||
|row| Ok((row.get(0)?, row.get(1)?)),
|
||||
)?;
|
||||
if history_deleted != 0 {
|
||||
|
|
@ -528,10 +766,16 @@ pub fn add_reaction(
|
|||
|
||||
let inserted = tx.execute(
|
||||
r#"
|
||||
INSERT OR IGNORE INTO reactions (message_id, user_id, reaction, created_at)
|
||||
VALUES (?1, ?2, ?3, ?4)
|
||||
INSERT OR IGNORE INTO reactions (message_id, user_id, user_principal, reaction, created_at)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5)
|
||||
"#,
|
||||
params![msg_id, user_id, reaction, now],
|
||||
params![
|
||||
msg_id,
|
||||
user_id,
|
||||
user_principal.map(|principal| principal.0),
|
||||
reaction,
|
||||
now
|
||||
],
|
||||
)?;
|
||||
if inserted > 0 {
|
||||
sync::record_event(
|
||||
|
|
@ -554,15 +798,65 @@ pub fn remove_reaction(
|
|||
message_time: i64,
|
||||
user_id: i64,
|
||||
reaction: &str,
|
||||
) -> Result<(), StorageError> {
|
||||
remove_reaction_with_principal(
|
||||
storage_owner,
|
||||
external_user,
|
||||
None,
|
||||
message_time,
|
||||
user_id,
|
||||
None,
|
||||
reaction,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn remove_reaction_for_principal(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: iota_identity::PrincipalHandle,
|
||||
message_time: i64,
|
||||
user_id: i64,
|
||||
user_principal: iota_identity::PrincipalHandle,
|
||||
reaction: &str,
|
||||
) -> Result<(), StorageError> {
|
||||
remove_reaction_with_principal(
|
||||
storage_owner,
|
||||
external_user,
|
||||
Some(external_principal),
|
||||
message_time,
|
||||
user_id,
|
||||
Some(user_principal),
|
||||
reaction,
|
||||
)
|
||||
}
|
||||
|
||||
fn remove_reaction_with_principal(
|
||||
storage_owner: i64,
|
||||
external_user: i64,
|
||||
external_principal: Option<iota_identity::PrincipalHandle>,
|
||||
message_time: i64,
|
||||
user_id: i64,
|
||||
user_principal: Option<iota_identity::PrincipalHandle>,
|
||||
reaction: &str,
|
||||
) -> Result<(), StorageError> {
|
||||
db::with_db(|conn| {
|
||||
let (msg_id, history_deleted): (i64, i64) = conn.query_row(
|
||||
r#"
|
||||
SELECT id, history_deleted FROM messages
|
||||
WHERE storage_owner = ?1 AND external_user = ?2 AND message_time = ?3
|
||||
WHERE storage_owner = ?1
|
||||
AND message_time = ?3
|
||||
AND (
|
||||
(?4 IS NULL AND external_user = ?2)
|
||||
OR external_principal = ?4
|
||||
)
|
||||
ORDER BY id DESC LIMIT 1
|
||||
"#,
|
||||
params![storage_owner, external_user, message_time],
|
||||
params![
|
||||
storage_owner,
|
||||
external_user,
|
||||
message_time,
|
||||
external_principal.map(|principal| principal.0)
|
||||
],
|
||||
|row| Ok((row.get(0)?, row.get(1)?)),
|
||||
)?;
|
||||
if history_deleted != 0 {
|
||||
|
|
@ -571,8 +865,13 @@ pub fn remove_reaction(
|
|||
|
||||
let tx = conn.unchecked_transaction()?;
|
||||
tx.execute(
|
||||
"DELETE FROM reactions WHERE message_id = ?1 AND user_id = ?2 AND reaction = ?3",
|
||||
params![msg_id, user_id, reaction],
|
||||
"DELETE FROM reactions WHERE message_id = ?1 AND ((?3 IS NULL AND user_id = ?2) OR user_principal = ?3) AND reaction = ?4",
|
||||
params![
|
||||
msg_id,
|
||||
user_id,
|
||||
user_principal.map(|principal| principal.0),
|
||||
reaction
|
||||
],
|
||||
)?;
|
||||
sync::record_event(
|
||||
&tx,
|
||||
|
|
@ -589,11 +888,13 @@ pub fn remove_reaction(
|
|||
pub fn add_message(message: NewMessage<'_>) -> Result<i64, StorageError> {
|
||||
let NewMessage {
|
||||
relay_signer_id,
|
||||
relay_signer_principal,
|
||||
relay_message_id,
|
||||
authored_at,
|
||||
send_time,
|
||||
storage_owner,
|
||||
external_user,
|
||||
external_principal,
|
||||
sent_by_self,
|
||||
content,
|
||||
height,
|
||||
|
|
@ -620,8 +921,9 @@ pub fn add_message(message: NewMessage<'_>) -> Result<i64, StorageError> {
|
|||
INSERT INTO messages (
|
||||
storage_owner, external_user, message_time, content, sent_by_self,
|
||||
message_state, height, key_version, reply_to, relay_signer_id, relay_message_id,
|
||||
authored_at, origin_iota_received_at, destination_iota_received_at, stored_at, expires_at
|
||||
) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16)
|
||||
authored_at, origin_iota_received_at, destination_iota_received_at, stored_at,
|
||||
expires_at, external_principal, relay_signer_principal
|
||||
) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18)
|
||||
"#,
|
||||
params![
|
||||
storage_owner,
|
||||
|
|
@ -640,6 +942,8 @@ pub fn add_message(message: NewMessage<'_>) -> Result<i64, StorageError> {
|
|||
destination_iota_received_at,
|
||||
stored_at,
|
||||
expires_at,
|
||||
external_principal.0,
|
||||
relay_signer_principal.0,
|
||||
],
|
||||
)?;
|
||||
let msg_id = tx.last_insert_rowid();
|
||||
|
|
@ -650,7 +954,8 @@ pub fn add_message(message: NewMessage<'_>) -> Result<i64, StorageError> {
|
|||
msg_id,
|
||||
Operation::Upsert,
|
||||
)?;
|
||||
let mut contact = crate::users::contact::Contact::new(external_user);
|
||||
let mut contact =
|
||||
crate::users::contact::Contact::for_principal(external_user, external_principal);
|
||||
contact.set_last_message_at(
|
||||
destination_iota_received_at
|
||||
.or(origin_iota_received_at)
|
||||
|
|
@ -659,8 +964,8 @@ pub fn add_message(message: NewMessage<'_>) -> Result<i64, StorageError> {
|
|||
crate::util::chats_util::upsert_contact(&tx, storage_owner, &contact)?;
|
||||
if !sent_by_self {
|
||||
tx.execute(
|
||||
"UPDATE contacts SET notifications = CASE WHEN notifications < 9223372036854775807 THEN notifications + 1 ELSE notifications END WHERE storage_owner = ?1 AND user_id = ?2",
|
||||
params![storage_owner, external_user],
|
||||
"UPDATE contacts SET notifications = CASE WHEN notifications < 9223372036854775807 THEN notifications + 1 ELSE notifications END WHERE storage_owner = ?1 AND principal_handle = ?2",
|
||||
params![storage_owner, external_principal.0],
|
||||
)?;
|
||||
}
|
||||
tx.commit()?;
|
||||
|
|
@ -670,7 +975,8 @@ pub fn add_message(message: NewMessage<'_>) -> Result<i64, StorageError> {
|
|||
|
||||
pub fn change_message_state_by_relay_id(
|
||||
storage_owner: i64,
|
||||
relay_signer_id: i64,
|
||||
_relay_signer_id: i64,
|
||||
relay_signer_principal: iota_identity::PrincipalHandle,
|
||||
relay_message_id: &str,
|
||||
new_state: MessageState,
|
||||
) -> Result<(), StorageError> {
|
||||
|
|
@ -678,8 +984,8 @@ pub fn change_message_state_by_relay_id(
|
|||
let tx = conn.unchecked_transaction()?;
|
||||
let Some((msg_id, current)) = tx
|
||||
.query_row(
|
||||
"SELECT id, message_state FROM messages WHERE storage_owner = ?1 AND relay_signer_id = ?2 AND relay_message_id = ?3",
|
||||
params![storage_owner, relay_signer_id, relay_message_id],
|
||||
"SELECT id, message_state FROM messages WHERE storage_owner = ?1 AND relay_signer_principal = ?2 AND relay_message_id = ?3",
|
||||
params![storage_owner, relay_signer_principal.0, relay_message_id],
|
||||
|row| Ok((row.get::<_, i64>(0)?, row.get::<_, String>(1)?)),
|
||||
)
|
||||
.optional()?
|
||||
|
|
@ -706,8 +1012,10 @@ pub fn change_message_state_by_relay_id(
|
|||
pub fn record_message_receipt(
|
||||
storage_owner: i64,
|
||||
target_signer_id: i64,
|
||||
target_signer_principal: iota_identity::PrincipalHandle,
|
||||
target_message_id: &str,
|
||||
receipt_signer_id: i64,
|
||||
receipt_signer_principal: iota_identity::PrincipalHandle,
|
||||
receipt_message_id: &str,
|
||||
receipt_type: MessageState,
|
||||
event_at: i64,
|
||||
|
|
@ -720,17 +1028,17 @@ pub fn record_message_receipt(
|
|||
};
|
||||
db::with_db(|conn| {
|
||||
let tx = conn.unchecked_transaction()?;
|
||||
let Some((message_id, external_user, authored_at, history_deleted)) = tx
|
||||
let Some((message_id, external_principal, authored_at, history_deleted)) = tx
|
||||
.query_row(
|
||||
"SELECT id, external_user, authored_at, history_deleted FROM messages WHERE storage_owner = ?1 AND relay_signer_id = ?2 AND relay_message_id = ?3",
|
||||
params![storage_owner, target_signer_id, target_message_id],
|
||||
"SELECT id, external_principal, authored_at, history_deleted FROM messages WHERE storage_owner = ?1 AND relay_signer_principal = ?2 AND relay_message_id = ?3",
|
||||
params![storage_owner, target_signer_principal.0, target_message_id],
|
||||
|row| Ok((row.get::<_, i64>(0)?, row.get::<_, i64>(1)?, row.get::<_, Option<i64>>(2)?, row.get::<_, i64>(3)?)),
|
||||
)
|
||||
.optional()?
|
||||
else {
|
||||
return Err(StorageError::Other("message receipt target was not found".into()));
|
||||
};
|
||||
if external_user != receipt_signer_id {
|
||||
if external_principal != receipt_signer_principal.0 {
|
||||
return Err(StorageError::Other(
|
||||
"message receipt signer is not the chat partner".into(),
|
||||
));
|
||||
|
|
@ -746,8 +1054,8 @@ pub fn record_message_receipt(
|
|||
return Ok(());
|
||||
}
|
||||
tx.execute(
|
||||
"INSERT OR IGNORE INTO message_receipts (storage_owner, target_signer_id, target_message_id, receipt_signer_id, receipt_message_id, receipt_type, event_at, recorded_at) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
|
||||
params![storage_owner, target_signer_id, target_message_id, receipt_signer_id, receipt_message_id, receipt_type, event_at, recorded_at],
|
||||
"INSERT OR IGNORE INTO message_receipts (storage_owner, target_signer_id, target_signer_principal, target_message_id, receipt_signer_id, receipt_signer_principal, receipt_message_id, receipt_type, event_at, recorded_at) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
|
||||
params![storage_owner, target_signer_id, target_signer_principal.0, target_message_id, receipt_signer_id, receipt_signer_principal.0, receipt_message_id, receipt_type, event_at, recorded_at],
|
||||
)?;
|
||||
let (state_column, recorded_column) = if receipt_type == "read" {
|
||||
("read_at", "read_recorded_at")
|
||||
|
|
@ -780,7 +1088,7 @@ pub fn record_message_receipt(
|
|||
|
||||
pub fn record_destination_iota_received(
|
||||
storage_owner: i64,
|
||||
relay_signer_id: i64,
|
||||
relay_signer_principal: iota_identity::PrincipalHandle,
|
||||
relay_message_id: &str,
|
||||
accepted_at: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
|
|
@ -788,8 +1096,8 @@ pub fn record_destination_iota_received(
|
|||
let tx = conn.unchecked_transaction()?;
|
||||
let Some(message_id) = tx
|
||||
.query_row(
|
||||
"SELECT id FROM messages WHERE storage_owner = ?1 AND relay_signer_id = ?2 AND relay_message_id = ?3",
|
||||
params![storage_owner, relay_signer_id, relay_message_id],
|
||||
"SELECT id FROM messages WHERE storage_owner = ?1 AND relay_signer_principal = ?2 AND relay_message_id = ?3",
|
||||
params![storage_owner, relay_signer_principal.0, relay_message_id],
|
||||
|row| row.get::<_, i64>(0),
|
||||
)
|
||||
.optional()?
|
||||
|
|
@ -814,7 +1122,7 @@ pub fn record_destination_iota_received(
|
|||
|
||||
pub fn record_delivery_failure(
|
||||
storage_owner: i64,
|
||||
relay_signer_id: i64,
|
||||
relay_signer_principal: iota_identity::PrincipalHandle,
|
||||
relay_message_id: &str,
|
||||
failure: &str,
|
||||
failed_at: i64,
|
||||
|
|
@ -823,8 +1131,8 @@ pub fn record_delivery_failure(
|
|||
let tx = conn.unchecked_transaction()?;
|
||||
let Some(message_id) = tx
|
||||
.query_row(
|
||||
"SELECT id FROM messages WHERE storage_owner = ?1 AND relay_signer_id = ?2 AND relay_message_id = ?3",
|
||||
params![storage_owner, relay_signer_id, relay_message_id],
|
||||
"SELECT id FROM messages WHERE storage_owner = ?1 AND relay_signer_principal = ?2 AND relay_message_id = ?3",
|
||||
params![storage_owner, relay_signer_principal.0, relay_message_id],
|
||||
|row| row.get::<_, i64>(0),
|
||||
)
|
||||
.optional()?
|
||||
|
|
@ -957,6 +1265,20 @@ pub fn get_messages(
|
|||
external_user: i64,
|
||||
loaded_messages: i64,
|
||||
amount: i64,
|
||||
) -> Result<Vec<StoredMessage>, StorageError> {
|
||||
let Some(principal) = crate::util::chats_util::get_user(storage_owner, external_user)?
|
||||
.and_then(|contact| contact.principal)
|
||||
else {
|
||||
return Ok(Vec::new());
|
||||
};
|
||||
get_messages_for_principal(storage_owner, principal, loaded_messages, amount)
|
||||
}
|
||||
|
||||
pub fn get_messages_for_principal(
|
||||
storage_owner: i64,
|
||||
external_principal: iota_identity::PrincipalHandle,
|
||||
loaded_messages: i64,
|
||||
amount: i64,
|
||||
) -> Result<Vec<StoredMessage>, StorageError> {
|
||||
if amount <= 0 || loaded_messages < 0 {
|
||||
return Ok(Vec::new());
|
||||
|
|
@ -969,21 +1291,25 @@ pub fn get_messages(
|
|||
origin_iota_received_at, destination_iota_received_at,
|
||||
client_received_at, client_received_recorded_at, read_at,
|
||||
read_recorded_at, delivery_failed_at, delivery_failure, content, sent_by_self, message_state, height, key_version,
|
||||
reply_to, edited_count
|
||||
reply_to, edited_count, external_user, relay_signer_principal
|
||||
FROM messages
|
||||
WHERE storage_owner = ?1 AND external_user = ?2 AND deleted_by_external = 0 AND history_deleted = 0
|
||||
WHERE storage_owner = ?1 AND external_principal = ?2 AND deleted_by_external = 0 AND history_deleted = 0
|
||||
ORDER BY COALESCE(destination_iota_received_at, origin_iota_received_at, authored_at, id) DESC, id DESC
|
||||
LIMIT ?3 OFFSET ?4
|
||||
"#,
|
||||
)?;
|
||||
|
||||
let rows = stmt.query_map(
|
||||
params![storage_owner, external_user, amount, loaded_messages],
|
||||
params![storage_owner, external_principal.0, amount, loaded_messages],
|
||||
|row| {
|
||||
Ok(StoredMessage {
|
||||
id: row.get(0)?,
|
||||
external_user,
|
||||
external_user: row.get(20)?,
|
||||
external_principal: Some(external_principal),
|
||||
relay_signer_id: row.get(1)?,
|
||||
relay_signer_principal: row
|
||||
.get::<_, Option<i64>>(21)?
|
||||
.map(iota_identity::PrincipalHandle),
|
||||
relay_message_id: row.get(2)?,
|
||||
message_time: row.get(3)?,
|
||||
authored_at: row.get(4)?,
|
||||
|
|
@ -1026,6 +1352,7 @@ pub fn get_message(
|
|||
storage_owner: i64,
|
||||
message_time: i64,
|
||||
external_user: Option<i64>,
|
||||
external_principal: Option<iota_identity::PrincipalHandle>,
|
||||
) -> Result<Option<StoredMessage>, StorageError> {
|
||||
db::with_db(|conn| {
|
||||
let mut stmt = conn.prepare(
|
||||
|
|
@ -1034,43 +1361,62 @@ pub fn get_message(
|
|||
origin_iota_received_at, destination_iota_received_at,
|
||||
client_received_at, client_received_recorded_at, read_at,
|
||||
read_recorded_at, delivery_failed_at, delivery_failure, content, sent_by_self, message_state, height, key_version,
|
||||
reply_to, edited_count, external_user
|
||||
reply_to, edited_count, external_user, external_principal,
|
||||
relay_signer_principal
|
||||
FROM messages
|
||||
WHERE storage_owner = ?1
|
||||
AND message_time = ?2
|
||||
AND deleted_by_external = 0
|
||||
AND history_deleted = 0
|
||||
AND (?3 IS NULL OR external_user = ?3)
|
||||
AND (
|
||||
?3 IS NULL
|
||||
OR (?4 IS NULL AND external_user = ?3)
|
||||
OR external_principal = ?4
|
||||
)
|
||||
ORDER BY id DESC
|
||||
"#,
|
||||
)?;
|
||||
|
||||
let rows = stmt.query_map(params![storage_owner, message_time, external_user], |row| {
|
||||
Ok(StoredMessage {
|
||||
id: row.get(0)?,
|
||||
relay_signer_id: row.get(1)?,
|
||||
relay_message_id: row.get(2)?,
|
||||
message_time: row.get(3)?,
|
||||
authored_at: row.get(4)?,
|
||||
origin_iota_received_at: row.get(5)?,
|
||||
destination_iota_received_at: row.get(6)?,
|
||||
client_received_at: row.get(7)?,
|
||||
client_received_recorded_at: row.get(8)?,
|
||||
read_at: row.get(9)?,
|
||||
read_recorded_at: row.get(10)?,
|
||||
delivery_failed_at: row.get(11)?,
|
||||
delivery_failure: row.get(12)?,
|
||||
content: row.get(13)?,
|
||||
sent_by_self: row.get::<_, i64>(14)? != 0,
|
||||
message_state: row.get(15)?,
|
||||
height: row.get(16)?,
|
||||
key_version: row.get(17)?,
|
||||
reply_to: row.get(18)?,
|
||||
edited: row.get::<_, i64>(19)? > 0,
|
||||
external_user: row.get(20)?,
|
||||
reactions: Vec::new(),
|
||||
})
|
||||
})?;
|
||||
let rows = stmt.query_map(
|
||||
params![
|
||||
storage_owner,
|
||||
message_time,
|
||||
external_user,
|
||||
external_principal.map(|principal| principal.0)
|
||||
],
|
||||
|row| {
|
||||
Ok(StoredMessage {
|
||||
id: row.get(0)?,
|
||||
relay_signer_id: row.get(1)?,
|
||||
relay_signer_principal: row
|
||||
.get::<_, Option<i64>>(22)?
|
||||
.map(iota_identity::PrincipalHandle),
|
||||
relay_message_id: row.get(2)?,
|
||||
message_time: row.get(3)?,
|
||||
authored_at: row.get(4)?,
|
||||
origin_iota_received_at: row.get(5)?,
|
||||
destination_iota_received_at: row.get(6)?,
|
||||
client_received_at: row.get(7)?,
|
||||
client_received_recorded_at: row.get(8)?,
|
||||
read_at: row.get(9)?,
|
||||
read_recorded_at: row.get(10)?,
|
||||
delivery_failed_at: row.get(11)?,
|
||||
delivery_failure: row.get(12)?,
|
||||
content: row.get(13)?,
|
||||
sent_by_self: row.get::<_, i64>(14)? != 0,
|
||||
message_state: row.get(15)?,
|
||||
height: row.get(16)?,
|
||||
key_version: row.get(17)?,
|
||||
reply_to: row.get(18)?,
|
||||
edited: row.get::<_, i64>(19)? > 0,
|
||||
external_user: row.get(20)?,
|
||||
external_principal: row
|
||||
.get::<_, Option<i64>>(21)?
|
||||
.map(iota_identity::PrincipalHandle),
|
||||
reactions: Vec::new(),
|
||||
})
|
||||
},
|
||||
)?;
|
||||
|
||||
let messages: Vec<StoredMessage> = rows.collect::<Result<_, _>>()?;
|
||||
if messages.is_empty() {
|
||||
|
|
@ -1079,7 +1425,7 @@ pub fn get_message(
|
|||
if external_user.is_none()
|
||||
&& messages
|
||||
.iter()
|
||||
.map(|message| message.external_user)
|
||||
.filter_map(|message| message.external_principal)
|
||||
.collect::<std::collections::HashSet<_>>()
|
||||
.len()
|
||||
> 1
|
||||
|
|
@ -1099,7 +1445,18 @@ pub fn get_message_with_offset(
|
|||
external_user: i64,
|
||||
message_time: i64,
|
||||
) -> Result<Option<(StoredMessage, i64)>, StorageError> {
|
||||
let Some(message) = get_message(storage_owner, message_time, Some(external_user))? else {
|
||||
let Some(external_principal) = crate::util::chats_util::get_user(storage_owner, external_user)?
|
||||
.and_then(|contact| contact.principal)
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
let Some(message) = get_message(
|
||||
storage_owner,
|
||||
message_time,
|
||||
Some(external_user),
|
||||
Some(external_principal),
|
||||
)?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
let offset = db::with_db(|conn| {
|
||||
|
|
@ -1108,7 +1465,7 @@ pub fn get_message_with_offset(
|
|||
SELECT COUNT(*)
|
||||
FROM messages
|
||||
WHERE storage_owner = ?1
|
||||
AND external_user = ?2
|
||||
AND external_principal = ?2
|
||||
AND deleted_by_external = 0
|
||||
AND history_deleted = 0
|
||||
AND (
|
||||
|
|
@ -1120,7 +1477,7 @@ pub fn get_message_with_offset(
|
|||
"#,
|
||||
params![
|
||||
storage_owner,
|
||||
external_user,
|
||||
external_principal.0,
|
||||
message.destination_iota_received_at.or(message.origin_iota_received_at).or(message.authored_at),
|
||||
message.id
|
||||
],
|
||||
|
|
@ -1142,13 +1499,19 @@ pub fn get_messages_by_ids(
|
|||
// A journal id uniquely identifies a row. Load all messages for this owner and retain only
|
||||
// those ids; this keeps reaction hydration identical to normal message loading.
|
||||
db::with_db(|conn| {
|
||||
let mut stmt = conn.prepare("SELECT id, relay_signer_id, relay_message_id, message_time, authored_at, origin_iota_received_at, destination_iota_received_at, client_received_at, client_received_recorded_at, read_at, read_recorded_at, delivery_failed_at, delivery_failure, content, sent_by_self, message_state, height, key_version, reply_to, edited_count, external_user FROM messages WHERE storage_owner = ?1 AND deleted_by_external = 0 AND history_deleted = 0")?;
|
||||
let mut stmt = conn.prepare("SELECT id, relay_signer_id, relay_message_id, message_time, authored_at, origin_iota_received_at, destination_iota_received_at, client_received_at, client_received_recorded_at, read_at, read_recorded_at, delivery_failed_at, delivery_failure, content, sent_by_self, message_state, height, key_version, reply_to, edited_count, external_user, external_principal, relay_signer_principal FROM messages WHERE storage_owner = ?1 AND deleted_by_external = 0 AND history_deleted = 0")?;
|
||||
let rows = stmt.query_map([storage_owner], |row| {
|
||||
let external_user: i64 = row.get(20)?;
|
||||
Ok(StoredMessage {
|
||||
id: row.get(0)?,
|
||||
external_user,
|
||||
external_principal: row
|
||||
.get::<_, Option<i64>>(21)?
|
||||
.map(iota_identity::PrincipalHandle),
|
||||
relay_signer_id: row.get(1)?,
|
||||
relay_signer_principal: row
|
||||
.get::<_, Option<i64>>(22)?
|
||||
.map(iota_identity::PrincipalHandle),
|
||||
relay_message_id: row.get(2)?,
|
||||
message_time: row.get(3)?,
|
||||
authored_at: row.get(4)?,
|
||||
|
|
|
|||
Loading…
Reference in a new issue