diff --git a/base_layer/chat_ffi/chat.h b/base_layer/chat_ffi/chat.h index 89893c9b37..7117f6df17 100644 --- a/base_layer/chat_ffi/chat.h +++ b/base_layer/chat_ffi/chat.h @@ -621,6 +621,21 @@ unsigned char read_chat_message_direction(struct Message *message, int *error_ou */ unsigned long long read_chat_message_stored_at(struct Message *message, int *error_out); +/** + * Returns a c_ulonglong representation of the sent at timestamp as seconds since epoch + * + * ## Arguments + * `message` - A pointer to a Message + * `error_out` - Pointer to an int which will be modified + * + * ## Returns + * `c_ulonglong` - The stored_at timestamp, seconds since epoch. Returns 0 if message is null. + * + * ## Safety + * `message` should be destroyed eventually + */ +unsigned long long read_chat_message_sent_at(struct Message *message, int *error_out); + /** * Returns a c_ulonglong representation of the delivery confirmation timestamp as seconds since epoch * diff --git a/base_layer/chat_ffi/src/message.rs b/base_layer/chat_ffi/src/message.rs index 9be70ab11b..859ca1a76f 100644 --- a/base_layer/chat_ffi/src/message.rs +++ b/base_layer/chat_ffi/src/message.rs @@ -332,6 +332,31 @@ pub unsafe extern "C" fn read_chat_message_stored_at(message: *mut Message, erro (*message).stored_at as c_ulonglong } +/// Returns a c_ulonglong representation of the sent at timestamp as seconds since epoch +/// +/// ## Arguments +/// `message` - A pointer to a Message +/// `error_out` - Pointer to an int which will be modified +/// +/// ## Returns +/// `c_ulonglong` - The stored_at timestamp, seconds since epoch. Returns 0 if message is null. +/// +/// ## Safety +/// `message` should be destroyed eventually +#[no_mangle] +pub unsafe extern "C" fn read_chat_message_sent_at(message: *mut Message, error_out: *mut c_int) -> c_ulonglong { + let mut error = 0; + ptr::swap(error_out, &mut error as *mut c_int); + + if message.is_null() { + error = LibChatError::from(InterfaceError::NullError("message".to_string())).code; + ptr::swap(error_out, &mut error as *mut c_int); + return 0; + } + + (*message).sent_at as c_ulonglong +} + /// Returns a c_ulonglong representation of the delivery confirmation timestamp as seconds since epoch /// /// ## Arguments diff --git a/base_layer/contacts/migrations/2024-04-30-155100_add_sent_timestamp/down.sql b/base_layer/contacts/migrations/2024-04-30-155100_add_sent_timestamp/down.sql new file mode 100644 index 0000000000..ec471b151f --- /dev/null +++ b/base_layer/contacts/migrations/2024-04-30-155100_add_sent_timestamp/down.sql @@ -0,0 +1 @@ +ALTER TABLE messages drop sent_at; diff --git a/base_layer/contacts/migrations/2024-04-30-155100_add_sent_timestamp/up.sql b/base_layer/contacts/migrations/2024-04-30-155100_add_sent_timestamp/up.sql new file mode 100644 index 0000000000..37bad863b2 --- /dev/null +++ b/base_layer/contacts/migrations/2024-04-30-155100_add_sent_timestamp/up.sql @@ -0,0 +1 @@ + ALTER TABLE messages ADD sent_at TIMESTAMP; diff --git a/base_layer/contacts/src/contacts_service/service.rs b/base_layer/contacts/src/contacts_service/service.rs index 87f6379dbb..c09e13fa32 100644 --- a/base_layer/contacts/src/contacts_service/service.rs +++ b/base_layer/contacts/src/contacts_service/service.rs @@ -299,6 +299,7 @@ where T: ContactsBackend + 'static Ok(result.map(ContactsServiceResponse::Messages)?) }, ContactsServiceRequest::SendMessage(address, mut message) => { + message.sent_at = Utc::now().naive_utc().timestamp() as u64; let ob_message = OutboundDomainMessage::from(MessageDispatch::Message(message.clone())); message.stored_at = Utc::now().naive_utc().timestamp() as u64; diff --git a/base_layer/contacts/src/contacts_service/storage/types/messages.rs b/base_layer/contacts/src/contacts_service/storage/types/messages.rs index 83c1339836..2f32fba8f3 100644 --- a/base_layer/contacts/src/contacts_service/storage/types/messages.rs +++ b/base_layer/contacts/src/contacts_service/storage/types/messages.rs @@ -46,6 +46,7 @@ pub struct MessagesSqlInsert { pub body: Vec, pub metadata: Vec, pub stored_at: NaiveDateTime, + pub sent_at: NaiveDateTime, pub direction: i32, } @@ -58,6 +59,7 @@ pub struct MessagesSql { pub body: Vec, pub metadata: Vec, pub stored_at: NaiveDateTime, + pub sent_at: NaiveDateTime, pub delivery_confirmation_at: Option, pub read_confirmation_at: Option, pub direction: i32, @@ -145,6 +147,7 @@ impl TryFrom for Message { u8::try_from(o.direction).map_err(|_| ContactsServiceStorageError::ConversionError)?, ) .ok_or(ContactsServiceStorageError::ConversionError)?, + sent_at: o.sent_at.timestamp() as u64, stored_at: o.stored_at.timestamp() as u64, delivery_confirmation_at: Some(o.stored_at.timestamp() as u64), read_confirmation_at: Some(o.stored_at.timestamp() as u64), @@ -168,7 +171,10 @@ impl TryFrom for MessagesSqlInsert { message_id: o.message_id, body: o.body, metadata: metadata.into_bytes().to_vec(), - stored_at: NaiveDateTime::from_timestamp_opt(o.stored_at as i64, 0).unwrap(), + stored_at: NaiveDateTime::from_timestamp_opt(o.stored_at as i64, 0) + .ok_or(ContactsServiceStorageError::ConversionError)?, + sent_at: NaiveDateTime::from_timestamp_opt(o.sent_at as i64, 0) + .ok_or(ContactsServiceStorageError::ConversionError)?, direction: i32::from(o.direction.as_byte()), }) } diff --git a/base_layer/contacts/src/contacts_service/types/message.rs b/base_layer/contacts/src/contacts_service/types/message.rs index d259f8da78..7f26c9aece 100644 --- a/base_layer/contacts/src/contacts_service/types/message.rs +++ b/base_layer/contacts/src/contacts_service/types/message.rs @@ -38,6 +38,7 @@ pub struct Message { pub metadata: Vec, pub address: TariAddress, pub direction: Direction, + pub sent_at: u64, pub stored_at: u64, pub delivery_confirmation_at: Option, pub read_confirmation_at: Option, diff --git a/base_layer/contacts/src/schema.rs b/base_layer/contacts/src/schema.rs index 9a57007c44..4e62b4534e 100644 --- a/base_layer/contacts/src/schema.rs +++ b/base_layer/contacts/src/schema.rs @@ -18,6 +18,7 @@ diesel::table! { body -> Binary, metadata -> Binary, stored_at -> Timestamp, + sent_at -> Timestamp, delivery_confirmation_at -> Nullable, read_confirmation_at -> Nullable, direction -> Integer, diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index ec5050a0ca..482d5b37a6 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -11576,6 +11576,7 @@ mod test { address: bob_wallet_address.clone(), direction: Direction::Outbound, stored_at: u64::from(i), + sent_at: u64::from(i), delivery_confirmation_at: None, read_confirmation_at: None, message_id: vec![i], @@ -11592,6 +11593,7 @@ mod test { address: alice_wallet_address.clone(), direction: Direction::Outbound, stored_at: u64::from(i), + sent_at: u64::from(i), delivery_confirmation_at: None, read_confirmation_at: None, message_id: vec![i],