Skip to content

Commit cd6d9d0

Browse files
KM-13514 Handle several situations with fatalErrors
1 parent af9e966 commit cd6d9d0

40 files changed

Lines changed: 238 additions & 212 deletions

LocalPackages/PIALibrary/Sources/PIALibrary/Account/EphemeralAccountProvider.swift

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77

88
import Foundation
99

10+
fileprivate let log = PIALogger.logger(for: EphemeralAccountProvider.self)
11+
1012
@available(tvOS 17.0, *)
1113
class EphemeralAccountProvider: AccountProvider, ProvidersAccess, InAppAccess {
1214

1315
// XXX: we want legit web services calls, yet allow the option to mock them
1416
private var webServices: WebServices? {
1517
guard let accountProvider = accessedProviders.accountProvider as? WebServicesConsumer else {
16-
fatalError("Current accountProvider is not a WebServicesConsumer. Use MockAccountProvider for mocking ephemeral Welcome process")
18+
log.error("Current accountProvider is not a WebServicesConsumer. Use MockAccountProvider for mocking ephemeral Welcome process")
19+
return nil
1720
}
1821
return accountProvider.webServices
1922
}
@@ -49,55 +52,55 @@ class EphemeralAccountProvider: AccountProvider, ProvidersAccess, InAppAccess {
4952
}
5053

5154
func migrateOldTokenIfNeeded(_ callback: ((Error?) -> Void)?) {
52-
fatalError("Not implemented")
55+
log.error("Not implemented")
5356
}
5457

5558
func login(with request: LoginRequest, _ callback: ((UserAccount?, Error?) -> Void)?) {
56-
fatalError("Not implemented")
59+
log.error("Not implemented")
5760
}
5861

5962
func login(with receiptRequest: LoginReceiptRequest, _ callback: ((UserAccount?, Error?) -> Void)?) {
60-
fatalError("Not implemented")
63+
log.error("Not implemented")
6164
}
6265

6366
func refreshAccountInfo(_ callback: ((AccountInfo?, Error?) -> Void)?) {
64-
fatalError("Not implemented")
67+
log.error("Not implemented")
6568
}
6669

6770
func accountInformation(_ callback: ((AccountInfo?, Error?) -> Void)?) {
68-
fatalError("Not implemented")
71+
log.error("Not implemented")
6972
}
7073

7174
func update(with request: UpdateAccountRequest, resetPassword reset: Bool, andPassword password: String, _ callback: ((AccountInfo?, Error?) -> Void)?) {
72-
fatalError("Not implemented")
75+
log.error("Not implemented")
7376
}
7477

7578
func login(with token: String, _ callback: ((UserAccount?, Error?) -> Void)?) {
76-
fatalError("Not implemented")
79+
log.error("Not implemented")
7780
}
7881

7982
func loginUsingMagicLink(withEmail email: String, _ callback: SuccessLibraryCallback?) {
80-
fatalError("Not implemented")
83+
log.error("Not implemented")
8184
}
8285

8386
func logout(_ callback: SuccessLibraryCallback?) {
84-
fatalError("Not implemented")
87+
log.error("Not implemented")
8588
}
8689

8790
func deleteAccount(_ callback: SuccessLibraryCallback?) {
88-
fatalError("Not implemented")
91+
log.error("Not implemented")
8992
}
9093

9194
func activateDIPTokens(_ dipToken: String, _ callback: LibraryCallback<DedicatedIPStatus>?) {
92-
fatalError("Not implemented")
95+
log.error("Not implemented")
9396
}
9497

9598
func cleanDatabase() {
96-
fatalError("Not implemented")
99+
log.error("Not implemented")
97100
}
98101

99102
func subscriptionInformation(_ callback: LibraryCallback<AppStoreInformation>?) {
100-
fatalError("Not implemented")
103+
log.error("Not implemented")
101104
}
102105

103106
func listPlanProducts(_ callback: (([Plan : InAppProduct]?, Error?) -> Void)?) {
@@ -131,11 +134,11 @@ class EphemeralAccountProvider: AccountProvider, ProvidersAccess, InAppAccess {
131134
}
132135

133136
func listRenewablePlans(_ callback: (([Plan]?, Error?) -> Void)?) {
134-
fatalError("Not implemented")
137+
log.error("Not implemented")
135138
}
136139

137140
func renew(with request: RenewRequest, _ callback: ((UserAccount?, Error?) -> Void)?) {
138-
fatalError("Not implemented")
141+
log.error("Not implemented")
139142
}
140143

141144
func isAPIEndpointAvailable(_ callback: LibraryCallback<Bool>?) {

LocalPackages/PIALibrary/Sources/PIALibrary/Client+Configuration.swift

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
import Foundation
2424

25+
fileprivate let log = PIALogger.logger(for: Client.Configuration.self)
26+
2527
@available(tvOS 17.0, *)
2628
extension Client {
2729

@@ -64,7 +66,8 @@ extension Client {
6466

6567
public var baseUrl: String {
6668
guard let url = baseUrls[Client.environment] else {
67-
fatalError("Base URL not found for environment \(Client.environment). Use setBaseURL(_:for:) to fix the issue.")
69+
log.error("Base URL not found for environment \(Client.environment). Falling back to production URL.")
70+
return "https://www.privateinternetaccess.com"
6871
}
6972
return url
7073
}
@@ -337,37 +340,5 @@ extension Client {
337340
}
338341

339342
#endif
340-
341-
// public init(name: String) {
342-
// guard let path = Bundle.main.path(forResource: name, ofType: "plist") else {
343-
// fatalError("Unable to read configuration from \(name).plist")
344-
// }
345-
// guard let dict = NSDictionary(contentsOfFile: path) else {
346-
// fatalError("Configuration file \(name).plist is malformed")
347-
// }
348-
//
349-
// isDevelopment = dict["Development"] as! Bool
350-
//
351-
// let ws = dict["WebServices"] as! [String: Any]
352-
// var baseUrls = [Client.Environment: String]()
353-
// for (envString, url) in ws["BaseURLs"] as! [String: String] {
354-
// guard let environment = Client.Environment(rawValue: envString) else {
355-
// continue
356-
// }
357-
// baseUrls[environment] = url
358-
// }
359-
// self.baseUrls = baseUrls
360-
// clientRoot = ws["ClientRoot"] as! String
361-
//
362-
// let iap = dict["InApp"] as! [String: String]
363-
// var inApps = [String: Plan]()
364-
// for (id, planString) in iap {
365-
// guard let plan = Plan(rawValue: planString) else {
366-
// continue
367-
// }
368-
// inApps[id] = plan
369-
// }
370-
// self.inApps = inApps
371-
// }
372343
}
373344
}

LocalPackages/PIALibrary/Sources/PIALibrary/ClientError.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,8 @@ public enum ClientError: Error, Equatable {
8888

8989
/// Cant retrieve regions
9090
case noRegions
91+
92+
/// No servers available
93+
case noServersAvailable
9194
#endif
9295
}

LocalPackages/PIALibrary/Sources/PIALibrary/Daemons/ConnectivityDaemon.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class ConnectivityDaemon: Daemon, ConfigurationAccess, DatabaseAccess, Preferenc
3737

3838
private(set) var hasEnabledUpdates: Bool
3939

40-
private let reachability: Reachability
40+
private let reachability = Reachability(hostname: "8.8.8.8")!
4141

4242
private var isCheckingConnectivity: Bool
4343

@@ -47,12 +47,6 @@ class ConnectivityDaemon: Daemon, ConfigurationAccess, DatabaseAccess, Preferenc
4747

4848
private init() {
4949
hasEnabledUpdates = false
50-
51-
guard let reachability = Reachability(hostname: "8.8.8.8") else {
52-
fatalError("Unable to create Reachability object")
53-
}
54-
self.reachability = reachability
55-
5650
isCheckingConnectivity = false
5751
failedConnectivityAttempts = 0
5852
wasConnected = false

LocalPackages/PIALibrary/Sources/PIALibrary/Daemons/VPNDaemon.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ class VPNDaemon: Daemon, DatabaseAccess, ProvidersAccess {
4949
nc.addObserver(self, selector: #selector(neStatusDidChange(notification:)), name: .NEVPNStatusDidChange, object: nil)
5050
nc.addObserver(self, selector: #selector(vpnIsChangingServer(notification:)), name: .PIAVPNIsChangingServer, object: nil)
5151

52-
accessedProviders.vpnProvider.prepare()
52+
do {
53+
try accessedProviders.vpnProvider.prepare()
54+
} catch {
55+
log.error("Faile to prepare VPN provider: \(error.localizedDescription)")
56+
}
57+
5358
if Client.providers.vpnProvider.isVPNConnected {
5459
self.lastKnownVpnStatus = .connected
5560
}
@@ -113,7 +118,7 @@ class VPNDaemon: Daemon, DatabaseAccess, ProvidersAccess {
113118
if fallbackTimer == nil {
114119

115120
fallbackTimer = Timer.scheduledTimer(withTimeInterval: Client.configuration.vpnConnectivityRetryDelay, repeats: true) { timer in
116-
let address = Client.providers.serverProvider.targetServer.bestAddress()
121+
let address = try? Client.providers.serverProvider.targetServer.bestAddress()
117122
address?.markServerAsUnavailable()
118123

119124
log.debug("NEVPNManager is still connecting. Reconnecting with a different server...")
@@ -244,7 +249,9 @@ class VPNDaemon: Daemon, DatabaseAccess, ProvidersAccess {
244249
self.isReconnecting = false
245250
self.numberOfAttempts = 0
246251
self.updateUIWithAttemptNumber(0)
247-
Client.providers.serverProvider.targetServer.addresses().forEach({$0.reset()})
252+
253+
let targetServer = try? Client.providers.serverProvider.targetServer
254+
targetServer?.addresses().forEach({$0.reset()})
248255
}
249256

250257
// MARK: Update UI

LocalPackages/PIALibrary/Sources/PIALibrary/InApp/AppStoreProvider.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ class AppStoreProvider: NSObject, InAppProvider {
9292

9393
func purchaseProduct(_ product: InAppProduct, _ callback: ((InAppTransaction?, Error?) -> Void)?) {
9494
guard product is AppStoreProduct else {
95-
fatalError("Product must be AppStoreProduct")
95+
log.error("Product must be AppStoreProduct, but got \(type(of: product))")
96+
callback?(nil, ClientError.productUnavailable)
97+
return
9698
}
9799
guard (purchaseCallback == nil) else {
98100
log.warning("Purchase in progress")
@@ -112,7 +114,8 @@ class AppStoreProvider: NSObject, InAppProvider {
112114

113115
func uncreditedTransaction(for product: InAppProduct) -> InAppTransaction? {
114116
guard product is AppStoreProduct else {
115-
fatalError("Product must be AppStoreProduct")
117+
log.error("Product must be AppStoreProduct, but got \(type(of: product))")
118+
return nil
116119
}
117120
for uncredited in uncreditedTransactions {
118121
let nativeTransaction = uncredited.native as! SKPaymentTransaction
@@ -126,7 +129,8 @@ class AppStoreProvider: NSObject, InAppProvider {
126129

127130
func finishTransaction(_ transaction: InAppTransaction, success: Bool) {
128131
guard transaction is AppStoreTransaction else {
129-
fatalError("Transaction must be AppStoreTransaction")
132+
log.error("Transaction must be AppStoreTransaction, but got \(type(of: transaction))")
133+
return
130134
}
131135
finishAndRemoveTransaction(transaction.native as! SKPaymentTransaction, success: success)
132136
}

LocalPackages/PIALibrary/Sources/PIALibrary/Persistence/UserDefaultsStore.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,7 @@ class UserDefaultsStore: PlainStore, ConfigurationAccess {
144144
}
145145

146146
init(group: String) {
147-
guard let backend = UserDefaults(suiteName: group) else {
148-
fatalError("Unable to create UserDefaults in app group '\(group)')")
149-
}
147+
let backend = UserDefaults(suiteName: group) ?? UserDefaults.standard
150148
self.backend = backend
151149
self.group = group
152150
loadComplexMaps()

LocalPackages/PIALibrary/Sources/PIALibrary/Server/DefaultServerProvider.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,16 @@ open class DefaultServerProvider: ServerProvider, ConfigurationAccess, DatabaseA
120120
}
121121

122122
public var targetServer: Server {
123-
guard let server = accessedPreferences.preferredServer ?? bestServer ?? accessedDatabase.plain.lastConnectedRegion else {
124-
guard let fallbackServer = currentServers.first else {
125-
fatalError("No servers available")
123+
get throws {
124+
guard let server = accessedPreferences.preferredServer ?? bestServer ?? accessedDatabase.plain.lastConnectedRegion else {
125+
guard let fallbackServer = currentServers.first else {
126+
log.error("No servers available")
127+
throw ClientError.noServersAvailable
128+
}
129+
return fallbackServer
126130
}
127-
return fallbackServer
131+
return server
128132
}
129-
return server
130133
}
131134

132135
public var dipTokens: [String]? {

LocalPackages/PIALibrary/Sources/PIALibrary/Server/ServerProvider.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import Foundation
2424

2525
/// Business interface related to VPN servers.
2626
@available(tvOS 17.0, *)
27-
public protocol ServerProvider: class {
27+
public protocol ServerProvider: AnyObject {
2828

2929
/// The `ServersBundle.Configuration` associated with this provider.
3030
///
@@ -43,7 +43,7 @@ public protocol ServerProvider: class {
4343
/// The target server for a VPN connection.
4444
///
4545
/// - Seealso: `VPNProvider`
46-
var targetServer: Server { get }
46+
var targetServer: Server { get throws }
4747

4848
/// The array of DIP tokens stored in the keychain, or `nil` if logged out.
4949
var dipTokens: [String]? { get }

LocalPackages/PIALibrary/Sources/PIALibrary/Util/Keychain.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
import Foundation
2424

25+
fileprivate let log = PIALogger.logger(for: Keychain.self)
26+
2527
/// Handled keychain errors.
2628
public enum KeychainError: Error {
2729

@@ -180,7 +182,7 @@ public class Keychain {
180182
} else if let accessGroup = accessGroup {
181183
query[kSecAttrAccessGroup as String] = accessGroup
182184
} else {
183-
fatalError("No service nor accessGroup set")
185+
log.error("Keychain: No service nor accessGroup set. Keychain operations may fail.")
184186
}
185187
}
186188
}

0 commit comments

Comments
 (0)