diff --git a/Sources/XMTPiOS/ConversationV1.swift b/Sources/XMTPiOS/ConversationV1.swift index ed2c395a..aa6960c0 100644 --- a/Sources/XMTPiOS/ConversationV1.swift +++ b/Sources/XMTPiOS/ConversationV1.swift @@ -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(content: T, options: SendOptions?) async throws -> PreparedMessage { @@ -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]) diff --git a/Sources/XMTPiOS/ConversationV2.swift b/Sources/XMTPiOS/ConversationV2.swift index e898a485..d119e1ea 100644 --- a/Sources/XMTPiOS/ConversationV2.swift +++ b/Sources/XMTPiOS/ConversationV2.swift @@ -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(content: T, options: SendOptions?) async throws -> PreparedMessage { @@ -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]) diff --git a/Sources/XMTPiOS/Conversations.swift b/Sources/XMTPiOS/Conversations.swift index 1691051c..d2b0fbe1 100644 --- a/Sources/XMTPiOS/Conversations.swift +++ b/Sources/XMTPiOS/Conversations.swift @@ -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 [] } @@ -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 [] } @@ -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( @@ -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 } @@ -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() @@ -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() @@ -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 } diff --git a/Sources/XMTPiOS/PreparedMessage.swift b/Sources/XMTPiOS/PreparedMessage.swift index f44ced6e..721d0bfd 100644 --- a/Sources/XMTPiOS/PreparedMessage.swift +++ b/Sources/XMTPiOS/PreparedMessage.swift @@ -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. diff --git a/Tests/XMTPTests/GroupTests.swift b/Tests/XMTPTests/GroupTests.swift index 80945344..0a392e4e 100644 --- a/Tests/XMTPTests/GroupTests.swift +++ b/Tests/XMTPTests/GroupTests.swift @@ -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() diff --git a/XMTP.podspec b/XMTP.podspec index e95d7f7c..c5f17f92 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -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.