Author: Adam <git@apiote.xyz>
query lines
api/api.go | 79 +++++-------------------------------------- server/router.go | 2 traffic/access.go | 30 ++++++++++++++++ traffic/convert.go | 53 ++++++++++++++++++++++------- traffic/structs_gen.go | 16 +++++---
diff --git a/api/api.go b/api/api.go index 72333af3ec86c830a0c82e95b5dc7d25c48ae670..743e589baf09e26c0d4a62baf6f40574eb0a2911 100644 --- a/api/api.go +++ b/api/api.go @@ -97,13 +97,13 @@ } return line, nil*/ } -func convertTrafficLine(line traffic.Line, context traffic.Context, t *traffic.Traffic) (LineV1, error) { - l := LineV1{ +func convertTrafficLine(line traffic.Line, context traffic.Context, t *traffic.Traffic) LineV1 { + return LineV1{ Name: line.Name, Colour: fromColor(line.Colour), - Kind: LineTypeV2(line.Type), // todo(BAF10) types - HeadsignsThere: []string{}, - HeadsignsBack: []string{}, + Kind: makeLineTypeV2(line), + HeadsignsThere: line.HeadsignsThere, + HeadsignsBack: line.HeadsignsBack, GraphThere: LineGraphV1{ Stops: []StopStubV1{}, NextNodes: line.GraphThere.NextNodes, @@ -115,62 +115,6 @@ NextNodes: line.GraphBack.NextNodes, PrevNodes: line.GraphBack.PrevNodes, }, } - - headsigns := map[string]struct{}{} - - for _, lastNode := range line.GraphThere.LastNodes() { - code := line.GraphThere.StopCodes[lastNode-1] - stop, err := traffic.GetStop(traffic.ID(code), context, t) - if err != nil { - return l, fmt.Errorf("while getting stop for %s: %w", code, err) - } - for _, order := range stop.Order { - trip, err := traffic.GetTripByOffset(order.TripOffset, context, t) // todo batch trips; open file once - if err != nil { - return l, fmt.Errorf("while getting trip at %d: %w", order.TripOffset, err) - } - if trip.LineName == line.Name && trip.Direction == 0 { - headsigns[trip.Headsign] = struct{}{} - } - } - } - - l.HeadsignsThere = make([]string, len(headsigns)) - - var i = 0 - for headsign := range headsigns { - l.HeadsignsThere[i] = headsign - i++ - } - - headsigns = map[string]struct{}{} - - for _, lastNode := range line.GraphBack.LastNodes() { - code := line.GraphBack.StopCodes[lastNode-1] - stop, err := traffic.GetStop(traffic.ID(code), context, t) - if err != nil { - return l, fmt.Errorf("while getting stop for %s: %w", code, err) - } - for _, order := range stop.Order { - trip, err := traffic.GetTripByOffset(order.TripOffset, context, t) - if err != nil { - return l, fmt.Errorf("while getting trip at %d: %w", order.TripOffset, err) - } - if trip.LineName == line.Name && trip.Direction == 1 { - headsigns[trip.Headsign] = struct{}{} - } - } - } - - l.HeadsignsBack = make([]string, len(headsigns)) - - i = 0 - for headsign := range headsigns { - l.HeadsignsBack[i] = headsign - i++ - } - - return l, nil } func convertTrafficVehicle(vehicle traffic.VehicleStatus, context traffic.Context, t *traffic.Traffic) (VehicleV1, error) { @@ -295,14 +239,11 @@ for _, item := range items { if stop, ok := item.(traffic.Stop); ok { s := convertTrafficStopV2(stop, context.FeedName) success.Queryables = append(success.Queryables, QueryableV2(s)) - } else if _ /*line*/, ok := item.(traffic.Line); ok { - /*l, err := convertTrafficLine(line, context, t) - if err != nil { - return success, err - } - l.GraphThere = LineGraph{} - l.GraphBack = LineGraph{} - success.Items = append(success.Items, Item(l))*/ + } else if line, ok := item.(traffic.Line); ok { + l := convertTrafficLine(line, context, t) + l.GraphThere = LineGraphV1{} + l.GraphBack = LineGraphV1{} + success.Queryables = append(success.Queryables, QueryableV2(l)) } else { // todo error } diff --git a/server/router.go b/server/router.go index da04ad0d535ffcfe19d14104742e7d4c778b5867..91eaf0f910cef201ac284ee2231c2bfc933aa0ab 100644 --- a/server/router.go +++ b/server/router.go @@ -375,7 +375,7 @@ } lines, err1 := traffic.QueryLines(query, cfg.FeedsPath, feedName, versionCode, t) stops, err2 := traffic.QueryStops(query, context, t) if err1 != nil && err2 != nil { - return fmt.Errorf("while querying stops and lines: %w", err) + return fmt.Errorf("while querying stops and lines: %w", errors.Join(err1, err2)) } items := []traffic.Item{} for _, line := range lines { diff --git a/traffic/access.go b/traffic/access.go index 33406a86d15997b3bc43950c83694d54c8e5a7b7..7d8ad43e666814fc12d2cbadea67e40bf254711d 100644 --- a/traffic/access.go +++ b/traffic/access.go @@ -873,6 +873,36 @@ return r.(_Result).FeedInfo, nil } } +func GetTripsByOffset(offsets []uint, context Context, t *Traffic, filter func(Trip) bool) ([]Trip, error) { + trips := []Trip{} + file, err := os.Open(filepath.Join(context.DataHome, context.FeedName, 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 = append(trips, trip) + } + } + return trips, nil +} + func GetTripByOffset(offset uint, context Context, t *Traffic) (Trip, error) { result := _Result{ Filename: "trips.bare", diff --git a/traffic/convert.go b/traffic/convert.go index 6c396ee7802c771c58d66051a8b23b2b1cca28c1..f9dc74a1f211e05258595bdc80287de0db83d793 100644 --- a/traffic/convert.go +++ b/traffic/convert.go @@ -69,6 +69,7 @@ StopsCodeIndex CodeIndex StopsNameIndex map[string][]uint Stops map[string]Stop LineGraphs map[string]map[uint]LineGraph + lineHeadsigns map[string]map[uint][]string LineIndex map[string][]uint ValidFrom time.Time ValidFromError []error @@ -482,8 +483,8 @@ fmt.Sscanf(record[fields["pickup_type"]], "%d", &departure.Pickup) fmt.Sscanf(record[fields["drop_off_type"]], "%d", &departure.Dropoff) tripsThroughStop[stopID] = append(tripsThroughStop[stopID], StopOrder{ - TripID: tripID, - Sequence: departure.StopSequence, + TripID: tripID, + Sequence: departure.StopSequence, }) if c.Feed.Flags().Headsign == HeadsignTripLastStop { @@ -644,7 +645,7 @@ trip.LineName = lineNames[record[fields["route_id"]]] fmt.Sscanf(record[fields["direction_id"]], "%d", &trip.Direction) tripChangeOpts[trip.Id] = ChangeOption{ - LineName: lineNames[record[fields["route_id"]]], + LineName: lineNames[record[fields["route_id"]]], Headsign: trip.Headsign, } @@ -752,7 +753,7 @@ for _, stopTrip := range stopTrips { changeOption := tripChangeOpts[stopTrip.TripID] stopOrder := StopOrder{ TripOffset: tripsOffsets[stopTrip.TripID], - Sequence: stopTrip.Sequence, + Sequence: stopTrip.Sequence, } stop.Order[stopTrip.TripID] = stopOrder changeOptionMap[changeOption.LineName+"->"+changeOption.Headsign] = changeOption @@ -794,15 +795,20 @@ } c.StopsCodeIndex = stopsOffsetsByCode c.StopsNameIndex = stopsOffsetsByName - c.Stops = stops // todo map[stopID]stopCode + c.Stops = stops // todo map[stopID]stopCode return c, nil } -func convertLineGraphs(c feedConverter) (feedConverter, error) { // O(n:stop_times) ; (tripsOffsets, stops -- lineGrapsh:map[lineName]map[direction]graph >> ) +func convertLineGraphs(c feedConverter) (feedConverter, error) { // O(n:stop_times) ; (tripsOffsets, stops -- lineGrapsh:map[lineName]map[direction]graph, lineHeadsigns:map[lineName]map[direction][]headsigns >> ) path := c.TmpFeedPath tripsOffsets := c.TripsOffsets stops := c.Stops + // lineNa dire headsi + lineHeadsignsMap := map[string]map[uint]map[string]struct{}{} + // lineNa dire headsi + lineHeadsigns := map[string]map[uint][]string{} + file, err := os.Open(filepath.Join(path, "stop_times.txt")) if err != nil { return c, fmt.Errorf("while opening stop_times: %w", err) @@ -849,6 +855,16 @@ return c, fmt.Errorf("while seeking: %w", err) } trip := unmarshalTripFromFile(trips) + if _, ok := lineHeadsignsMap[trip.LineName]; !ok { + lineHeadsignsMap[trip.LineName] = map[uint]map[string]struct{}{} + lineHeadsigns[trip.LineName] = map[uint][]string{} + } + if _, ok := lineHeadsignsMap[trip.LineName][trip.Direction.Value()]; !ok { + lineHeadsignsMap[trip.LineName][trip.Direction.Value()] = map[string]struct{}{} + lineHeadsigns[trip.LineName][trip.Direction.Value()] = []string{} + } + lineHeadsignsMap[trip.LineName][trip.Direction.Value()][trip.Headsign] = struct{}{} + if _, ok := graphs[trip.LineName]; !ok { graphs[trip.LineName] = map[uint]LineGraph{} graphs[trip.LineName][0] = LineGraph{ @@ -933,11 +949,20 @@ if !connectionDone { g.NextNodes[previous] = append(g.NextNodes[previous], -1) } + for lineName, directions := range lineHeadsignsMap { + for direction, headsigns := range directions { + for headsign := range headsigns { + lineHeadsigns[lineName][direction] = append(lineHeadsigns[lineName][direction], headsign) + } + } + } + + c.lineHeadsigns = lineHeadsigns c.LineGraphs = graphs return c, nil } -func convertLines(c feedConverter) (feedConverter, error) { // O(n:routes) ; (lineGraphs -- lineIndex:map[lineName][]offsets >> lines) +func convertLines(c feedConverter) (feedConverter, error) { // O(n:routes) ; (lineGraphs, lineHeadsigns -- lineIndex:map[lineName][]offsets >> lines) path := c.TmpFeedPath feed := c.Feed @@ -991,12 +1016,14 @@ colour = "ffffff" } line := Line{ - Id: routeID, - Name: lineName, - Colour: hex2colour(colour), - Kind: LineType(kind), - GraphThere: c.LineGraphs[lineName][0], - GraphBack: c.LineGraphs[lineName][1], + Id: routeID, + Name: lineName, + Colour: hex2colour(colour), + Kind: LineType(kind), + GraphThere: c.LineGraphs[lineName][0], + GraphBack: c.LineGraphs[lineName][1], + HeadsignsThere: c.lineHeadsigns[lineName][0], + HeadsignsBack: c.lineHeadsigns[lineName][1], } if field, present := fields["agency_id"]; present { diff --git a/traffic/structs_gen.go b/traffic/structs_gen.go index 2a2cbfda15f7555fde3f08e186f79c976416f1e8..fb8859898c4991e4c4fc50ce4f4cb0bb5a13738f 100644 --- a/traffic/structs_gen.go +++ b/traffic/structs_gen.go @@ -144,13 +144,15 @@ return bare.Marshal(t) } type Line struct { - Id string `bare:"id"` - Name string `bare:"name"` - Colour Colour `bare:"colour"` - Kind LineType `bare:"kind"` - AgencyID string `bare:"agencyID"` - GraphThere LineGraph `bare:"graphThere"` - GraphBack LineGraph `bare:"graphBack"` + Id string `bare:"id"` + Name string `bare:"name"` + Colour Colour `bare:"colour"` + Kind LineType `bare:"kind"` + AgencyID string `bare:"agencyID"` + HeadsignsThere []string `bare:"headsignsThere"` + HeadsignsBack []string `bare:"headsignsBack"` + GraphThere LineGraph `bare:"graphThere"` + GraphBack LineGraph `bare:"graphBack"` } func (t *Line) Decode(data []byte) error {