diff --git a/ConsentViewController/Classes/Consents/SPUserData.swift b/ConsentViewController/Classes/Consents/SPUserData.swift index f49db0f3a..051681b7f 100644 --- a/ConsentViewController/Classes/Consents/SPUserData.swift +++ b/ConsentViewController/Classes/Consents/SPUserData.swift @@ -76,6 +76,13 @@ public class SPConsent: NSObject, usnat: .init(uuid: usnat?.consents?.uuid, webConsentPayload: usnat?.consents?.webConsentPayload) )} + var isNotEmpty: Bool { + self != SPUserData() && + gdpr?.consents != SPGDPRConsent.empty() && + ccpa?.consents != SPCCPAConsent.empty() && + usnat?.consents != SPUSNatConsent.empty() + } + override public var description: String { "gdpr: \(String(describing: gdpr)), ccpa: \(String(describing: ccpa)), usnat: \(String(describing: usnat))" } diff --git a/ConsentViewController/Classes/SPConsentManager.swift b/ConsentViewController/Classes/SPConsentManager.swift index fe83057a9..75c764652 100644 --- a/ConsentViewController/Classes/SPConsentManager.swift +++ b/ConsentViewController/Classes/SPConsentManager.swift @@ -242,7 +242,7 @@ import UIKit } public func gracefullyDegradeOnError(_ error: SPError) { - if !userData.isEqual(SPUserData()) { + if userData.isNotEmpty { spCoordinator.logErrorMetrics(error) onConsentReady(userData: userData) handleSDKDone() diff --git a/ConsentViewController/Classes/SPError.swift b/ConsentViewController/Classes/SPError.swift index aa9774880..baaf9a52f 100644 --- a/ConsentViewController/Classes/SPError.swift +++ b/ConsentViewController/Classes/SPError.swift @@ -1,7 +1,7 @@ import Foundation // swiftlint:disable line_length @objcMembers public class SPError: NSError, LocalizedError { - public var spCode: String { "sp_metric_generic_sdk_error" } + public var spCode: String { "sp_metric_generic_sdk_error_\(code)" } override public var description: String { "Something went wrong in the SDK" } public var failureReason: String { originalError.debugDescription } @@ -154,6 +154,49 @@ import Foundation override public var description: String { "Something went wrong while loading the Rendering App. onMessageReady was not called within the specified timeout." } } +@objcMembers public class ClientRequestTimeoutError: SPError { + let apiSufix: InvalidResponsAPICode + let timeoutValue: TimeInterval? + + // swiftlint:disable:next force_unwrapping + var timeoutString: String { timeoutValue != nil ? String(timeoutValue!) : "" } + + override public var spCode: String { + "sp_metric_client_side_timeout\(apiSufix.code)_\(timeoutString)" + } + override public var description: String { + "The request could not be fullfiled within the timeout (\(timeoutString)) specified by the client" + } + + init(apiSufix: InvalidResponsAPICode, timeoutValue: TimeInterval?) { + self.apiSufix = apiSufix + self.timeoutValue = timeoutValue + super.init() + } + + @available(*, unavailable) + required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } +} + +@objcMembers public class GenericNetworkError: SPError { + let apiSufix: InvalidResponsAPICode + let error: NSError + + override public var spCode: String { "sp_metric_generic_network_error\(apiSufix.code)_\(error.code)" } + override public var description: String { + "Something went wrong when calling \(apiSufix.code)" + } + + init(apiSufix: InvalidResponsAPICode, error: NSError) { + self.apiSufix = apiSufix + self.error = error + super.init() + } + + @available(*, unavailable) + required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } +} + @objcMembers public class UnableToInjectMessageIntoRenderingApp: SPError { override public var spCode: String { "sp_metric_unable_to_stringify_msgJSON" } override public var description: String { "The SDK could convert the message into JSON." } diff --git a/ConsentViewController/Classes/SourcePointClient/SimpleClient.swift b/ConsentViewController/Classes/SourcePointClient/SimpleClient.swift index 8026dda5f..0d4e59f42 100644 --- a/ConsentViewController/Classes/SourcePointClient/SimpleClient.swift +++ b/ConsentViewController/Classes/SourcePointClient/SimpleClient.swift @@ -111,6 +111,19 @@ class SimpleClient: HttpClient { apiCode: apiCode, statusCode: String(response.statusCode) ))) + } else if let error = error as? NSError { + switch error.code { + case NSURLErrorTimedOut: + handler(.failure( + ClientRequestTimeoutError( + apiSufix: apiCode, + timeoutValue: self?.session.configuration.timeoutIntervalForResource + ) + )) + + default: + handler(.failure(GenericNetworkError(apiSufix: apiCode, error: error))) + } } } else { handler(.success(data)) diff --git a/ConsentViewController/Classes/SourcePointClient/SourcepointClientCoordinator.swift b/ConsentViewController/Classes/SourcePointClient/SourcepointClientCoordinator.swift index 89be723a9..d88e1c6ee 100644 --- a/ConsentViewController/Classes/SourcePointClient/SourcepointClientCoordinator.swift +++ b/ConsentViewController/Classes/SourcePointClient/SourcepointClientCoordinator.swift @@ -8,6 +8,7 @@ import Foundation +typealias ErrorHandler = (SPError) -> Void typealias LoadMessagesReturnType = ([MessageToDisplay], SPUserData) typealias MessagesAndConsentsHandler = (Result) -> Void typealias GDPRCustomConsentHandler = (Result) -> Void @@ -463,8 +464,14 @@ class SourcepointClientCoordinator: SPClientCoordinator { self.authId = authId resetStateIfAuthIdChanged() - metaData { - self.consentStatus { + + let onError: ErrorHandler = { + self.logErrorMetrics($0) + handler(Result.failure($0)) + } + + metaData(onError) { + self.consentStatus(onError) { self.state.udpateGDPRStatus() self.state.udpateUSNatStatus() self.messages { messagesResponse in @@ -503,7 +510,7 @@ class SourcepointClientCoordinator: SPClientCoordinator { storage.spState = state } - func metaData(next: @escaping () -> Void) { + func metaData(_ errorHandler: @escaping ErrorHandler, next: @escaping () -> Void) { spClient.metaData( accountId: accountId, propertyId: propertyId, @@ -512,11 +519,10 @@ class SourcepointClientCoordinator: SPClientCoordinator { switch result { case .success(let response): self.handleMetaDataResponse(response) + next() - case .failure(let error): - self.logErrorMetrics(error) + case .failure(let error): errorHandler(error) } - next() } } @@ -570,7 +576,7 @@ class SourcepointClientCoordinator: SPClientCoordinator { storage.spState = state } - func consentStatus(next: @escaping () -> Void) { + func consentStatus(_ errorHandler: ErrorHandler, next: @escaping () -> Void) { if shouldCallConsentStatus { spClient.consentStatus( propertyId: propertyId, @@ -654,6 +660,7 @@ class SourcepointClientCoordinator: SPClientCoordinator { handler(Result.success(self.handleMessagesResponse(response))) case .failure(let error): + self.logErrorMetrics(error) handler(Result.failure(error)) } }