-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMtaClient.swift
149 lines (123 loc) · 4.23 KB
/
MtaClient.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//
// MtaClient.swift
// mta-widget
//
// Created by Pallav Agarwal on 9/8/24.
//
import Foundation
import SwiftUI
// Helpers
let mtaColors: [String: Color] = [
"1": .red,
"2": .red,
"3": .red,
"4": .green,
"5": .green,
"6": .green,
"7": .purple,
"A": .blue,
"C": .blue,
"E": .blue,
"B": .orange,
"D": .orange,
"F": .orange,
"M": .orange,
"G": .green,
"J": .brown,
"Z": .brown,
"L": .gray,
"N": .yellow,
"Q": .yellow,
"R": .yellow,
"W": .yellow,
"S": .gray // Shuttle
]
struct Route {
let station: String
let routeId: String
let stopId: String
}
func populateRoutes() -> [Route] {
let calendar = Calendar.current
let now = Date()
let components = calendar.dateComponents([.hour, .minute, .weekday], from: now)
guard let hour = components.hour, let weekday = components.weekday else {
return []
}
var routes: [Route] = []
// Call the function that populates the routes array based on conditions
addRoutes(hour: hour, weekday: weekday, routes: &routes)
return routes
}
func addRoute(startHour: Int, endHour: Int, validWeekdays: [Int], hour: Int, weekday: Int, route: Route, routes: inout [Route]) {
if hour >= startHour && hour < endHour && validWeekdays.contains(weekday) {
routes.append(route)
}
}
func callTrainEstimateAPI(_ route: Route) async throws -> [Date] {
// The URL of the MTA GTFS feed for the A, C, E lines
var apiUrl = "https://api-endpoint.mta.info/Dataservice/mtagtfsfeeds/nyct%2Fgtfs-ace"
if route.routeId == "M" {
apiUrl = "https://api-endpoint.mta.info/Dataservice/mtagtfsfeeds/nyct%2Fgtfs-bdfm"
}
if route.routeId == "7" {
apiUrl = "https://api-endpoint.mta.info/Dataservice/mtagtfsfeeds/nyct%2Fgtfs"
}
guard let url = URL(string: apiUrl) else {
throw URLError(.badURL)
}
// Make the GET request
let (data, response) = try await URLSession.shared.data(for: URLRequest(url: url))
// Check if the response is valid
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
// Decode the protobuf data into the GTFSRealtime_FeedMessage model
let feed = try TransitRealtime_FeedMessage(serializedBytes: data)
// The specific route and stop ID we're interested in
// let targetRouteId = "E"
// let targetStopId = "F09S"
let targetRouteId = route.routeId
let targetStopId = route.stopId
// Find and output the arrival times for Route 'E' and Stop 'F09N'
var arrivalTimes: [Date] = []
var stops = Set<String>()
var routeIds = Set<String>()
for entity in feed.entity {
let tripUpdate = entity.tripUpdate
routeIds.insert(entity.tripUpdate.trip.routeID)
if entity.tripUpdate.trip.routeID == targetRouteId {
for stopTimeUpdate in tripUpdate.stopTimeUpdate {
if stopTimeUpdate.stopID == targetStopId {
let arrivalTime = stopTimeUpdate.arrival.time
let arrivalDate = Date(timeIntervalSince1970: TimeInterval(arrivalTime))
arrivalTimes.append(arrivalDate)
}
stops.insert("\(stopTimeUpdate.stopID)")
}
}
}
// print(routeIds)
// print(stops)
var estimates = [Date]()
// Output the arrival times
if arrivalTimes.isEmpty {
print("No upcoming arrivals found for Route \(targetRouteId) at Stop \(targetStopId).")
throw URLError(.badServerResponse)
} else {
// print("Upcoming arrivals for Route \(targetRouteId) at Stop \(targetStopId):")
for (_, arrivalTime) in arrivalTimes.sorted().enumerated() {
estimates.append(arrivalTime)
if estimates.count == 2 {
return estimates
}
}
}
throw URLError(.badServerResponse)
}
func dateToString(_ date: Date) -> String {
return DateFormatter.localizedString(from: date, dateStyle: .none, timeStyle: .medium)
}
func datesToString(_ dates: [Date]) -> String {
return dates.map { dateToString($0) }.joined(separator: "\n")
}