Skip to content

Commit

Permalink
Expand usage of SwiftyJson (fixes #8)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-albers committed Feb 25, 2022
1 parent 13b67e1 commit 7cd7e63
Show file tree
Hide file tree
Showing 8 changed files with 457 additions and 473 deletions.
2 changes: 1 addition & 1 deletion Sources/TripKit/Model/Stop.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class Stop: NSObject, NSSecureCoding {
public let message: String?
/// URL for querying the wagon sequence of a train.
/// See `DbProvider.getWagonSequenceUrl()`
public let wagonSequenceContext: URL?
public var wagonSequenceContext: URL?

/// Returns the earliest time of the stop, either departure or arrival.
public var minTime: Date? {
Expand Down
770 changes: 361 additions & 409 deletions Sources/TripKit/Provider/AbstractHafasClientInterfaceProvider.swift

Large diffs are not rendered by default.

109 changes: 64 additions & 45 deletions Sources/TripKit/Provider/AbstractHafasLegacyProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Foundation
import os.log
import Gzip
import SWXMLHash
import SwiftyJSON

public class AbstractHafasLegacyProvider: AbstractHafasProvider {

Expand Down Expand Up @@ -328,20 +329,32 @@ public class AbstractHafasLegacyProvider: AbstractHafasProvider {
// MARK: NetworkProvider responses

override func suggestLocationsParsing(request: HttpRequest, constraint: String, types: [LocationType]?, maxLocations: Int, completion: @escaping (HttpRequest, SuggestLocationsResult) -> Void) throws {
guard let data = request.responseData else { throw ParseError(reason: "no response") }
var locations: [SuggestedLocation] = []
guard let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any], let suggestions = json["suggestions"] as? [Any] else {
throw ParseError(reason: "suggestions not found")
guard let data = request.responseData?.encodedData(encoding: self.jsonNearbyLocationsEncoding) else {
throw ParseError(reason: "no response")
}
for (index, suggestion) in suggestions.enumerated() {
guard let suggestion = suggestion as? [String: Any] else { continue }
guard let type = Int(suggestion["type"] as? String ?? ""), let value = suggestion["value"] as? String, let lat = Int(suggestion["ycoord"] as? String ?? ""), let lon = Int(suggestion["xcoord"] as? String ?? ""), let id = suggestion["id"] as? String else {
os_log("%{public}@: failed to parse suggestions", log: .requestLogger, type: .error, #function)
let json = try JSON(data: data, options: .allowFragments)
if let error = json["error"].string, error != "0" {
throw ParseError(reason: "received hafas error code \(error)")
}

var locations: [SuggestedLocation] = []
for (index, suggestion) in json["suggestions"].arrayValue.enumerated() {
guard let type = Int(suggestion["type"].stringValue) else {
continue
}
let weight = jsonGetStopsUseWeight ? Int(suggestion["weight"] as? String ?? "") ?? -index : -index
let id = suggestion["id"].string
let value = suggestion["value"].string

let coord: LocationPoint?
if let lat = Int(suggestion["ycoord"].stringValue), let lon = Int(suggestion["xcoord"].stringValue) {
coord = LocationPoint(lat: lat, lon: lon)
} else {
coord = nil
}

let weight = jsonGetStopsUseWeight ? Int(suggestion["weight"].stringValue) ?? -index : -index
let localId: String?
if let match = self.P_AJAX_GET_STOPS_ID.firstMatch(in: id, options: [], range: NSMakeRange(0, id.count)) {
if let id = id, let match = self.P_AJAX_GET_STOPS_ID.firstMatch(in: id, options: [], range: NSMakeRange(0, id.count)) {
localId = (id as NSString).substring(with: match.range(at: 1))
} else {
localId = nil
Expand All @@ -350,16 +363,16 @@ public class AbstractHafasLegacyProvider: AbstractHafasProvider {
let location: Location?
if type == 1 {
let placeAndName = split(stationName: value)
location = Location(type: .station, id: localId, coord: LocationPoint(lat: lat, lon: lon), place: placeAndName.0, name: placeAndName.1)
location = Location(type: .station, id: localId, coord: coord, place: placeAndName.0, name: placeAndName.1)
} else if type == 2 {
let placeAndName = split(address: value)
location = Location(type: .address, id: localId, coord: LocationPoint(lat: lat, lon: lon), place: placeAndName.0, name: placeAndName.1)
location = Location(type: .address, id: localId, coord: coord, place: placeAndName.0, name: placeAndName.1)
} else if type == 4 {
let placeAndName = split(poi: value)
location = Location(type: .poi, id: localId, coord: LocationPoint(lat: lat, lon: lon), place: placeAndName.0, name: placeAndName.1)
location = Location(type: .poi, id: localId, coord: coord, place: placeAndName.0, name: placeAndName.1)
} else if type == 128 {
let placeAndName = split(address: value)
location = Location(type: .address, id: localId, coord: LocationPoint(lat: lat, lon: lon), place: placeAndName.0, name: placeAndName.1)
location = Location(type: .address, id: localId, coord: coord, place: placeAndName.0, name: placeAndName.1)
} else {
location = nil
}
Expand All @@ -371,44 +384,50 @@ public class AbstractHafasLegacyProvider: AbstractHafasProvider {
}

override func queryNearbyLocationsByCoordinateParsing(request: HttpRequest, location: Location, types: [LocationType]?, maxDistance: Int, maxLocations: Int, completion: @escaping (HttpRequest, NearbyLocationsResult) -> Void) throws {
guard let json = try request.responseData?.toJson(encoding: self.jsonNearbyLocationsEncoding) as? [String: Any], let error = json["error"] as? String else {
throw ParseError(reason: "could not parse json")
guard let data = request.responseData?.encodedData(encoding: self.jsonNearbyLocationsEncoding) else {
throw ParseError(reason: "no response")
}
if error != "0" {
let json = try JSON(data: data)
if let error = json["error"].string, error != "0" {
throw ParseError(reason: "received hafas error code \(error)")
}
var locations: [Location] = []
if let stops = json["stops"] as? [Any] {
for stop in stops {
guard let stop = stop as? [String: Any], let id = stop["extId"] as? String, let urlname = (stop["urlname"] as? String), let lat = Int(stop["y"] as? String ?? ""), let lon = Int(stop["x"] as? String ?? "") else {
throw ParseError(reason: "failed to parse stop")
}
let name = urlname.decodeUrl(using: jsonNearbyLocationsEncoding) ?? urlname
let prodclass = Int(stop["prodclass"] as? String ?? "") ?? -1
let stopWeight = Int(stop["stopweight"] as? String ?? "") ?? -1

if stopWeight != 0 {
let placeAndName = split(stationName: name)
let products = prodclass != -1 ? self.products(from: prodclass) : nil
let location = Location(type: .station, id: id, coord: LocationPoint(lat: lat, lon: lon), place: placeAndName.0, name: placeAndName.1, products: products)
if let location = location {
locations.append(location)
}
}
for stop in json["stops"].arrayValue {
let id = stop["extId"].string
let urlname = stop["urlname"].string

let coord: LocationPoint?
if let lat = Int(stop["y"].stringValue), let lon = Int(stop["x"].stringValue) {
coord = LocationPoint(lat: lat, lon: lon)
} else {
coord = nil
}

let name = urlname?.decodeUrl(using: jsonNearbyLocationsEncoding) ?? urlname
let prodclass = Int(stop["prodclass"].stringValue) ?? -1
let stopWeight = Int(stop["stopweight"].stringValue) ?? -1

guard stopWeight != 0 else { continue }
let placeAndName = split(stationName: name)
let products = prodclass != -1 ? self.products(from: prodclass) : nil

guard let location = Location(type: .station, id: id, coord: coord, place: placeAndName.0, name: placeAndName.1, products: products) else { continue }
locations.append(location)
}
if let pois = json["pois"] as? [Any] {
for poi in pois {
guard let poi = poi as? [String: Any], let id = poi["extId"] as? String, let urlname = (poi["urlname"] as? String)?.removingPercentEncoding, let lat = Int(poi["y"] as? String ?? ""), let lon = Int(poi["x"] as? String ?? "") else {
throw ParseError(reason: "failed to parse stop")
}

let placeAndName = split(stationName: urlname)
let location = Location(type: .poi, id: id, coord: LocationPoint(lat: lat, lon: lon), place: placeAndName.0, name: placeAndName.1)
if let location = location {
locations.append(location)
}
for poi in json["pois"].arrayValue {
let id = poi["extId"].string
let urlname = poi["urlname"].string

let coord: LocationPoint?
if let lat = Int(poi["y"].stringValue), let lon = Int(poi["x"].stringValue) {
coord = LocationPoint(lat: lat, lon: lon)
} else {
coord = nil
}

let placeAndName = split(stationName: urlname)
guard let location = Location(type: .poi, id: id, coord: coord, place: placeAndName.0, name: placeAndName.1) else { continue }
locations.append(location)
}

completion(request, .success(locations: locations))
Expand Down
18 changes: 9 additions & 9 deletions Sources/TripKit/Provider/Implementations/BvgProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,24 +202,24 @@ public class BvgProvider: AbstractHafasClientInterfaceProvider {
// }
// }

override func newLine(network: String?, product: Product?, name: String?, shortName: String?, number: String?, vehicleNumber: String?) -> Line {
override func newLine(id: String?, network: String?, product: Product?, name: String?, shortName: String?, number: String?, vehicleNumber: String?) -> Line {
let label = name ?? ""
if product == .suburbanTrain && label == "S41" {
return Line(id: nil, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.circleClockwise], message: nil)
return Line(id: id, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.circleClockwise], message: nil)
} else if product == .suburbanTrain && label == "S42" {
return Line(id: nil, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.circleAnticlockwise], message: nil)
return Line(id: id, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.circleAnticlockwise], message: nil)
} else if product == .bus && label == "S41" {
return Line(id: nil, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.serviceReplacement, .circleClockwise], message: nil)
return Line(id: id, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.serviceReplacement, .circleClockwise], message: nil)
} else if product == .bus && label == "S42" {
return Line(id: nil, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.serviceReplacement, .circleAnticlockwise], message: nil)
return Line(id: id, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.serviceReplacement, .circleAnticlockwise], message: nil)
} else if product == .bus && label == "TXL" {
return Line(id: nil, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.lineAirport], message: nil)
return Line(id: id, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.lineAirport], message: nil)
} else if product == .suburbanTrain && label == "S9" {
return Line(id: nil, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.lineAirport], message: nil)
return Line(id: id, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.lineAirport], message: nil)
} else if product == .suburbanTrain && label == "S45" {
return Line(id: nil, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.lineAirport], message: nil)
return Line(id: id, network: network, product: product, label: label, name: nil, number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: product, label: label), attr: [.lineAirport], message: nil)
} else {
return super.newLine(network: network, product: product, name: name, shortName: shortName, number: number, vehicleNumber: vehicleNumber)
return super.newLine(id: id, network: network, product: product, name: name, shortName: shortName, number: number, vehicleNumber: vehicleNumber)
}
}

Expand Down
8 changes: 4 additions & 4 deletions Sources/TripKit/Provider/Implementations/VbnProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,13 @@ public class VbnProvider: AbstractHafasClientInterfaceProvider {
return super.split(address: address)
}

override func newLine(network: String?, product: Product?, name: String?, shortName: String?, number: String?, vehicleNumber: String?) -> Line {
let line = super.newLine(network: network, product: product, name: name, shortName: shortName, number: number, vehicleNumber: vehicleNumber)
override func newLine(id: String?, network: String?, product: Product?, name: String?, shortName: String?, number: String?, vehicleNumber: String?) -> Line {
let line = super.newLine(id: id, network: network, product: product, name: name, shortName: shortName, number: number, vehicleNumber: vehicleNumber)

if line.product == .bus && "57" == line.label {
return Line(id: nil, network: line.network, product: line.product, label: line.label, name: line.name, style: line.style, attr: [.serviceReplacement, .circleClockwise], message: line.message)
return Line(id: id, network: line.network, product: line.product, label: line.label, name: line.name, style: line.style, attr: [.serviceReplacement, .circleClockwise], message: line.message)
} else if line.product == .bus && "58" == line.label {
return Line(id: nil, network: line.network, product: line.product, label: line.label, name: line.name, style: line.style, attr: [.serviceReplacement, .circleAnticlockwise], message: line.message)
return Line(id: id, network: line.network, product: line.product, label: line.label, name: line.name, style: line.style, attr: [.serviceReplacement, .circleAnticlockwise], message: line.message)
} else {
return line
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/TripKit/Provider/Implementations/VvtProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ public class VvtProvider: AbstractHafasClientInterfaceProvider {
return super.split(address: address)
}

override func newLine(network: String?, product: Product?, name: String?, shortName: String?, number: String?, vehicleNumber: String?) -> Line {
override func newLine(id: String?, network: String?, product: Product?, name: String?, shortName: String?, number: String?, vehicleNumber: String?) -> Line {
if product == .tram && name == "HBB" {
return Line(id: nil, network: network, product: .cablecar, label: name, name: "Hungerburgbahn", number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: .cablecar, label: name), attr: [], message: nil)
return Line(id: id, network: network, product: .cablecar, label: name, name: "Hungerburgbahn", number: number, vehicleNumber: vehicleNumber, style: lineStyle(network: network, product: .cablecar, label: name), attr: [], message: nil)
} else {
return super.newLine(network: network, product: product, name: name, shortName: shortName, number: number, vehicleNumber: vehicleNumber)
return super.newLine(id: id, network: network, product: product, name: name, shortName: shortName, number: number, vehicleNumber: vehicleNumber)
}
}

Expand Down
9 changes: 9 additions & 0 deletions Sources/TripKit/TripKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,12 @@ extension Sequence where Element: Hashable {
return filter { set.insert($0).inserted }
}
}

extension Collection {

/// Returns the element at the specified index if it is within bounds, otherwise nil.
subscript(safe index: Index?) -> Element? {
guard let index = index else { return nil }
return indices.contains(index) ? self[index] : nil
}
}
8 changes: 6 additions & 2 deletions Sources/TripKit/Util/HttpClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,19 @@ public class HttpRequest {

extension Data {

func toJson(encoding: String.Encoding = .utf8) throws -> Any? {
func encodedData(encoding: String.Encoding) -> Data? {
let encodedData: Data?
if encoding == .utf8 {
encodedData = self
} else {
let string = String(data: self, encoding: encoding)
encodedData = string?.data(using: .utf8, allowLossyConversion: true)
}
if let encodedData = encodedData {
return encodedData
}

func toJson(encoding: String.Encoding = .utf8) throws -> Any? {
if let encodedData = encodedData(encoding: encoding) {
return try JSONSerialization.jsonObject(with: encodedData, options: .allowFragments)
} else {
return nil
Expand Down

0 comments on commit 7cd7e63

Please sign in to comment.