Skip to content

Commit

Permalink
Make Conversations and Contacts actors. (#161)
Browse files Browse the repository at this point in the history
* Make Conversations and Contacts actors.

Hopefully will fix #159.

* bump podspec
  • Loading branch information
nakajima authored Sep 19, 2023
1 parent 2b0bdc4 commit dbb39bc
Show file tree
Hide file tree
Showing 9 changed files with 22 additions and 81 deletions.
12 changes: 10 additions & 2 deletions Sources/XMTP/Contacts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Foundation

/// Provides access to contact bundles.
public struct Contacts {
public actor Contacts {
var client: Client

// Save all bundles here
Expand All @@ -17,6 +17,14 @@ public struct Contacts {
// Whether or not we have sent invite/intro to this contact
var hasIntroduced: [String: Bool] = [:]

init(client: Client) {
self.client = client
}

func markIntroduced(_ peerAddress: String, _ isIntroduced: Bool) {
hasIntroduced[peerAddress] = isIntroduced
}

func has(_ peerAddress: String) -> Bool {
return knownBundles[peerAddress] != nil
}
Expand All @@ -25,7 +33,7 @@ public struct Contacts {
return hasIntroduced[peerAddress] != true
}

mutating func find(_ peerAddress: String) async throws -> ContactBundle? {
func find(_ peerAddress: String) async throws -> ContactBundle? {
if let knownBundle = knownBundles[peerAddress] {
return knownBundle
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/XMTP/ConversationV1.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public struct ConversationV1 {
message: msg
)
var envelopes = [messageEnvelope]
if client.contacts.needsIntroduction(peerAddress) && !isEphemeral {
if (await client.contacts.needsIntroduction(peerAddress)) && !isEphemeral {
envelopes.append(contentsOf: [
Envelope(
topic: .userIntro(peerAddress),
Expand All @@ -85,7 +85,7 @@ public struct ConversationV1 {
),
])

client.contacts.hasIntroduced[peerAddress] = true
await client.contacts.markIntroduced(peerAddress, true)
}

return PreparedMessage(envelopes: envelopes)
Expand Down
2 changes: 1 addition & 1 deletion Sources/XMTP/Conversations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public enum ConversationError: Error {
}

/// Handles listing and creating Conversations.
public class Conversations {
public actor Conversations {
var client: Client
var conversationsByTopic: [String: Conversation] = [:]

Expand Down
3 changes: 2 additions & 1 deletion Tests/XMTPTests/ContactsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class ContactsTests: XCTestCase {
XCTAssertEqual(contactBundle.walletAddress, fixtures.bob.walletAddress)
}

XCTAssert(fixtures.aliceClient.contacts.has(fixtures.bob.walletAddress))
let hasContact = await fixtures.aliceClient.contacts.has(fixtures.bob.walletAddress)
XCTAssert(hasContact)
}
}
70 changes: 1 addition & 69 deletions Tests/XMTPTests/ConversationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class ConversationTests: XCTestCase {
expectation1.expectedFulfillmentCount = 2

Task(priority: .userInitiated) {
for try await conversation in bobClient.conversations.stream() {
for try await conversation in await bobClient.conversations.stream() {
expectation1.fulfill()
}
}
Expand Down Expand Up @@ -549,30 +549,6 @@ class ConversationTests: XCTestCase {
XCTAssertEqual("hi", decodedMessage2.body)
}

func testCanSendEncodedContentV1Message() async throws {
try await publishLegacyContact(client: bobClient)
try await publishLegacyContact(client: aliceClient)

guard case let .v1(bobConversation) = try await bobClient.conversations.newConversation(with: alice.address) else {
XCTFail("did not get a v1 conversation for alice")
return
}

guard case let .v1(aliceConversation) = try await aliceClient.conversations.newConversation(with: bob.address) else {
XCTFail("did not get a v1 conversation for alice")
return
}

let encodedContent = try TextCodec().encode(content: "hi")

try await bobConversation.send(encodedContent: encodedContent, options: nil)

let messages = try await aliceConversation.messages()

XCTAssertEqual(1, messages.count)
XCTAssertEqual("hi", try messages[0].content())
}

func testCanSendEncodedContentV2Message() async throws {
guard case let .v2(bobConversation) = try await bobClient.conversations.newConversation(with: alice.address, context: InvitationV1.Context(conversationID: "hi")) else {
XCTFail("did not get a v1 conversation for alice")
Expand All @@ -594,50 +570,6 @@ class ConversationTests: XCTestCase {
XCTAssertEqual("hi", try messages[0].content())
}

func testCanSendGzipCompressedV1Messages() async throws {
try await publishLegacyContact(client: bobClient)
try await publishLegacyContact(client: aliceClient)

guard case let .v1(bobConversation) = try await bobClient.conversations.newConversation(with: alice.address) else {
XCTFail("did not get a v1 conversation for alice")
return
}

guard case let .v1(aliceConversation) = try await aliceClient.conversations.newConversation(with: bob.address) else {
XCTFail("did not get a v1 conversation for alice")
return
}

try await bobConversation.send(content: Array(repeating: "A", count: 1000).joined(), options: .init(compression: .gzip))

let messages = try await aliceConversation.messages()

XCTAssertEqual(1, messages.count)
XCTAssertEqual(Array(repeating: "A", count: 1000).joined(), try messages[0].content())
}

func testCanSendDeflateCompressedV1Messages() async throws {
try await publishLegacyContact(client: bobClient)
try await publishLegacyContact(client: aliceClient)

guard case let .v1(bobConversation) = try await bobClient.conversations.newConversation(with: alice.address) else {
XCTFail("did not get a v1 conversation for alice")
return
}

guard case let .v1(aliceConversation) = try await aliceClient.conversations.newConversation(with: bob.address) else {
XCTFail("did not get a v1 conversation for alice")
return
}

try await bobConversation.send(content: Array(repeating: "A", count: 1000).joined(), options: .init(compression: .deflate))

let messages = try await aliceConversation.messages()

XCTAssertEqual(1, messages.count)
XCTAssertEqual(Array(repeating: "A", count: 1000).joined(), try messages[0].content())
}

func testCanSendGzipCompressedV2Messages() async throws {
guard case let .v2(bobConversation) = try await bobClient.conversations.newConversation(with: alice.address, context: InvitationV1.Context(conversationID: "hi")) else {
XCTFail("did not get a v2 conversation for alice")
Expand Down
4 changes: 2 additions & 2 deletions Tests/XMTPTests/ConversationsTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class ConversationsTests: XCTestCase {

let envelope = Envelope(topic: .userIntro(client.address), timestamp: created, message: try Message(v1: message).serializedData())

let conversation = try client.conversations.fromIntro(envelope: envelope)
let conversation = try await client.conversations.fromIntro(envelope: envelope)
XCTAssertEqual(conversation.peerAddress, newWallet.address)
XCTAssertEqual(conversation.createdAt.description, created.description)
}
Expand All @@ -55,7 +55,7 @@ class ConversationsTests: XCTestCase {
let peerAddress = fixtures.alice.walletAddress
let envelope = Envelope(topic: .userInvite(peerAddress), timestamp: created, message: try sealed.serializedData())

let conversation = try client.conversations.fromInvite(envelope: envelope)
let conversation = try await client.conversations.fromInvite(envelope: envelope)
XCTAssertEqual(conversation.peerAddress, newWallet.address)
XCTAssertEqual(conversation.createdAt.description, created.description)
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/XMTPTests/IntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ final class IntegrationTests: XCTestCase {
options: opt
)
// And it uses the saved topic data for the conversation
let aliceConvo2 = alice2.conversations.importTopicData(
let aliceConvo2 = await alice2.conversations.importTopicData(
data: try Xmtp_KeystoreApi_V1_TopicMap.TopicData(serializedData: topicData))
XCTAssertEqual("example.com/alice-bob-1", aliceConvo2.conversationID)

Expand Down Expand Up @@ -520,7 +520,7 @@ final class IntegrationTests: XCTestCase {
expectation1.expectedFulfillmentCount = 2

Task(priority: .userInitiated) {
for try await convo in bobClient.conversations.stream() {
for try await convo in await bobClient.conversations.stream() {
expectation1.fulfill()
}
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/XMTPTests/PaginationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class PaginationTests: XCTestCase {
expectation1.expectedFulfillmentCount = 2

Task(priority: .userInitiated) {
for try await _ in bobClient.conversations.stream() {
for try await _ in await bobClient.conversations.stream() {
print("Got one conversation")
expectation1.fulfill()
}
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.5.7-alpha0"
spec.version = "0.5.8-alpha0"
spec.summary = "XMTP SDK Cocoapod"

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

0 comments on commit dbb39bc

Please sign in to comment.