Author: Adam <git@apiote.xyz>
use traffic structs from DSL
api/api.go | 62 ++++---- mkfile | 9 server/router.go | 6 traffic/access.go | 81 +++++----- traffic/convert.go | 74 +++++---- traffic/poznan_ztm.go | 2 traffic/structs.go | 83 ++++++----- traffic/structs_gen.go | 314 ++++++++++++++++++++++++++++++++++++++++++++
diff --git a/api/api.go b/api/api.go index 282afc5ffb45cc568cc417d31a4a14e185c7087c..72333af3ec86c830a0c82e95b5dc7d25c48ae670 100644 --- a/api/api.go +++ b/api/api.go @@ -10,7 +10,7 @@ "encoding/hex" "errors" "fmt" - "image/color" + //"image/color" "log" "sort" "time" @@ -41,7 +41,7 @@ s := StopV1{ Code: stop.Code, Name: stop.NodeName, Zone: stop.Zone, - Position: PositionV1{Lat: stop.Coordinates.Lat, Lon: stop.Coordinates.Lon}, + Position: PositionV1{Lat: stop.Position.Lat, Lon: stop.Position.Lon}, ChangeOptions: []ChangeOptionV1{}, } for _, option := range stop.ChangeOptions { @@ -57,7 +57,7 @@ Name: stop.Name, NodeName: stop.NodeName, Zone: stop.Zone, FeedID: feedID, - Position: PositionV1{Lat: stop.Coordinates.Lat, Lon: stop.Coordinates.Lon}, + Position: PositionV1{Lat: stop.Position.Lat, Lon: stop.Position.Lon}, ChangeOptions: []ChangeOptionV1{}, } for _, option := range stop.ChangeOptions { @@ -173,7 +173,7 @@ return l, nil } -func convertTrafficVehicle(vehicle traffic.Vehicle, context traffic.Context, t *traffic.Traffic) (VehicleV1, error) { +func convertTrafficVehicle(vehicle traffic.VehicleStatus, context traffic.Context, t *traffic.Traffic) (VehicleV1, error) { line, err := traffic.GetLine(vehicle.LineName, context, t) if err != nil { return VehicleV1{}, fmt.Errorf("while getting line %s: %w", vehicle.LineName, err) @@ -181,7 +181,7 @@ } log.Printf("convertTrafficVehicle:: trafficVehicle: %+v, line: %+v\n", vehicle, line) return VehicleV1{ Id: string(vehicle.Id), - Position: PositionV1{vehicle.Coordinates.Lat, vehicle.Coordinates.Lon}, + Position: PositionV1{vehicle.Position.Lat, vehicle.Position.Lon}, Capabilities: vehicle.Capabilities, Speed: vehicle.Speed, Line: LineStubV1{Name: line.Name, Kind: makeLineTypeV1(line), Colour: fromColor(line.Colour)}, @@ -193,7 +193,7 @@ // todo Delay }, nil } -func convertTrafficVehicleV2(vehicle traffic.Vehicle, context traffic.Context, t *traffic.Traffic) (VehicleV2, error) { +func convertTrafficVehicleV2(vehicle traffic.VehicleStatus, context traffic.Context, t *traffic.Traffic) (VehicleV2, error) { line, err := traffic.GetLine(vehicle.LineName, context, t) if err != nil { return VehicleV2{}, fmt.Errorf("while getting line %s: %w", vehicle.LineName, err) @@ -201,7 +201,7 @@ } log.Printf("convertTrafficVehicle:: trafficVehicle: %+v, line: %+v\n", vehicle, line) return VehicleV2{ Id: string(vehicle.Id), - Position: PositionV1{vehicle.Coordinates.Lat, vehicle.Coordinates.Lon}, + Position: PositionV1{vehicle.Position.Lat, vehicle.Position.Lon}, Capabilities: vehicle.Capabilities, Speed: vehicle.Speed, Line: LineStubV2{Name: line.Name, Kind: makeLineTypeV2(line), Colour: fromColor(line.Colour)}, @@ -229,7 +229,7 @@ func marshalStopOrder(tripOffset uint, stopOrder int) (string, error) { order := traffic.StopOrder{ TripOffset: tripOffset, - Order: stopOrder, + Sequence: stopOrder, } bytes, err := bare.Marshal(&order) return hex.EncodeToString(bytes), err @@ -378,7 +378,7 @@ for _, locatable := range locatables { if stop, ok := locatable.(traffic.Stop); ok { s := convertTrafficStop(stop) success.Locatables = append(success.Locatables, LocatableV1(s)) - } else if vehicle, ok := locatable.(traffic.Vehicle); ok { + } 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) @@ -402,7 +402,7 @@ for _, locatable := range locatables { if stop, ok := locatable.(traffic.Stop); ok { s := convertTrafficStopV2(stop, context.FeedName) success.Locatables = append(success.Locatables, LocatableV2(s)) - } else if vehicle, ok := locatable.(traffic.Vehicle); ok { + } 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) @@ -434,11 +434,11 @@ return success, nil*/ } -func convertVehicle(update gtfs_rt.Update, vehicles map[traffic.ID]traffic.Vehicle, line traffic.Line, headsign string) VehicleV1 { +func convertVehicle(update gtfs_rt.Update, vehicles map[string]traffic.Vehicle, line traffic.Line, headsign string) VehicleV1 { return VehicleV1{ Id: update.VehicleID, Position: PositionV1{Lat: float64(update.Latitude), Lon: float64(update.Longitude)}, - Capabilities: vehicles[traffic.ID(update.VehicleID)].Capabilities, + Capabilities: vehicles[update.VehicleID].Capabilities, Speed: update.Speed, Line: LineStubV1{Name: line.Name, Kind: makeLineTypeV1(line), Colour: fromColor(line.Colour)}, Headsign: headsign, @@ -447,11 +447,11 @@ // todo OccupancyStatus } } -func convertVehicleV2(update gtfs_rt.Update, vehicles map[traffic.ID]traffic.Vehicle, line traffic.Line, headsign string) VehicleV2 { +func convertVehicleV2(update gtfs_rt.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[traffic.ID(update.VehicleID)].Capabilities, + Capabilities: vehicles[update.VehicleID].Capabilities, Speed: update.Speed, Line: LineStubV2{Name: line.Name, Kind: makeLineTypeV2(line), Colour: fromColor(line.Colour)}, Headsign: headsign, @@ -461,7 +461,7 @@ } } func CreateSuccessDeparturesV1(stop traffic.Stop, departures []traffic.DepartureRealtime, - date time.Time, vehicles map[traffic.ID]traffic.Vehicle, alerts []traffic.Alert, ctx traffic.Context, t *traffic.Traffic, accept uint) (DeparturesResponse, error) { + date time.Time, vehicles map[string]traffic.Vehicle, alerts []traffic.Alert, ctx traffic.Context, t *traffic.Traffic, accept uint) (DeparturesResponse, error) { d := []DepartureV1{} var success DeparturesResponse now := time.Now() @@ -473,7 +473,7 @@ datetime := time.Date(date.Year(), date.Month(), date.Day(), now.Hour(), now.Minute(), now.Second(), 0, timezone) for _, trafficDeparture := range departures { zoneAbbr := trafficDeparture.Update.Time.Location().String() - stopOrder, err := marshalStopOrder(trafficDeparture.Order.TripOffset, trafficDeparture.Order.Order) + stopOrder, err := marshalStopOrder(trafficDeparture.Order.TripOffset, trafficDeparture.Order.Sequence) if err != nil { return success, err } @@ -546,7 +546,7 @@ return success, nil } func CreateSuccessDeparturesV2(stop traffic.Stop, departures []traffic.DepartureRealtime, - date time.Time, vehicles map[traffic.ID]traffic.Vehicle, alerts []traffic.Alert, ctx traffic.Context, t *traffic.Traffic, accept uint) (DeparturesResponse, error) { + date time.Time, vehicles map[string]traffic.Vehicle, alerts []traffic.Alert, ctx traffic.Context, t *traffic.Traffic, accept uint) (DeparturesResponse, error) { d := []DepartureV2{} var success DeparturesResponse now := time.Now() @@ -558,7 +558,7 @@ datetime := time.Date(date.Year(), date.Month(), date.Day(), now.Hour(), now.Minute(), now.Second(), 0, timezone) for _, trafficDeparture := range departures { zoneAbbr := trafficDeparture.Update.Time.Location().String() - stopOrder, err := marshalStopOrder(trafficDeparture.Order.TripOffset, trafficDeparture.Order.Order) + stopOrder, err := marshalStopOrder(trafficDeparture.Order.TripOffset, trafficDeparture.Order.Sequence) if err != nil { return success, err } @@ -630,7 +630,7 @@ } return success, nil } -func fromColor(c color.RGBA) ColourV1 { +func fromColor(c traffic.Colour) ColourV1 { return ColourV1{ R: c.R, G: c.G, @@ -639,9 +639,9 @@ } } func makeLineTypeV1(line traffic.Line) LineTypeV1 { - if line.Type == 0 { + if line.Kind == traffic.TRAM { return TRAM - } else if line.Type == 3 { + } else if line.Kind == traffic.BUS { return BUS } else { return LINE_UNKNOWN @@ -649,11 +649,11 @@ } } func makeLineTypeV2(line traffic.Line) LineTypeV2 { - if line.Type == 0 { + if line.Kind == traffic.TRAM { return LINE_V2_TRAM - } else if line.Type == 3 { + } else if line.Kind == traffic.BUS { return LINE_V2_BUS - } else if line.Type == 11 { + } else if line.Kind == traffic.TROLLEYBUS { return LINE_V2_TROLLEYBUS } else { return LINE_V2_UNKNOWN @@ -667,20 +667,20 @@ Headsign: option.Headsign, } } -func makeBoardingV1(pickup, dropoff uint) uint8 { +func makeBoardingV1(pickup, dropoff traffic.Boarding) uint8 { b := BOARDING_NONE - if pickup == 0 { + if pickup == traffic.REGULAR { b |= ONBOARDING_REGULAR - } else if pickup == 2 { + } else if pickup == traffic.BY_PHONE { b |= ONBOARDING_PHONE - } else if pickup == 3 { + } else if pickup == traffic.BY_DRIVER { b |= ONBOARDING_DRIVER } - if dropoff == 0 { + if dropoff == traffic.REGULAR { b |= OFFBOARDING_REGULAR - } else if dropoff == 2 { + } else if dropoff == traffic.BY_PHONE { b |= OFFBOARDING_PHONE - } else if dropoff == 3 { + } else if dropoff == traffic.BY_DRIVER { b |= OFFBOARDING_DRIVER } return uint8(b) diff --git a/mkfile b/mkfile index db35f09ce4ce2a93d899cc44161f7ff08912200d..2117ab05ae5dfbfe4ab578399fc7ea23805fb286 100644 --- a/mkfile +++ b/mkfile @@ -1,13 +1,13 @@ ALL=`echo api/* config/* file/* gtfs_rt/* main.go server/* traffic/* transformers/*` -all:V: bimba_server +all:V: szczanieckiej -init:V: api/structs_gen.go +init:V: api/structs_gen.go traffic/structs_gen.go lint:V: golangci-lint -j 2 run --fast --timeout 30m --skip-files '(gtfs-realtime.pb.go|structs_gen.go)' -E asasalint -E asciicheck -E bidichk -E bodyclose -E contextcheck -E decorder -E dupl -E durationcheck -E errcheck -E errname -E errorlint -E exhaustive -E exhaustruct -E exportloopref -E gocritic -E gofmt -E goimports -E gofumpt -E gomnd -E gomoddirectives -E gosec -E gosimple -E govet -E importas -E ineffassign -E interfacer -E ireturn -E loggercheck -E misspell -E nilerr -E nilnil -E noctx -E nolintlint -E prealloc -E predeclared -E reassign -E revive -E staticcheck -E stylecheck -E tagliatelle -E unconvert -E unparam -E unused -E usestdlibvars -E wastedassign -E wrapcheck -D containedctx -D cyclop -D deadcode -D depguard -D dogsled -D dupword -D errchkjson -D execinquery -D exhaustivestruct -D forbidigo -D forcetypeassert -D funlen -D gci -D ginkgolinter -D gocheckcompilerdirectives -D gochecknoglobals -D gochecknoinits -D gocognit -D goconst -D gocyclo -D godox -D goerr113 -D goheader -D golint -D gomodguard -D goprintffuncname -D grouper -D ifshort -D interfacebloat -D lll -D maintidx -D makezero -D maligned -D musttag -D nestif -D nlreturn -D nonamedreturns -D nosnakecase -D nosprintfhostport -D paralleltest -D promlinter -D testpackage -D typecheck -D varnamelen -D whitespace -D wsl -bimba_server: $ALL +szczanieckiej: $ALL go build api/structs_gen.go: ../traffic/api/api.bare @@ -15,3 +15,6 @@ bare-gen -p api ../traffic/api/api.bare api/structs_gen2.go awk '!seen[$0]++ || $0 !~ /func \(_ StopV1\) IsUnion\(\) \{\}/' api/structs_gen2.go >api/structs_gen3.go awk '!seen[$0]++ || $0 !~ /func \(_ StopV2\) IsUnion\(\) \{\}/' api/structs_gen3.go >api/structs_gen.go rm api/structs_gen2.go api/structs_gen3.go + +traffic/structs_gen.go: ../traffic/traffic.bare + bare-gen -p traffic ../traffic/traffic.bare traffic/structs_gen.go diff --git a/server/router.go b/server/router.go index 84c4a432f7143949bdc7e26efd85f45f7ce67a1e..da04ad0d535ffcfe19d14104742e7d4c778b5867 100644 --- a/server/router.go +++ b/server/router.go @@ -351,7 +351,7 @@ return fmt.Errorf("while creating stopsSuccess from near stops: %w", err) } } else { ix := t.CodeIndexes[feedName][versionCode] - code := traffic.ID(query) + code := query _, exists := ix[code] if exists { stop, err := traffic.GetStop(code, context, t) @@ -420,7 +420,7 @@ err := r.ParseForm() if err != nil { return fmt.Errorf("while parsing form: %w", err) } - code := traffic.ID(r.Form.Get("code")) + code := r.Form.Get("code") if code == "" { return ServerError{ code: http.StatusBadRequest, @@ -569,7 +569,7 @@ FeedName: feedName, Version: versionCode, } - trip, err := traffic.GetTripFromStop(tripID, traffic.ID(stopCode), context, t) + trip, err := traffic.GetTripFromStop(tripID, stopCode, context, t) if err != nil { return fmt.Errorf("while getting line: %w", err) } diff --git a/traffic/access.go b/traffic/access.go index 7fbd3560db527c48871124959d2b3b76f7a03a9b..33406a86d15997b3bc43950c83694d54c8e5a7b7 100644 --- a/traffic/access.go +++ b/traffic/access.go @@ -87,7 +87,7 @@ date := time.Format(DateFormat) for _, schedule := range calendar { if schedule.StartDate <= date && date <= schedule.EndDate && (schedule.Weekdays&weekday != 0) { - schedules[schedule.ScheduleID] = struct{}{} + schedules[schedule.Id] = struct{}{} } } var err error @@ -254,7 +254,7 @@ func readTrips(input ...interface{}) (interface{}, error) { result := input[0].(_Result) trips := map[string]Trip{} - orders := []StopOrder{} + orders := map[string]StopOrder{} for _, order := range result.Stop.Order { _, err := result.TripsFile.Seek(int64(order.TripOffset), 0) @@ -270,9 +270,9 @@ _, inToday := result.TodaySchedule[trip.ScheduleID] _, inYesterday := result.YesterdaySchedule[trip.ScheduleID] if inToday || inYesterday { - trips[trip.ID] = trip - order.TripID = trip.ID - orders = append(orders, order) + trips[trip.Id] = trip + order.TripID = trip.Id + orders[trip.Id] = order } } result.Stop.Order = orders @@ -318,7 +318,7 @@ found := false departureRt := DepartureRealtime{} var finalErr error for _, departure := range trip.Departures { - if departure.StopSeq == order.Order { + if departure.StopSequence == order.Sequence { departureRt.Departure = departure departureRt.Headsign = trip.Headsign @@ -336,7 +336,7 @@ if departureTime.After(result.Midnight) { if result.DeparturesType == DEPARTURES_HYBRID && !timedOut { departureRt.Update, err = getRealtimeOffset(order.TripID, - order.Order, feed) + order.Sequence, feed) if err != nil { if isTimeout(err) { timedOut = true @@ -359,8 +359,8 @@ } } if !found { return departureRt, traffic_errors.NoStopOrder{ - TripID: trip.ID, - Order: order.Order, + TripID: trip.Id, + Order: order.Sequence, } } return departureRt, finalErr @@ -439,7 +439,7 @@ v, err := r.ReadUint() if err != nil { return ix, fmt.Errorf("while reading value at %d: %w\n", i, err) } - ix[ID(k)] = uint(v) + ix[k] = uint(v) } return ix, nil @@ -619,6 +619,7 @@ return feedPositionIndex, fmt.Errorf("while unmarshaling: %w", err) } } stop.Name = "" + stop.NodeName = "" stop.ChangeOptions = nil stop.Zone = "" stop.Order = nil @@ -646,6 +647,7 @@ } func Initialise(sigChan chan os.Signal, doneChan chan bool, cfg config.Config, traffic *Traffic) { + bare.MaxMapSize(8192) for { sig := <-sigChan if sig == os.Interrupt { @@ -712,7 +714,7 @@ } doneChan <- true } -func GetDepartures(stopCode ID, lineName, dataHome, feedName string, +func GetDepartures(stopCode string, lineName, dataHome, feedName string, versionCode Validity, traffic *Traffic, date time.Time, departuresType DeparturesType) ([]DepartureRealtime, error) { @@ -758,7 +760,7 @@ } } -func GetTripFromStop(tripID string, stopCode ID, context Context, traffic *Traffic) ([]TimedStopStub, error) { +func GetTripFromStop(tripID string, stopCode string, context Context, traffic *Traffic) ([]TimedStopStub, error) { stubs := []TimedStopStub{} var ( @@ -776,12 +778,9 @@ return stubs, fmt.Errorf("while getting starting stop: %w", err) } tripOffset := -1 order = -1 - for _, o := range startingStop.Order { - if o.TripID == tripID { - tripOffset = int(o.TripOffset) - order = o.Order - } - } + o := startingStop.Order[tripID] + tripOffset = int(o.TripOffset) + order = o.Sequence if tripOffset == -1 { return stubs, fmt.Errorf("trip for starting stop not found") } @@ -797,7 +796,7 @@ } } for _, departure := range trip.Departures { - if departure.StopSeq >= order { + if departure.StopSequence >= order { stop, err := getStopByOffset(uint(departure.StopOffset), context, traffic) if err != nil { return stubs, fmt.Errorf("while getting stop: %w", err) @@ -810,7 +809,7 @@ StopStub: StopStub{ Code: stop.Code, Name: stop.Name, Zone: stop.Zone, - OnDemand: departure.Pickup == 3, // todo BAF10 + OnDemand: departure.Pickup == BY_DRIVER || departure.Dropoff == BY_DRIVER, }, Time: time, }) @@ -892,12 +891,12 @@ return r.(_Result).Trip, nil } } -func GetStop(stopCode ID, context Context, traffic *Traffic) (Stop, error) { +func GetStop(stopCode string, context Context, traffic *Traffic) (Stop, error) { codeIndex := traffic.CodeIndexes[context.FeedName][context.Version] return getStopByOffset(codeIndex[stopCode], context, traffic) } -func GetStopStub(stopCode ID, lineName string, context Context, traffic *Traffic) (StopStub, error) { +func GetStopStub(stopCode string, lineName string, context Context, traffic *Traffic) (StopStub, error) { stop, err := GetStop(stopCode, context, traffic) if err != nil { return StopStub{}, err @@ -909,7 +908,7 @@ for _, order := range stop.Order { offset := order.TripOffset trip, _ = GetTripByOffset(offset, context, traffic) if trip.LineName == lineName { - stopOrder = order.Order + stopOrder = order.Sequence break } } @@ -918,7 +917,7 @@ stopStub := StopStub{ Code: stop.Code, Name: stop.Name, Zone: stop.Zone, - OnDemand: trip.Departures[stopOrder].Pickup == 3, // todo BAF10 + OnDemand: trip.Departures[stopOrder].Pickup == BY_DRIVER || trip.Departures[stopOrder].Dropoff == BY_DRIVER, } return stopStub, nil } @@ -991,7 +990,7 @@ positionIndex := traffic.PositionIndexes[context.FeedName][context.Version] codeIndex := traffic.CodeIndexes[context.FeedName][context.Version] spatials := positionIndex.NearestNeighbors(12, rtreego.Point{location.Lat, location.Lon}) for _, spatial := range spatials { - stop, err := getStopByOffset(codeIndex[ID(spatial.(Stop).Code)], context, traffic) + stop, err := getStopByOffset(codeIndex[spatial.(Stop).Code], context, traffic) if err != nil { return stops, fmt.Errorf("while getting stop by offset for %s: %w", spatial.(Stop).Code, err) } @@ -1014,8 +1013,8 @@ return []Alert{}, fmt.Errorf("while geting alerts: %w", err) } lastUpdatedGtfsRt[feed.String()] = lastUpdated - stop, err := GetStop(ID(stopCode), context, traffic) - for _, pos := range gtfsAlerts.ByStop[stop.ID] { + stop, err := GetStop(stopCode, context, traffic) + for _, pos := range gtfsAlerts.ByStop[stop.Id] { alertPositions[pos] = struct{}{} } for _, option := range stop.ChangeOptions { @@ -1023,10 +1022,10 @@ line, err := GetLine(option.LineName, context, traffic) if err != nil { return []Alert{}, fmt.Errorf("while getting line %s: %w", option.LineName, err) } - for _, pos := range gtfsAlerts.ByRoute[line.ID] { + for _, pos := range gtfsAlerts.ByRoute[line.Id] { alertPositions[pos] = struct{}{} } - for _, pos := range gtfsAlerts.ByType[line.Type] { + for _, pos := range gtfsAlerts.ByType[line.Kind.Value()] { alertPositions[pos] = struct{}{} } } @@ -1035,7 +1034,7 @@ trip, err := GetTripByOffset(order.TripOffset, context, traffic) if err != nil { return []Alert{}, fmt.Errorf("while getting trip at %d: %w", order.TripOffset, err) } - for _, pos := range gtfsAlerts.ByTrip[trip.ID] { + for _, pos := range gtfsAlerts.ByTrip[trip.Id] { alertPositions[pos] = struct{}{} } } @@ -1132,25 +1131,25 @@ err = file.CleanOldVersions(FeedPath(cfg, feed), validVersionsMap) return err } -func convertVehicle(update gtfs_rt.Update, context Context, t *Traffic) (Vehicle, error) { +func convertVehicle(update gtfs_rt.Update, context Context, t *Traffic) (VehicleStatus, error) { vehicles := t.Vehicles[context.FeedName][context.Version] tripID := update.TripUpdate.GetTrip().GetTripId() trip, err := GetTrip(tripID, context, t) if err != nil { - return Vehicle{}, fmt.Errorf("while converting vehicle: %w", err) + return VehicleStatus{}, fmt.Errorf("while converting vehicle: %w", err) } - return Vehicle{ - Id: ID(update.VehicleID), - Coordinates: Position{float64(update.Latitude), float64(update.Longitude)}, - Capabilities: vehicles[ID(update.VehicleID)].Capabilities, + return VehicleStatus{ + Id: update.VehicleID, + Position: Position{float64(update.Latitude), float64(update.Longitude)}, + Capabilities: vehicles[update.VehicleID].Capabilities, Speed: update.Speed, Headsign: trip.Headsign, LineName: trip.LineName, }, nil } -func GetVehicle(tripID string, context Context, t *Traffic) (Vehicle, error) { - vehicle := Vehicle{} +func GetVehicle(tripID string, context Context, t *Traffic) (VehicleStatus, error) { + vehicle := VehicleStatus{} update, err := getRealtimeOffset(tripID, 0, t.Feeds[context.FeedName]) if err != nil { return vehicle, fmt.Errorf("while getting realtime update: %w", err) @@ -1173,7 +1172,7 @@ return stops, fmt.Errorf("while creating a rect: %w", err) } spatials := positionIndex.SearchIntersect(rect) for _, spatial := range spatials { - stop, err := getStopByOffset(codeIndex[ID(spatial.(Stop).Code)], context, traffic) + stop, err := getStopByOffset(codeIndex[spatial.(Stop).Code], context, traffic) if err != nil { return stops, fmt.Errorf("while getting stop by offset for %s: %w", spatial.(Stop).Code, err) } @@ -1182,9 +1181,9 @@ } return stops, nil } -func GetVehiclesIn(lb, rt Position, context Context, t *Traffic) ([]Vehicle, error) { +func GetVehiclesIn(lb, rt Position, context Context, t *Traffic) ([]VehicleStatus, error) { // todo limit rect size - vehicles := []Vehicle{} + vehicles := []VehicleStatus{} updates, err := getRealtimeUpdates(t.Feeds[context.FeedName]) if err != nil { return vehicles, err diff --git a/traffic/convert.go b/traffic/convert.go index c8456d4d4fa983cda021547b19779cbc4fc03fb7..6c396ee7802c771c58d66051a8b23b2b1cca28c1 100644 --- a/traffic/convert.go +++ b/traffic/convert.go @@ -11,7 +11,7 @@ "bufio" "encoding/csv" "errors" "fmt" - "image/color" + //"image/color" "io" "io/fs" "log" @@ -80,11 +80,11 @@ } // helper functions -func hex2colour(hex string) color.RGBA { +func hex2colour(hex string) Colour { if hex[0] == '#' { hex = hex[1:] } - colour := color.RGBA{ + colour := Colour{ A: 0xff, } hexToByte := func(b byte) byte { @@ -305,7 +305,7 @@ } if err != nil { return c, fmt.Errorf("while reading a record: %w", err) } - schedule.ScheduleID = record[fields["service_id"]] + schedule.Id = record[fields["service_id"]] startDate := record[fields["start_date"]] endDate := record[fields["end_date"]] schedule.StartDate = startDate[:4] + "-" + startDate[4:6] + "-" + startDate[6:] @@ -390,7 +390,7 @@ return c, fmt.Errorf("while reading a record: %w", err) } if record[fields["exception_type"]] == "1" { date := record[fields["date"]] - schedule.ScheduleID = record[fields["service_id"]] + schedule.Id = record[fields["service_id"]] schedule.StartDate = date[:4] + "-" + date[4:6] + "-" + date[6:] schedule.EndDate = date[:4] + "-" + date[4:6] + "-" + date[6:] schedule.Weekdays = 0xff @@ -477,13 +477,13 @@ stopID := record[fields["stop_id"]] tripID := record[fields["trip_id"]] - fmt.Sscanf(record[fields["stop_sequence"]], "%d", &departure.StopSeq) + fmt.Sscanf(record[fields["stop_sequence"]], "%d", &departure.StopSequence) 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, - Order: departure.StopSeq, + Sequence: departure.StopSequence, }) if c.Feed.Flags().Headsign == HeadsignTripLastStop { @@ -630,21 +630,21 @@ if err != nil { return c, fmt.Errorf("while reading a record: %w", err) } - trip.ID = record[fields["trip_id"]] + trip.Id = record[fields["trip_id"]] switch c.Feed.Flags().Headsign { case HeadsignTripHeadsing: trip.Headsign = record[fields["trip_headsign"]] case HeadsignTripLastStop: - trip.Headsign = c.stopNames[c.tripHeadsigns[trip.ID]] + trip.Headsign = c.stopNames[c.tripHeadsigns[trip.Id]] } - trip.Departures = departures[trip.ID] + trip.Departures = departures[trip.Id] trip.ScheduleID = record[fields["service_id"]] trip.LineName = lineNames[record[fields["route_id"]]] fmt.Sscanf(record[fields["direction_id"]], "%d", &trip.Direction) - tripChangeOpts[trip.ID] = ChangeOption{ - LineID: record[fields["route_id"]], + tripChangeOpts[trip.Id] = ChangeOption{ + LineName: lineNames[record[fields["route_id"]]], Headsign: trip.Headsign, } @@ -656,7 +656,7 @@ b, err := result.Write(bytes) if err != nil { return c, fmt.Errorf("while writing: %w", err) } - tripsOffsets[trip.ID] = offset + tripsOffsets[trip.Id] = offset offset += uint(b) } @@ -668,7 +668,6 @@ func convertStops(c feedConverter) (feedConverter, error) { // O(n:stops) ; (tripsThroughStop, lineNames, tripChangeOpts, tripOffsets -- stopsOffsetsByCode:CodeIndex, stopsOffsetsByName:map[name][]offsets >> stops) path := c.TmpFeedPath tripsThroughStop := c.TripsThroughStop - lineNames := c.LineNames tripChangeOpts := c.TripChangeOpts tripsOffsets := c.TripsOffsets @@ -699,6 +698,8 @@ stopsOffsetsByName := map[string][]uint{} stopsOffsetsByCode := CodeIndex{} stops := map[string]Stop{} + maxStopTripsLength := 0 + for { stop := Stop{} record, err := r.Read() @@ -712,8 +713,12 @@ stopID := record[fields["stop_id"]] stopTrips := tripsThroughStop[stopID] + stopTripsLength := len(stopTrips) + if maxStopTripsLength < stopTripsLength { + maxStopTripsLength = stopTripsLength + } - stop.ID = stopID + stop.Id = stopID templates := []string{"stop_code", "stop_id", "stop_name"} stop.Code = c.Feed.Flags().StopIdFormat @@ -738,21 +743,18 @@ var lat, lon float64 fmt.Sscanf(record[fields["stop_lat"]], "%f", &lat) fmt.Sscanf(record[fields["stop_lon"]], "%f", &lon) - stop.Coordinates = Position{lat, lon} + stop.Position = Position{lat, lon} changeOptionMap := map[string]ChangeOption{} stop.ChangeOptions = []ChangeOption{} - stop.Order = []StopOrder{} + stop.Order = map[string]StopOrder{} for _, stopTrip := range stopTrips { - changeOption := ChangeOption{ - LineName: lineNames[tripChangeOpts[stopTrip.TripID].LineID], - Headsign: tripChangeOpts[stopTrip.TripID].Headsign, - } + changeOption := tripChangeOpts[stopTrip.TripID] stopOrder := StopOrder{ TripOffset: tripsOffsets[stopTrip.TripID], - Order: stopTrip.Order, + Sequence: stopTrip.Sequence, } - stop.Order = append(stop.Order, stopOrder) + stop.Order[stopTrip.TripID] = stopOrder changeOptionMap[changeOption.LineName+"->"+changeOption.Headsign] = changeOption } for _, option := range changeOptionMap { @@ -782,13 +784,17 @@ if err != nil { return c, fmt.Errorf("while writing: %w", err) } stopsOffsetsByName[stop.Name] = append(stopsOffsetsByName[stop.Name], offset) - stopsOffsetsByCode[ID(stop.Code)] = offset + stopsOffsetsByCode[stop.Code] = offset offset += uint(b) } + if maxStopTripsLength > 8192 { + log.Printf("maximum length of StopOrder is %d, more than 8192, which may need to be tweaked", maxStopTripsLength) + } + c.StopsCodeIndex = stopsOffsetsByCode c.StopsNameIndex = stopsOffsetsByName - c.Stops = stops + c.Stops = stops // todo map[stopID]stopCode return c, nil } @@ -858,7 +864,7 @@ if previousTripID != tripID { if previousTripID != "" { // last of previous trip - previousGraph := graphs[previousTrip.LineName][previousTrip.Direction] + previousGraph := graphs[previousTrip.LineName][previousTrip.Direction.Value()] connectionDone := false for _, n := range previousGraph.NextNodes[previous] { if n == -1 { @@ -868,11 +874,11 @@ } if !connectionDone { previousGraph.NextNodes[previous] = append(previousGraph.NextNodes[previous], -1) } - graphs[previousTrip.LineName][previousTrip.Direction] = previousGraph + graphs[previousTrip.LineName][previousTrip.Direction.Value()] = previousGraph } } - graph := graphs[trip.LineName][trip.Direction] + graph := graphs[trip.LineName][trip.Direction.Value()] current := -1 for i, code := range graph.StopCodes { if code == stop.Code { @@ -913,10 +919,10 @@ previous = current previousTripID = tripID previousTrip = trip - graphs[trip.LineName][trip.Direction] = graph + graphs[trip.LineName][trip.Direction.Value()] = graph } - g := graphs[previousTrip.LineName][previousTrip.Direction] + g := graphs[previousTrip.LineName][previousTrip.Direction.Value()] connectionDone := false for _, n := range g.NextNodes[previous] { if n == -1 { @@ -985,16 +991,16 @@ colour = "ffffff" } line := Line{ - ID: routeID, + Id: routeID, Name: lineName, Colour: hex2colour(colour), - Type: kind, + Kind: LineType(kind), GraphThere: c.LineGraphs[lineName][0], GraphBack: c.LineGraphs[lineName][1], } if field, present := fields["agency_id"]; present { - line.AgencyID = ID(record[field]) + line.AgencyID = record[field] } bytes, err := bare.Marshal(&line) @@ -1115,7 +1121,7 @@ return fmt.Errorf("while reading a record: %w", err) } agency := Agency{ - ID: ID(record[fields["agency_id"]]), + Id: record[fields["agency_id"]], Name: record[fields["agency_name"]], Website: record[fields["agency_url"]], Timezone: record[fields["agency_timezone"]], diff --git a/traffic/poznan_ztm.go b/traffic/poznan_ztm.go index 83a1153840637fe625350d9667c25e0dae729f2f..fab3fade1b39c58903819def516c639cf9408275 100644 --- a/traffic/poznan_ztm.go +++ b/traffic/poznan_ztm.go @@ -94,7 +94,7 @@ capabilites |= 0b1000_0000 } vehicle := Vehicle{ - Id: ID(record[0]), + Id: record[0], Capabilities: capabilites, } diff --git a/traffic/structs.go b/traffic/structs.go index dfd36966a1a64e112b83754ed69f9e9ed9e14baf..eec7e43349a5ce8857a165ed0cf8bb076d67f0c6 100644 --- a/traffic/structs.go +++ b/traffic/structs.go @@ -3,7 +3,7 @@ import ( "apiote.xyz/p/szczanieckiej/gtfs_rt" - "image/color" + //"image/color" "strings" "time" @@ -17,14 +17,14 @@ DEPARTURES_HYBRID DeparturesType = iota DEPARTURES_FULL ) -type Position struct { +/*type Position struct { Lat float64 Lon float64 -} +}*/ // todo(BAF10) change IDs to type ID, string to type OLC -type Agency struct { +/*type Agency struct { ID ID Name string Website string @@ -33,18 +33,18 @@ PhoneNumber string // todo(BAF10) PhoneNumber Language string // todo(BAF10) language.Tag Email string FareWebsite string -} +}*/ -type FeedInfo struct { +/*type FeedInfo struct { Name string Website string Language string // todo(BAF10) language.Tag -} +}*/ -type Vehicle struct { // todo(BAF10) two types of vehicles — descriptions ID-Capabilities, and an actual vehicle that runs on a trip - Id ID +type VehicleStatus struct { // todo(BAF10) two types of vehicles — descriptions ID-Capabilities, and an actual vehicle that runs on a trip + Id string Capabilities uint16 - Coordinates Position + Position Position Speed float32 Delay int32 // todo(BAF31) LineName string @@ -54,17 +54,25 @@ // Occupancy // Congestion } -func (v Vehicle) Location() Position { - return v.Coordinates +func (v VehicleStatus) Location() Position { + return v.Position +} + +func (k LineType) Value() uint { + return uint(k) +} + +func (d Direction) Value() uint { + return uint(d) } -type Departure struct { +/*type Departure struct { StopSeq int Time uint Pickup uint // todo(BAF10) enum Dropoff uint // todo(BAF10) enum StopOffset uint64 -} +}*/ type DepartureRealtime struct { Departure Departure @@ -74,7 +82,7 @@ Order StopOrder Update gtfs_rt.Update } -type Trip struct { +/*type Trip struct { ID string Headsign string Direction uint @@ -82,13 +90,13 @@ LineName string ScheduleID string ShapeID ID // todo(BAF11) Departures []Departure -} +}*/ -type LineGraph struct { +/*type LineGraph struct { StopCodes []string NextNodes map[int][]int PrevNodes map[int][]int -} +}*/ func (g LineGraph) LastNodes() []int { lastNodes := []int{} @@ -103,7 +111,7 @@ } return lastNodes } -type Line struct { +/*type Line struct { ID string Name string Colour color.RGBA @@ -111,7 +119,7 @@ Type uint // todo(BAF10) enum AgencyID ID GraphThere LineGraph GraphBack LineGraph -} +}*/ type LineStub struct { Name string @@ -129,24 +137,23 @@ type Shape struct { // todo(BAF11) Points []string // OLC } -type Schedule struct { +/*type Schedule struct { ScheduleID string Weekdays uint8 StartDate string EndDate string -} +}*/ -type StopOrder struct { - TripID string `bare:"-"` +/*type StopOrder struct { TripOffset uint Order int -} + TripID string +}*/ -type ChangeOption struct { - LineID string `bare:"-"` +/*type ChangeOption struct { LineName string Headsign string -} +}*/ type Item interface { // todo(BAF12) name: ‘query-able’ eg. IsItem() @@ -157,7 +164,7 @@ type Locatable interface { Location() Position } -type Stop struct { +/*type Stop struct { ID string Code string Name string @@ -167,20 +174,20 @@ Zone string Coordinates Position Order []StopOrder Timezone string -} +}*/ func (s Stop) DisplayName() string { return s.Name } func (s Stop) Location() Position { - return s.Coordinates + return s.Position } func (s Stop) Bounds() *rtreego.Rect { rect, err := rtreego.NewRectFromPoints( - rtreego.Point{s.Coordinates.Lat, s.Coordinates.Lon}, - rtreego.Point{s.Coordinates.Lat, s.Coordinates.Lon}, + rtreego.Point{s.Position.Lat, s.Position.Lon}, + rtreego.Point{s.Position.Lat, s.Position.Lon}, ) if err != nil { panic(err.Error()) @@ -210,7 +217,7 @@ Cause int32 // todo(BAF10) Effect int32 // todo(BAF10) } -type ID string +// type ID string type Validity string // 20060102_20060102 func (v Validity) Start() string { return strings.Split(string(v), "_")[0] @@ -219,14 +226,14 @@ func (v Validity) End() string { return strings.Split(string(v), "_")[1] } -type CodeIndex map[ID]uint +// type CodeIndex map[ID]uint type FeedCodeIndex map[Validity]CodeIndex type GlobalCodeIndex map[string]FeedCodeIndex -type NameOffset struct { +/*type NameOffset struct { Name string Offsets []uint -} +}*/ type NameIndex []NameOffset type FeedNameIndex map[Validity]NameIndex @@ -243,7 +250,7 @@ type FeedCalendar map[Validity][]Schedule type GlobalCalendar map[string]FeedCalendar -type Vehicles map[ID]Vehicle +type Vehicles map[string]Vehicle type FeedVehicles map[Validity]Vehicles type GlobalVehicles map[string]FeedVehicles diff --git a/traffic/structs_gen.go b/traffic/structs_gen.go new file mode 100644 index 0000000000000000000000000000000000000000..2a2cbfda15f7555fde3f08e186f79c976416f1e8 --- /dev/null +++ b/traffic/structs_gen.go @@ -0,0 +1,314 @@ +package traffic + +// Code generated by go-bare/cmd/gen, DO NOT EDIT. + +import ( + "errors" + "git.sr.ht/~sircmpwn/go-bare" +) + +type Trip struct { + Id string `bare:"id"` + Headsign string `bare:"headsign"` + Direction Direction `bare:"direction"` + LineName string `bare:"lineName"` + ScheduleID string `bare:"scheduleID"` + ShapeID string `bare:"shapeID"` + Departures []Departure `bare:"departures"` +} + +func (t *Trip) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *Trip) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type Vehicle struct { + Id string `bare:"id"` + Capabilities uint16 `bare:"capabilities"` +} + +func (t *Vehicle) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *Vehicle) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type Departure struct { + StopSequence int `bare:"stopSequence"` + Time uint `bare:"time"` + Pickup Boarding `bare:"pickup"` + Dropoff Boarding `bare:"dropoff"` + StopOffset uint `bare:"stopOffset"` +} + +func (t *Departure) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *Departure) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type Stop struct { + Id string `bare:"id"` + Code string `bare:"code"` + Name string `bare:"name"` + NodeName string `bare:"nodeName"` + ChangeOptions []ChangeOption `bare:"changeOptions"` + Zone string `bare:"zone"` + Position Position `bare:"position"` + Order map[string]StopOrder `bare:"order"` + Timezone string `bare:"timezone"` +} + +func (t *Stop) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *Stop) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type ChangeOption struct { + LineName string `bare:"lineName"` + Headsign string `bare:"headsign"` +} + +func (t *ChangeOption) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *ChangeOption) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type Position struct { + Lat float64 `bare:"lat"` + Lon float64 `bare:"lon"` +} + +func (t *Position) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *Position) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type LineGraph struct { + StopCodes []string `bare:"stopCodes"` + NextNodes map[int][]int `bare:"nextNodes"` + PrevNodes map[int][]int `bare:"prevNodes"` +} + +func (t *LineGraph) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *LineGraph) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type StopOrder struct { + TripOffset uint `bare:"tripOffset"` + Sequence int `bare:"sequence"` + TripID string `bare:"tripID"` +} + +func (t *StopOrder) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *StopOrder) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type Colour struct { + R uint8 `bare:"r"` + G uint8 `bare:"g"` + B uint8 `bare:"b"` + A uint8 `bare:"a"` +} + +func (t *Colour) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *Colour) Encode() ([]byte, error) { + 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"` +} + +func (t *Line) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *Line) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type FeedInfo struct { + Name string `bare:"name"` + Website string `bare:"website"` + Language string `bare:"language"` +} + +func (t *FeedInfo) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *FeedInfo) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type Agency struct { + Id string `bare:"id"` + Name string `bare:"name"` + Website string `bare:"website"` + Timezone string `bare:"timezone"` + PhoneNumber string `bare:"phoneNumber"` + Language string `bare:"language"` + Email string `bare:"email"` + FareWebsite string `bare:"fareWebsite"` +} + +func (t *Agency) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *Agency) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type NameOffset struct { + Name string `bare:"name"` + Offsets []uint `bare:"offsets"` +} + +func (t *NameOffset) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *NameOffset) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type CodeIndex map[string]uint + +func (t *CodeIndex) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *CodeIndex) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type Schedule struct { + Id string `bare:"id"` + Weekdays uint8 `bare:"weekdays"` + StartDate string `bare:"startDate"` + EndDate string `bare:"endDate"` +} + +func (t *Schedule) Decode(data []byte) error { + return bare.Unmarshal(data, t) +} + +func (t *Schedule) Encode() ([]byte, error) { + return bare.Marshal(t) +} + +type Direction uint + +const ( + THERE Direction = 0 + BACK Direction = 1 +) + +func (t Direction) String() string { + switch t { + case THERE: + return "THERE" + case BACK: + return "BACK" + } + panic(errors.New("Invalid Direction value")) +} + +type Boarding uint + +const ( + REGULAR Boarding = 0 + NONE Boarding = 1 + BY_PHONE Boarding = 2 + BY_DRIVER Boarding = 3 +) + +func (t Boarding) String() string { + switch t { + case REGULAR: + return "REGULAR" + case NONE: + return "NONE" + case BY_PHONE: + return "BY_PHONE" + case BY_DRIVER: + return "BY_DRIVER" + } + panic(errors.New("Invalid Boarding value")) +} + +type LineType uint + +const ( + TRAM LineType = 0 + METRO LineType = 1 + RAIL LineType = 2 + BUS LineType = 3 + FERRY LineType = 4 + CABLE_TRAM LineType = 5 + CABLE_CAR LineType = 6 + FUNICULAR LineType = 7 + TROLLEYBUS LineType = 11 + MONORAIL LineType = 12 +) + +func (t LineType) String() string { + switch t { + case TRAM: + return "TRAM" + case METRO: + return "METRO" + case RAIL: + return "RAIL" + case BUS: + return "BUS" + case FERRY: + return "FERRY" + case CABLE_TRAM: + return "CABLE_TRAM" + case CABLE_CAR: + return "CABLE_CAR" + case FUNICULAR: + return "FUNICULAR" + case TROLLEYBUS: + return "TROLLEYBUS" + case MONORAIL: + return "MONORAIL" + } + panic(errors.New("Invalid LineType value")) +}