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

Dual Send 1to1 Conversations in V3 #414

Merged
merged 5 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
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("ConversationV1 send \(error)")
nplasterer marked this conversation as resolved.
Show resolved Hide resolved
}
}
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
Loading