Skip to content

Commit

Permalink
Group message delivery status (#232)
Browse files Browse the repository at this point in the history
* dump the schema changes

* dump the latest jni

* add delivery status to message

* correctly return message id

* fix the test

* add test for filtering
  • Loading branch information
nplasterer authored Apr 18, 2024
1 parent 6030e8c commit e6a7bfe
Show file tree
Hide file tree
Showing 12 changed files with 138 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.xmtp.android.library.codecs.Reaction
import org.xmtp.android.library.codecs.ReactionAction
import org.xmtp.android.library.codecs.ReactionCodec
import org.xmtp.android.library.codecs.ReactionSchema
import org.xmtp.android.library.messages.MessageDeliveryStatus
import org.xmtp.android.library.messages.PrivateKey
import org.xmtp.android.library.messages.PrivateKeyBuilder
import org.xmtp.android.library.messages.walletAddress
Expand Down Expand Up @@ -330,9 +331,11 @@ class GroupTest {
fun testCanSendMessageToGroup() {
val group = runBlocking { boClient.conversations.newGroup(listOf(alix.walletAddress)) }
runBlocking { group.send("howdy") }
runBlocking { group.send("gm") }
val messageId = runBlocking { group.send("gm") }
runBlocking { group.sync() }
assertEquals(group.messages().first().body, "gm")
assertEquals(group.messages().first().id, messageId)
assertEquals(group.messages().first().deliveryStatus, MessageDeliveryStatus.PUBLISHED)
assertEquals(group.messages().size, 3)

runBlocking { alixClient.conversations.syncGroups() }
Expand All @@ -342,6 +345,28 @@ class GroupTest {
assertEquals(sameGroup.messages().first().body, "gm")
}

@Test
fun testCanListGroupMessages() {
val group = runBlocking { boClient.conversations.newGroup(listOf(alix.walletAddress)) }
runBlocking {
group.send("howdy")
group.send("gm")
}

assertEquals(group.messages().size, 3)
assertEquals(group.messages(deliveryStatus = MessageDeliveryStatus.UNPUBLISHED).size, 2)
assertEquals(group.messages(deliveryStatus = MessageDeliveryStatus.PUBLISHED).size, 1)
runBlocking { group.sync() }
assertEquals(group.messages().size, 3)
assertEquals(group.messages(deliveryStatus = MessageDeliveryStatus.UNPUBLISHED).size, 0)
assertEquals(group.messages(deliveryStatus = MessageDeliveryStatus.PUBLISHED).size, 3)

runBlocking { alixClient.conversations.syncGroups() }
val sameGroup = runBlocking { alixClient.conversations.listGroups().last() }
runBlocking { sameGroup.sync() }
assertEquals(sameGroup.messages(deliveryStatus = MessageDeliveryStatus.PUBLISHED).size, 2)
}

@Test
fun testCanSendContentTypesToGroup() {
Client.register(codec = ReactionCodec())
Expand Down
4 changes: 2 additions & 2 deletions library/src/main/java/libxmtp-version.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Version: 4068715
Version: 5b62701
Branch: main
Date: 2024-04-06 04:27:39 +0000
Date: 2024-04-18 03:59:02 +0000
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.xmtp.android.library

import org.xmtp.android.library.codecs.TextCodec
import org.xmtp.android.library.codecs.decoded
import org.xmtp.android.library.messages.MessageDeliveryStatus
import org.xmtp.proto.message.contents.Content
import java.util.Date

Expand All @@ -12,6 +13,7 @@ data class DecodedMessage(
var encodedContent: Content.EncodedContent,
var senderAddress: String,
var sent: Date,
var deliveryStatus: MessageDeliveryStatus = MessageDeliveryStatus.PUBLISHED
) {
companion object {
fun preview(client: Client, topic: String, body: String, senderAddress: String, sent: Date): DecodedMessage {
Expand Down
24 changes: 20 additions & 4 deletions library/src/main/java/org/xmtp/android/library/Group.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import org.xmtp.android.library.codecs.EncodedContent
import org.xmtp.android.library.codecs.compress
import org.xmtp.android.library.libxmtp.MessageV3
import org.xmtp.android.library.messages.DecryptedMessage
import org.xmtp.android.library.messages.MessageDeliveryStatus
import org.xmtp.android.library.messages.PagingInfoSortDirection
import org.xmtp.android.library.messages.Topic
import org.xmtp.proto.message.api.v1.MessageApiOuterClass
import uniffi.xmtpv3.FfiDeliveryStatus
import uniffi.xmtpv3.FfiGroup
import uniffi.xmtpv3.FfiGroupMetadata
import uniffi.xmtpv3.FfiListMessagesOptions
Expand Down Expand Up @@ -47,8 +49,8 @@ class Group(val client: Client, private val libXMTPGroup: FfiGroup) {
if (client.contacts.consentList.groupState(groupId = id) == ConsentState.UNKNOWN) {
client.contacts.allowGroup(groupIds = listOf(id))
}
libXMTPGroup.send(contentBytes = encodedContent.toByteArray())
return id.toHex()
val messageId = libXMTPGroup.send(contentBytes = encodedContent.toByteArray())
return messageId.toHex()
}

fun <T> prepareMessage(content: T, options: SendOptions?): EncodedContent {
Expand Down Expand Up @@ -86,12 +88,19 @@ class Group(val client: Client, private val libXMTPGroup: FfiGroup) {
before: Date? = null,
after: Date? = null,
direction: PagingInfoSortDirection = MessageApiOuterClass.SortDirection.SORT_DIRECTION_DESCENDING,
deliveryStatus: MessageDeliveryStatus = MessageDeliveryStatus.ALL,
): List<DecodedMessage> {
val messages = libXMTPGroup.findMessages(
opts = FfiListMessagesOptions(
sentBeforeNs = before?.time?.nanoseconds?.toLong(DurationUnit.NANOSECONDS),
sentAfterNs = after?.time?.nanoseconds?.toLong(DurationUnit.NANOSECONDS),
limit = limit?.toLong()
limit = limit?.toLong(),
deliveryStatus = when (deliveryStatus) {
MessageDeliveryStatus.PUBLISHED -> FfiDeliveryStatus.PUBLISHED
MessageDeliveryStatus.UNPUBLISHED -> FfiDeliveryStatus.UNPUBLISHED
MessageDeliveryStatus.FAILED -> FfiDeliveryStatus.FAILED
else -> null
}
)
).mapNotNull {
MessageV3(client, it).decodeOrNull()
Expand All @@ -108,12 +117,19 @@ class Group(val client: Client, private val libXMTPGroup: FfiGroup) {
before: Date? = null,
after: Date? = null,
direction: PagingInfoSortDirection = MessageApiOuterClass.SortDirection.SORT_DIRECTION_DESCENDING,
deliveryStatus: MessageDeliveryStatus = MessageDeliveryStatus.ALL,
): List<DecryptedMessage> {
val messages = libXMTPGroup.findMessages(
opts = FfiListMessagesOptions(
sentBeforeNs = before?.time?.nanoseconds?.toLong(DurationUnit.NANOSECONDS),
sentAfterNs = after?.time?.nanoseconds?.toLong(DurationUnit.NANOSECONDS),
limit = limit?.toLong()
limit = limit?.toLong(),
deliveryStatus = when (deliveryStatus) {
MessageDeliveryStatus.PUBLISHED -> FfiDeliveryStatus.PUBLISHED
MessageDeliveryStatus.UNPUBLISHED -> FfiDeliveryStatus.UNPUBLISHED
MessageDeliveryStatus.FAILED -> FfiDeliveryStatus.FAILED
else -> null
}
)
).mapNotNull {
MessageV3(client, it).decryptOrNull()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import org.xmtp.android.library.DecodedMessage
import org.xmtp.android.library.XMTPException
import org.xmtp.android.library.codecs.EncodedContent
import org.xmtp.android.library.messages.DecryptedMessage
import org.xmtp.android.library.messages.MessageDeliveryStatus
import org.xmtp.android.library.messages.Topic
import org.xmtp.android.library.toHex
import uniffi.xmtpv3.FfiDeliveryStatus
import uniffi.xmtpv3.FfiGroupMessageKind
import uniffi.xmtpv3.FfiMessage
import uniffi.xmtpv3.org.xmtp.android.library.codecs.ContentTypeGroupMembershipChange
Expand All @@ -27,6 +29,13 @@ data class MessageV3(val client: Client, private val libXMTPMessage: FfiMessage)
val sentAt: Date
get() = Date(libXMTPMessage.sentAtNs / 1_000_000)

val deliveryStatus: MessageDeliveryStatus
get() = when (libXMTPMessage.deliveryStatus) {
FfiDeliveryStatus.UNPUBLISHED -> MessageDeliveryStatus.UNPUBLISHED
FfiDeliveryStatus.PUBLISHED -> MessageDeliveryStatus.PUBLISHED
FfiDeliveryStatus.FAILED -> MessageDeliveryStatus.FAILED
}

fun decode(): DecodedMessage {
try {
val decodedMessage = DecodedMessage(
Expand All @@ -36,6 +45,7 @@ data class MessageV3(val client: Client, private val libXMTPMessage: FfiMessage)
encodedContent = EncodedContent.parseFrom(libXMTPMessage.content),
senderAddress = senderAddress,
sent = sentAt,
deliveryStatus = deliveryStatus
)
if (decodedMessage.encodedContent.type == ContentTypeGroupMembershipChange && libXMTPMessage.kind != FfiGroupMessageKind.MEMBERSHIP_CHANGE) {
throw XMTPException("Error decoding group membership change")
Expand Down Expand Up @@ -71,6 +81,7 @@ data class MessageV3(val client: Client, private val libXMTPMessage: FfiMessage)
encodedContent = decode().encodedContent,
senderAddress = senderAddress,
sentAt = Date(),
deliveryStatus = deliveryStatus
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ data class DecryptedMessage(
var senderAddress: String,
var sentAt: Date,
var topic: String = "",
var deliveryStatus: MessageDeliveryStatus = MessageDeliveryStatus.PUBLISHED
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package org.xmtp.android.library.messages

typealias Message = org.xmtp.proto.message.contents.MessageOuterClass.Message

enum class MessageDeliveryStatus {
ALL, PUBLISHED, UNPUBLISHED, FAILED
}

enum class MessageVersion(val rawValue: String) {
V1("v1"),
V2("v2");
Expand Down
84 changes: 72 additions & 12 deletions library/src/main/java/xmtpv3.kt
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,7 @@ private fun uniffiCheckApiChecksums(lib: _UniFFILib) {
if (lib.uniffi_xmtpv3_checksum_method_ffigroup_remove_members() != 1645.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_xmtpv3_checksum_method_ffigroup_send() != 55957.toShort()) {
if (lib.uniffi_xmtpv3_checksum_method_ffigroup_send() != 2523.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_xmtpv3_checksum_method_ffigroup_stream() != 7482.toShort()) {
Expand Down Expand Up @@ -1505,7 +1505,7 @@ public interface FfiGroupInterface {
fun `listMembers`(): List<FfiGroupMember>@Throws(GenericException::class)
suspend fun `processStreamedGroupMessage`(`envelopeBytes`: ByteArray): FfiMessage@Throws(GenericException::class)
suspend fun `removeMembers`(`accountAddresses`: List<String>)@Throws(GenericException::class)
suspend fun `send`(`contentBytes`: ByteArray)@Throws(GenericException::class)
suspend fun `send`(`contentBytes`: ByteArray): ByteArray@Throws(GenericException::class)
suspend fun `stream`(`messageCallback`: FfiMessageCallback): FfiStreamCloser@Throws(GenericException::class)
suspend fun `sync`()
companion object
Expand Down Expand Up @@ -1676,20 +1676,19 @@ class FfiGroup(

@Throws(GenericException::class)
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
override suspend fun `send`(`contentBytes`: ByteArray) {
override suspend fun `send`(`contentBytes`: ByteArray) : ByteArray {
return uniffiRustCallAsync(
callWithPointer { thisPtr ->
_UniFFILib.INSTANCE.uniffi_xmtpv3_fn_method_ffigroup_send(
thisPtr,
FfiConverterByteArray.lower(`contentBytes`),
)
},
{ future, continuation -> _UniFFILib.INSTANCE.ffi_xmtpv3_rust_future_poll_void(future, continuation) },
{ future, continuation -> _UniFFILib.INSTANCE.ffi_xmtpv3_rust_future_complete_void(future, continuation) },
{ future -> _UniFFILib.INSTANCE.ffi_xmtpv3_rust_future_free_void(future) },
{ future, continuation -> _UniFFILib.INSTANCE.ffi_xmtpv3_rust_future_poll_rust_buffer(future, continuation) },
{ future, continuation -> _UniFFILib.INSTANCE.ffi_xmtpv3_rust_future_complete_rust_buffer(future, continuation) },
{ future -> _UniFFILib.INSTANCE.ffi_xmtpv3_rust_future_free_rust_buffer(future) },
// lift function
{ Unit },

{ FfiConverterByteArray.lift(it) },
// Error FFI converter
GenericException.ErrorHandler,
)
Expand Down Expand Up @@ -2484,7 +2483,8 @@ public object FfiConverterTypeFfiListConversationsOptions: FfiConverterRustBuffe
data class FfiListMessagesOptions (
var `sentBeforeNs`: Long?,
var `sentAfterNs`: Long?,
var `limit`: Long?
var `limit`: Long?,
var `deliveryStatus`: FfiDeliveryStatus?
) {

companion object
Expand All @@ -2496,19 +2496,22 @@ public object FfiConverterTypeFfiListMessagesOptions: FfiConverterRustBuffer<Ffi
FfiConverterOptionalLong.read(buf),
FfiConverterOptionalLong.read(buf),
FfiConverterOptionalLong.read(buf),
FfiConverterOptionalTypeFfiDeliveryStatus.read(buf),
)
}

override fun allocationSize(value: FfiListMessagesOptions) = (
FfiConverterOptionalLong.allocationSize(value.`sentBeforeNs`) +
FfiConverterOptionalLong.allocationSize(value.`sentAfterNs`) +
FfiConverterOptionalLong.allocationSize(value.`limit`)
FfiConverterOptionalLong.allocationSize(value.`limit`) +
FfiConverterOptionalTypeFfiDeliveryStatus.allocationSize(value.`deliveryStatus`)
)

override fun write(value: FfiListMessagesOptions, buf: ByteBuffer) {
FfiConverterOptionalLong.write(value.`sentBeforeNs`, buf)
FfiConverterOptionalLong.write(value.`sentAfterNs`, buf)
FfiConverterOptionalLong.write(value.`limit`, buf)
FfiConverterOptionalTypeFfiDeliveryStatus.write(value.`deliveryStatus`, buf)
}
}

Expand All @@ -2521,7 +2524,8 @@ data class FfiMessage (
var `convoId`: ByteArray,
var `addrFrom`: String,
var `content`: ByteArray,
var `kind`: FfiGroupMessageKind
var `kind`: FfiGroupMessageKind,
var `deliveryStatus`: FfiDeliveryStatus
) {

companion object
Expand All @@ -2536,6 +2540,7 @@ public object FfiConverterTypeFfiMessage: FfiConverterRustBuffer<FfiMessage> {
FfiConverterString.read(buf),
FfiConverterByteArray.read(buf),
FfiConverterTypeFfiGroupMessageKind.read(buf),
FfiConverterTypeFfiDeliveryStatus.read(buf),
)
}

Expand All @@ -2545,7 +2550,8 @@ public object FfiConverterTypeFfiMessage: FfiConverterRustBuffer<FfiMessage> {
FfiConverterByteArray.allocationSize(value.`convoId`) +
FfiConverterString.allocationSize(value.`addrFrom`) +
FfiConverterByteArray.allocationSize(value.`content`) +
FfiConverterTypeFfiGroupMessageKind.allocationSize(value.`kind`)
FfiConverterTypeFfiGroupMessageKind.allocationSize(value.`kind`) +
FfiConverterTypeFfiDeliveryStatus.allocationSize(value.`deliveryStatus`)
)

override fun write(value: FfiMessage, buf: ByteBuffer) {
Expand All @@ -2555,6 +2561,7 @@ public object FfiConverterTypeFfiMessage: FfiConverterRustBuffer<FfiMessage> {
FfiConverterString.write(value.`addrFrom`, buf)
FfiConverterByteArray.write(value.`content`, buf)
FfiConverterTypeFfiGroupMessageKind.write(value.`kind`, buf)
FfiConverterTypeFfiDeliveryStatus.write(value.`deliveryStatus`, buf)
}
}

Expand Down Expand Up @@ -2767,6 +2774,30 @@ public object FfiConverterTypeFfiV2SubscribeRequest: FfiConverterRustBuffer<FfiV



enum class FfiDeliveryStatus {
UNPUBLISHED,PUBLISHED,FAILED;
companion object
}

public object FfiConverterTypeFfiDeliveryStatus: FfiConverterRustBuffer<FfiDeliveryStatus> {
override fun read(buf: ByteBuffer) = try {
FfiDeliveryStatus.values()[buf.getInt() - 1]
} catch (e: IndexOutOfBoundsException) {
throw RuntimeException("invalid enum value, something is very wrong!!", e)
}

override fun allocationSize(value: FfiDeliveryStatus) = 4

override fun write(value: FfiDeliveryStatus, buf: ByteBuffer) {
buf.putInt(value.ordinal + 1)
}
}






enum class FfiGroupMessageKind {
APPLICATION,MEMBERSHIP_CHANGE;
companion object
Expand Down Expand Up @@ -3591,6 +3622,35 @@ public object FfiConverterOptionalTypeFfiPagingInfo: FfiConverterRustBuffer<FfiP



public object FfiConverterOptionalTypeFfiDeliveryStatus: FfiConverterRustBuffer<FfiDeliveryStatus?> {
override fun read(buf: ByteBuffer): FfiDeliveryStatus? {
if (buf.get().toInt() == 0) {
return null
}
return FfiConverterTypeFfiDeliveryStatus.read(buf)
}

override fun allocationSize(value: FfiDeliveryStatus?): Int {
if (value == null) {
return 1
} else {
return 1 + FfiConverterTypeFfiDeliveryStatus.allocationSize(value)
}
}

override fun write(value: FfiDeliveryStatus?, buf: ByteBuffer) {
if (value == null) {
buf.put(0)
} else {
buf.put(1)
FfiConverterTypeFfiDeliveryStatus.write(value, buf)
}
}
}




public object FfiConverterOptionalTypeGroupPermissions: FfiConverterRustBuffer<GroupPermissions?> {
override fun read(buf: ByteBuffer): GroupPermissions? {
if (buf.get().toInt() == 0) {
Expand Down
Binary file modified library/src/main/jniLibs/arm64-v8a/libuniffi_xmtpv3.so
Binary file not shown.
Binary file modified library/src/main/jniLibs/armeabi-v7a/libuniffi_xmtpv3.so
Binary file not shown.
Binary file modified library/src/main/jniLibs/x86/libuniffi_xmtpv3.so
Binary file not shown.
Binary file modified library/src/main/jniLibs/x86_64/libuniffi_xmtpv3.so
Binary file not shown.

0 comments on commit e6a7bfe

Please sign in to comment.