Author: Adam Evyčędo <git@apiote.xyz>
adapt API to new realtime
api/api.go | 105 +++++++++++++---------------------------- traffic/access.go | 6 +- traffic/realtime.go | 21 ++++++-- traffic/realtime_gtfs.go | 2 traffic/structs.go | 5 +
diff --git a/api/api.go b/api/api.go index e798463f1504a2cdcf9c4b3dd6975701e8231039..f3b950de9b401a75d64da8dc73582b8ddb74b993 100644 --- a/api/api.go +++ b/api/api.go @@ -153,9 +153,9 @@ return VehicleV1{}, fmt.Errorf("while getting line %s: %w", vehicle.LineName, err) } log.Printf("convertTrafficVehicle:: trafficVehicle: %+v, line: %+v\n", vehicle, line) return VehicleV1{ - Id: string(vehicle.Id), - Position: PositionV1{vehicle.Position.Lat, vehicle.Position.Lon}, - Capabilities: vehicle.Capabilities, + Id: string(vehicle.VehicleID), + Position: PositionV1{vehicle.Latitude, vehicle.Longitude}, + Capabilities: t.Vehicles[string(context.Version)][traffic.Validity(context.FeedID)][vehicle.VehicleID].Capabilities, Speed: vehicle.Speed, Line: LineStubV1{Name: line.Name, Kind: makeLineTypeV1(line), Colour: fromColor(line.Colour)}, Headsign: vehicle.Headsign, @@ -173,9 +173,9 @@ return VehicleV2{}, fmt.Errorf("while getting line %s: %w", vehicle.LineName, err) } log.Printf("convertTrafficVehicle:: trafficVehicle: %+v, line: %+v\n", vehicle, line) return VehicleV2{ - Id: string(vehicle.Id), - Position: PositionV1{vehicle.Position.Lat, vehicle.Position.Lon}, - Capabilities: vehicle.Capabilities, + Id: string(vehicle.VehicleID), + Position: PositionV1{vehicle.Latitude, vehicle.Longitude}, + Capabilities: t.Vehicles[string(context.Version)][traffic.Validity(context.FeedID)][vehicle.VehicleID].Capabilities, Speed: vehicle.Speed, Line: LineStubV2{Name: line.Name, Kind: makeLineTypeV2(line), Colour: fromColor(line.Colour)}, Headsign: vehicle.Headsign, @@ -193,9 +193,9 @@ return VehicleV3{}, fmt.Errorf("while getting line %s: %w", vehicle.LineName, err) } log.Printf("convertTrafficVehicle:: trafficVehicle: %+v, line: %+v\n", vehicle, line) return VehicleV3{ - Id: string(vehicle.Id), - Position: PositionV1{vehicle.Position.Lat, vehicle.Position.Lon}, - Capabilities: vehicle.Capabilities, + Id: string(vehicle.VehicleID), + Position: PositionV1{vehicle.Latitude, vehicle.Longitude}, + Capabilities: t.Vehicles[string(context.Version)][traffic.Validity(context.FeedID)][vehicle.VehicleID].Capabilities, Speed: vehicle.Speed, Line: LineStubV3{Name: line.Name, Kind: makeLineTypeV3(line), Colour: fromColor(line.Colour)}, Headsign: vehicle.Headsign, @@ -499,7 +499,7 @@ success.Locatables = append(success.Locatables, LocatableV1(s)) } else if vehicle, ok := locatable.(traffic.VehicleStatus); ok { v, err := convertTrafficVehicle(vehicle, context, t) if err != nil { - return success, fmt.Errorf("while converting Traffic Vehicle %s: %w", vehicle.Id, err) + return success, fmt.Errorf("while converting Traffic Vehicle %s: %w", vehicle.VehicleID, err) } success.Locatables = append(success.Locatables, LocatableV1(v)) } @@ -523,7 +523,7 @@ success.Locatables = append(success.Locatables, LocatableV2(s)) } else if vehicle, ok := locatable.(traffic.VehicleStatus); ok { v, err := convertTrafficVehicleV2(vehicle, context, t) if err != nil { - return success, fmt.Errorf("while converting Traffic Vehicle %s: %w", vehicle.Id, err) + return success, fmt.Errorf("while converting Traffic Vehicle %s: %w", vehicle.VehicleID, err) } success.Locatables = append(success.Locatables, LocatableV2(v)) } @@ -547,7 +547,7 @@ success.Locatables = append(success.Locatables, LocatableV3(s)) } else if vehicle, ok := locatable.(traffic.VehicleStatus); ok { v, err := convertTrafficVehicleV3(vehicle, context, t) if err != nil { - return success, fmt.Errorf("while converting Traffic Vehicle %s: %w", vehicle.Id, err) + return success, fmt.Errorf("while converting Traffic Vehicle %s: %w", vehicle.VehicleID, err) } success.Locatables = append(success.Locatables, LocatableV3(v)) } @@ -637,45 +637,6 @@ return OCCUPANCY_UNKNOWN } } -func convertVehicle(update traffic.Update, vehicles map[string]traffic.Vehicle, line traffic.Line, headsign string) VehicleV1 { - return VehicleV1{ - Id: update.VehicleID, - Position: PositionV1{Lat: update.Latitude, Lon: update.Longitude}, - Capabilities: vehicles[update.VehicleID].Capabilities, - Speed: update.Speed, - Line: LineStubV1{Name: line.Name, Kind: makeLineTypeV1(line), Colour: fromColor(line.Colour)}, - Headsign: headsign, - // todo CongestionLevel - // todo OccupancyStatus - } -} - -func convertVehicleV2(update traffic.Update, vehicles map[string]traffic.Vehicle, line traffic.Line, headsign string) VehicleV2 { - return VehicleV2{ - Id: update.VehicleID, - Position: PositionV1{Lat: float64(update.Latitude), Lon: float64(update.Longitude)}, - Capabilities: vehicles[update.VehicleID].Capabilities, - Speed: update.Speed, - Line: LineStubV2{Name: line.Name, Kind: makeLineTypeV2(line), Colour: fromColor(line.Colour)}, - Headsign: headsign, - // todo CongestionLevel - // todo OccupancyStatus - } -} - -func convertVehicleV3(update traffic.Update, vehicles map[string]traffic.Vehicle, line traffic.Line, headsign string) VehicleV3 { - return VehicleV3{ - Id: update.VehicleID, - Position: PositionV1{Lat: float64(update.Latitude), Lon: float64(update.Longitude)}, - Capabilities: vehicles[update.VehicleID].Capabilities, - Speed: update.Speed, - Line: LineStubV3{Name: line.Name, Kind: makeLineTypeV3(line), Colour: fromColor(line.Colour)}, - Headsign: headsign, - // todo CongestionLevel - // todo OccupancyStatus - } -} - func CreateSuccessDeparturesV1(stop traffic.Stop, departures []traffic.DepartureRealtime, date time.Time, vehicles map[string]traffic.Vehicle, alerts []traffic.Alert, ctx traffic.Context, t *traffic.Traffic, accept uint, preferredLanguages []language.Tag) (DeparturesResponse, error) { d := []DepartureV1{} var success DeparturesResponse @@ -692,9 +653,9 @@ stopOrder, err := marshalStopOrder(trafficDeparture.Order.TripOffset, trafficDeparture.Order.Sequence) if err != nil { return success, err } - line, err := traffic.GetLine(trafficDeparture.LineName, ctx, t) + vehicle, err := convertTrafficVehicle(trafficDeparture.Update.VehicleStatus, ctx, t) if err != nil { - return success, fmt.Errorf("while getting line %s: %w", trafficDeparture.LineName, err) + return success, fmt.Errorf("while converting vehicle status: %w", err) } departureTime := traffic.GetTimeWithDelay(trafficDeparture) departure := DepartureV1{ @@ -707,15 +668,15 @@ Second: uint8(departureTime.Second()), Zone: zoneAbbr, }, Status: STATUS_IN_TRANSIT, - IsRealtime: trafficDeparture.Update.Delay != nil, - Vehicle: convertVehicle(trafficDeparture.Update, vehicles, line, trafficDeparture.Headsign), + IsRealtime: trafficDeparture.Update.TimetableRelationship != traffic.NO_TRIP_DATA && trafficDeparture.Update.TimetableRelationship != traffic.NOT_REALTIME, + Vehicle: vehicle, Boarding: makeBoardingV1(trafficDeparture.Departure.Pickup, trafficDeparture.Departure.Dropoff), } timeToArrival := departureTime.Sub(datetime).Minutes() if departure.IsRealtime { - departure.Status = convertVehicleStatusV1(trafficDeparture.Update.Status, timeToArrival) - departure.Vehicle.CongestionLevel = convertCongestionLevelV1(trafficDeparture.Update.CongestionLevel) - departure.Vehicle.OccupancyStatus = convertOccupancyStatusV1(trafficDeparture.Update.OccupancyStatus) + departure.Status = convertVehicleStatusV1(trafficDeparture.Update.VehicleStatus.Status, timeToArrival) + departure.Vehicle.CongestionLevel = convertCongestionLevelV1(trafficDeparture.Update.VehicleStatus.CongestionLevel) + departure.Vehicle.OccupancyStatus = convertOccupancyStatusV1(trafficDeparture.Update.VehicleStatus.OccupancyStatus) } d = append(d, departure) } @@ -743,9 +704,9 @@ stopOrder, err := marshalStopOrder(trafficDeparture.Order.TripOffset, trafficDeparture.Order.Sequence) if err != nil { return success, err } - line, err := traffic.GetLine(trafficDeparture.LineName, ctx, t) + vehicle, err := convertTrafficVehicleV2(trafficDeparture.Update.VehicleStatus, ctx, t) if err != nil { - return success, fmt.Errorf("while getting line %s: %w", trafficDeparture.LineName, err) + return success, fmt.Errorf("while converting vehicle status: %w", err) } departureTime := traffic.GetTimeWithDelay(trafficDeparture) departure := DepartureV2{ @@ -758,15 +719,15 @@ Second: uint8(departureTime.Second()), Zone: zoneAbbr, }, Status: STATUS_IN_TRANSIT, - IsRealtime: trafficDeparture.Update.Delay != nil, - Vehicle: convertVehicleV2(trafficDeparture.Update, vehicles, line, trafficDeparture.Headsign), + IsRealtime: trafficDeparture.Update.TimetableRelationship != traffic.NO_TRIP_DATA && trafficDeparture.Update.TimetableRelationship != traffic.NOT_REALTIME, + Vehicle: vehicle, Boarding: makeBoardingV1(trafficDeparture.Departure.Pickup, trafficDeparture.Departure.Dropoff), } timeToArrival := departureTime.Sub(datetime).Minutes() if departure.IsRealtime { - departure.Status = convertVehicleStatusV1(trafficDeparture.Update.Status, timeToArrival) - departure.Vehicle.CongestionLevel = convertCongestionLevelV1(trafficDeparture.Update.CongestionLevel) - departure.Vehicle.OccupancyStatus = convertOccupancyStatusV1(trafficDeparture.Update.OccupancyStatus) + departure.Status = convertVehicleStatusV1(trafficDeparture.Update.VehicleStatus.Status, timeToArrival) + departure.Vehicle.CongestionLevel = convertCongestionLevelV1(trafficDeparture.Update.VehicleStatus.CongestionLevel) + departure.Vehicle.OccupancyStatus = convertOccupancyStatusV1(trafficDeparture.Update.VehicleStatus.OccupancyStatus) } d = append(d, departure) } @@ -794,9 +755,9 @@ stopOrder, err := marshalStopOrder(trafficDeparture.Order.TripOffset, trafficDeparture.Order.Sequence) if err != nil { return success, err } - line, err := traffic.GetLine(trafficDeparture.LineName, ctx, t) + vehicle, err := convertTrafficVehicleV3(trafficDeparture.Update.VehicleStatus, ctx, t) if err != nil { - return success, fmt.Errorf("while getting line %s: %w", trafficDeparture.LineName, err) + return success, fmt.Errorf("while converting vehicle status: %w", err) } departureTime := traffic.GetTimeWithDelay(trafficDeparture) departure := DepartureV3{ @@ -809,15 +770,15 @@ Second: uint8(departureTime.Second()), Zone: zoneAbbr, }, Status: STATUS_IN_TRANSIT, - IsRealtime: trafficDeparture.Update.Delay != nil, - Vehicle: convertVehicleV3(trafficDeparture.Update, vehicles, line, trafficDeparture.Headsign), + IsRealtime: trafficDeparture.Update.TimetableRelationship != traffic.NO_TRIP_DATA && trafficDeparture.Update.TimetableRelationship != traffic.NOT_REALTIME, + Vehicle: vehicle, Boarding: makeBoardingV1(trafficDeparture.Departure.Pickup, trafficDeparture.Departure.Dropoff), } timeToArrival := departureTime.Sub(datetime).Minutes() if departure.IsRealtime { - departure.Status = convertVehicleStatusV1(trafficDeparture.Update.Status, timeToArrival) - departure.Vehicle.CongestionLevel = convertCongestionLevelV1(trafficDeparture.Update.CongestionLevel) - departure.Vehicle.OccupancyStatus = convertOccupancyStatusV1(trafficDeparture.Update.OccupancyStatus) + departure.Status = convertVehicleStatusV1(trafficDeparture.Update.VehicleStatus.Status, timeToArrival) + departure.Vehicle.CongestionLevel = convertCongestionLevelV1(trafficDeparture.Update.VehicleStatus.CongestionLevel) + departure.Vehicle.OccupancyStatus = convertOccupancyStatusV1(trafficDeparture.Update.VehicleStatus.OccupancyStatus) } d = append(d, departure) } diff --git a/traffic/access.go b/traffic/access.go index 6c4202848618de5e909e77fa5f62d0835f291bdd..271e5218cfad43dc678c7183034e1b1b5d92c6d1 100644 --- a/traffic/access.go +++ b/traffic/access.go @@ -835,8 +835,8 @@ return r.(_Result).FeedInfo, nil } } -func GetTripsByOffset(offsets []uint, context Context, t *Traffic, filter func(Trip) bool) ([]Trip, error) { - trips := []Trip{} +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) @@ -859,7 +859,7 @@ if err != nil { return trips, fmt.Errorf("while unmarshalling at %d: %w", offset, err) } if filter(trip) { - trips = append(trips, trip) + trips[offset] = trip } } return trips, nil diff --git a/traffic/realtime.go b/traffic/realtime.go index ecfbbe902b7a44a3abec303fdbd77335c325226b..2a6f7f14b912703a052897956670754098d45393 100644 --- a/traffic/realtime.go +++ b/traffic/realtime.go @@ -19,7 +19,7 @@ TRIP_CANCELED TRIP_DELETED TRIP_ADDED STOP_SKIPPED - NO_DATA + NO_TRIP_DATA ) type Update struct { @@ -38,6 +38,8 @@ Latitude float64 Longitude float64 Speed float32 // m/s Bearing float64 // radians clockwise from north // TODO maybe (-π, π) + LineName string + Headsign string } type CongestionLevel uint @@ -92,8 +94,6 @@ var updates map[string]Update var alerts Alerts var vehicleStatuses map[string]VehicleStatus - -// TODO vehicles cache func getTripID(tripsFile *os.File, offset int64) (string, error) { _, err := tripsFile.Seek(offset, 0) @@ -126,21 +126,30 @@ } midnight := time.Date(datetime.Year(), datetime.Month(), datetime.Day(), 0, 0, 0, 0, timezone) if departuresType == DEPARTURES_HYBRID { + offsets := make([]uint, len(departures)) + for i, departure := range departures { + offsets[i] = departure.Order.TripOffset + } + trips, err := GetTripsByOffset(offsets, ctx, func(Trip) bool { return true }) + if err != nil { + log.Printf("while getting trips: %v\n", err) + } for i, departure := range departures { if departure.Time.After(midnight) { - tripID, err := getTripID(tripsFile, int64(departure.Order.TripOffset)) if err != nil { log.Printf("while getting trip id for %s -> %s (%v): %v\n", departure.LineName, departure.Headsign, departure.Time, err) continue } - update, err := enrichMethod(tripID, departure.Order.Sequence, ctx) + update, err := enrichMethod(trips[departure.Order.TripOffset].Id, departure.Order.Sequence, ctx) if err != nil { - if isTimeout(err) { + if isTimeout(err) { // TODO or any other connection problem break } else { log.Printf("while enriching departure %s -> %s (%v): %v\n", departure.LineName, departure.Headsign, departure.Time, err) } } else { + update.VehicleStatus.LineName = trips[departure.Order.TripOffset].LineName + update.VehicleStatus.Headsign = trips[departure.Order.TripOffset].Headsign enrichedDepartures[i] = departure.WithUpdate(update) } } diff --git a/traffic/realtime_gtfs.go b/traffic/realtime_gtfs.go index 94a8350131bb232277698e15ab97d7af66a8e230..9aee8bd384c480f9c81ce318338fd8d1c77320a2 100644 --- a/traffic/realtime_gtfs.go +++ b/traffic/realtime_gtfs.go @@ -29,7 +29,7 @@ func makeTimetableRelationshipFromStopTrip(r pb.TripUpdate_StopTimeUpdate_ScheduleRelationship) TimetableRelationship { switch r { case pb.TripUpdate_StopTimeUpdate_NO_DATA: - return NO_DATA + return NO_TRIP_DATA case pb.TripUpdate_StopTimeUpdate_SKIPPED: return STOP_SKIPPED default: diff --git a/traffic/structs.go b/traffic/structs.go index 6cdd0a9e773a966bbad232858337ad216f86f471..6f33ff3997a3c1d24735c74695d31a7ad9db4b73 100644 --- a/traffic/structs.go +++ b/traffic/structs.go @@ -53,7 +53,10 @@ // // Congestion // } func (v VehicleStatus) Location() Position { - return v.Position + return Position{ + Lat: v.Latitude, + Lon: v.Longitude, + } } func (k LineType) Value() uint {