diff --git a/Core/Pixel.swift b/Core/Pixel.swift index dd0a8e77a6..edf6d6611b 100644 --- a/Core/Pixel.swift +++ b/Core/Pixel.swift @@ -249,6 +249,16 @@ extension Pixel { } } +/// NSError supports this through `NSUnderlyingError`, but there's no support for this for Swift's `Error`. This protocol does that. +/// +/// The reason why this protocol returns a code and a domain instead of just an `Error` or `NSError` is so that the error implementing +/// this protocol has full control over these values, and is able to override them as it best sees fit. +/// +protocol ErrorWithUnderlyingError: Error { + var underlyingErrorCode: Int { get } + var underlyingErrorDomain: String { get } +} + extension Dictionary where Key == String, Value == String { mutating func appendErrorPixelParams(error: Error) { let nsError = error as NSError @@ -256,7 +266,10 @@ extension Dictionary where Key == String, Value == String { self[PixelParameters.errorCode] = "\(nsError.code)" self[PixelParameters.errorDomain] = nsError.domain - if let underlyingError = nsError.userInfo["NSUnderlyingError"] as? NSError { + if let underlyingError = error as? ErrorWithUnderlyingError { + self[PixelParameters.underlyingErrorCode] = "\(underlyingError.underlyingErrorCode)" + self[PixelParameters.underlyingErrorDomain] = underlyingError.underlyingErrorDomain + } else if let underlyingError = nsError.userInfo["NSUnderlyingError"] as? NSError { self[PixelParameters.underlyingErrorCode] = "\(underlyingError.code)" self[PixelParameters.underlyingErrorDomain] = underlyingError.domain } else if let sqlErrorCode = nsError.userInfo["NSSQLiteErrorDomain"] as? NSNumber { diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 527ce9c495..8925cb5716 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -266,6 +266,18 @@ extension Pixel { case networkProtectionActiveUser case networkProtectionNewUser + case networkProtectionControllerStartAttempt + case networkProtectionControllerStartSuccess + case networkProtectionControllerStartFailure + + case networkProtectionTunnelStartAttempt + case networkProtectionTunnelStartSuccess + case networkProtectionTunnelStartFailure + + case networkProtectionTunnelUpdateAttempt + case networkProtectionTunnelUpdateSuccess + case networkProtectionTunnelUpdateFailure + case networkProtectionEnableAttemptConnecting case networkProtectionEnableAttemptSuccess case networkProtectionEnableAttemptFailure @@ -280,6 +292,8 @@ extension Pixel { case networkProtectionBreakageReport + case networkProtectionRekeyAttempt + case networkProtectionRekeyFailure case networkProtectionRekeyCompleted case networkProtectionTunnelConfigurationNoServerRegistrationInfo @@ -785,6 +799,15 @@ extension Pixel.Event { case .networkProtectionActiveUser: return "m_netp_daily_active_d" case .networkProtectionNewUser: return "m_netp_daily_active_u" + case .networkProtectionControllerStartAttempt: return "m_netp_controller_start_attempt" + case .networkProtectionControllerStartSuccess: return "m_netp_controller_start_success" + case .networkProtectionControllerStartFailure: return "m_netp_controller_start_failure" + case .networkProtectionTunnelStartAttempt: return "m_netp_tunnel_start_attempt" + case .networkProtectionTunnelStartSuccess: return "m_netp_tunnel_start_success" + case .networkProtectionTunnelStartFailure: return "m_netp_tunnel_start_failure" + case .networkProtectionTunnelUpdateAttempt: return "m_netp_tunnel_update_attempt" + case .networkProtectionTunnelUpdateSuccess: return "m_netp_tunnel_update_success" + case .networkProtectionTunnelUpdateFailure: return "m_netp_tunnel_update_failure" case .networkProtectionEnableAttemptConnecting: return "m_netp_ev_enable_attempt" case .networkProtectionEnableAttemptSuccess: return "m_netp_ev_enable_attempt_success" case .networkProtectionEnableAttemptFailure: return "m_netp_ev_enable_attempt_failure" @@ -792,7 +815,9 @@ extension Pixel.Event { case .networkProtectionTunnelFailureRecovered: return "m_netp_ev_tunnel_failure_recovered" case .networkProtectionLatency(let quality): return "m_netp_ev_\(quality.rawValue)_latency" case .networkProtectionLatencyError: return "m_netp_ev_latency_error_d" + case .networkProtectionRekeyAttempt: return "m_mac_netp_rekey_attempt" case .networkProtectionRekeyCompleted: return "m_netp_rekey_completed" + case .networkProtectionRekeyFailure: return "m_netp_rekey_failure" case .networkProtectionEnabledOnSearch: return "m_netp_ev_enabled_on_search" case .networkProtectionBreakageReport: return "m_vpn_breakage_report" case .networkProtectionTunnelConfigurationNoServerRegistrationInfo: return "m_netp_tunnel_config_error_no_server_registration_info" diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 09fa88e566..00e2248435 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9981,7 +9981,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 114.1.0; + version = "114.1.0-1"; }; }; B6F997C22B8F374300476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 018b6e092f..6d70031d01 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "045a8782c3dbbf79fc088b38120dea1efadc13e1", - "version" : "114.1.0" + "revision" : "d9de416d3b77082f818a91b065bee1a2025c8e46", + "version" : "114.1.0-1" } }, { diff --git a/DuckDuckGo/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtectionTunnelController.swift index 77a09a12e1..2ba3add399 100644 --- a/DuckDuckGo/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtectionTunnelController.swift @@ -49,9 +49,14 @@ final class NetworkProtectionTunnelController: TunnelController { /// Starts the VPN connection used for Network Protection /// func start() async { + Pixel.fire(pixel: .networkProtectionControllerStartAttempt) + do { try await startWithError() + Pixel.fire(pixel: .networkProtectionControllerStartSuccess) } catch { + Pixel.fire(pixel: .networkProtectionControllerStartFailure, error: error) + #if DEBUG errorStore.lastErrorMessage = error.localizedDescription #endif diff --git a/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift b/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift index f9e7fa92f7..feadafba5c 100644 --- a/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift +++ b/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift @@ -28,6 +28,8 @@ import NetworkExtension import NetworkProtection import Subscription +// swiftlint:disable type_body_length + // Initial implementation for initial Network Protection tests. Will be fleshed out with https://app.asana.com/0/1203137811378537/1204630829332227/f final class NetworkProtectionPacketTunnelProvider: PacketTunnelProvider { @@ -68,8 +70,33 @@ final class NetworkProtectionPacketTunnelProvider: PacketTunnelProvider { guard quality != .unknown else { return } DailyPixel.fireDailyAndCount(pixel: .networkProtectionLatency(quality: quality)) } - case .rekeyCompleted: - Pixel.fire(pixel: .networkProtectionRekeyCompleted) + case .rekeyAttempt(let step): + switch step { + case .begin: + DailyPixel.fireDailyAndCount(pixel: .networkProtectionRekeyAttempt) + case .failure(let error): + DailyPixel.fireDailyAndCount(pixel: .networkProtectionRekeyFailure, error: error) + case .success: + DailyPixel.fireDailyAndCount(pixel: .networkProtectionRekeyCompleted) + } + case .tunnelStartAttempt(let step): + switch step { + case .begin: + DailyPixel.fireDailyAndCount(pixel: .networkProtectionTunnelStartAttempt) + case .failure(let error): + DailyPixel.fireDailyAndCount(pixel: .networkProtectionTunnelStartFailure, error: error) + case .success: + DailyPixel.fireDailyAndCount(pixel: .networkProtectionTunnelStartSuccess) + } + case .tunnelUpdateAttempt(let step): + switch step { + case .begin: + DailyPixel.fireDailyAndCount(pixel: .networkProtectionTunnelUpdateAttempt) + case .failure(let error): + DailyPixel.fireDailyAndCount(pixel: .networkProtectionTunnelUpdateFailure, error: error) + case .success: + DailyPixel.fireDailyAndCount(pixel: .networkProtectionTunnelUpdateSuccess) + } } } @@ -287,4 +314,6 @@ final class NetworkProtectionPacketTunnelProvider: PacketTunnelProvider { } } +// swiftlint:enable type_body_length + #endif