Skip to content

Commit

Permalink
Merge pull request #535 from xmtp/np/inbox-state
Browse files Browse the repository at this point in the history
List of inbox states for inbox ids
  • Loading branch information
nplasterer authored Nov 13, 2024
2 parents f1c31ce + 19afe06 commit 2a7b196
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 16 deletions.
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ repositories {
dependencies {
implementation project(':expo-modules-core')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
implementation "org.xmtp:android:3.0.3"
implementation "org.xmtp:android:3.0.4"
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.facebook.react:react-native:0.71.3'
implementation "com.daveanthonythomas.moshipack:moshipack:1.0.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,14 @@ class XMTPModule : Module() {
}
}

AsyncFunction("getInboxStates") Coroutine { inboxId: String, refreshFromNetwork: Boolean, inboxIds: List<String> ->
withContext(Dispatchers.IO) {
val client = clients[inboxId] ?: throw XMTPException("No client")
val inboxStates = client.inboxStatesForInboxIds(refreshFromNetwork, inboxIds)
inboxStates.map { InboxStateWrapper.encode(it) }
}
}

Function("preAuthenticateToInboxCallbackCompleted") {
logV("preAuthenticateToInboxCallbackCompleted")
preAuthenticateToInboxCallbackDeferred?.complete(Unit)
Expand Down Expand Up @@ -531,11 +539,22 @@ class XMTPModule : Module() {
}
}

AsyncFunction("findDmByInboxId") Coroutine { inboxId: String, peerInboxId: String ->
withContext(Dispatchers.IO) {
logV("findDmByInboxId")
val client = clients[inboxId] ?: throw XMTPException("No client")
val dm = client.findDmByInboxId(peerInboxId)
dm?.let {
DmWrapper.encode(client, dm)
}
}
}

AsyncFunction("findDmByAddress") Coroutine { inboxId: String, peerAddress: String ->
withContext(Dispatchers.IO) {
logV("findDmByAddress")
val client = clients[inboxId] ?: throw XMTPException("No client")
val dm = client.findDm(peerAddress)
val dm = client.findDmByAddress(peerAddress)
dm?.let {
DmWrapper.encode(client, dm)
}
Expand Down
8 changes: 4 additions & 4 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ PODS:
- GenericJSON (~> 2.0)
- Logging (~> 1.0.0)
- secp256k1.swift (~> 0.1)
- XMTP (3.0.3):
- XMTP (3.0.4):
- Connect-Swift (= 0.12.0)
- GzipSwift
- LibXMTP (= 3.0.0)
Expand All @@ -458,7 +458,7 @@ PODS:
- ExpoModulesCore
- MessagePacker
- secp256k1.swift
- XMTP (= 3.0.3)
- XMTP (= 3.0.4)
- Yoga (1.14.0)

DEPENDENCIES:
Expand Down Expand Up @@ -763,8 +763,8 @@ SPEC CHECKSUMS:
secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634
SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1
web3.swift: 2263d1e12e121b2c42ffb63a5a7beb1acaf33959
XMTP: ab14d9456330823f1c52b08ce5281d1e20c03f7f
XMTPReactNative: f7c9dc2eadef5c7d9590d2b7764ab805d16c7a5e
XMTP: dba23b4f3bcee464ca2f7569e1dc05fd9f4c0148
XMTPReactNative: 117d8a00b063044029c11f50320a6b9c8abcdea7
Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9

PODFILE CHECKSUM: 0e6fe50018f34e575d38dc6a1fdf1f99c9596cdd
Expand Down
16 changes: 16 additions & 0 deletions example/src/tests/clientTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,19 @@ test('production client creation does not error', async () => {
}
return true
})

test('can find others inbox states', async () => {
const [alix, bo, caro] = await createClients(3)

const states = await alix.inboxStates(true, [bo.inboxId, caro.inboxId])
assert(
states[0].recoveryAddress.toLowerCase === bo.address.toLowerCase,
`addresses dont match ${states[0].recoveryAddress} and ${bo.address}`
)
assert(
states[1].addresses[0].toLowerCase === caro.address.toLowerCase,
`clients dont match ${states[1].addresses[0]} and ${caro.address}`
)

return true
})
15 changes: 15 additions & 0 deletions example/src/tests/conversationTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ test('can find a conversation by topic', async () => {
return true
})

test('can find a dm by inbox id', async () => {
const [alixClient, boClient] = await createClients(2)
const alixDm = await alixClient.conversations.findOrCreateDm(boClient.address)

await boClient.conversations.sync()
const boDm = await boClient.conversations.findDmByInboxId(alixClient.inboxId)

assert(
boDm?.id === alixDm.id,
`bo dm id ${boDm?.id} does not match alix dm id ${alixDm.id}`
)

return true
})

test('can find a dm by address', async () => {
const [alixClient, boClient] = await createClients(2)
const alixDm = await alixClient.conversations.findOrCreateDm(boClient.address)
Expand Down
45 changes: 38 additions & 7 deletions ios/XMTPModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,18 @@ public class XMTPModule: Module {
return try InboxStateWrapper.encode(inboxState)
}

AsyncFunction("getInboxStates") {
(inboxId: String, refreshFromNetwork: Bool, inboxIds: [String])
-> [String] in
guard let client = await clientsManager.getClient(key: inboxId)
else {
throw Error.noClient
}
let inboxStates = try await client.inboxStatesForInboxIds(
refreshFromNetwork: refreshFromNetwork, inboxIds: inboxIds)
return try inboxStates.map { try InboxStateWrapper.encode($0) }
}

Function("preAuthenticateToInboxCallbackCompleted") {
DispatchQueue.global().async {
self.preAuthenticateToInboxCallbackDeferred?.signal()
Expand Down Expand Up @@ -545,13 +557,26 @@ public class XMTPModule: Module {
}
}

AsyncFunction("findDmByInboxId") {
(inboxId: String, peerInboxId: String) -> String? in
guard let client = await clientsManager.getClient(key: inboxId)
else {
throw Error.noClient
}
if let dm = try client.findDmByInboxId(inboxId: peerInboxId) {
return try await DmWrapper.encode(dm, client: client)
} else {
return nil
}
}

AsyncFunction("findDmByAddress") {
(inboxId: String, peerAddress: String) -> String? in
guard let client = await clientsManager.getClient(key: inboxId)
else {
throw Error.noClient
}
if let dm = try await client.findDm(address: peerAddress) {
if let dm = try await client.findDmByAddress(address: peerAddress) {
return try await DmWrapper.encode(dm, client: client)
} else {
return nil
Expand Down Expand Up @@ -1001,7 +1026,8 @@ public class XMTPModule: Module {

AsyncFunction("isAdmin") {
(clientInboxId: String, id: String, inboxId: String) -> Bool in
guard let client = await clientsManager.getClient(key: clientInboxId)
guard
let client = await clientsManager.getClient(key: clientInboxId)
else {
throw Error.noClient
}
Expand All @@ -1014,7 +1040,8 @@ public class XMTPModule: Module {

AsyncFunction("isSuperAdmin") {
(clientInboxId: String, id: String, inboxId: String) -> Bool in
guard let client = await clientsManager.getClient(key: clientInboxId)
guard
let client = await clientsManager.getClient(key: clientInboxId)
else {
throw Error.noClient
}
Expand Down Expand Up @@ -1053,7 +1080,8 @@ public class XMTPModule: Module {

AsyncFunction("addAdmin") {
(clientInboxId: String, id: String, inboxId: String) in
guard let client = await clientsManager.getClient(key: clientInboxId)
guard
let client = await clientsManager.getClient(key: clientInboxId)
else {
throw Error.noClient
}
Expand All @@ -1066,7 +1094,8 @@ public class XMTPModule: Module {

AsyncFunction("addSuperAdmin") {
(clientInboxId: String, id: String, inboxId: String) in
guard let client = await clientsManager.getClient(key: clientInboxId)
guard
let client = await clientsManager.getClient(key: clientInboxId)
else {
throw Error.noClient
}
Expand All @@ -1079,7 +1108,8 @@ public class XMTPModule: Module {

AsyncFunction("removeAdmin") {
(clientInboxId: String, id: String, inboxId: String) in
guard let client = await clientsManager.getClient(key: clientInboxId)
guard
let client = await clientsManager.getClient(key: clientInboxId)
else {
throw Error.noClient
}
Expand All @@ -1092,7 +1122,8 @@ public class XMTPModule: Module {

AsyncFunction("removeSuperAdmin") {
(clientInboxId: String, id: String, inboxId: String) in
guard let client = await clientsManager.getClient(key: clientInboxId)
guard
let client = await clientsManager.getClient(key: clientInboxId)
else {
throw Error.noClient
}
Expand Down
2 changes: 1 addition & 1 deletion ios/XMTPReactNative.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ Pod::Spec.new do |s|
s.source_files = "**/*.{h,m,swift}"
s.dependency 'secp256k1.swift'
s.dependency "MessagePacker"
s.dependency "XMTP", "= 3.0.3"
s.dependency "XMTP", "= 3.0.4"
end
26 changes: 26 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ export async function getInboxState(
return InboxState.from(inboxState)
}

export async function getInboxStates(
inboxId: InboxId,
refreshFromNetwork: boolean,
inboxIds: InboxId[],
): Promise<InboxState[]> {
const inboxStates = await XMTPModule.getInboxStates(inboxId, refreshFromNetwork, inboxIds)
return inboxStates.map((json: string) => {
return InboxState.from(json)
})
}

export function preAuthenticateToInboxCallbackCompleted() {
XMTPModule.preAuthenticateToInboxCallbackCompleted()
}
Expand Down Expand Up @@ -374,6 +385,21 @@ export async function findConversationByTopic<
}
}

export async function findDmByInboxId<
ContentTypes extends DefaultContentTypes = DefaultContentTypes,
>(
client: Client<ContentTypes>,
peerInboxId: InboxId
): Promise<Dm<ContentTypes> | undefined> {
const json = await XMTPModule.findDmByInboxId(client.inboxId, peerInboxId)
const dm = JSON.parse(json)
if (!dm || Object.keys(dm).length === 0) {
return undefined
}

return new Dm(client, dm)
}

export async function findDmByAddress<
ContentTypes extends DefaultContentTypes = DefaultContentTypes,
>(
Expand Down
13 changes: 12 additions & 1 deletion src/lib/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ export class Client<
}

/**
* Make a request for a inboxs state.
* Make a request for your inbox state.
*
* @param {boolean} refreshFromNetwork - If you want to refresh the current state of in the inbox from the network or not.
* @returns {Promise<InboxState>} A Promise resolving to a InboxState.
Expand All @@ -402,6 +402,17 @@ export class Client<
return await XMTPModule.getInboxState(this.inboxId, refreshFromNetwork)
}

/**
* Make a request for a list of inbox states.
*
* @param {InboxId[]} inboxIds - The inboxIds to get the associate inbox states for.
* @param {boolean} refreshFromNetwork - If you want to refresh the current state the inbox from the network or not.
* @returns {Promise<InboxState[]>} A Promise resolving to a list of InboxState.
*/
async inboxStates(refreshFromNetwork: boolean, inboxIds: InboxId[]): Promise<InboxState[]> {
return await XMTPModule.getInboxStates(this.inboxId, refreshFromNetwork, inboxIds)
}

/**
* Determines whether the current user can send messages to the specified peers over groups.
*
Expand Down
14 changes: 13 additions & 1 deletion src/lib/Conversations.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Client } from './Client'
import { Client, InboxId } from './Client'
import { ConversationVersion } from './Conversation'
import { DecodedMessage } from './DecodedMessage'
import { Dm, DmParams } from './Dm'
Expand Down Expand Up @@ -105,6 +105,18 @@ export default class Conversations<
return await XMTPModule.findGroup(this.client, groupId)
}

/**
* This method returns a Dm by the inboxId if that dm exists in the local database.
* To get the latest list of dms from the network, call sync() first.
*
* @returns {Promise<Dm>} A Promise that resolves to a Dm or undefined if not found.
*/
async findDmByInboxId(
inboxId: InboxId
): Promise<Dm<ContentTypes> | undefined> {
return await XMTPModule.findDmByInboxId(this.client, inboxId)
}

/**
* This method returns a Dm by the address if that dm exists in the local database.
* To get the latest list of dms from the network, call sync() first.
Expand Down

0 comments on commit 2a7b196

Please sign in to comment.