Retry after an error
This commit is contained in:
parent
cdbab6ec07
commit
fd8c099e23
|
@ -1,3 +1,5 @@
|
|||
import Foundation
|
||||
|
||||
protocol ErrorActionHandling {
|
||||
func handle(error: RocketChatError)
|
||||
}
|
||||
|
@ -12,18 +14,26 @@ final class ErrorActionHandler {
|
|||
init(server: Server) {
|
||||
self.server = server
|
||||
}
|
||||
}
|
||||
|
||||
extension ErrorActionHandler: ErrorActionHandling {
|
||||
func handle(error: RocketChatError) {
|
||||
|
||||
private func handleOnMain(error: RocketChatError) {
|
||||
switch error {
|
||||
case .server(let response):
|
||||
router.present(error: response)
|
||||
case .unauthorized:
|
||||
router.route(to: .serverList)
|
||||
|
||||
database.remove()
|
||||
serversDB.remove(server)
|
||||
default:
|
||||
break
|
||||
case .unknown:
|
||||
print("Unexpected error on Client.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ErrorActionHandler: ErrorActionHandling {
|
||||
func handle(error: RocketChatError) {
|
||||
DispatchQueue.main.async {
|
||||
self.handleOnMain(error: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,16 +2,27 @@ import Foundation
|
|||
|
||||
protocol AppRouting {
|
||||
func route(to route: Route)
|
||||
func present(error: ErrorResponse)
|
||||
}
|
||||
|
||||
final class AppRouter: ObservableObject {
|
||||
@Published private(set) var route: Route = .loading
|
||||
|
||||
@Published var error: ErrorResponse?
|
||||
}
|
||||
|
||||
extension AppRouter: AppRouting {
|
||||
func route(to route: Route) {
|
||||
self.route = route
|
||||
}
|
||||
|
||||
func present(error: ErrorResponse) {
|
||||
guard self.error == nil else {
|
||||
return
|
||||
}
|
||||
|
||||
self.error = error
|
||||
}
|
||||
}
|
||||
|
||||
enum Route: Equatable {
|
||||
|
|
|
@ -26,6 +26,11 @@ struct AppView: View {
|
|||
.onAppear {
|
||||
loadRoute()
|
||||
}
|
||||
.sheet(item: $router.error) { error in
|
||||
Text(error.error)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadRoute() {
|
||||
|
|
|
@ -12,6 +12,8 @@ protocol RocketChatClientProtocol {
|
|||
}
|
||||
|
||||
final class RocketChatClient: NSObject {
|
||||
@Dependency private var errorActionHandler: ErrorActionHandling
|
||||
|
||||
private let server: Server
|
||||
|
||||
init(server: Server) {
|
||||
|
@ -42,22 +44,27 @@ final class RocketChatClient: NSObject {
|
|||
urlRequest.httpBody = request.body
|
||||
|
||||
return session.dataTaskPublisher(for: urlRequest)
|
||||
.tryMap { (data, response) in
|
||||
guard let httpResponse = response as? HTTPURLResponse, 200...299 ~= httpResponse.statusCode else {
|
||||
.tryMap { data, response in
|
||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
||||
throw RocketChatError.unauthorized
|
||||
}
|
||||
|
||||
return try data.decode(T.Response.self)
|
||||
}
|
||||
.mapError { error in
|
||||
if let error = error as? DecodingError {
|
||||
return .decoding(error: error)
|
||||
}
|
||||
if let error = error as? RocketChatError {
|
||||
return error
|
||||
let decoder = JSONDecoder()
|
||||
|
||||
if let response = try? decoder.decode(T.Response.self, from: data) {
|
||||
return response
|
||||
}
|
||||
|
||||
return .unknown(error: error)
|
||||
let response = try decoder.decode(ErrorResponse.self, from: data)
|
||||
throw RocketChatError.server(response: response)
|
||||
}
|
||||
.mapError { [weak self] error in
|
||||
guard let error = error as? RocketChatError else {
|
||||
return .unknown
|
||||
}
|
||||
|
||||
self?.errorActionHandler.handle(error: error)
|
||||
return error
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
import Foundation
|
||||
|
||||
enum RocketChatError: Error {
|
||||
case decoding(error: Error)
|
||||
case unknown(error: Error)
|
||||
case unauthorized
|
||||
struct ErrorResponse: Codable, Identifiable {
|
||||
var id: String {
|
||||
error
|
||||
}
|
||||
|
||||
let error: String
|
||||
}
|
||||
|
||||
enum RocketChatError: Error {
|
||||
case server(response: ErrorResponse)
|
||||
case unauthorized
|
||||
case unknown
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ final class MessagesLoader {
|
|||
@Dependency private var client: RocketChatClientProtocol
|
||||
@Dependency private var database: Database
|
||||
@Dependency private var serversDB: ServersDatabase
|
||||
@Dependency private var errorActionHandler: ErrorActionHandling
|
||||
|
||||
private var roomID: String?
|
||||
|
||||
|
@ -34,8 +33,8 @@ final class MessagesLoader {
|
|||
client.syncMessages(rid: rid, updatedSince: date)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] completion in
|
||||
if case .failure(let error) = completion {
|
||||
self?.errorActionHandler.handle(error: error)
|
||||
if case .failure = completion {
|
||||
self?.scheduledSyncMessages(in: room, from: newUpdatedSince)
|
||||
}
|
||||
} receiveValue: { [weak self] messagesResponse in
|
||||
let messages = messagesResponse.result.updated
|
||||
|
@ -58,9 +57,9 @@ final class MessagesLoader {
|
|||
|
||||
client.getHistory(rid: rid, t: room.t ?? "", latest: date)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] completion in
|
||||
.sink { completion in
|
||||
if case .failure(let error) = completion {
|
||||
self?.errorActionHandler.handle(error: error)
|
||||
print(error)
|
||||
}
|
||||
} receiveValue: { [weak self] messagesResponse in
|
||||
let messages = messagesResponse.messages
|
||||
|
@ -85,9 +84,9 @@ final class MessagesLoader {
|
|||
|
||||
client.sendRead(rid: rid)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] completion in
|
||||
.sink { completion in
|
||||
if case .failure(let error) = completion {
|
||||
self?.errorActionHandler.handle(error: error)
|
||||
print(error)
|
||||
}
|
||||
} receiveValue: { _ in
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ final class RoomsLoader {
|
|||
@Dependency private var client: RocketChatClientProtocol
|
||||
@Dependency private var database: Database
|
||||
@Dependency private var serversDB: ServersDatabase
|
||||
@Dependency private var errorActionHandler: ErrorActionHandling
|
||||
|
||||
private var timer: Timer?
|
||||
private var cancellable = CancelBag()
|
||||
|
@ -33,8 +32,8 @@ final class RoomsLoader {
|
|||
)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] completion in
|
||||
if case .failure(let error) = completion {
|
||||
self?.errorActionHandler.handle(error: error)
|
||||
if case .failure = completion {
|
||||
self?.scheduledLoadRooms(in: server)
|
||||
}
|
||||
} receiveValue: { (roomsResponse, subscriptionsResponse) in
|
||||
let rooms = roomsResponse.update
|
||||
|
|
Loading…
Reference in New Issue