-
-
Notifications
You must be signed in to change notification settings - Fork 128
Expand file tree
/
Copy pathgtfsService.ts
More file actions
156 lines (149 loc) · 4.47 KB
/
Copy pathgtfsService.ts
File metadata and controls
156 lines (149 loc) · 4.47 KB
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
150
151
152
153
154
155
156
import { GTFS_API } from 'src/api/apiConfig'
import dayjs, { utcNoonForDateStr } from 'src/dayjs'
import { BusRoute, fromGtfsRoute } from 'src/model/busRoute'
import { BusStop, fromGtfsStop } from 'src/model/busStop'
/** GTFS routes running between two calendar dates ("YYYY-MM-DD", Israel time, both
* inclusive), merged by route key so a line's variants collapse into one entry
* carrying all its routeIds. Pass the same date twice for a single day. */
export async function getRoutesAsync(
fromDate: string,
toDate: string,
operatorId?: string,
lineNumber?: string,
signal?: AbortSignal,
): Promise<BusRoute[]> {
const gtfsRoutes = await GTFS_API.gtfsRoutesListGet(
{
routeShortName: lineNumber,
operatorRefs: operatorId,
dateFrom: utcNoonForDateStr(fromDate),
dateTo: utcNoonForDateStr(toDate),
limit: 15000,
},
{ signal },
)
const routes = Object.values(
gtfsRoutes
.map((route) => fromGtfsRoute(route))
.reduce(
(agg, line) => {
const groupByKey = line.key
const prevLine = agg[groupByKey] || { routeIds: [] }
agg[groupByKey] = {
...line,
...prevLine,
routeIds: [...prevLine.routeIds, ...line.routeIds],
}
return agg
},
{} as Record<string, BusRoute>,
),
)
return routes
}
export async function getStopsForRouteAsync(
routeIds: number[],
time: dayjs.Dayjs,
): Promise<BusStop[]> {
const stops: BusStop[] = []
for (const routeId of routeIds) {
const rides = await GTFS_API.gtfsRidesListGet({
gtfsRouteId: routeId,
startTimeFrom: time.subtract(1, 'day').second(0).millisecond(0).toDate(),
startTimeTo: time.add(1, 'day').second(0).millisecond(0).toDate(),
limit: 1,
orderBy: 'start_time',
})
if (rides.length === 0) {
continue
}
const rideRepresentative = rides[0]
const rideStops = await GTFS_API.gtfsRideStopsListGet({
gtfsRideIds: rideRepresentative.id!.toString(),
})
await Promise.all(
rideStops.map(async (rideStop) => {
if (
!rideStop.gtfsStopId ||
stops.find((b) => b.code === rideStop.gtfsStopCode?.toString())
) {
return
}
const stop = await GTFS_API.gtfsStopsGetGet({ id: rideStop.gtfsStopId })
stops.push(fromGtfsStop(rideStop, stop, rideRepresentative))
}),
)
}
return stops.sort((a, b) =>
a.stopSequence === b.stopSequence
? a.name.localeCompare(b.name)
: a.stopSequence - b.stopSequence,
)
}
export async function getGtfsStopHitTimesAsync(stop: BusStop, time: dayjs.Dayjs) {
try {
return await GTFS_API.gtfsRideStopsListGet({
gtfsRideGtfsRouteId: stop.routeId,
gtfsStopIds: stop.stopId.toString(),
arrivalTimeFrom: time.subtract(4, 'hour').toDate(),
arrivalTimeTo: time.add(4, 'hour').toDate(),
orderBy: 'arrival_time asc',
})
} catch (error) {
console.error(`Error fetching stop hits for stop ${stop.stopId}:`, error)
return []
}
}
export async function getRouteById(routeId?: string, signal?: AbortSignal) {
try {
if (!routeId?.trim()) {
throw new Error('Route id is required and cannot be empty')
}
const id = Number(routeId)
if (!Number.isInteger(id) || id <= 0 || id > Number.MAX_SAFE_INTEGER) {
throw new Error(`Invalid route id: ${routeId}.`)
}
return await GTFS_API.gtfsRoutesGetGet({ id }, { signal })
} catch (error) {
let errorMessage: string
if (error instanceof Error) {
errorMessage =
error.message === 'Response returned an error code'
? `Route with id ${routeId} not found`
: error.message
} else {
errorMessage = 'An unexpected error occurred while fetching route data'
}
console.error(`Failed to get route ${routeId}:`, errorMessage)
throw new Error(errorMessage)
}
}
export async function getAllRoutesList(operatorId: string, date: Date, signal?: AbortSignal) {
return await GTFS_API.gtfsRoutesListGet(
{
operatorRefs: operatorId,
dateFrom: date,
dateTo: date,
orderBy: 'route_long_name asc',
limit: 15000,
},
{ signal },
)
}
export async function getRoutesByLineRef(
operatorId: string,
lineRefs: string,
date: Date,
signal?: AbortSignal,
) {
return await GTFS_API.gtfsRoutesListGet(
{
operatorRefs: operatorId,
dateFrom: date,
dateTo: date,
lineRefs,
limit: 1,
},
{ signal },
)
}