Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Group Admin Updates #185

Merged
merged 9 commits into from
Feb 21, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ class GroupTest {
runBlocking { alixGroup.sync() }
assertEquals(alixGroup.memberAddresses().size, 3)
assertEquals(boGroup.memberAddresses().size, 3)

assertEquals(boGroup.permissionLevel(), GroupPermissions.EVERYONE_IS_ADMIN)
assertEquals(alixGroup.permissionLevel(), GroupPermissions.EVERYONE_IS_ADMIN)
assertEquals(boGroup.adminAddress().lowercase(), boClient.address.lowercase())
assertEquals(alixGroup.adminAddress().lowercase(), boClient.address.lowercase())
assert(boGroup.isAdmin())
assert(!alixGroup.isAdmin())
}

@Test
Expand Down Expand Up @@ -115,6 +122,13 @@ class GroupTest {
runBlocking { boGroup.sync() }
assertEquals(alixGroup.memberAddresses().size, 2)
assertEquals(boGroup.memberAddresses().size, 2)

assertEquals(boGroup.permissionLevel(), GroupPermissions.GROUP_CREATOR_IS_ADMIN)
assertEquals(alixGroup.permissionLevel(), GroupPermissions.GROUP_CREATOR_IS_ADMIN)
assertEquals(boGroup.adminAddress().lowercase(), boClient.address.lowercase())
assertEquals(alixGroup.adminAddress().lowercase(), boClient.address.lowercase())
assert(boGroup.isAdmin())
assert(!alixGroup.isAdmin())
}

@Test
Expand Down
17 changes: 17 additions & 0 deletions library/src/main/java/org/xmtp/android/library/Group.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import org.xmtp.android.library.messages.DecryptedMessage
import org.xmtp.android.library.messages.PagingInfoSortDirection
import org.xmtp.proto.message.api.v1.MessageApiOuterClass
import uniffi.xmtpv3.FfiGroup
import uniffi.xmtpv3.FfiGroupMetadata
import uniffi.xmtpv3.FfiListMessagesOptions
import uniffi.xmtpv3.FfiMessage
import uniffi.xmtpv3.FfiMessageCallback
import uniffi.xmtpv3.GroupPermissions
import java.lang.Exception
import java.util.Date
import kotlin.time.Duration.Companion.nanoseconds
Expand All @@ -27,6 +29,9 @@ class Group(val client: Client, private val libXMTPGroup: FfiGroup) {
val createdAt: Date
get() = Date(libXMTPGroup.createdAtNs() / 1_000_000)

private val metadata: FfiGroupMetadata
get() = libXMTPGroup.groupMetadata()

fun send(text: String): String {
return send(prepareMessage(content = text, options = null))
}
Expand Down Expand Up @@ -133,6 +138,18 @@ class Group(val client: Client, private val libXMTPGroup: FfiGroup) {
return libXMTPGroup.isActive()
}

fun permissionLevel(): GroupPermissions {
return metadata.policyType()
}

fun isAdmin(): Boolean {
return metadata.creatorAccountAddress().lowercase() == client.address.lowercase()
}

fun adminAddress(): String {
return metadata.creatorAccountAddress()
}

fun addMembers(addresses: List<String>) {
try {
runBlocking { libXMTPGroup.addMembers(addresses) }
Expand Down
175 changes: 172 additions & 3 deletions library/src/main/java/xmtpv3.kt
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,8 @@ internal interface _UniFFILib : Library {
): Pointer
fun uniffi_xmtpv3_fn_method_fficonversations_stream(`ptr`: Pointer,`callback`: Long,
): Pointer
fun uniffi_xmtpv3_fn_method_fficonversations_stream_all_messages(`ptr`: Pointer,`messageCallback`: Long,
): Pointer
fun uniffi_xmtpv3_fn_method_fficonversations_sync(`ptr`: Pointer,
): Pointer
fun uniffi_xmtpv3_fn_free_ffigroup(`ptr`: Pointer,_uniffi_out_err: RustCallStatus,
Expand All @@ -411,6 +413,8 @@ internal interface _UniFFILib : Library {
): Long
fun uniffi_xmtpv3_fn_method_ffigroup_find_messages(`ptr`: Pointer,`opts`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
): RustBuffer.ByValue
fun uniffi_xmtpv3_fn_method_ffigroup_group_metadata(`ptr`: Pointer,_uniffi_out_err: RustCallStatus,
): Pointer
fun uniffi_xmtpv3_fn_method_ffigroup_id(`ptr`: Pointer,_uniffi_out_err: RustCallStatus,
): RustBuffer.ByValue
fun uniffi_xmtpv3_fn_method_ffigroup_is_active(`ptr`: Pointer,_uniffi_out_err: RustCallStatus,
Expand All @@ -425,6 +429,14 @@ internal interface _UniFFILib : Library {
): Pointer
fun uniffi_xmtpv3_fn_method_ffigroup_sync(`ptr`: Pointer,
): Pointer
fun uniffi_xmtpv3_fn_free_ffigroupmetadata(`ptr`: Pointer,_uniffi_out_err: RustCallStatus,
): Unit
fun uniffi_xmtpv3_fn_method_ffigroupmetadata_conversation_type(`ptr`: Pointer,_uniffi_out_err: RustCallStatus,
): RustBuffer.ByValue
fun uniffi_xmtpv3_fn_method_ffigroupmetadata_creator_account_address(`ptr`: Pointer,_uniffi_out_err: RustCallStatus,
): RustBuffer.ByValue
fun uniffi_xmtpv3_fn_method_ffigroupmetadata_policy_type(`ptr`: Pointer,_uniffi_out_err: RustCallStatus,
): RustBuffer.ByValue
fun uniffi_xmtpv3_fn_free_ffistreamcloser(`ptr`: Pointer,_uniffi_out_err: RustCallStatus,
): Unit
fun uniffi_xmtpv3_fn_method_ffistreamcloser_end(`ptr`: Pointer,_uniffi_out_err: RustCallStatus,
Expand Down Expand Up @@ -647,6 +659,8 @@ internal interface _UniFFILib : Library {
): Short
fun uniffi_xmtpv3_checksum_method_fficonversations_stream(
): Short
fun uniffi_xmtpv3_checksum_method_fficonversations_stream_all_messages(
): Short
fun uniffi_xmtpv3_checksum_method_fficonversations_sync(
): Short
fun uniffi_xmtpv3_checksum_method_ffigroup_add_members(
Expand All @@ -655,6 +669,8 @@ internal interface _UniFFILib : Library {
): Short
fun uniffi_xmtpv3_checksum_method_ffigroup_find_messages(
): Short
fun uniffi_xmtpv3_checksum_method_ffigroup_group_metadata(
): Short
fun uniffi_xmtpv3_checksum_method_ffigroup_id(
): Short
fun uniffi_xmtpv3_checksum_method_ffigroup_is_active(
Expand All @@ -669,6 +685,12 @@ internal interface _UniFFILib : Library {
): Short
fun uniffi_xmtpv3_checksum_method_ffigroup_sync(
): Short
fun uniffi_xmtpv3_checksum_method_ffigroupmetadata_conversation_type(
): Short
fun uniffi_xmtpv3_checksum_method_ffigroupmetadata_creator_account_address(
): Short
fun uniffi_xmtpv3_checksum_method_ffigroupmetadata_policy_type(
): Short
fun uniffi_xmtpv3_checksum_method_ffistreamcloser_end(
): Short
fun uniffi_xmtpv3_checksum_method_ffistreamcloser_is_closed(
Expand Down Expand Up @@ -777,6 +799,9 @@ private fun uniffiCheckApiChecksums(lib: _UniFFILib) {
if (lib.uniffi_xmtpv3_checksum_method_fficonversations_stream() != 60583.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_xmtpv3_checksum_method_fficonversations_stream_all_messages() != 65211.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_xmtpv3_checksum_method_fficonversations_sync() != 62598.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
Expand All @@ -789,6 +814,9 @@ private fun uniffiCheckApiChecksums(lib: _UniFFILib) {
if (lib.uniffi_xmtpv3_checksum_method_ffigroup_find_messages() != 61973.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_xmtpv3_checksum_method_ffigroup_group_metadata() != 3690.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_xmtpv3_checksum_method_ffigroup_id() != 35243.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
Expand All @@ -810,6 +838,15 @@ private fun uniffiCheckApiChecksums(lib: _UniFFILib) {
if (lib.uniffi_xmtpv3_checksum_method_ffigroup_sync() != 9422.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_xmtpv3_checksum_method_ffigroupmetadata_conversation_type() != 37015.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_xmtpv3_checksum_method_ffigroupmetadata_creator_account_address() != 1906.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_xmtpv3_checksum_method_ffigroupmetadata_policy_type() != 22845.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_xmtpv3_checksum_method_ffistreamcloser_end() != 47211.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
Expand Down Expand Up @@ -1259,6 +1296,7 @@ public interface FfiConversationsInterface {
suspend fun `createGroup`(`accountAddresses`: List<String>, `permissions`: GroupPermissions?): FfiGroup@Throws(GenericException::class)
suspend fun `list`(`opts`: FfiListConversationsOptions): List<FfiGroup>@Throws(GenericException::class)
suspend fun `stream`(`callback`: FfiConversationCallback): FfiStreamCloser@Throws(GenericException::class)
suspend fun `streamAllMessages`(`messageCallback`: FfiMessageCallback): FfiStreamCloser@Throws(GenericException::class)
suspend fun `sync`()
companion object
}
Expand Down Expand Up @@ -1342,6 +1380,26 @@ class FfiConversations(
)
}

@Throws(GenericException::class)
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
override suspend fun `streamAllMessages`(`messageCallback`: FfiMessageCallback) : FfiStreamCloser {
return uniffiRustCallAsync(
callWithPointer { thisPtr ->
_UniFFILib.INSTANCE.uniffi_xmtpv3_fn_method_fficonversations_stream_all_messages(
thisPtr,
FfiConverterTypeFfiMessageCallback.lower(`messageCallback`),
)
},
{ future, continuation -> _UniFFILib.INSTANCE.ffi_xmtpv3_rust_future_poll_pointer(future, continuation) },
{ future, continuation -> _UniFFILib.INSTANCE.ffi_xmtpv3_rust_future_complete_pointer(future, continuation) },
{ future -> _UniFFILib.INSTANCE.ffi_xmtpv3_rust_future_free_pointer(future) },
// lift function
{ FfiConverterTypeFfiStreamCloser.lift(it) },
// Error FFI converter
GenericException.ErrorHandler,
)
}

@Throws(GenericException::class)
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
override suspend fun `sync`() {
Expand Down Expand Up @@ -1398,7 +1456,8 @@ public interface FfiGroupInterface {
@Throws(GenericException::class)
suspend fun `addMembers`(`accountAddresses`: List<String>)
fun `createdAtNs`(): Long@Throws(GenericException::class)
fun `findMessages`(`opts`: FfiListMessagesOptions): List<FfiMessage>
fun `findMessages`(`opts`: FfiListMessagesOptions): List<FfiMessage>@Throws(GenericException::class)
fun `groupMetadata`(): FfiGroupMetadata
fun `id`(): ByteArray@Throws(GenericException::class)
fun `isActive`(): Boolean@Throws(GenericException::class)
fun `listMembers`(): List<FfiGroupMember>@Throws(GenericException::class)
Expand Down Expand Up @@ -1471,6 +1530,18 @@ class FfiGroup(
FfiConverterSequenceTypeFfiMessage.lift(it)
}


@Throws(GenericException::class)override fun `groupMetadata`(): FfiGroupMetadata =
callWithPointer {
rustCallWithError(GenericException) { _status ->
_UniFFILib.INSTANCE.uniffi_xmtpv3_fn_method_ffigroup_group_metadata(it,

_status)
}
}.let {
FfiConverterTypeFfiGroupMetadata.lift(it)
}

override fun `id`(): ByteArray =
callWithPointer {
rustCall() { _status ->
Expand Down Expand Up @@ -1621,6 +1692,98 @@ public object FfiConverterTypeFfiGroup: FfiConverter<FfiGroup, Pointer> {



public interface FfiGroupMetadataInterface {

fun `conversationType`(): String
fun `creatorAccountAddress`(): String@Throws(GenericException::class)
fun `policyType`(): GroupPermissions
companion object
}

class FfiGroupMetadata(
pointer: Pointer
) : FFIObject(pointer), FfiGroupMetadataInterface {

/**
* Disconnect the object from the underlying Rust object.
*
* It can be called more than once, but once called, interacting with the object
* causes an `IllegalStateException`.
*
* Clients **must** call this method once done with the object, or cause a memory leak.
*/
override protected fun freeRustArcPtr() {
rustCall() { status ->
_UniFFILib.INSTANCE.uniffi_xmtpv3_fn_free_ffigroupmetadata(this.pointer, status)
}
}

override fun `conversationType`(): String =
callWithPointer {
rustCall() { _status ->
_UniFFILib.INSTANCE.uniffi_xmtpv3_fn_method_ffigroupmetadata_conversation_type(it,

_status)
}
}.let {
FfiConverterString.lift(it)
}

override fun `creatorAccountAddress`(): String =
callWithPointer {
rustCall() { _status ->
_UniFFILib.INSTANCE.uniffi_xmtpv3_fn_method_ffigroupmetadata_creator_account_address(it,

_status)
}
}.let {
FfiConverterString.lift(it)
}


@Throws(GenericException::class)override fun `policyType`(): GroupPermissions =
callWithPointer {
rustCallWithError(GenericException) { _status ->
_UniFFILib.INSTANCE.uniffi_xmtpv3_fn_method_ffigroupmetadata_policy_type(it,

_status)
}
}.let {
FfiConverterTypeGroupPermissions.lift(it)
}




companion object

}

public object FfiConverterTypeFfiGroupMetadata: FfiConverter<FfiGroupMetadata, Pointer> {
override fun lower(value: FfiGroupMetadata): Pointer = value.callWithPointer { it }

override fun lift(value: Pointer): FfiGroupMetadata {
return FfiGroupMetadata(value)
}

override fun read(buf: ByteBuffer): FfiGroupMetadata {
// The Rust code always writes pointers as 8 bytes, and will
// fail to compile if they don't fit.
return lift(Pointer(buf.getLong()))
}

override fun allocationSize(value: FfiGroupMetadata) = 8

override fun write(value: FfiGroupMetadata, buf: ByteBuffer) {
// The Rust code always expects pointers written as 8 bytes,
// and will fail to compile if they don't fit.
buf.putLong(Pointer.nativeValue(lower(value)))
}
}




public interface FfiStreamCloserInterface {

fun `end`()
Expand Down Expand Up @@ -2547,6 +2710,7 @@ sealed class GenericException(message: String): Exception(message) {
class ApiException(message: String) : GenericException(message)
class GroupException(message: String) : GenericException(message)
class Signature(message: String) : GenericException(message)
class GroupMetadata(message: String) : GenericException(message)
class Generic(message: String) : GenericException(message)


Expand All @@ -2565,7 +2729,8 @@ public object FfiConverterTypeGenericError : FfiConverterRustBuffer<GenericExcep
4 -> GenericException.ApiException(FfiConverterString.read(buf))
5 -> GenericException.GroupException(FfiConverterString.read(buf))
6 -> GenericException.Signature(FfiConverterString.read(buf))
7 -> GenericException.Generic(FfiConverterString.read(buf))
7 -> GenericException.GroupMetadata(FfiConverterString.read(buf))
8 -> GenericException.Generic(FfiConverterString.read(buf))
else -> throw RuntimeException("invalid error enum value, something is very wrong!!")
}

Expand Down Expand Up @@ -2601,10 +2766,14 @@ public object FfiConverterTypeGenericError : FfiConverterRustBuffer<GenericExcep
buf.putInt(6)
Unit
}
is GenericException.Generic -> {
is GenericException.GroupMetadata -> {
buf.putInt(7)
Unit
}
is GenericException.Generic -> {
buf.putInt(8)
Unit
}
}.let { /* this makes the `when` an expression, which ensures it is exhaustive */ }
}

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.
Loading