From 4251762553e3845e77777c575e66982fcc73904c Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Tue, 16 Jul 2024 17:19:37 +0400 Subject: [PATCH] ios: better errors (#4462) --- apps/ios/Shared/Model/SimpleXAPI.swift | 34 +++++++++---------- .../Views/Migration/MigrateFromDevice.swift | 2 +- apps/ios/SimpleXChat/API.swift | 22 ++++++++---- apps/ios/SimpleXChat/APITypes.swift | 4 +-- 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index dd0610e48c..fff1d6d497 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -397,7 +397,7 @@ private func sendMessageErrorAlert(_ r: ChatResponse) { logger.error("send message error: \(String(describing: r))") AlertManager.shared.showAlertMsg( title: "Error sending message", - message: "Error: \(String(describing: r))" + message: "Error: \(responseError(r))" ) } @@ -405,7 +405,7 @@ private func createChatItemErrorAlert(_ r: ChatResponse) { logger.error("apiCreateChatItem error: \(String(describing: r))") AlertManager.shared.showAlertMsg( title: "Error creating message", - message: "Error: \(String(describing: r))" + message: "Error: \(responseError(r))" ) } @@ -699,7 +699,7 @@ func apiConnect_(incognito: Bool, connReq: String) async -> ((ConnReqType, Pendi message: "Please check that you used the correct link or ask your contact to send you another one." ) return (nil, alert) - case .chatCmdError(_, .errorAgent(.SMP(.AUTH))): + case .chatCmdError(_, .errorAgent(.SMP(_, .AUTH))): let alert = mkAlert( title: "Connection error (AUTH)", message: "Unless your contact deleted the connection or this link was already used, it might be a bug - please report it.\nTo connect, please ask your contact to create another connection link and check that you have a stable network connection." @@ -732,7 +732,7 @@ private func connectionErrorAlert(_ r: ChatResponse) -> Alert { } else { return mkAlert( title: "Connection error", - message: "Error: \(String(describing: r))" + message: "Error: \(responseError(r))" ) } } @@ -898,7 +898,7 @@ func apiAcceptContactRequest(incognito: Bool, contactReqId: Int64) async -> Cont let am = AlertManager.shared if case let .acceptingContactRequest(_, contact) = r { return contact } - if case .chatCmdError(_, .errorAgent(.SMP(.AUTH))) = r { + if case .chatCmdError(_, .errorAgent(.SMP(_, .AUTH))) = r { am.showAlertMsg( title: "Connection error (AUTH)", message: "Sender may have deleted the connection request." @@ -909,7 +909,7 @@ func apiAcceptContactRequest(incognito: Bool, contactReqId: Int64) async -> Cont logger.error("apiAcceptContactRequest error: \(String(describing: r))") am.showAlertMsg( title: "Error accepting contact request", - message: "Error: \(String(describing: r))" + message: "Error: \(responseError(r))" ) } return nil @@ -935,7 +935,7 @@ func uploadStandaloneFile(user: any UserLike, file: CryptoFile, ctrl: chat_ctrl? return (fileTransferMeta, nil) } else { logger.error("uploadStandaloneFile error: \(String(describing: r))") - return (nil, String(describing: r)) + return (nil, responseError(r)) } } @@ -945,7 +945,7 @@ func downloadStandaloneFile(user: any UserLike, url: String, file: CryptoFile, c return (rcvFileTransfer, nil) } else { logger.error("downloadStandaloneFile error: \(String(describing: r))") - return (nil, String(describing: r)) + return (nil, responseError(r)) } } @@ -1025,7 +1025,7 @@ func apiReceiveFile(fileId: Int64, userApprovedRelays: Bool, encrypted: Bool, in if !auto { am.showAlertMsg( title: "Error receiving file", - message: "Error: \(String(describing: r))" + message: "Error: \(responseError(r))" ) } } @@ -1106,16 +1106,16 @@ func getNetworkErrorAlert(_ r: ChatResponse) -> ErrorAlert? { return ErrorAlert(title: "Connection error", message: "Server address is incompatible with network settings: \(serverHostname(addr)).") case let .chatCmdError(_, .errorAgent(.BROKER(addr, .TRANSPORT(.version)))): return ErrorAlert(title: "Connection error", message: "Server version is incompatible with your app: \(serverHostname(addr)).") - case let .chatCmdError(_, .errorAgent(.SMP(.PROXY(proxyErr)))): - return proxyErrorAlert(proxyErr) - case let .chatCmdError(_, .errorAgent(.PROXY(_, _, .protocolError(.PROXY(proxyErr))))): - return proxyErrorAlert(proxyErr) + case let .chatCmdError(_, .errorAgent(.SMP(serverAddress, .PROXY(proxyErr)))): + return proxyErrorAlert(proxyErr, serverAddress) + case let .chatCmdError(_, .errorAgent(.PROXY(proxyServer, _, .protocolError(.PROXY(proxyErr))))): + return proxyErrorAlert(proxyErr, proxyServer) default: return nil } } -private func proxyErrorAlert(_ proxyErr: ProxyError) -> ErrorAlert? { +private func proxyErrorAlert(_ proxyErr: ProxyError, _ srvAddr: String) -> ErrorAlert? { switch proxyErr { case .BROKER(brokerErr: .TIMEOUT): return ErrorAlert(title: "Private routing error", message: "Please try later.") @@ -1124,9 +1124,9 @@ private func proxyErrorAlert(_ proxyErr: ProxyError) -> ErrorAlert? { case .NO_SESSION: return ErrorAlert(title: "Private routing error", message: "Please try later.") case .BROKER(brokerErr: .HOST): - return ErrorAlert(title: "Private routing error", message: "Server address is incompatible with network settings.") + return ErrorAlert(title: "Private routing error", message: "Server address is incompatible with network settings: \(serverHostname(srvAddr)).") case .BROKER(brokerErr: .TRANSPORT(.version)): - return ErrorAlert(title: "Private routing error", message: "Server version is incompatible with network settings.") + return ErrorAlert(title: "Private routing error", message: "Server version is incompatible with network settings: \(serverHostname(srvAddr)).") default: return nil } @@ -1280,7 +1280,7 @@ func apiJoinGroup(_ groupId: Int64) async throws -> JoinGroupResult { let r = await chatSendCmd(.apiJoinGroup(groupId: groupId)) switch r { case let .userAcceptedGroupSent(_, groupInfo, _): return .joined(groupInfo: groupInfo) - case .chatCmdError(_, .errorAgent(.SMP(.AUTH))): return .invitationRemoved + case .chatCmdError(_, .errorAgent(.SMP(_, .AUTH))): return .invitationRemoved case .chatCmdError(_, .errorStore(.groupNotFound)): return .groupNotFound default: throw r } diff --git a/apps/ios/Shared/Views/Migration/MigrateFromDevice.swift b/apps/ios/Shared/Views/Migration/MigrateFromDevice.swift index ec2ce883c5..028a6d179f 100644 --- a/apps/ios/Shared/Views/Migration/MigrateFromDevice.swift +++ b/apps/ios/Shared/Views/Migration/MigrateFromDevice.swift @@ -662,7 +662,7 @@ private struct PassphraseConfirmationView: View { if case .chatCmdError(_, .errorDatabase(.errorOpen(.errorNotADatabase))) = error as? ChatResponse { showErrorOnMigrationIfNeeded(.errorNotADatabase(dbFile: ""), $alert) } else { - alert = .error(title: "Error", error: NSLocalizedString("Error verifying passphrase:", comment: "") + " " + String(String(describing: error))) + alert = .error(title: "Error", error: NSLocalizedString("Error verifying passphrase:", comment: "") + " " + String(responseError(error))) } } } diff --git a/apps/ios/SimpleXChat/API.swift b/apps/ios/SimpleXChat/API.swift index e2f4adc60f..bc8a413e8f 100644 --- a/apps/ios/SimpleXChat/API.swift +++ b/apps/ios/SimpleXChat/API.swift @@ -205,7 +205,7 @@ public func chatResponse(_ s: String) -> ChatResponse { if let chatData = try? parseChatData(jChat) { return chatData } - return ChatData.invalidJSON(prettyJSON(jChat) ?? "") + return ChatData.invalidJSON(serializeJSON(jChat, options: .prettyPrinted) ?? "") } return .apiChats(user: user, chats: chats) } @@ -218,15 +218,15 @@ public func chatResponse(_ s: String) -> ChatResponse { } } else if type == "chatCmdError" { if let jError = jResp["chatCmdError"] as? NSDictionary { - return .chatCmdError(user_: decodeUser_(jError), chatError: .invalidJSON(json: prettyJSON(jError) ?? "")) + return .chatCmdError(user_: decodeUser_(jError), chatError: .invalidJSON(json: errorJson(jError) ?? "")) } } else if type == "chatError" { if let jError = jResp["chatError"] as? NSDictionary { - return .chatError(user_: decodeUser_(jError), chatError: .invalidJSON(json: prettyJSON(jError) ?? "")) + return .chatError(user_: decodeUser_(jError), chatError: .invalidJSON(json: errorJson(jError) ?? "")) } } } - json = prettyJSON(j) + json = serializeJSON(j, options: .prettyPrinted) } return ChatResponse.response(type: type ?? "invalid", json: json ?? s) } @@ -239,6 +239,14 @@ private func decodeUser_(_ jDict: NSDictionary) -> UserRef? { } } +private func errorJson(_ jDict: NSDictionary) -> String? { + if let chatError = jDict["chatError"] { + serializeJSON(chatError) + } else { + serializeJSON(jDict) + } +} + func parseChatData(_ jChat: Any) throws -> ChatData { let jChatDict = jChat as! NSDictionary let chatInfo: ChatInfo = try decodeObject(jChatDict["chatInfo"]!) @@ -251,7 +259,7 @@ func parseChatData(_ jChat: Any) throws -> ChatData { return ChatItem.invalidJSON( chatDir: decodeProperty(jCI, "chatDir"), meta: decodeProperty(jCI, "meta"), - json: prettyJSON(jCI) ?? "" + json: serializeJSON(jCI, options: .prettyPrinted) ?? "" ) } return ChatData(chatInfo: chatInfo, chatItems: chatItems, chatStats: chatStats) @@ -268,8 +276,8 @@ func decodeProperty(_ obj: Any, _ prop: NSString) -> T? { return nil } -func prettyJSON(_ obj: Any) -> String? { - if let d = try? JSONSerialization.data(withJSONObject: obj, options: .prettyPrinted) { +func serializeJSON(_ obj: Any, options: JSONSerialization.WritingOptions = []) -> String? { + if let d = try? JSONSerialization.data(withJSONObject: obj, options: options) { return String(decoding: d, as: UTF8.self) } return nil diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index 81b638d7be..4478aa5b62 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -1228,7 +1228,7 @@ public struct ProtocolTestFailure: Decodable, Error, Equatable { public var localizedDescription: String { let err = String.localizedStringWithFormat(NSLocalizedString("Test failed at step %@.", comment: "server test failure"), testStep.text) switch testError { - case .SMP(.AUTH): + case .SMP(_, .AUTH): return err + " " + NSLocalizedString("Server requires authorization to create queues, check password", comment: "server test error") case .XFTP(.AUTH): return err + " " + NSLocalizedString("Server requires authorization to upload, check password", comment: "server test error") @@ -1887,7 +1887,7 @@ public enum SQLiteError: Decodable, Hashable { public enum AgentErrorType: Decodable, Hashable { case CMD(cmdErr: CommandErrorType) case CONN(connErr: ConnectionErrorType) - case SMP(smpErr: ProtocolErrorType) + case SMP(serverAddress: String, smpErr: ProtocolErrorType) case NTF(ntfErr: ProtocolErrorType) case XFTP(xftpErr: XFTPErrorType) case PROXY(proxyServer: String, relayServer: String, proxyErr: ProxyClientError)