Skip to content

Commit

Permalink
Dual Send 1to1 Conversations in V3 (#414)
Browse files Browse the repository at this point in the history
* dual send messages

* dual create conversation as well

* add tests for the dual sending

* Update Sources/XMTPiOS/ConversationV2.swift

Co-authored-by: Mojtaba Chenani <chenani@outlook.com>

* bump the pod

---------

Co-authored-by: Mojtaba Chenani <chenani@outlook.com>
  • Loading branch information
nplasterer and mchenani authored Nov 4, 2024
1 parent 67b94e6 commit 1bb951d
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 41 deletions.
12 changes: 11 additions & 1 deletion Sources/XMTPiOS/ConversationV1.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public struct ConversationV1 {
await client.contacts.markIntroduced(peerAddress, true)
}

return PreparedMessage(envelopes: envelopes)
return PreparedMessage(envelopes: envelopes, encodedContent: encodedContent)
}

func prepareMessage<T>(content: T, options: SendOptions?) async throws -> PreparedMessage {
Expand Down Expand Up @@ -139,6 +139,16 @@ public struct ConversationV1 {
}

@discardableResult func send(prepared: PreparedMessage) async throws -> String {
if (client.v3Client != nil) {
do {
let dm = try await client.conversations.findOrCreateDm(with: peerAddress)
if let encodedContent = prepared.encodedContent {
try await dm.send(encodedContent: encodedContent)
}
} catch {
print("ConversationV1 send \(error)")
}
}
try await client.publish(envelopes: prepared.envelopes)
if((try await client.contacts.consentList.state(address: peerAddress)) == .unknown) {
try await client.contacts.allow(addresses: [peerAddress])
Expand Down
12 changes: 11 additions & 1 deletion Sources/XMTPiOS/ConversationV2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public struct ConversationV2 {
let topic = options?.ephemeral == true ? ephemeralTopic : topic

let envelope = Envelope(topic: topic, timestamp: Date(), message: try Message(v2: message).serializedData())
return PreparedMessage(envelopes: [envelope])
return PreparedMessage(envelopes: [envelope], encodedContent: encodedContent)
}

func prepareMessage<T>(content: T, options: SendOptions?) async throws -> PreparedMessage {
Expand Down Expand Up @@ -255,6 +255,16 @@ public struct ConversationV2 {
}

@discardableResult func send(prepared: PreparedMessage) async throws -> String {
if (client.v3Client != nil) {
do {
let dm = try await client.conversations.findOrCreateDm(with: peerAddress)
if let encodedContent = prepared.encodedContent {
try await dm.send(encodedContent: encodedContent)
}
} catch {
print("ConversationV2 send \(error)")
}
}
try await client.publish(envelopes: prepared.envelopes)
if((try await client.contacts.consentList.state(address: peerAddress)) == .unknown) {
try await client.contacts.allow(addresses: [peerAddress])
Expand Down
44 changes: 7 additions & 37 deletions Sources/XMTPiOS/Conversations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,6 @@ public actor Conversations {
public func dms(
createdAfter: Date? = nil, createdBefore: Date? = nil, limit: Int? = nil
) async throws -> [Dm] {
if client.hasV2Client {
throw ConversationError.v2NotSupported(
"Only supported with V3 only clients use newConversation instead"
)
}
guard let v3Client = client.v3Client else {
return []
}
Expand All @@ -214,11 +209,6 @@ public actor Conversations {
limit: Int? = nil, order: ConversationOrder = .createdAt,
consentState: ConsentState? = nil
) async throws -> [Conversation] {
if client.hasV2Client {
throw ConversationError.v2NotSupported(
"Only supported with V3 only clients use list instead")
}
// Todo: add ability to order and consent state
guard let v3Client = client.v3Client else {
return []
}
Expand Down Expand Up @@ -350,13 +340,6 @@ public actor Conversations {
Conversation, Error
> {
AsyncThrowingStream { continuation in
if client.hasV2Client {
continuation.finish(
throwing: ConversationError.v2NotSupported(
"Only supported with V3 only clients use stream instead"
))
return
}
let ffiStreamActor = FfiStreamActor()
let task = Task {
let stream = await self.client.v3Client?.conversations().stream(
Expand Down Expand Up @@ -405,12 +388,6 @@ public actor Conversations {
}

public func findOrCreateDm(with peerAddress: String) async throws -> Dm {
if client.hasV2Client {
throw ConversationError.v2NotSupported(
"Only supported with V3 only clients use newConversation instead"
)
}

guard let v3Client = client.v3Client else {
throw GroupError.alphaMLSNotEnabled
}
Expand Down Expand Up @@ -537,13 +514,6 @@ public actor Conversations {
DecodedMessage, Error
> {
AsyncThrowingStream { continuation in
if client.hasV2Client {
continuation.finish(
throwing: ConversationError.v2NotSupported(
"Only supported with V3 clients. Use streamAllMessages instead."
))
return
}
let ffiStreamActor = FfiStreamActor()
let task = Task {
let stream = await self.client.v3Client?.conversations()
Expand Down Expand Up @@ -583,13 +553,6 @@ public actor Conversations {
DecryptedMessage, Error
> {
AsyncThrowingStream { continuation in
if client.hasV2Client {
continuation.finish(
throwing: ConversationError.v2NotSupported(
"Only supported with V3 clients. Use streamAllMessages instead."
))
return
}
let ffiStreamActor = FfiStreamActor()
let task = Task {
let stream = await self.client.v3Client?.conversations()
Expand Down Expand Up @@ -853,6 +816,13 @@ public actor Conversations {
Task {
await self.addConversation(conversation)
}
if client.v3Client != nil {
do {
try await client.conversations.findOrCreateDm(with: peerAddress)
} catch {
print("newConversation \(error)")
}
}
return conversation
}

Expand Down
3 changes: 2 additions & 1 deletion Sources/XMTPiOS/PreparedMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ public struct PreparedMessage {
// Any more are for required intros/invites etc.
// A client can just publish these when it has connectivity.
public let envelopes: [Envelope]
public let encodedContent: EncodedContent?

// Note: we serialize as a PublishRequest as a convenient `envelopes` wrapper.
public static func fromSerializedData(_ serializedData: Data) throws -> PreparedMessage {
let req = try Xmtp_MessageApi_V1_PublishRequest(serializedData: serializedData)
return PreparedMessage(envelopes: req.envelopes)
return PreparedMessage(envelopes: req.envelopes, encodedContent: nil)
}

// Note: we serialize as a PublishRequest as a convenient `envelopes` wrapper.
Expand Down
57 changes: 57 additions & 0 deletions Tests/XMTPTests/GroupTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,63 @@ class GroupTests: XCTestCase {
davonV3Client: davonV3Client
)
}

func testCanDualSendConversations() async throws {
let fixtures = try await localFixtures()
let v2Convo = try await fixtures.aliceClient.conversations.newConversation(with: fixtures.bob.walletAddress)

try await fixtures.aliceClient.conversations.sync()
try await fixtures.bobClient.conversations.sync()

let alixDm = try await fixtures.aliceClient.findDm(address: fixtures.bob.walletAddress)
let boDm = try await fixtures.bobClient.findDm(address: fixtures.alice.walletAddress)

XCTAssertEqual(alixDm?.id, boDm?.id)

let alixConversationsListCount = try await fixtures.aliceClient.conversations.list().count
XCTAssertEqual(alixConversationsListCount, 1)

let alixDmsListCount = try await fixtures.aliceClient.conversations.dms().count
XCTAssertEqual(alixDmsListCount, 1)

let boDmsListCount = try await fixtures.bobClient.conversations.dms().count
XCTAssertEqual(boDmsListCount, 1)

let boConversationsListCount = try await fixtures.bobClient.conversations.list().count
XCTAssertEqual(boConversationsListCount, 1)

let boFirstTopic = try await fixtures.bobClient.conversations.list().first?.topic
XCTAssertEqual(v2Convo.topic, boFirstTopic)
}

func testCanDualSendMessages() async throws {
let fixtures = try await localFixtures()
let alixV2Convo = try await fixtures.aliceClient.conversations.newConversation(with: fixtures.bob.walletAddress)
let boV2Convo = try await fixtures.bobClient.conversations.list().first!

try await fixtures.bobClient.conversations.sync()

let alixDm = try await fixtures.aliceClient.findDm(address: fixtures.bob.walletAddress)
let boDm = try await fixtures.bobClient.findDm(address: fixtures.alice.walletAddress)

try await alixV2Convo.send(content: "first")
try await boV2Convo.send(content: "second")

try await alixDm?.sync()
try await boDm?.sync()

let alixV2ConvoMessageCount = try await alixV2Convo.messages().count
XCTAssertEqual(alixV2ConvoMessageCount, 2)

let boV2ConvoMessageCount = try await boV2Convo.messages().count
XCTAssertEqual(alixV2ConvoMessageCount, boV2ConvoMessageCount)

let boDmMessageCount = try await boDm?.messages().count
XCTAssertEqual(boDmMessageCount, 2)

let alixDmMessageCount = try await alixDm?.messages().count
XCTAssertEqual(alixDmMessageCount, 3) // Including the group membership update in the DM
}

func testCanCreateAGroupWithDefaultPermissions() async throws {
let fixtures = try await localFixtures()
Expand Down
2 changes: 1 addition & 1 deletion XMTP.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Pod::Spec.new do |spec|
#

spec.name = "XMTP"
spec.version = "0.16.1"
spec.version = "0.16.2"
spec.summary = "XMTP SDK Cocoapod"

# This description is used to generate tags and improve search results.
Expand Down

0 comments on commit 1bb951d

Please sign in to comment.