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

feat: Rust V2 #219

Merged
merged 40 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
e26fe3a
add v2 rust client to the client creation methods
nplasterer Mar 2, 2024
211f6a4
fix up how v2 is setup
nplasterer Apr 9, 2024
cb2986d
get it working for publish
nplasterer Apr 9, 2024
b6e4646
do it all for query
nplasterer Apr 9, 2024
49b6553
fix it all for batch query
nplasterer Apr 9, 2024
c2a37fe
try and get subscriptions working
nplasterer Apr 9, 2024
93dd97f
set the app version still
nplasterer Apr 9, 2024
7f347b8
add back the env
nplasterer Apr 9, 2024
895820b
Merge branch 'main' of https://github.com/xmtp/xmtp-android into np/v…
nplasterer Apr 10, 2024
0935df3
some subscribe tweaks
nplasterer Apr 10, 2024
36cfcb1
make tweaks to stream all
nplasterer Apr 10, 2024
520896a
fix up the linter
nplasterer Apr 10, 2024
e607128
fix up tests
nplasterer Apr 10, 2024
71e2b15
tweaks to example for better debugging
nplasterer Apr 10, 2024
40181b7
fix lint
nplasterer Apr 10, 2024
2bbeb13
revert subscription work
nplasterer Apr 11, 2024
bc7d5ad
small tweaks
nplasterer Apr 11, 2024
8cab289
confirm all streaming tests work
nplasterer Apr 11, 2024
99ba60c
Merge branch 'main' of https://github.com/xmtp/xmtp-android into np/v…
nplasterer Apr 11, 2024
9742bcf
fix up linter
nplasterer Apr 11, 2024
634456e
fix up linter and some flaking test
nplasterer Apr 11, 2024
009de37
Merge branch 'main' of https://github.com/xmtp/xmtp-android into np/v…
nplasterer Jun 24, 2024
22a77d8
Merge branch 'main' of https://github.com/xmtp/xmtp-android into np/v…
nplasterer Jun 26, 2024
b93e351
add hex util to make group comparison easier
nplasterer Jun 26, 2024
9e57578
update the readme
nplasterer Jun 26, 2024
7b4810a
modify the bindings
nplasterer Jun 26, 2024
0a3f7e8
getting closer on the subscribe work
nplasterer Jun 27, 2024
7550a1d
update all the subscribe functions
nplasterer Jun 27, 2024
ab7293a
try to figure out how to resubscribe to the callback
nplasterer Jun 28, 2024
f998cf7
get the stream all working
nplasterer Jun 28, 2024
7dfa3e5
a small amount of clean up
nplasterer Jun 28, 2024
3fd7109
all tests passing but 1
nplasterer Jun 28, 2024
7f11382
bad test
nplasterer Jun 28, 2024
37d3742
fix up the linter
nplasterer Jun 28, 2024
ea8bdbd
reformat
nplasterer Jun 28, 2024
52b553e
bring back env so that the app works
nplasterer Jun 28, 2024
0899d42
missing one iterator
nplasterer Jun 28, 2024
25a8a48
fix up some tests
nplasterer Jun 28, 2024
5dd425b
remove some runblocking
nplasterer Jun 29, 2024
2785b4d
feat: get it working performantly
nplasterer Jul 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
Expand Down Expand Up @@ -182,6 +183,7 @@ class MainActivity : AppCompatActivity(),

private fun showError(message: String) {
val error = message.ifBlank { resources.getString(R.string.error) }
Log.e("MainActivity", message)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Want this log still?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya it helps with logging errors in the example. Otherwise it just says "An Error Happened" with no details.

Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
}

Expand Down
6 changes: 3 additions & 3 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ dependencies {
implementation 'io.grpc:grpc-kotlin-stub:1.4.1'
implementation 'io.grpc:grpc-okhttp:1.62.2'
implementation 'io.grpc:grpc-protobuf-lite:1.62.2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0'
implementation 'org.web3j:crypto:5.0.0'
implementation "net.java.dev.jna:jna:5.14.0@aar"
api 'com.google.protobuf:protobuf-kotlin-lite:3.22.3'
api 'org.xmtp:proto-kotlin:3.61.1'

testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'app.cash.turbine:turbine:0.12.1'
androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
androidTestImplementation 'app.cash.turbine:turbine:1.1.0'
androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ class ClientTest {
fun testCanMessage() {
val fixtures = fixtures()
val notOnNetwork = PrivateKeyBuilder()
val canMessage = fixtures.aliceClient.canMessage(fixtures.bobClient.address)
val cannotMessage = fixtures.aliceClient.canMessage(notOnNetwork.address)
val canMessage = runBlocking { fixtures.aliceClient.canMessage(fixtures.bobClient.address) }
val cannotMessage = runBlocking { fixtures.aliceClient.canMessage(notOnNetwork.address) }
assert(canMessage)
assert(!cannotMessage)
}
Expand All @@ -248,8 +248,8 @@ class ClientTest {
val aliceClient = Client().create(aliceWallet, opts)
runBlocking { aliceClient.ensureUserContactPublished() }

val canMessage = Client.canMessage(aliceWallet.address, opts)
val cannotMessage = Client.canMessage(notOnNetwork.address, opts)
val canMessage = runBlocking { Client.canMessage(aliceWallet.address, opts) }
val cannotMessage = runBlocking { Client.canMessage(notOnNetwork.address, opts) }

assert(canMessage)
assert(!cannotMessage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,6 @@ class ContactsTest {
assertEquals(contactBundle?.walletAddress, fixtures.bob.walletAddress)
}

@Test
fun testCachesContacts() {
alexrisch marked this conversation as resolved.
Show resolved Hide resolved
val fixtures = fixtures()
runBlocking { fixtures.bobClient.ensureUserContactPublished() }
// Look up the first time
fixtures.aliceClient.contacts.find(fixtures.bob.walletAddress)
fixtures.fakeApiClient.assertNoQuery {
val contactBundle = fixtures.aliceClient.contacts.find(fixtures.bob.walletAddress)
assertEquals(contactBundle?.walletAddress, fixtures.bob.walletAddress)
}
assert(fixtures.aliceClient.contacts.has(fixtures.bob.walletAddress))
}

@Test
fun testAllowAddress() {
val fixtures = fixtures()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.xmtp.android.library

import androidx.test.ext.junit.runners.AndroidJUnit4
import app.cash.turbine.test
import com.google.protobuf.kotlin.toByteString
import com.google.protobuf.kotlin.toByteStringUtf8
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
Expand Down Expand Up @@ -46,7 +48,6 @@ import java.util.Date

@RunWith(AndroidJUnit4::class)
class ConversationTest {
lateinit var fakeApiClient: FakeApiClient
lateinit var aliceWallet: PrivateKeyBuilder
lateinit var bobWallet: PrivateKeyBuilder
lateinit var alice: PrivateKey
Expand All @@ -62,7 +63,6 @@ class ConversationTest {
alice = fixtures.alice
bobWallet = fixtures.bobAccount
bob = fixtures.bob
fakeApiClient = fixtures.fakeApiClient
aliceClient = fixtures.aliceClient
bobClient = fixtures.bobClient
}
Expand Down Expand Up @@ -120,42 +120,11 @@ class ConversationTest {
runBlocking { aliceClient.conversations.newConversation(bob.walletAddress) }
assertEquals(conversation.peerAddress, bob.walletAddress)
assertEquals(conversation.createdAt, someTimeAgo)
val existingMessages = fakeApiClient.published.size
conversation = runBlocking { bobClient.conversations.newConversation(alice.walletAddress) }

assertEquals(
"published more messages when we shouldn't have",
existingMessages,
fakeApiClient.published.size,
)
assertEquals(conversation.peerAddress, alice.walletAddress)
assertEquals(conversation.createdAt, someTimeAgo)
}

@Test
fun testCanFindExistingV2Conversation() {
val existingConversation = runBlocking {
bobClient.conversations.newConversation(
alice.walletAddress,
context = InvitationV1ContextBuilder.buildFromConversation("http://example.com/2"),
)
}
var conversation: Conversation? = null
fakeApiClient.assertNoPublish {
runBlocking {
conversation = bobClient.conversations.newConversation(
alice.walletAddress,
context = InvitationV1ContextBuilder.buildFromConversation("http://example.com/2"),
)
}
}
assertEquals(
"made new conversation instead of using existing one",
conversation!!.topic,
existingConversation.topic,
)
}

@Test
fun testCanLoadV1Messages() {
// Overwrite contact as legacy so we can get v1
Expand Down Expand Up @@ -405,15 +374,6 @@ class ConversationTest {
}
}

@Test
fun testCanUseCachedConversation() {
runBlocking { bobClient.conversations.newConversation(alice.walletAddress) }

fakeApiClient.assertNoQuery {
runBlocking { bobClient.conversations.newConversation(alice.walletAddress) }
}
}

@Test
@Ignore("Rust seems to be Flaky with V1")
fun testCanPaginateV1Messages() {
Expand Down Expand Up @@ -493,9 +453,18 @@ class ConversationTest {
(topic.equals(steveConversation.topic) || topic.equals(bobConversation.topic))
}
assertEquals(3, messages.size)
assertTrue("isSteveOrBobConversation message 0", isSteveOrBobConversation(messages[0].topic))
assertTrue("isSteveOrBobConversation message 1", isSteveOrBobConversation(messages[1].topic))
assertTrue("isSteveOrBobConversation message 2", isSteveOrBobConversation(messages[2].topic))
assertTrue(
"isSteveOrBobConversation message 0",
isSteveOrBobConversation(messages[0].topic)
)
assertTrue(
"isSteveOrBobConversation message 1",
isSteveOrBobConversation(messages[1].topic)
)
assertTrue(
"isSteveOrBobConversation message 2",
isSteveOrBobConversation(messages[2].topic)
)
}

@Test
Expand Down Expand Up @@ -587,33 +556,82 @@ class ConversationTest {
}

@Test
fun testCanStreamConversationsV2() = kotlinx.coroutines.test.runTest {
bobClient.conversations.stream().test {
val conversation = bobClient.conversations.newConversation(alice.walletAddress)
conversation.send(content = "hi")
assertEquals("hi", awaitItem().messages(limit = 1).first().body)
fun testCanStreamConversationsV2() {
val allMessages = mutableListOf<String>()

val job = CoroutineScope(Dispatchers.IO).launch {
try {
bobClient.conversations.stream()
.collect { message ->
allMessages.add(message.topic)
}
} catch (e: Exception) {
}
}
Thread.sleep(2500)

runBlocking {
bobClient.conversations.newConversation(alice.walletAddress)
}

Thread.sleep(1000)

assertEquals(1, allMessages.size)

job.cancel()
}

@Test
fun testStreamingMessagesFromV1Conversation() = kotlinx.coroutines.test.runTest {
fun testStreamingMessagesFromV1Conversation() {
// Overwrite contact as legacy
fixtures.publishLegacyContact(client = bobClient)
fixtures.publishLegacyContact(client = aliceClient)
val conversation = aliceClient.conversations.newConversation(bob.walletAddress)
conversation.streamMessages().test {
conversation.send("hi alice")
assertEquals("hi alice", awaitItem().encodedContent.content.toStringUtf8())
val conversation =
runBlocking { aliceClient.conversations.newConversation(bob.walletAddress) }
val allMessages = mutableListOf<DecodedMessage>()

val job = CoroutineScope(Dispatchers.IO).launch {
try {
conversation.streamMessages().collect { message ->
allMessages.add(message)
}
} catch (e: Exception) {
}
}
Thread.sleep(2500)

for (i in 0 until 5) {
runBlocking { conversation.send(text = "Message $i") }
Thread.sleep(1000)
}

assertEquals(allMessages.size, 5)
job.cancel()
}

@Test
fun testStreamingMessagesFromV2Conversations() = kotlinx.coroutines.test.runTest {
val conversation = aliceClient.conversations.newConversation(bob.walletAddress)
conversation.streamMessages().test {
conversation.send("hi alice")
assertEquals("hi alice", awaitItem().encodedContent.content.toStringUtf8())
fun testStreamingMessagesFromV2Conversations() {
val conversation =
runBlocking { aliceClient.conversations.newConversation(bob.walletAddress) }
val allMessages = mutableListOf<DecodedMessage>()

val job = CoroutineScope(Dispatchers.IO).launch {
try {
conversation.streamMessages().collect { message ->
allMessages.add(message)
}
} catch (e: Exception) {
}
}
Thread.sleep(2500)

for (i in 0 until 5) {
runBlocking { conversation.send(text = "Message $i") }
Thread.sleep(1000)
}

assertEquals(allMessages.size, 5)
job.cancel()
}

@Test
Expand Down Expand Up @@ -743,7 +761,6 @@ class ConversationTest {
}.build()

val client = Client().create(account = PrivateKeyBuilder(key))
assertEquals(client.apiClient.environment, XMTPEnvironment.DEV)
runBlocking {
val conversations = client.conversations.list()
assertEquals(1, conversations.size)
Expand Down Expand Up @@ -788,11 +805,14 @@ class ConversationTest {
fun testCanHaveConsentState() {
val bobConversation =
runBlocking { bobClient.conversations.newConversation(alice.walletAddress, null) }
Thread.sleep(1000)
val isAllowed = bobConversation.consentState() == ConsentState.ALLOWED

// Conversations you start should start as allowed
assertTrue("Bob convo should be allowed", isAllowed)
assertTrue("Bob contacts should be allowed", bobClient.contacts.isAllowed(alice.walletAddress))
assertTrue(
"Bob contacts should be allowed",
bobClient.contacts.isAllowed(alice.walletAddress)
)

runBlocking {
bobClient.contacts.deny(listOf(alice.walletAddress))
Expand Down Expand Up @@ -829,6 +849,7 @@ class ConversationTest {
fun testCanHaveImplicitConsentOnMessageSend() {
val bobConversation =
runBlocking { bobClient.conversations.newConversation(alice.walletAddress, null) }
Thread.sleep(1000)
val isAllowed = bobConversation.consentState() == ConsentState.ALLOWED

// Conversations you start should start as allowed
Expand Down Expand Up @@ -860,12 +881,24 @@ class ConversationTest {
bobClient.contacts.refreshConsentList()
Thread.sleep(1000)
assertEquals(bobClient.contacts.consentList.entries.size, 2)
assertTrue("Bob convo should be allowed", bobConversation.consentState() == ConsentState.ALLOWED)
assertTrue("Caro convo should be allowed", caroConversation.consentState() == ConsentState.ALLOWED)
assertTrue(
"Bob convo should be allowed",
bobConversation.consentState() == ConsentState.ALLOWED
)
assertTrue(
"Caro convo should be allowed",
caroConversation.consentState() == ConsentState.ALLOWED
)
bobClient.contacts.deny(listOf(alice.walletAddress, fixtures.caro.walletAddress))
assertEquals(bobClient.contacts.consentList.entries.size, 2)
assertTrue("Bob convo should be denied", bobConversation.consentState() == ConsentState.DENIED)
assertTrue("Caro convo should be denied", caroConversation.consentState() == ConsentState.DENIED)
assertTrue(
"Bob convo should be denied",
bobConversation.consentState() == ConsentState.DENIED
)
assertTrue(
"Caro convo should be denied",
caroConversation.consentState() == ConsentState.DENIED
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import java.util.Date

@RunWith(AndroidJUnit4::class)
class ConversationsTest {
lateinit var fakeApiClient: FakeApiClient
lateinit var alixWallet: PrivateKeyBuilder
lateinit var boWallet: PrivateKeyBuilder
lateinit var alix: PrivateKey
Expand All @@ -53,7 +52,6 @@ class ConversationsTest {
alix = fixtures.alice
boWallet = fixtures.bobAccount
bo = fixtures.bob
fakeApiClient = fixtures.fakeApiClient
alixClient = fixtures.aliceClient
boClient = fixtures.bobClient
caroClient = fixtures.caroClient
Expand Down Expand Up @@ -128,7 +126,7 @@ class ConversationsTest {
runBlocking { boConversation.send(text = "Message $i") }
sleep(1000)
}
assertEquals(allMessages.size, 5)
assertEquals(5, allMessages.size)

val caroConversation =
runBlocking { caroClient.conversations.newConversation(alixClient.address) }
Expand All @@ -139,7 +137,7 @@ class ConversationsTest {
sleep(1000)
}

assertEquals(allMessages.size, 10)
assertEquals(10, allMessages.size)

job.cancel()

Expand All @@ -158,7 +156,7 @@ class ConversationsTest {
sleep(1000)
}

assertEquals(allMessages.size, 15)
assertEquals(15, allMessages.size)
}

@Test
Expand Down
Loading
Loading