From a32ddaca7add06e285415f73af82d681f94ba630 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 6 Feb 2024 16:34:19 -0600 Subject: [PATCH 1/8] Improve error messages (#240) * let errors be more descriptive * remove test * bump the podspec --- Sources/XMTPiOS/ApiClient.swift | 15 ++++++++++++++- Sources/XMTPiOS/Client.swift | 9 ++++++++- .../Codecs/RemoteAttachmentCodec.swift | 19 ++++++++++++++++++- Sources/XMTPiOS/Conversations.swift | 13 ++++++++++++- Sources/XMTPiOS/Messages/PrivateKey.swift | 13 ++++++++++++- .../XMTPiOS/Messages/SealedInvitation.swift | 6 +++++- Sources/XMTPiOS/Messages/Signature.swift | 6 +++++- XMTP.podspec | 2 +- .../xcshareddata/swiftpm/Package.resolved | 4 ++-- 9 files changed, 77 insertions(+), 10 deletions(-) diff --git a/Sources/XMTPiOS/ApiClient.swift b/Sources/XMTPiOS/ApiClient.swift index d85692fd..e4411b50 100644 --- a/Sources/XMTPiOS/ApiClient.swift +++ b/Sources/XMTPiOS/ApiClient.swift @@ -17,11 +17,24 @@ public typealias QueryRequest = Xmtp_MessageApi_V1_QueryRequest public typealias QueryResponse = Xmtp_MessageApi_V1_QueryResponse public typealias SubscribeRequest = Xmtp_MessageApi_V1_SubscribeRequest -public enum ApiClientError: Error { +public enum ApiClientError: Error, CustomStringConvertible { case batchQueryError(String) case queryError(String) case publishError(String) case subscribeError(String) + + public var description: String { + switch self { + case .batchQueryError(let err): + return "ApiClientError.batchQueryError: \(err)" + case .queryError(let err): + return "ApiClientError.queryError: \(err)" + case .publishError(let err): + return "ApiClientError.publishError: \(err)" + case .subscribeError(let err): + return "ApiClientError.subscribeError: \(err)" + } + } } protocol ApiClient: Sendable { diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index 7e6199a8..6822721a 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -11,8 +11,15 @@ import web3 public typealias PreEventCallback = () async throws -> Void -public enum ClientError: Error { +public enum ClientError: Error, CustomStringConvertible { case creationError(String) + + public var description: String { + switch self { + case .creationError(let err): + return "ClientError.creationError: \(err)" + } + } } /// Specify configuration options for creating a ``Client``. diff --git a/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift b/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift index 62af9969..32c1b103 100644 --- a/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift +++ b/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift @@ -11,8 +11,25 @@ import web3 public let ContentTypeRemoteAttachment = ContentTypeID(authorityID: "xmtp.org", typeID: "remoteStaticAttachment", versionMajor: 1, versionMinor: 0) -public enum RemoteAttachmentError: Error { +public enum RemoteAttachmentError: Error, CustomStringConvertible { case invalidURL, v1NotSupported, invalidParameters(String), invalidDigest(String), invalidScheme(String), payloadNotFound + + public var description: String { + switch self { + case .invalidURL: + return "RemoteAttachmentError.invalidURL" + case .v1NotSupported: + return "RemoteAttachmentError.v1NotSupported" + case .invalidParameters(let string): + return "RemoteAttachmentError.invalidParameters: \(string)" + case .invalidDigest(let string): + return "RemoteAttachmentError.invalidDigest: \(string)" + case .invalidScheme(let string): + return "RemoteAttachmentError.invalidScheme: \(string)" + case .payloadNotFound: + return "RemoteAttachmentError.payloadNotFound" + } + } } protocol RemoteContentFetcher { diff --git a/Sources/XMTPiOS/Conversations.swift b/Sources/XMTPiOS/Conversations.swift index b6e2072a..12aba501 100644 --- a/Sources/XMTPiOS/Conversations.swift +++ b/Sources/XMTPiOS/Conversations.swift @@ -1,7 +1,18 @@ import Foundation -public enum ConversationError: Error { +public enum ConversationError: Error, CustomStringConvertible { case recipientNotOnNetwork, recipientIsSender, v1NotSupported(String) + + public var description: String { + switch self { + case .recipientIsSender: + return "ConversationError.recipientIsSender: Recipient cannot be sender" + case .recipientNotOnNetwork: + return "ConversationError.recipientNotOnNetwork: Recipient is not on network" + case .v1NotSupported(let str): + return "ConversationError.v1NotSupported: V1 does not support: \(str)" + } + } } /// Handles listing and creating Conversations. diff --git a/Sources/XMTPiOS/Messages/PrivateKey.swift b/Sources/XMTPiOS/Messages/PrivateKey.swift index 4e2f4186..8d862dd3 100644 --- a/Sources/XMTPiOS/Messages/PrivateKey.swift +++ b/Sources/XMTPiOS/Messages/PrivateKey.swift @@ -13,8 +13,19 @@ import CryptoKit /// to create a ``Client``. public typealias PrivateKey = Xmtp_MessageContents_PrivateKey -enum PrivateKeyError: Error { +enum PrivateKeyError: Error, CustomStringConvertible { case invalidSignatureText, invalidPrefix, invalidSignature + + var description: String { + switch self { + case .invalidSignatureText: + return "PrivateKeyError.invalidSignatureText" + case .invalidPrefix: + return "PrivateKeyError.invalidPrefix" + case .invalidSignature: + return "PrivateKeyError.invalidSignature" + } + } } extension PrivateKey: SigningKey { diff --git a/Sources/XMTPiOS/Messages/SealedInvitation.swift b/Sources/XMTPiOS/Messages/SealedInvitation.swift index 2d5cae01..920ee2fc 100644 --- a/Sources/XMTPiOS/Messages/SealedInvitation.swift +++ b/Sources/XMTPiOS/Messages/SealedInvitation.swift @@ -10,8 +10,12 @@ import Foundation typealias SealedInvitation = Xmtp_MessageContents_SealedInvitation -enum SealedInvitationError: Error { +enum SealedInvitationError: Error, CustomStringConvertible { case noSignature + + var description: String { + "SealedInvitationError.noSignature" + } } extension SealedInvitation { diff --git a/Sources/XMTPiOS/Messages/Signature.swift b/Sources/XMTPiOS/Messages/Signature.swift index 01bf381f..e2964e36 100644 --- a/Sources/XMTPiOS/Messages/Signature.swift +++ b/Sources/XMTPiOS/Messages/Signature.swift @@ -11,8 +11,12 @@ import LibXMTP /// Represents a secp256k1 compact recoverable signature. public typealias Signature = Xmtp_MessageContents_Signature -enum SignatureError: Error { +enum SignatureError: Error, CustomStringConvertible { case invalidMessage + + var description: String { + return "SignatureError.invalidMessage" + } } public extension Signature { diff --git a/XMTP.podspec b/XMTP.podspec index bf9cb3e9..cb5e0eae 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.8.0" + spec.version = "0.8.1" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 30e11be1..4ce86ce4 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -51,7 +51,7 @@ "location" : "https://github.com/kishikawakatsumi/KeychainAccess", "state" : { "branch" : "master", - "revision" : "ecb18d8ce4d88277cc4fb103973352d91e18c535" + "revision" : "e0c7eebc5a4465a3c4680764f26b7a61f567cdaf" } }, { @@ -231,7 +231,7 @@ "location" : "https://github.com/WalletConnect/WalletConnectSwiftV2", "state" : { "branch" : "main", - "revision" : "13446a81e678e8eddc6ab506e85c522df0163f1f" + "revision" : "f2db5e796976e6294b40da01c443f39a16b4732a" } }, { From b42437ffcd45b5b43d1450be159fce029a2c20dd Mon Sep 17 00:00:00 2001 From: Fabri Date: Wed, 7 Feb 2024 01:15:05 -0300 Subject: [PATCH 2/8] Update CODEOWNERS (#237) Change @jhaaaa to @fabriguespe --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fa46580d..eb2bb74b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # Global rule: * @xmtp/mobile -*.md @jhaaaa +*.md @fabriguespe From 05be35ac5d01d6d1c7220bc4894d968b89bd0c08 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 7 Feb 2024 13:56:42 -0600 Subject: [PATCH 3/8] rename members to member addresses --- Sources/XMTPiOS/Group.swift | 2 +- XMTPiOSExample/XMTPiOSExample/Views/ConversationListView.swift | 2 +- XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift | 2 +- XMTPiOSExample/XMTPiOSExample/Views/NewConversationView.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/XMTPiOS/Group.swift b/Sources/XMTPiOS/Group.swift index 0660a15e..3b781b32 100644 --- a/Sources/XMTPiOS/Group.swift +++ b/Sources/XMTPiOS/Group.swift @@ -36,7 +36,7 @@ public struct Group: Identifiable, Equatable, Hashable { id.hash(into: &hasher) } - public var members: [String] { + public var memberAddresses: [String] { do { return try ffiGroup.listMembers().map(\.fromFFI.accountAddress) } catch { diff --git a/XMTPiOSExample/XMTPiOSExample/Views/ConversationListView.swift b/XMTPiOSExample/XMTPiOSExample/Views/ConversationListView.swift index d8fff910..812bf66b 100644 --- a/XMTPiOSExample/XMTPiOSExample/Views/ConversationListView.swift +++ b/XMTPiOSExample/XMTPiOSExample/Views/ConversationListView.swift @@ -40,7 +40,7 @@ struct ConversationListView: View { case .conversation(let conversation): Text(Util.abbreviate(address: conversation.peerAddress)) case .group(let group): - Text(group.members.sorted().map { Util.abbreviate(address: $0) }.joined(separator: ", ")) + Text(group.memberAddresses.sorted().map { Util.abbreviate(address: $0) }.joined(separator: ", ")) } Text(item.createdAt.formatted()) diff --git a/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift b/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift index 659b0a0d..ae152465 100644 --- a/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift +++ b/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift @@ -116,7 +116,7 @@ struct GroupSettingsView: View { private func syncGroupMembers() async { try? await group.sync() await MainActor.run { - self.groupMembers = group.members + self.groupMembers = group.memberAddresses } } } diff --git a/XMTPiOSExample/XMTPiOSExample/Views/NewConversationView.swift b/XMTPiOSExample/XMTPiOSExample/Views/NewConversationView.swift index 7586683a..e76bb025 100644 --- a/XMTPiOSExample/XMTPiOSExample/Views/NewConversationView.swift +++ b/XMTPiOSExample/XMTPiOSExample/Views/NewConversationView.swift @@ -24,7 +24,7 @@ enum ConversationOrGroup: Identifiable, Hashable { case .conversation(let conversation): return conversation.peerAddress case .group(let group): - return group.members.joined(separator: ",") + return group.memberAddresses.joined(separator: ",") } } From a5eacd38f02d43c9c7e88ac78e4bebc8026fbe5a Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 7 Feb 2024 13:59:26 -0600 Subject: [PATCH 4/8] uncomment local node skip --- Sources/XMTPTestHelpers/TestHelpers.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/XMTPTestHelpers/TestHelpers.swift b/Sources/XMTPTestHelpers/TestHelpers.swift index 5182b70b..9ef4a82e 100644 --- a/Sources/XMTPTestHelpers/TestHelpers.swift +++ b/Sources/XMTPTestHelpers/TestHelpers.swift @@ -23,7 +23,7 @@ public struct TestConfig { } static public func skipIfNotRunningLocalNodeTests() throws { -// try XCTSkipIf(!TEST_SERVER_ENABLED, "requires local node") + try XCTSkipIf(!TEST_SERVER_ENABLED, "requires local node") } static public func skip(because: String) throws { From 7ef5510bd12a3eb8ed436710fd12bfcc238c595d Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 7 Feb 2024 14:00:55 -0600 Subject: [PATCH 5/8] improve group error --- Sources/XMTPiOS/Conversations.swift | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Sources/XMTPiOS/Conversations.swift b/Sources/XMTPiOS/Conversations.swift index 1c18390a..29b407a8 100644 --- a/Sources/XMTPiOS/Conversations.swift +++ b/Sources/XMTPiOS/Conversations.swift @@ -16,8 +16,21 @@ public enum ConversationError: Error, CustomStringConvertible { } } -public enum GroupError: Error { +public enum GroupError: Error, CustomStringConvertible { case alphaMLSNotEnabled, emptyCreation, memberCannotBeSelf, memberNotRegistered([String]) + + public var description: String { + switch self { + case .alphaMLSNotEnabled: + return "GroupError.alphaMLSNotEnabled" + case .emptyCreation: + return "GroupError.emptyCreation you cannot create an empty group" + case .memberCannotBeSelf: + return "GroupError.memberCannotBeSelf you cannot add yourself to a group" + case .memberNotRegistered(let array): + return "GroupError.memberNotRegistered members not registered: \(array.joined(separator: ", "))" + } + } } /// Handles listing and creating Conversations. From 33c20c0f2a89a1b1731206432d942925bb2cbe39 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 7 Feb 2024 14:02:52 -0600 Subject: [PATCH 6/8] use group id for topic --- Sources/XMTPiOS/Group.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/XMTPiOS/Group.swift b/Sources/XMTPiOS/Group.swift index 3b781b32..335ea908 100644 --- a/Sources/XMTPiOS/Group.swift +++ b/Sources/XMTPiOS/Group.swift @@ -109,7 +109,7 @@ public struct Group: Identifiable, Equatable, Hashable { return DecodedMessage( client: client, - topic: "", + topic: id.toHex, encodedContent: encodedContent, senderAddress: ffiMessage.addrFrom, sent: Date(timeIntervalSince1970: TimeInterval(ffiMessage.sentAtNs / 1_000_000_000)) From 7f09636b2effd484cde2b406ceabba5822529efa Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 7 Feb 2024 14:05:09 -0600 Subject: [PATCH 7/8] fix lint --- XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift b/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift index ae152465..87a66376 100644 --- a/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift +++ b/XMTPiOSExample/XMTPiOSExample/Views/GroupSettingsView.swift @@ -114,7 +114,9 @@ struct GroupSettingsView: View { } private func syncGroupMembers() async { + // swiftlint:disable no_optional_try try? await group.sync() + // swiftlint:enable no_optional_try await MainActor.run { self.groupMembers = group.memberAddresses } From 15d34aa1394ba887ce10bdaad3948787869097aa Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 7 Feb 2024 14:08:35 -0600 Subject: [PATCH 8/8] allow mls on dev, other cleanup --- Sources/XMTPiOS/Client.swift | 10 +++++----- Sources/XMTPiOS/XMTPEnvironment.swift | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index 6822721a..fa5c3797 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -107,7 +107,7 @@ public final class Client { public static func create(account: SigningKey, options: ClientOptions? = nil) async throws -> Client { let options = options ?? ClientOptions() do { - let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env != .local) + let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env.isSecure) let apiClient = try GRPCApiClient( environment: options.api.env, secure: options.api.isSecure, @@ -126,12 +126,12 @@ public final class Client { privateKeyBundleV1: PrivateKeyBundleV1, signingKey: SigningKey? ) async throws -> FfiXmtpClient? { - if options?.mlsAlpha == true, options?.api.env == .local { + if options?.mlsAlpha == true, options?.api.env.supportsMLS == true { let dbURL = URL.documentsDirectory.appendingPathComponent("xmtp-\(options?.api.env.rawValue ?? "")-\(address).db3") let v3Client = try await LibXMTP.createClient( logger: XMTPLogger(), host: (options?.api.env ?? .local).url, - isSecure: (options?.api.env ?? .local) != .local, + isSecure: options?.api.env.isSecure == true, db: dbURL.path, encryptionKey: options?.mlsEncryptionKey, accountAddress: address, @@ -249,7 +249,7 @@ public final class Client { let options = options ?? ClientOptions() - let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env != .local) + let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env.isSecure) let apiClient = try GRPCApiClient( environment: options.api.env, secure: options.api.isSecure, @@ -303,7 +303,7 @@ public final class Client { public static func canMessage(_ peerAddress: String, options: ClientOptions? = nil) async throws -> Bool { let options = options ?? ClientOptions() - let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env != .local) + let client = try await LibXMTP.createV2Client(host: options.api.env.url, isSecure: options.api.env.isSecure) let apiClient = try GRPCApiClient( environment: options.api.env, secure: options.api.isSecure, diff --git a/Sources/XMTPiOS/XMTPEnvironment.swift b/Sources/XMTPiOS/XMTPEnvironment.swift index 1c175069..4f12c8d2 100644 --- a/Sources/XMTPiOS/XMTPEnvironment.swift +++ b/Sources/XMTPiOS/XMTPEnvironment.swift @@ -23,4 +23,12 @@ public enum XMTPEnvironment: String, Sendable { return "http://\(rawValue)" } } + + public var supportsMLS: Bool { + self != .production + } + + public var isSecure: Bool { + url.starts(with: "https") + } }