From eb539cd7f691ec4a3b30b65e2140282a5015f96c Mon Sep 17 00:00:00 2001 From: Magesh K <47920326+mahee96@users.noreply.github.com> Date: Mon, 20 Jan 2025 23:02:06 +0530 Subject: [PATCH] [ErrorProcessing]: Make toast show underlying errors (if there are any) --- AltStore.xcodeproj/project.pbxproj | 12 +++ AltStore/Components/ToastView.swift | 24 +----- .../dignostics/errors/ErrorProcessing.swift | 81 +++++++++++++++++++ 3 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 SideStore/Utils/dignostics/errors/ErrorProcessing.swift diff --git a/AltStore.xcodeproj/project.pbxproj b/AltStore.xcodeproj/project.pbxproj index 4f8bab84..914ff9a8 100644 --- a/AltStore.xcodeproj/project.pbxproj +++ b/AltStore.xcodeproj/project.pbxproj @@ -62,6 +62,7 @@ A82067C42D03E0DE00645C0D /* SemanticVersion in Frameworks */ = {isa = PBXBuildFile; productRef = A82067C32D03E0DE00645C0D /* SemanticVersion */; }; A859ED5C2D1EE827003DCC58 /* OpenSSL.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */; }; A859ED5D2D1EE827003DCC58 /* OpenSSL.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A859ED5B2D1EE80D003DCC58 /* OpenSSL.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + A86315DF2D3EB2DE0048FA40 /* ErrorProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86315DE2D3EB2D80048FA40 /* ErrorProcessing.swift */; }; A868CFE42D31999A002F1201 /* SingletonGenericMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868CFE32D319988002F1201 /* SingletonGenericMap.swift */; }; A8696EE42D34512C00E96389 /* RemoveAppExtensionsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */; }; A88B8C492D35AD3200F53F9D /* OperationsLoggingContolView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88B8C482D35AD3200F53F9D /* OperationsLoggingContolView.swift */; }; @@ -645,6 +646,7 @@ A85ACB932D1F31C400AA3DE7 /* AltWidgetExtension.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltWidgetExtension.xcconfig; sourceTree = ""; }; A86202322D1F35640091187B /* AltStore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltStore.xcconfig; sourceTree = ""; }; A86202332D1F35640091187B /* AltStoreCore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltStoreCore.xcconfig; sourceTree = ""; }; + A86315DE2D3EB2D80048FA40 /* ErrorProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorProcessing.swift; sourceTree = ""; }; A868CFE32D319988002F1201 /* SingletonGenericMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingletonGenericMap.swift; sourceTree = ""; }; A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAppExtensionsOperation.swift; sourceTree = ""; }; A88B8C482D35AD3200F53F9D /* OperationsLoggingContolView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationsLoggingContolView.swift; sourceTree = ""; }; @@ -1214,6 +1216,14 @@ path = xcconfigs; sourceTree = ""; }; + A86315DD2D3EB2BD0048FA40 /* errors */ = { + isa = PBXGroup; + children = ( + A86315DE2D3EB2D80048FA40 /* ErrorProcessing.swift */, + ); + path = errors; + sourceTree = ""; + }; A88B8C532D35F1E800F53F9D /* operations */ = { isa = PBXGroup; children = ( @@ -1260,6 +1270,7 @@ A8B516DE2D2666900047047C /* dignostics */ = { isa = PBXGroup; children = ( + A86315DD2D3EB2BD0048FA40 /* errors */, A88B8C532D35F1E800F53F9D /* operations */, A8B516DF2D2666A00047047C /* database */, ); @@ -3008,6 +3019,7 @@ BF56D2AC23DF8E170006506D /* FetchAppIDsOperation.swift in Sources */, BFC1F38D22AEE3A4003AC21A /* DownloadAppOperation.swift in Sources */, BFE6073A231ADF82002B0E8E /* SettingsViewController.swift in Sources */, + A86315DF2D3EB2DE0048FA40 /* ErrorProcessing.swift in Sources */, D57F2C9126E0070200B9FA39 /* EnableJITOperation.swift in Sources */, BF8CAE4E248AEABA004D6CCE /* UIDevice+Jailbreak.swift in Sources */, D5E1E7C128077DE90016FC96 /* UpdateKnownSourcesOperation.swift in Sources */, diff --git a/AltStore/Components/ToastView.swift b/AltStore/Components/ToastView.swift index 77c93212..f940b4ac 100644 --- a/AltStore/Components/ToastView.swift +++ b/AltStore/Components/ToastView.swift @@ -67,30 +67,10 @@ class ToastView: RSTToastView convenience init(error: Error) { - var error = error as NSError - var underlyingError = error.underlyingError + let error = error as NSError - if - let unwrappedUnderlyingError = underlyingError, - error.domain == AltServerErrorDomain && error.code == ALTServerError.Code.underlyingError.rawValue - { - // Treat underlyingError as the primary error, but keep localized title + failure. - - let nsError = error as NSError - error = unwrappedUnderlyingError as NSError - - if let localizedTitle = nsError.localizedTitle { - error = error.withLocalizedTitle(localizedTitle) - } - if let localizedFailure = nsError.localizedFailure { - error = error.withLocalizedFailure(localizedFailure) - } - - underlyingError = nil - } let text = error.localizedTitle ?? NSLocalizedString("Operation Failed", comment: "") - let detailText = error.localizedDescription - + let detailText = ErrorProcessing(.fullError).getDescription(error: error) self.init(text: text, detailText: detailText) } diff --git a/SideStore/Utils/dignostics/errors/ErrorProcessing.swift b/SideStore/Utils/dignostics/errors/ErrorProcessing.swift new file mode 100644 index 00000000..15489f58 --- /dev/null +++ b/SideStore/Utils/dignostics/errors/ErrorProcessing.swift @@ -0,0 +1,81 @@ +// +// ErrorProcessing.swift +// AltStore +// +// Created by Magesh K on 20/01/25. +// Copyright © 2025 SideStore. All rights reserved. +// + +class ErrorProcessing { + + enum InfoMode: String { + case fullError + case localizedDescription + } + + let info: InfoMode + let unique: Bool + let recur: Bool + + + var errors: Set = [] + + // by default we will process only the localDesc on first level errors + init(_ mode: InfoMode = .localizedDescription, unique: Bool = false, recur: Bool = false){ + self.info = mode + self.unique = unique + self.recur = recur + } + + private func processError(_ error: NSError, getMoreErrors: (_ error: NSError)->String) -> String{ + // if unique was requested and if this error is duplicate, ignore processing it + let serializedError = "\(error)" + if unique && errors.contains(serializedError) { + return "" + } + errors.insert(serializedError) // mark this as processed + + var title = "" + var desc = "" + switch (info){ + case .localizedDescription: + title = (error.localizedTitle.map{$0+"\n"} ?? "") + desc = error.localizedDescription + case .fullError: + desc = serializedError + } + var moreErrors = getMoreErrors(error) + moreErrors = moreErrors == "" ? "" : "\n" + moreErrors + return title + desc + moreErrors + } + + func getDescription(error: NSError) -> String{ + errors = [] // reinit for each request + return getDescriptionText(error: error) + } + + private lazy var recurseErrors = { error in + self.getDescriptionText(error: error) // recursively process underlying error(s) if any + } + + func getDescriptionText(error: NSError) -> String{ + var description = "" + + // process current error only if recur was not requested + let processMoreErrors = recur ? recurseErrors : {_ in ""} + + let underlyingErrors = error.underlyingErrors + if !underlyingErrors.isEmpty { + description += underlyingErrors.map{ error in + let error = error as NSError + return processError(error, getMoreErrors: processMoreErrors) + }.joined(separator: "\n") + } else if let underlyingError = error.underlyingError as? NSError { + let error = underlyingError as NSError + description += processError(error, getMoreErrors: processMoreErrors) + } else { + description += processError(error, getMoreErrors: processMoreErrors) + } + return description + } +}