-
Notifications
You must be signed in to change notification settings - Fork 110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Critical error handling and presentation #367
Conversation
Added ConnectionError Presenter/View Added Option to disable full screen critical errors Added ConnectionError Route Updated CDNLoader callback tests Added Tests for new Presenter/View
func load(_ callback: @escaping (Connections?) -> ()) { | ||
func load(_ callback: @escaping (Connections?, RemoteConnectionLoaderError?) -> ()) { | ||
let sessionConfiguration = URLSessionConfiguration.default | ||
sessionConfiguration.timeoutIntervalForRequest = 30 // Default 60 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why the change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yeah should have mentioned, I added it for testing but 60 is a LONG time and we did mention timeout tweaking. Happy to remove if you feel it is too short?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use the default, probably we can inject the session to the interactor in some way
guard error == nil else { | ||
self.logger.error("Failed to load with error \(error!)") | ||
callback(nil) | ||
if let error = error, error._code == NSURLErrorTimedOut { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might rewrite this whole error handling like
guard error?._code != NSURLErrorTimedOut else { return callback(.connectionTimeout) }
guard error == nil else { return callback(.requestIssue) }
@@ -54,12 +62,15 @@ struct CDNLoaderInteractor: RemoteConnectionLoader, Loggable { | |||
} | |||
guard 200...299 ~= response.statusCode else { | |||
self.logger.error("HTTP response was not successful. HTTP \(response.statusCode) <\(payload ?? "No Body")>") | |||
return callback(nil) | |||
if response.statusCode == 403 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not have a guard
before this one? (or an if
) like
guard response.statusCode != 403 else { return callback(nil, RemoteConnectionLoaderError.invalidClient) }
} | ||
|
||
guard var jsonp = payload else { | ||
self.logger.error("HTTP response had no jsonp \(payload ?? "No Body")") | ||
return callback(nil) | ||
return callback(nil, RemoteConnectionLoaderError.invalidClientInfo) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can omit the class name here
@@ -93,10 +104,14 @@ struct CDNLoaderInteractor: RemoteConnectionLoader, Loggable { | |||
info.oauth2.forEach { strategy in | |||
strategy.connections.forEach { connections.social(name: $0.name, style: AuthStyle.style(forStrategy: strategy.name, connectionName: $0.name)) } | |||
} | |||
callback(connections) | |||
if connections.isEmpty { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not use guard
?
|
||
import Foundation | ||
|
||
enum RemoteConnectionLoaderError: Error, LocalizableError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a unrecoverable error enum with some of this errors already
case invalidClient | ||
case invalidClientInfo | ||
case noConnections | ||
case requestIssue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this one and the next have no message so why have a different case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to distinguish the error from the ones we care about, from the users perspective they will show connectionTimeout message. However, they are not technically the same thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what I mean we can merge them and said just request failed since at this point we discarded network or client issues so it only is that the server is unavailable
|
||
enum RemoteConnectionLoaderError: Error, LocalizableError { | ||
case connectionTimeout | ||
case invalidClient |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one and the next are exactly the same thing from user perspective
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends on the circumstance, invalidClientInfo could be a temp issue as your credentials are valid but for whatever reason the response isn't right.
invalidClient
is more a developer one really, saying you're credentials are invalid based upon the 403. Although again technically could be a temp server issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But for the developer is the same thing (check your clientid and try again) and the end user is even simpler. If we need more debug info or fine grained errors for it the developer can use the log or even debug it
|
||
import Foundation | ||
|
||
class ConnectionErrorPresenter: Presentable, Loggable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make this presenter (and views) generic like UnrecoverableErrorPresenter
or similar so we can reuse
var localizableMessage: String { | ||
switch self { | ||
case .invalidClient: | ||
return "No client information found, please check your Auth0 client credentials.".i18n(key: "com.auth0.lock.critical.credentials", comment: "Invalid client credentials") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use the prefix com.auth0.lock.error
and maybe unrecoverable
too
I've unified the errors into UnrecoverableError. However there is an annoying issue due to equitability. We have Route: Equatable https://github.com/auth0/Lock.iOS-OSX/blob/feature_critical_errors/Lock/Routes.swift#L74 This is a requirement due to one line of code in Lock: https://github.com/auth0/Lock.iOS-OSX/blob/feature_critical_errors/Lock/Router.swift#L170 Now because UniversalError will now contain an enum case with a value. case invalidOptions(cause: String) It will also need to be made equatable to satisfy as the errors are of type UniversalError case (.connectionError(let lhsError), .connectionError(let rhsError)):
return lhsError == rhsError Rather than having having two custom equatable enums and two equatable unit tests (both need to be maintained for any additions). Could we remove all of this and simply satisfy the original requirement in enum Route? var isRoot: Bool {
switch self {
case .root:
return true
default:
return false
}
} UPDATE: Actually there are a few genuine requirements in LockTests for Route Equatable. I've made UniversalError: Equatable for now. |
Soft errors now default, option removed. Added more tests, updated existing tests General code style improvements
952c1b0
to
5b9fefe
Compare
var localizableMessage: String { | ||
switch self { | ||
case .invalidClientOrDomain: | ||
return "No client information found, please check your Auth0 client credentials.".i18n(key: "com.auth0.lock.error.invalidclient", comment: "Invalid client") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add to the prefix com.auth0.lock.error
an extra part like unrecoverable
for all keys of unrecoverable error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also move this error to the requestIssue
case
case .invalidClientOrDomain: | ||
return "No client information found, please check your Auth0 client credentials.".i18n(key: "com.auth0.lock.error.invalidclient", comment: "Invalid client") | ||
case .clientWithNoConnections: | ||
return "No connections available for this client, please check your Auth0 client setup.".i18n(key: "com.auth0.lock.error.noconnections", comment: "No client connections") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No authentication methods found for this client. Please check your client setup.
case .clientWithNoConnections: | ||
return "No connections available for this client, please check your Auth0 client setup.".i18n(key: "com.auth0.lock.error.noconnections", comment: "No client connections") | ||
case .connectionTimeout, .requestIssue: | ||
return "There was a problem with your request, please try again later.".i18n(key: "com.auth0.lock.error.requestfailed", comment: "Generic request failure") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
var userVisible: Bool { | ||
switch self { | ||
case .missingDatabaseConnection, .invalidOptions: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also invalidClientOrDomain
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make all visible, those who were previously non visible we should show the message https://github.com/auth0/lock/blob/master/src/i18n/en.js#L97
return "No connections available for this client, please check your Auth0 client setup.".i18n(key: "com.auth0.lock.error.noconnections", comment: "No client connections") | ||
case .connectionTimeout, .requestIssue: | ||
return "There was a problem with your request, please try again later.".i18n(key: "com.auth0.lock.error.requestfailed", comment: "Generic request failure") | ||
case .missingDatabaseConnection: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this error to the requestIssue
case
Update UnrecoverableError Tests
d7bbb07
to
1792803
Compare
Added Error support to CDNLoader callback
Added ConnectionError Presenter/View
Added Option to disable full screen critical errors
Added ConnectionError Route
Updated CDNLoader callback tests
Added Tests for new Presenter/View