|
@@ -17,7 +17,7 @@ import (
|
|
|
"net"
|
|
|
"os"
|
|
|
"path/filepath"
|
|
|
- "slices"
|
|
|
+ "sort"
|
|
|
"strings"
|
|
|
"time"
|
|
|
|
|
@@ -31,6 +31,15 @@ import (
|
|
|
"notabug.org/apiote/gott"
|
|
|
)
|
|
|
|
|
|
+type OlcError struct {
|
|
|
+ Value string
|
|
|
+ Err error
|
|
|
+}
|
|
|
+
|
|
|
+func (e OlcError) Error() string {
|
|
|
+ return e.Err.Error()
|
|
|
+}
|
|
|
+
|
|
|
type _Result struct {
|
|
|
Filename string
|
|
|
Offset uint
|
|
@@ -54,12 +63,11 @@ type _Result struct {
|
|
|
TripsFile *os.File
|
|
|
Trips map[string]Trip
|
|
|
|
|
|
- Departures []DepartureRealtime
|
|
|
- DeparturesSchedule []Departure
|
|
|
- Stop Stop
|
|
|
- Line Line
|
|
|
- Trip Trip
|
|
|
- FeedInfo FeedInfo
|
|
|
+ Departures []DepartureRealtime
|
|
|
+ Stop Stop
|
|
|
+ Line Line
|
|
|
+ Trip Trip
|
|
|
+ FeedInfo FeedInfo
|
|
|
}
|
|
|
|
|
|
func isTimeout(err error) bool {
|
|
@@ -94,6 +102,62 @@ func findSchedule(home string, time time.Time, calendar []Schedule) (map[string]
|
|
|
return schedules, err
|
|
|
}
|
|
|
|
|
|
+func calculateGtfsTime(gtfsTime uint, delay int32, date time.Time,
|
|
|
+ timezone *time.Location) time.Time {
|
|
|
+ noon := time.Date(date.Year(), date.Month(), date.Day(), 12, 0, 0, 0,
|
|
|
+ timezone)
|
|
|
+ return noon.Add(time.Duration(-12) * time.Hour).Add(time.Duration(gtfsTime) * time.Minute).Add(time.Duration(delay) * time.Second)
|
|
|
+}
|
|
|
+
|
|
|
+func loadLocation(input ...interface{}) (interface{}, error) {
|
|
|
+ result := input[0].(_Result)
|
|
|
+ var err error = nil
|
|
|
+ result.Location, err = GetTimezone(result.Stop, result.Traffic, result.Ctx.FeedID)
|
|
|
+ return result, err
|
|
|
+}
|
|
|
+
|
|
|
+func loadTime(input ...interface{}) interface{} {
|
|
|
+ result := input[0].(_Result)
|
|
|
+
|
|
|
+ now := time.Now()
|
|
|
+ datetime := time.Date(result.Date.Year(), result.Date.Month(),
|
|
|
+ result.Date.Day(), now.Hour(), now.Minute(), now.Second(), 0, now.Location()).In(result.Location)
|
|
|
+ result.Datetime = datetime
|
|
|
+ result.MinuteB4Datetime = datetime.Add(time.Duration(-1) * time.Minute)
|
|
|
+ return result
|
|
|
+}
|
|
|
+
|
|
|
+func loadTodaySchedule(input ...interface{}) (interface{}, error) {
|
|
|
+ result := input[0].(_Result)
|
|
|
+
|
|
|
+ todaySchedule, err := findSchedule(result.TimetableHome, result.Date,
|
|
|
+ result.Calendar)
|
|
|
+ result.TodaySchedule = todaySchedule
|
|
|
+ return result, err
|
|
|
+}
|
|
|
+
|
|
|
+func loadYesterdaySchedule(input ...interface{}) (interface{}, error) {
|
|
|
+ result := input[0].(_Result)
|
|
|
+
|
|
|
+ yesterday := result.Date.AddDate(0, 0, -1)
|
|
|
+ yesterdaySchedule, err := findSchedule(result.TimetableHome, yesterday,
|
|
|
+ result.Calendar)
|
|
|
+ result.YesterdaySchedule = yesterdaySchedule
|
|
|
+ return result, err
|
|
|
+}
|
|
|
+
|
|
|
+func recoverYesterdaySchedule(input ...interface{}) (interface{}, error) {
|
|
|
+ result := input[0].(_Result)
|
|
|
+ err := input[1].(error)
|
|
|
+
|
|
|
+ dayBefore := result.Date.AddDate(0, 0, -1).Format(DateFormat)
|
|
|
+ if err, ok := err.(traffic_errors.NoSchedule); ok && err.Date == dayBefore {
|
|
|
+ result.YesterdaySchedule = map[string]struct{}{}
|
|
|
+ return gott.Tuple{result}, nil
|
|
|
+ }
|
|
|
+ return gott.Tuple{result}, err
|
|
|
+}
|
|
|
+
|
|
|
func openFile(input ...interface{}) (interface{}, error) {
|
|
|
result := input[0].(_Result)
|
|
|
|
|
@@ -141,9 +205,127 @@ func unmarshalTrip(input ...interface{}) (interface{}, error) {
|
|
|
|
|
|
result.Trip = Trip{}
|
|
|
err := bare.UnmarshalReader(result.file, &result.Trip)
|
|
|
+ result.file.Close()
|
|
|
+ return result, err
|
|
|
+}
|
|
|
+
|
|
|
+func openTripsFile(input ...interface{}) (interface{}, error) {
|
|
|
+ result := input[0].(_Result)
|
|
|
+
|
|
|
+ tripsFile, err := os.Open(filepath.Join(result.TimetableHome, "trips.bare"))
|
|
|
+ result.TripsFile = tripsFile
|
|
|
+ return result, err
|
|
|
+}
|
|
|
+
|
|
|
+func readTrips(input ...interface{}) (interface{}, error) {
|
|
|
+ result := input[0].(_Result)
|
|
|
+ trips := map[string]Trip{}
|
|
|
+ orders := map[string]StopOrder{}
|
|
|
+
|
|
|
+ for _, order := range result.Stop.Order {
|
|
|
+ _, err := result.TripsFile.Seek(int64(order.TripOffset), 0)
|
|
|
+ if err != nil {
|
|
|
+ return result, err
|
|
|
+ }
|
|
|
+ trip := Trip{}
|
|
|
+ err = bare.UnmarshalReader(result.TripsFile, &trip)
|
|
|
+ if err != nil {
|
|
|
+ return result, err
|
|
|
+ }
|
|
|
+
|
|
|
+ _, inToday := result.TodaySchedule[trip.ScheduleID]
|
|
|
+ _, inYesterday := result.YesterdaySchedule[trip.ScheduleID]
|
|
|
+ if inToday || inYesterday {
|
|
|
+ trips[trip.Id] = trip
|
|
|
+ orders[trip.Id] = order
|
|
|
+ }
|
|
|
+ }
|
|
|
+ result.Stop.Order = orders
|
|
|
+ result.Trips = trips
|
|
|
+ return result, nil
|
|
|
+}
|
|
|
+
|
|
|
+func getDepartures(input ...interface{}) (interface{}, error) {
|
|
|
+ result := input[0].(_Result)
|
|
|
+ departures := []DepartureRealtime{}
|
|
|
+ timedOut := false
|
|
|
+ for tripID, order := range result.Stop.Order {
|
|
|
+ trip := result.Trips[tripID]
|
|
|
+
|
|
|
+ var date time.Time
|
|
|
+ if _, ok := result.TodaySchedule[trip.ScheduleID]; ok {
|
|
|
+ date = result.Date
|
|
|
+ } else if _, ok := result.YesterdaySchedule[trip.ScheduleID]; ok {
|
|
|
+ date = result.Date.AddDate(0, 0, -1)
|
|
|
+ } else {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ departure, err := getDeparture(date, result, order, trip, result.Feed, timedOut)
|
|
|
+ if err != nil {
|
|
|
+ if isTimeout(err) {
|
|
|
+ timedOut = true
|
|
|
+ err = nil
|
|
|
+ } else {
|
|
|
+ return result, err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ departures = append(departures, departure)
|
|
|
+ }
|
|
|
+ result.Departures = departures
|
|
|
+ return result, nil
|
|
|
+}
|
|
|
+
|
|
|
+func makeDeparturesRealtime(input ...interface{}) (interface{}, error) {
|
|
|
+ result := input[0].(_Result)
|
|
|
+ departures, err := enrichDepartures(result.Stop.Id, result.Stop.Code, result.Departures, result.Datetime, result.DeparturesType, result.Ctx, result.TripsFile, result.Location, result.Languages)
|
|
|
+ result.TripsFile.Close()
|
|
|
+ result.Departures = departures
|
|
|
return result, err
|
|
|
}
|
|
|
|
|
|
+func addAlerts(input ...interface{}) interface{} {
|
|
|
+ result := input[0].(_Result)
|
|
|
+ alertedDepartures := make([]DepartureRealtime, len(result.Departures))
|
|
|
+ for i, d := range result.Departures {
|
|
|
+ if len(d.Alerts) == 0 {
|
|
|
+ d.Alerts = GetAlerts("", "", int(d.Order.TripOffset), result.Ctx, result.Traffic, result.Languages)
|
|
|
+ }
|
|
|
+ alertedDepartures[i] = d
|
|
|
+ }
|
|
|
+ result.Departures = alertedDepartures
|
|
|
+ return result
|
|
|
+}
|
|
|
+
|
|
|
+func getDeparture(date time.Time, result _Result, order StopOrder,
|
|
|
+ trip Trip, feed Feed, timedOut bool) (DepartureRealtime, error) {
|
|
|
+ found := false
|
|
|
+ departureRt := DepartureRealtime{}
|
|
|
+ var finalErr error
|
|
|
+ for _, departure := range trip.Departures {
|
|
|
+ if departure.StopSequence == order.Sequence {
|
|
|
+
|
|
|
+ departureRt.Departure = departure
|
|
|
+ departureRt.Headsign = trip.Headsign
|
|
|
+ departureRt.LineID = trip.LineID
|
|
|
+ departureRt.Order = order
|
|
|
+ departureRt.Update = Update{}
|
|
|
+
|
|
|
+ departureRt.Time = calculateGtfsTime(departure.Time, 0, date,
|
|
|
+ result.Location)
|
|
|
+ found = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if !found {
|
|
|
+ return departureRt, traffic_errors.NoStopOrder{
|
|
|
+ TripID: trip.Id,
|
|
|
+ Order: order.Sequence,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return departureRt, finalErr
|
|
|
+}
|
|
|
+
|
|
|
func GetTimeWithDelay(departure DepartureRealtime) time.Time {
|
|
|
if departure.Update.TimeUTC != "" {
|
|
|
updateTimeUTC, err := time.Parse("150405", departure.Update.Time)
|
|
@@ -165,6 +347,54 @@ func GetTimeWithDelay(departure DepartureRealtime) time.Time {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func filterDepartures(input ...interface{}) interface{} {
|
|
|
+ result := input[0].(_Result)
|
|
|
+ departures := []DepartureRealtime{}
|
|
|
+ midnight := result.Date
|
|
|
+ for _, departure := range result.Departures {
|
|
|
+ if (result.DeparturesType == DEPARTURES_FULL && GetTimeWithDelay(departure).After(midnight)) || (result.DeparturesType == DEPARTURES_HYBRID && GetTimeWithDelay(departure).After(result.MinuteB4Datetime)) {
|
|
|
+ departures = append(departures, departure)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ result.Departures = departures
|
|
|
+ return result
|
|
|
+}
|
|
|
+
|
|
|
+func filterDeparturesByLine(input ...interface{}) interface{} {
|
|
|
+ result := input[0].(_Result)
|
|
|
+ departures := []DepartureRealtime{}
|
|
|
+ if result.LineID != "" {
|
|
|
+ for _, departure := range result.Departures {
|
|
|
+ if departure.LineID == result.LineID {
|
|
|
+ departures = append(departures, departure)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ result.Departures = departures
|
|
|
+ }
|
|
|
+ return result
|
|
|
+}
|
|
|
+
|
|
|
+func sortDepartures(input ...interface{}) interface{} {
|
|
|
+ result := input[0].(_Result)
|
|
|
+ sort.Slice(result.Departures, func(i, j int) bool {
|
|
|
+ return GetTimeWithDelay(result.Departures[i]).Before(GetTimeWithDelay(result.Departures[j]))
|
|
|
+ })
|
|
|
+
|
|
|
+ return result
|
|
|
+}
|
|
|
+
|
|
|
+func closeFiles(input ...interface{}) (interface{}, error) {
|
|
|
+ result := input[0].(_Result)
|
|
|
+ err := input[1].(error)
|
|
|
+ if result.file != nil {
|
|
|
+ result.file.Close()
|
|
|
+ }
|
|
|
+ if result.TripsFile != nil {
|
|
|
+ result.TripsFile.Close()
|
|
|
+ }
|
|
|
+ return result, err
|
|
|
+}
|
|
|
+
|
|
|
func unmarshalCodeIndex(timetableHome, filename string) (CodeIndex, error) {
|
|
|
ix := CodeIndex{}
|
|
|
|
|
@@ -394,6 +624,12 @@ func createPositionIndex(feedHome string, versions []Version) (FeedPositionIndex
|
|
|
return feedPositionIndex, nil
|
|
|
}
|
|
|
|
|
|
+func unmarshalTripFromFile(tripsFile *os.File) Trip {
|
|
|
+ trip := Trip{}
|
|
|
+ _ = bare.UnmarshalReader(tripsFile, &trip)
|
|
|
+ return trip
|
|
|
+}
|
|
|
+
|
|
|
func EnableFeeds(cfg config.Config, traffic *Traffic) {
|
|
|
feedsMap := RegisterFeeds()
|
|
|
feeds := map[string]Feed{}
|
|
@@ -409,7 +645,7 @@ func EnableFeeds(cfg config.Config, traffic *Traffic) {
|
|
|
|
|
|
func Initialise(sigChan chan os.Signal, doneChan chan bool, initedChan chan bool, cfg config.Config,
|
|
|
traffic *Traffic) {
|
|
|
- bare.MaxMapSize(8192)
|
|
|
+ bare.MaxMapSize(12288)
|
|
|
alreadyInitialised := false
|
|
|
for {
|
|
|
sig := <-sigChan
|
|
@@ -504,6 +740,56 @@ func Initialise(sigChan chan os.Signal, doneChan chan bool, initedChan chan bool
|
|
|
doneChan <- true
|
|
|
}
|
|
|
|
|
|
+func GetDepartures(stopCode, lineID string, ctx Context, traffic *Traffic, date time.Time,
|
|
|
+ departuresType DeparturesType, languages []language.Tag) ([]DepartureRealtime, error) {
|
|
|
+
|
|
|
+ codeIndex := traffic.CodeIndexes[ctx.FeedID][ctx.Version]
|
|
|
+ calendar := traffic.Calendars[ctx.FeedID][ctx.Version]
|
|
|
+ vehicles := traffic.Vehicles[ctx.FeedID][ctx.Version]
|
|
|
+
|
|
|
+ result := _Result{
|
|
|
+ Offset: codeIndex[stopCode],
|
|
|
+ Filename: "stops.bare",
|
|
|
+ Date: date,
|
|
|
+ LineID: lineID,
|
|
|
+ TimetableHome: filepath.Join(ctx.DataHome, ctx.FeedID, string(ctx.Version)),
|
|
|
+ Calendar: calendar,
|
|
|
+ DeparturesType: departuresType,
|
|
|
+ Vehicles: vehicles,
|
|
|
+ Feed: traffic.Feeds[ctx.FeedID],
|
|
|
+ Ctx: ctx,
|
|
|
+ Traffic: traffic,
|
|
|
+ Languages: languages,
|
|
|
+ }
|
|
|
+
|
|
|
+ r, e := gott.NewResult(result).
|
|
|
+ Bind(loadLocation).
|
|
|
+ Map(loadTime).
|
|
|
+ Bind(loadTodaySchedule).
|
|
|
+ Bind(loadYesterdaySchedule).
|
|
|
+ Recover(recoverYesterdaySchedule).
|
|
|
+ Bind(openFile).
|
|
|
+ Bind(seek).
|
|
|
+ Bind(unmarshalStop).
|
|
|
+ Bind(openTripsFile).
|
|
|
+ Bind(readTrips).
|
|
|
+ Bind(getDepartures).
|
|
|
+ Bind(makeDeparturesRealtime).
|
|
|
+ Map(addAlerts).
|
|
|
+ Map(filterDepartures).
|
|
|
+ Map(filterDeparturesByLine).
|
|
|
+ Map(sortDepartures).
|
|
|
+ Recover(closeFiles).
|
|
|
+ Finish()
|
|
|
+
|
|
|
+ if e != nil {
|
|
|
+ return []DepartureRealtime{}, e
|
|
|
+ } else {
|
|
|
+ return r.(_Result).Departures, nil
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
func GetTripFromStop(tripID string, stopCode string, context Context, traffic *Traffic) ([]TimedStopStub, error) {
|
|
|
stubs := []TimedStopStub{}
|
|
|
|
|
@@ -515,11 +801,6 @@ func GetTripFromStop(tripID string, stopCode string, context Context, traffic *T
|
|
|
time uint = 0
|
|
|
)
|
|
|
|
|
|
- file, err := openTrips(context)
|
|
|
- if err != nil {
|
|
|
- return stubs, fmt.Errorf("while opening trips: %w", err)
|
|
|
- }
|
|
|
- defer file.Close()
|
|
|
if stopCode != "" {
|
|
|
startingStop, err := GetStop(stopCode, context, traffic)
|
|
|
if err != nil {
|
|
@@ -533,22 +814,18 @@ func GetTripFromStop(tripID string, stopCode string, context Context, traffic *T
|
|
|
if tripOffset == -1 {
|
|
|
return stubs, fmt.Errorf("trip for starting stop not found")
|
|
|
}
|
|
|
- trip, err = GetTripByOffset(file, uint(tripOffset), context)
|
|
|
+ trip, err = GetTripByOffset(uint(tripOffset), context, traffic)
|
|
|
if err != nil {
|
|
|
return stubs, fmt.Errorf("while getting trip: %w", err)
|
|
|
}
|
|
|
} else {
|
|
|
- trip, err = GetTrip(file, tripID, context, traffic)
|
|
|
+ trip, err = GetTrip(tripID, context, traffic)
|
|
|
if err != nil {
|
|
|
return stubs, fmt.Errorf("while getting trip: %w", err)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- departures, err := getTripDepartures(trip, context)
|
|
|
- if err != nil {
|
|
|
- return stubs, fmt.Errorf("while getting trip departures: %w", err)
|
|
|
- }
|
|
|
- for _, departure := range departures {
|
|
|
+ for _, departure := range trip.Departures {
|
|
|
if departure.StopSequence >= order {
|
|
|
stop, err := getStopByOffset(uint(departure.StopOffset), context, traffic)
|
|
|
if err != nil {
|
|
@@ -626,6 +903,68 @@ func getFeedInfo(dataHome string, feedName string, versionCode Validity) (FeedIn
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func GetTrips(ids []string, ctx Context, t *Traffic) (map[string]Trip, error) { // TODO optimise
|
|
|
+ trips := map[string]Trip{}
|
|
|
+ e := []error{}
|
|
|
+ for _, id := range ids {
|
|
|
+ trip, err := GetTrip(id, ctx, t)
|
|
|
+ if err != nil {
|
|
|
+ e = append(e, err)
|
|
|
+ } else {
|
|
|
+ trips[trip.Id] = trip
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return trips, errors.Join(e...)
|
|
|
+}
|
|
|
+
|
|
|
+func GetTripsByOffset(offsets []uint, context Context, filter func(Trip) bool) (map[uint]Trip, error) {
|
|
|
+ trips := map[uint]Trip{}
|
|
|
+ file, err := os.Open(filepath.Join(context.DataHome, context.FeedID, string(context.Version), "trips.bare"))
|
|
|
+ if err != nil {
|
|
|
+ return trips, fmt.Errorf("while opening file: %w", err)
|
|
|
+ }
|
|
|
+ defer file.Close()
|
|
|
+
|
|
|
+ offsetsSet := map[uint]struct{}{}
|
|
|
+ for _, offset := range offsets {
|
|
|
+ offsetsSet[offset] = struct{}{}
|
|
|
+ }
|
|
|
+
|
|
|
+ for offset := range offsetsSet {
|
|
|
+ _, err = file.Seek(int64(offset), 0)
|
|
|
+ if err != nil {
|
|
|
+ return trips, fmt.Errorf("while seeking to %d: %w", offset, err)
|
|
|
+ }
|
|
|
+ trip := Trip{}
|
|
|
+ err = bare.UnmarshalReader(file, &trip)
|
|
|
+ if err != nil {
|
|
|
+ return trips, fmt.Errorf("while unmarshalling at %d: %w", offset, err)
|
|
|
+ }
|
|
|
+ if filter(trip) {
|
|
|
+ trips[offset] = trip
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return trips, nil
|
|
|
+}
|
|
|
+
|
|
|
+func GetTripByOffset(offset uint, context Context, t *Traffic) (Trip, error) {
|
|
|
+ result := _Result{
|
|
|
+ Filename: "trips.bare",
|
|
|
+ Offset: offset,
|
|
|
+ TimetableHome: filepath.Join(context.DataHome, context.FeedID, string(context.Version)),
|
|
|
+ }
|
|
|
+ r, e := gott.NewResult(result).
|
|
|
+ Bind(openFile).
|
|
|
+ Bind(seek).
|
|
|
+ Bind(unmarshalTrip).
|
|
|
+ Finish()
|
|
|
+ if e != nil {
|
|
|
+ return Trip{}, e
|
|
|
+ } else {
|
|
|
+ return r.(_Result).Trip, nil
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
func GetStop(stopCode string, context Context, traffic *Traffic) (Stop, error) {
|
|
|
codeIndex := traffic.CodeIndexes[context.FeedID][context.Version]
|
|
|
return getStopByOffset(codeIndex[stopCode], context, traffic)
|
|
@@ -639,14 +978,9 @@ func GetStopStub(stopCode string, lineID string, context Context, traffic *Traff
|
|
|
|
|
|
var trip Trip
|
|
|
var stopOrder = -1
|
|
|
- file, err := openTrips(context)
|
|
|
- if err != nil {
|
|
|
- return StopStub{}, fmt.Errorf("while opening trips: %w", err)
|
|
|
- }
|
|
|
- defer file.Close()
|
|
|
for _, order := range stop.Order {
|
|
|
offset := order.TripOffset
|
|
|
- trip, _ = GetTripByOffset(file, offset, context)
|
|
|
+ trip, _ = GetTripByOffset(offset, context, traffic)
|
|
|
if trip.LineID == lineID {
|
|
|
stopOrder = order.Sequence
|
|
|
break
|
|
@@ -656,14 +990,14 @@ func GetStopStub(stopCode string, lineID string, context Context, traffic *Traff
|
|
|
return StopStub{}, fmt.Errorf("cannot the stop on given line")
|
|
|
}
|
|
|
|
|
|
- departures, err := getTripDepartures(trip, context)
|
|
|
- if err != nil {
|
|
|
- return StopStub{}, fmt.Errorf("while getting trip departures: %w", err)
|
|
|
+ var departure *Departure
|
|
|
+ for _, d := range trip.Departures {
|
|
|
+ if d.StopSequence == stopOrder { // todo binary search
|
|
|
+ departure = &d
|
|
|
+ break
|
|
|
+ }
|
|
|
}
|
|
|
- ix, ok := slices.BinarySearchFunc(departures, stopOrder, func(d Departure, stopOrder int) int {
|
|
|
- return d.StopSequence - stopOrder
|
|
|
- })
|
|
|
- if !ok {
|
|
|
+ if departure == nil {
|
|
|
return StopStub{}, fmt.Errorf("cannot find departure at sequence %d", stopOrder)
|
|
|
}
|
|
|
|
|
@@ -672,7 +1006,7 @@ func GetStopStub(stopCode string, lineID string, context Context, traffic *Traff
|
|
|
Name: stop.Name,
|
|
|
NodeName: stop.NodeName,
|
|
|
Zone: stop.Zone,
|
|
|
- OnDemand: departures[ix].Pickup == BY_DRIVER || departures[ix].Dropoff == BY_DRIVER,
|
|
|
+ OnDemand: departure.Pickup == BY_DRIVER || departure.Dropoff == BY_DRIVER,
|
|
|
}
|
|
|
return stopStub, nil
|
|
|
}
|
|
@@ -696,6 +1030,16 @@ func GetLineOld(name string, context Context, traffic *Traffic) (Line, error) {
|
|
|
return Line{}, nil
|
|
|
}
|
|
|
|
|
|
+func GetTrip(id string, context Context, traffic *Traffic) (Trip, error) {
|
|
|
+ tripIndex := traffic.TripIndexes[context.FeedID][context.Version]
|
|
|
+ for _, o := range tripIndex {
|
|
|
+ if o.Name == id {
|
|
|
+ return GetTripByOffset(o.Offsets[0], context, traffic)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Trip{}, fmt.Errorf("trip by id %s not found", id)
|
|
|
+}
|
|
|
+
|
|
|
func QueryLines(query string, dataHome string, feedName string,
|
|
|
versionCode Validity, traffic *Traffic) ([]Line, error) {
|
|
|
linesSet := map[string]Line{}
|