Skip to content

Commit

Permalink
Message kind (#310)
Browse files Browse the repository at this point in the history
* update to latest rust version

* update the package resolve

* filter out messages by kind

* tweak the logic a big

* write tests for it

* bump the pod
  • Loading branch information
nplasterer authored Apr 12, 2024
1 parent 636e4a1 commit b77879f
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ let package = Package(
.package(url: "https://github.com/1024jp/GzipSwift", from: "5.2.0"),
.package(url: "https://github.com/bufbuild/connect-swift", exact: "0.12.0"),
.package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"),
.package(url: "https://github.com/xmtp/libxmtp-swift", exact: "0.4.3-beta4"),
.package(url: "https://github.com/xmtp/libxmtp-swift", exact: "0.4.3-beta5"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand Down
8 changes: 4 additions & 4 deletions Sources/XMTPiOS/Conversation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,10 @@ public enum Conversation: Sendable {
case let .v2(conversationV2):
return try conversationV2.decode(envelope: envelope)
case let .group(group):
guard let messageDecoded = try message?.fromFFI(client: client) else {
guard let message = message else {
throw GroupError.groupsRequireMessagePassed
}
return messageDecoded
return try MessageV3(client: client, ffiMessage: message).decode()
}
}

Expand All @@ -161,10 +161,10 @@ public enum Conversation: Sendable {
case let .v2(conversationV2):
return try conversationV2.decrypt(envelope: envelope)
case let .group(group):
guard let messageDecrypted = try message?.fromFFIDecrypted(client: client) else {
guard let message = message else {
throw GroupError.groupsRequireMessagePassed
}
return messageDecrypted
return try MessageV3(client: client, ffiMessage: message).decrypt()
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/XMTPiOS/Conversations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ public actor Conversations {
self.streamHolder.stream = try await self.client.v3Client?.conversations().streamAllMessages(
messageCallback: MessageCallback(client: self.client) { message in
do {
continuation.yield(try message.fromFFI(client: self.client))
continuation.yield(try MessageV3(client: self.client, ffiMessage: message).decode())
} catch {
print("Error onMessage \(error)")
}
Expand Down Expand Up @@ -335,7 +335,7 @@ public actor Conversations {
self.streamHolder.stream = try await self.client.v3Client?.conversations().streamAllMessages(
messageCallback: MessageCallback(client: self.client) { message in
do {
continuation.yield(try message.fromFFIDecrypted(client: self.client))
continuation.yield(try MessageV3(client: self.client, ffiMessage: message).decrypt())
} catch {
print("Error onMessage \(error)")
}
Expand Down
28 changes: 0 additions & 28 deletions Sources/XMTPiOS/Extensions/Ffi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -193,34 +193,6 @@ extension FfiV2SubscribeRequest {
}
}

// MARK: Messages

extension FfiMessage {
func fromFFI(client: Client) throws -> DecodedMessage {
let encodedContent = try EncodedContent(serializedData: content)

return DecodedMessage(
client: client,
topic: Topic.groupMessage(convoId.toHex).description,
encodedContent: encodedContent,
senderAddress: addrFrom,
sent: Date(timeIntervalSince1970: TimeInterval(sentAtNs / 1_000_000_000))
)
}

func fromFFIDecrypted(client: Client) throws -> DecryptedMessage {
let encodedContent = try EncodedContent(serializedData: content)

return DecryptedMessage(
id: id.toHex,
encodedContent: encodedContent,
senderAddress: addrFrom,
sentAt: Date(timeIntervalSince1970: TimeInterval(sentAtNs / 1_000_000_000)),
topic: Topic.groupMessage(convoId.toHex).description
)
}
}

// MARK: Group

extension FfiGroup {
Expand Down
16 changes: 8 additions & 8 deletions Sources/XMTPiOS/Group.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ public struct Group: Identifiable, Equatable, Hashable {

public func processMessage(envelopeBytes: Data) async throws -> DecodedMessage {
let message = try await ffiGroup.processStreamedGroupMessage(envelopeBytes: envelopeBytes)
return try message.fromFFI(client: client)
return try MessageV3(client: client, ffiMessage: message).decode()
}

public func processMessageDecrypted(envelopeBytes: Data) async throws -> DecryptedMessage {
let message = try await ffiGroup.processStreamedGroupMessage(envelopeBytes: envelopeBytes)
return try message.fromFFIDecrypted(client: client)
return try MessageV3(client: client, ffiMessage: message).decrypt()
}

public func send<T>(content: T, options: SendOptions? = nil) async throws -> String {
Expand Down Expand Up @@ -176,7 +176,7 @@ public struct Group: Identifiable, Equatable, Hashable {
self.streamHolder.stream = try await ffiGroup.stream(
messageCallback: MessageCallback(client: self.client) { message in
do {
continuation.yield(try message.fromFFI(client: self.client))
continuation.yield(try MessageV3(client: self.client, ffiMessage: message).decode())
} catch {
print("Error onMessage \(error)")
}
Expand All @@ -196,7 +196,7 @@ public struct Group: Identifiable, Equatable, Hashable {
self.streamHolder.stream = try await ffiGroup.stream(
messageCallback: MessageCallback(client: self.client) { message in
do {
continuation.yield(try message.fromFFIDecrypted(client: self.client))
continuation.yield(try MessageV3(client: self.client, ffiMessage: message).decrypt())
} catch {
print("Error onMessage \(error)")
}
Expand Down Expand Up @@ -224,8 +224,8 @@ public struct Group: Identifiable, Equatable, Hashable {
options.limit = Int64(limit)
}

let messages = try ffiGroup.findMessages(opts: options).map { ffiMessage in
try ffiMessage.fromFFI(client: client)
let messages = try ffiGroup.findMessages(opts: options).compactMap { ffiMessage in
return MessageV3(client: self.client, ffiMessage: ffiMessage).decodeOrNull()
}

switch direction {
Expand All @@ -251,8 +251,8 @@ public struct Group: Identifiable, Equatable, Hashable {
options.limit = Int64(limit)
}

let messages = try ffiGroup.findMessages(opts: options).map { ffiMessage in
try ffiMessage.fromFFIDecrypted(client: client)
let messages = try ffiGroup.findMessages(opts: options).compactMap { ffiMessage in
return MessageV3(client: self.client, ffiMessage: ffiMessage).decryptOrNull()
}

switch direction {
Expand Down
98 changes: 98 additions & 0 deletions Sources/XMTPiOS/Mls/MessageV3.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//
// MessageV3.swift
//
//
// Created by Naomi Plasterer on 4/10/24.
//

import Foundation
import LibXMTP

enum MessageV3Error: Error {
case decodeError(String)
}

public struct MessageV3: Identifiable {
let client: Client
let ffiMessage: FfiMessage

init(client: Client, ffiMessage: FfiMessage) {
self.client = client
self.ffiMessage = ffiMessage
}

public var id: Data {
return ffiMessage.id
}

var convoId: Data {
return ffiMessage.convoId
}

var senderAddress: String {
return ffiMessage.addrFrom
}

var sentAt: Date {
return Date(timeIntervalSince1970: TimeInterval(ffiMessage.sentAtNs) / 1_000_000_000)
}

public func decode() throws -> DecodedMessage {
do {
let encodedContent = try EncodedContent(serializedData: ffiMessage.content)

let decodedMessage = DecodedMessage(
id: id.toHex,
client: client,
topic: Topic.groupMessage(convoId.toHex).description,
encodedContent: encodedContent,
senderAddress: senderAddress,
sent: sentAt
)

if decodedMessage.encodedContent.type == ContentTypeGroupMembershipChanged && ffiMessage.kind != .membershipChange {
throw MessageV3Error.decodeError("Error decoding group membership change")
}

return decodedMessage
} catch {
throw MessageV3Error.decodeError("Error decoding message: \(error.localizedDescription)")
}
}

public func decodeOrNull() -> DecodedMessage? {
do {
return try decode()
} catch {
print("MESSAGE_V3: discarding message that failed to decode", error)
return nil
}
}

public func decryptOrNull() -> DecryptedMessage? {
do {
return try decrypt()
} catch {
print("MESSAGE_V3: discarding message that failed to decrypt", error)
return nil
}
}

public func decrypt() throws -> DecryptedMessage {
let encodedContent = try EncodedContent(serializedData: ffiMessage.content)

let decrytedMessage = DecryptedMessage(
id: id.toHex,
encodedContent: encodedContent,
senderAddress: senderAddress,
sentAt: Date(),
topic: Topic.groupMessage(convoId.toHex).description
)

if decrytedMessage.encodedContent.type == ContentTypeGroupMembershipChanged && ffiMessage.kind != .membershipChange {
throw MessageV3Error.decodeError("Error decoding group membership change")
}

return decrytedMessage
}
}
24 changes: 24 additions & 0 deletions Tests/XMTPTests/GroupTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -353,12 +353,14 @@ class GroupTests: XCTestCase {
func testCanSendMessagesToGroup() async throws {
let fixtures = try await localFixtures()
let aliceGroup = try await fixtures.aliceClient.conversations.newGroup(with: [fixtures.bob.address])
let membershipChange = GroupMembershipChanges()

try await fixtures.bobClient.conversations.sync()
let bobGroup = try await fixtures.bobClient.conversations.groups()[0]

_ = try await aliceGroup.send(content: "sup gang original")
_ = try await aliceGroup.send(content: "sup gang")
_ = try await aliceGroup.send(content: membershipChange, options: SendOptions(contentType: ContentTypeGroupMembershipChanged))

try await aliceGroup.sync()
let aliceGroupsCount = try await aliceGroup.messages().count
Expand All @@ -374,6 +376,7 @@ class GroupTests: XCTestCase {
XCTAssertEqual("sup gang", try bobMessage.content())
}


func testCanSendMessagesToGroupDecrypted() async throws {
let fixtures = try await localFixtures()
let aliceGroup = try await fixtures.aliceClient.conversations.newGroup(with: [fixtures.bob.address])
Expand All @@ -398,6 +401,25 @@ class GroupTests: XCTestCase {
XCTAssertEqual("sup gang", String(data: Data(bobMessage.encodedContent.content), encoding: .utf8))
}

func testCanStreamGroupMessages() async throws {
let fixtures = try await localFixtures()
let group = try await fixtures.bobClient.conversations.newGroup(with: [fixtures.alice.address])
let membershipChange = GroupMembershipChanges()
let expectation1 = expectation(description: "got a message")
expectation1.expectedFulfillmentCount = 1

Task(priority: .userInitiated) {
for try await _ in group.streamMessages() {
expectation1.fulfill()
}
}

_ = try await group.send(content: "hi")
_ = try await group.send(content: membershipChange, options: SendOptions(contentType: ContentTypeGroupMembershipChanged))

await waitForExpectations(timeout: 3)
}

func testCanStreamGroups() async throws {
let fixtures = try await localFixtures()

Expand Down Expand Up @@ -454,6 +476,7 @@ class GroupTests: XCTestCase {

func testCanStreamAllDecryptedMessages() async throws {
let fixtures = try await localFixtures()
let membershipChange = GroupMembershipChanges()

let expectation1 = expectation(description: "got a conversation")
expectation1.expectedFulfillmentCount = 2
Expand All @@ -467,6 +490,7 @@ class GroupTests: XCTestCase {
}

_ = try await group.send(content: "hi")
_ = try await group.send(content: membershipChange, options: SendOptions(contentType: ContentTypeGroupMembershipChanged))
_ = try await convo.send(content: "hi")

await waitForExpectations(timeout: 3)
Expand Down
4 changes: 2 additions & 2 deletions 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.10.0"
spec.version = "0.10.1"
spec.summary = "XMTP SDK Cocoapod"

# This description is used to generate tags and improve search results.
Expand Down Expand Up @@ -44,5 +44,5 @@ Pod::Spec.new do |spec|
spec.dependency "web3.swift"
spec.dependency "GzipSwift"
spec.dependency "Connect-Swift", "= 0.12.0"
spec.dependency 'LibXMTP', '= 0.4.3-beta4'
spec.dependency 'LibXMTP', '= 0.4.3-beta5'
end
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/xmtp/libxmtp-swift",
"state" : {
"revision" : "fa57437cc1a84df566c91bbd5df1d0619d404e09",
"version" : "0.4.3-beta4"
"revision" : "1d315cfadfcc70b4145b6bf6a732a97c0f76763f",
"version" : "0.4.3-beta5"
}
},
{
Expand Down

0 comments on commit b77879f

Please sign in to comment.