Retry after an error

This commit is contained in:
Djorkaeff Alexandre 2024-02-15 17:38:37 -03:00
parent cdbab6ec07
commit fd8c099e23
7 changed files with 70 additions and 31 deletions

View File

@ -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)
}
}
}

View File

@ -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 {

View File

@ -26,6 +26,11 @@ struct AppView: View {
.onAppear {
loadRoute()
}
.sheet(item: $router.error) { error in
Text(error.error)
.multilineTextAlignment(.center)
.padding()
}
}
private func loadRoute() {

View File

@ -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()
}

View File

@ -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
}

View File

@ -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

View File

@ -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