Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 6 additions & 73 deletions Sources/DBConnect/ICEDataController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ public final class ICEDataController: NSObject, TrainDataController {
if demoMode {
return MoyaProvider<ICEPortalAPI>(stubClosure: MoyaProvider.immediatelyStub)
} else {
return MoyaProvider<ICEPortalAPI>(stubClosure: MoyaProvider.neverStub)
return MoyaProvider<ICEPortalAPI>(stubClosure: MoyaProvider.neverStub,
session: alamofireSessionWithFasterTimeout)
}
}

Expand All @@ -33,43 +34,10 @@ public final class ICEDataController: NSObject, TrainDataController {
}

public func loadTripData(demoMode: Bool = false, completionHandler: @escaping (TripResponse?, Error?) -> ()){
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(DateFormatter.yyyyMMdd)
let provider = getProvider(demoMode: demoMode)
provider.request(.trip) { result in
switch result {
case .success(let response):
do {
let response = try response.filterSuccessfulStatusCodes()
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(DateFormatter.yyyyMMdd)
let trip = try decoder.decode(TripResponse.self, from: response.data)
completionHandler(trip, nil)
} catch DecodingError.dataCorrupted(let context) {
if response.data.count == 0 {
// iceportal.de outside WiFi returns 200 with an empty body.
completionHandler(nil, TrainConnectionError.notConnected)
break
}
print(context)
} catch DecodingError.keyNotFound(let key, let context) {
print("Key '\(key)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch DecodingError.valueNotFound(let value, let context) {
print("Value '\(value)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch DecodingError.typeMismatch(let type, let context) {
print("Type '\(type)' mismatch:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch {
print(error.localizedDescription)
completionHandler(nil, error)
}
break
case .failure(let error):
print(error.localizedDescription)
completionHandler(nil, error)
break
}
}
provider.loadJson(decoder: decoder, target: .trip, completionHandler: completionHandler)
}


Expand All @@ -80,42 +48,7 @@ public final class ICEDataController: NSObject, TrainDataController {
}

public func loadStatus(demoMode: Bool = false, completionHandler: @escaping (Status?, Error?) -> ()) {
let provider = getProvider(demoMode: demoMode)
provider.request(.status) { result in
switch result {
case .success(let response):
do {
let response = try response.filterSuccessfulStatusCodes()
let decoder = JSONDecoder()
let status = try decoder.decode(Status.self, from: response.data)
completionHandler(status, nil)
} catch DecodingError.dataCorrupted(let context) {
if response.data.count == 0 {
// iceportal.de outside WiFi returns 200 with an empty body.
completionHandler(nil, TrainConnectionError.notConnected)
break
}
print(context)
} catch DecodingError.keyNotFound(let key, let context) {
print("Key '\(key)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch DecodingError.valueNotFound(let value, let context) {
print("Value '\(value)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch DecodingError.typeMismatch(let type, let context) {
print("Type '\(type)' mismatch:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch {
print(error.localizedDescription)
completionHandler(nil, error)
}
break
case .failure(let error):
print(error.localizedDescription)
completionHandler(nil, error)
break
}
}
getProvider(demoMode: demoMode).loadJson(target: .status, completionHandler: completionHandler)
}
}

Expand Down
104 changes: 7 additions & 97 deletions Sources/SNCFConnect/TGVDataController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public class TGVDataController: NSObject, TrainDataController {
if demoMode {
return MoyaProvider<TGVPortalAPI>(stubClosure: MoyaProvider.immediatelyStub)
} else {
return MoyaProvider<TGVPortalAPI>(stubClosure: MoyaProvider.neverStub)
return MoyaProvider<TGVPortalAPI>(stubClosure: MoyaProvider.neverStub,
session: alamofireSessionWithFasterTimeout)
}
}

Expand All @@ -43,40 +44,10 @@ public class TGVDataController: NSObject, TrainDataController {
})
}
private func loadDetails(demoMode: Bool, completionHandler: @escaping (DetailsResponse?, Error?) -> ()){

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(DateFormatter.tgvFormatter)
let provider = getProvider(demoMode: demoMode)
provider.request(.details) { result in
switch result {
case .success(let response):
do {
let response = try response.filterSuccessfulStatusCodes()
let decoder = JSONDecoder()
print(DateFormatter.tgvFormatter.string(from: .init()))
decoder.dateDecodingStrategy = .formatted(DateFormatter.tgvFormatter)
let trip = try decoder.decode(DetailsResponse.self, from: response.data)
completionHandler(trip, nil)
} catch DecodingError.dataCorrupted(let context) {
print(context)
} catch DecodingError.keyNotFound(let key, let context) {
print("Key '\(key)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch DecodingError.valueNotFound(let value, let context) {
print("Value '\(value)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch DecodingError.typeMismatch(let type, let context) {
print("Type '\(type)' mismatch:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch {
print(error.localizedDescription)
completionHandler(nil, error)
}
break
case .failure(let error):
print(error.localizedDescription)
completionHandler(nil, error)
break
}
}
provider.loadJson(decoder: decoder, target: .details, completionHandler: completionHandler)
}

public func loadTrainStatus(demoMode: Bool = false, completionHandler: @escaping (TrainStatus?, Error?) -> ()) {
Expand All @@ -102,71 +73,11 @@ public class TGVDataController: NSObject, TrainDataController {
}

private func loadGPS(demoMode: Bool = false, completionHandler: @escaping (GPSResponse?, Error?) -> ()) {
let provider = getProvider(demoMode: demoMode)
provider.request(.gps) { result in
switch result {
case .success(let response):
do {
let response = try response.filterSuccessfulStatusCodes()
let decoder = JSONDecoder()
let status = try decoder.decode(GPSResponse.self, from: response.data)
completionHandler(status, nil)
} catch DecodingError.dataCorrupted(let context) {
print(context)
} catch DecodingError.keyNotFound(let key, let context) {
print("Key '\(key)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch DecodingError.valueNotFound(let value, let context) {
print("Value '\(value)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch DecodingError.typeMismatch(let type, let context) {
print("Type '\(type)' mismatch:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch {
print(error.localizedDescription)
completionHandler(nil, error)
}
break
case .failure(let error):
print(error.localizedDescription)
completionHandler(nil, error)
break
}
}
getProvider(demoMode: demoMode).loadJson(target: .gps, completionHandler: completionHandler)
}

private func loadStatistics(demoMode: Bool = false, completionHandler: @escaping (StatisticsResponse?, Error?) -> ()) {
let provider = getProvider(demoMode: demoMode)
provider.request(.statistics) { result in
switch result {
case .success(let response):
do {
let response = try response.filterSuccessfulStatusCodes()
let decoder = JSONDecoder()
let status = try decoder.decode(StatisticsResponse.self, from: response.data)
completionHandler(status, nil)
} catch DecodingError.dataCorrupted(let context) {
print(context)
} catch DecodingError.keyNotFound(let key, let context) {
print("Key '\(key)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch DecodingError.valueNotFound(let value, let context) {
print("Value '\(value)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch DecodingError.typeMismatch(let type, let context) {
print("Type '\(type)' mismatch:", context.debugDescription)
print("codingPath:", context.codingPath)
} catch {
print(error.localizedDescription)
completionHandler(nil, error)
}
break
case .failure(let error):
print(error.localizedDescription)
completionHandler(nil, error)
break
}
}
getProvider(demoMode: demoMode).loadJson(target: .statistics, completionHandler: completionHandler)
}
}

Expand All @@ -184,4 +95,3 @@ public class TGVDataController: NSObject, TrainDataController {
// return stop
// }
//}

60 changes: 60 additions & 0 deletions Sources/TrainConnect/TrainDataCommon.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Foundation
import Moya
import Alamofire

public extension MoyaProvider {
func loadJson<D: Decodable>(decoder: JSONDecoder = .init(),
target: Target,
completionHandler: @escaping (D?, Error?) -> ()) {
request(target) { result in
switch result {
case .success(let response):
do {
let response = try response.filterSuccessfulStatusCodes()
if response.data.isEmpty {
// iceportal.de outside WiFi returns 200 with an empty body.
completionHandler(nil, TrainConnectionError.notConnected)
}
else {
let result = try decoder.decode(D.self, from: response.data)
completionHandler(result, nil)
}
} catch let error {
logDecodingError(error: error)
completionHandler(nil, error)
}
break
case .failure(let error):
print(error.localizedDescription)
completionHandler(nil, error)
break
}
}
}
}

private func logDecodingError(error: Error) {
switch error {
case DecodingError.dataCorrupted(let context):
print(context)
case DecodingError.keyNotFound(let key, let context):
print("Key '\(key)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
case DecodingError.valueNotFound(let value, let context):
print("Value '\(value)' not found:", context.debugDescription)
print("codingPath:", context.codingPath)
case DecodingError.typeMismatch(let type, let context):
print("Type '\(type)' mismatch:", context.debugDescription)
print("codingPath:", context.codingPath)
default:
print(error.localizedDescription)
}
}

public let alamofireSessionWithFasterTimeout: Alamofire.Session = {
let configuration = URLSessionConfiguration.default
// Use a very short timeout so we don't wait a minute before showing the "not connected" UI
configuration.timeoutIntervalForRequest = 2
configuration.timeoutIntervalForResource = 2
return Alamofire.Session(configuration: configuration)
}()
31 changes: 13 additions & 18 deletions Sources/TrainConnect/TrainDataController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,31 @@ public class CombinedDataController: TrainDataController {
}

public func loadTrip(demoMode: Bool, completionHandler: @escaping (TrainTrip?, Error?) -> ()) {
var completed: Bool = false
var failed: Int = 0
for controller in controllers {
controller.loadTrip(demoMode: demoMode) {
if let error = $1 {
failed += 1
if failed >= self.controllers.count {
completionHandler(nil, error)
}
} else if !completed, let trip = $0 {
completed = true
completionHandler(trip, nil)
}
}
delegate(completionHandler: completionHandler) {
$0.loadTrip(demoMode: demoMode, completionHandler: $1)
}
}

public func loadTrainStatus(demoMode: Bool, completionHandler: @escaping (TrainStatus?, Error?) -> ()) {
delegate(completionHandler: completionHandler) {
$0.loadTrainStatus(demoMode: demoMode, completionHandler: $1)
}
}

private func delegate<D>(completionHandler: @escaping (D?, Error?) -> (),
action: (TrainDataController, @escaping (D?, Error?) -> ()) -> ()) {
var completed: Bool = false
var failed: Int = 0
for controller in controllers {
controller.loadTrainStatus(demoMode: demoMode) {
if let error = $1 {
action(controller) { result, error in
if let error = error {
failed += 1
if failed >= self.controllers.count {
completionHandler(nil, error)
}
} else if !completed, let status = $0 {
} else if !completed, let result = result {
completed = true
completionHandler(status, nil)
completionHandler(result, nil)
}
}
}
Expand Down