diff --git a/cmd/main.go b/cmd/main.go index 7d60ce4..0730453 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -73,21 +73,21 @@ func getStationForVehicle(vehicle *pb.VehiclePosition) *pb.VehicleFeed_Station { return nearestStop } -func getVehicles() ([]*pb.VehiclePosition, error) { +func getVehicles() ([]*pb.VehiclePosition, *pb.FeedHeader, error) { resp, err := http.Get("https://apps.rideuta.com/tms/gtfs/Vehicle") if err != nil { - return nil, err + return nil, nil, err } bytes, err := io.ReadAll(resp.Body) if err != nil { - return nil, err + return nil, nil, err } feed := pb.FeedMessage{} err = proto.Unmarshal(bytes, &feed) if err != nil { - return nil, err + return nil, nil, err } log.Printf("Found %d vehicles...", len(feed.Entity)) @@ -99,7 +99,7 @@ func getVehicles() ([]*pb.VehiclePosition, error) { } } - return vehicles, nil + return vehicles, feed.Header, nil } type TripInfo struct { @@ -108,80 +108,72 @@ type TripInfo struct { Headsign string } -var trips = make(map[string]*TripInfo) - -func loadTrips() error { - rows, err := scheduleDb.Query("SELECT route_id, trip_id, trip_headsign, direction_id FROM trips;") - if err != nil { - return err - } - - for { - if next := rows.Next(); next { - trip_info := new(TripInfo) - - var route_id string - var trip_id string - var trip_headsign string - var direction_id int32 - - err = rows.Scan(&route_id, &trip_id, &trip_headsign, &direction_id) - if err != nil { - continue - } - - trip_info.Headsign = trip_headsign - - trip_info.Direction = direction_id - - switch route_id { - case "8246": - trip_info.Line = pb.VehicleFeed_RED - trips[trip_id] = trip_info - case "39020": - trip_info.Line = pb.VehicleFeed_GREEN - trips[trip_id] = trip_info - case "5907": - trip_info.Line = pb.VehicleFeed_BLUE - trips[trip_id] = trip_info - case "45389": - trip_info.Line = pb.VehicleFeed_STREETCAR - trips[trip_id] = trip_info - // case "41065": - // trip_info.Line = pb.VehicleFeed_FRONTRUNNER - // trips[record[trip_id]] = trip_info - } - } else { - break - } - } - - return nil -} - -func feedifyVehicles(vehicles []*pb.VehiclePosition) pb.VehicleFeed { +func feedifyVehicles(vehicles []*pb.VehiclePosition, header *pb.FeedHeader) pb.VehicleFeed { vehicle_feed := make([]*pb.VehicleFeed_Vehicle, 0, len(vehicles)) for _, vehicle := range vehicles { - trip, ok := trips[*vehicle.Trip.TripId] - if !ok { - log.Printf("No matching trip '%s', skipping...", *vehicle.Trip.TripId) + rows, err := scheduleDb.Query(` + SELECT + trips.route_id, + trips.trip_headsign, + routes.route_type, + routes.route_color, + routes.route_short_name, + routes.route_long_name + FROM trips + INNER JOIN routes ON routes.route_id = trips.route_id + WHERE trips.trip_id = ? + LIMIT 1; + `, *vehicle.Trip.TripId) + if err != nil { + fmt.Println(err) continue } + var route_id string + var trip_headsign sql.NullString + var route_type int32 + var route_color sql.NullString + var route_short_name sql.NullString + var route_long_name sql.NullString + + if !rows.Next() { + fmt.Println(rows.Err()) + continue + } + + err = rows.Scan(&route_id, &trip_headsign, &route_type, &route_color, &route_short_name, &route_long_name) + if err != nil { + fmt.Println(err) + continue + } + + rows.Close() + vehicle_feed = append(vehicle_feed, &pb.VehicleFeed_Vehicle{ - Lat: *vehicle.Position.Latitude, - Lon: *vehicle.Position.Longitude, - Line: trip.Line, - Id: *vehicle.Vehicle.Id, - Direction: trip.Direction, + Lat: *vehicle.Position.Latitude, + Lon: *vehicle.Position.Longitude, + Bearing: *vehicle.Position.Bearing, + // Line: trip.Line, + Id: *vehicle.Vehicle.Id, + // Direction: trip.Direction, NearestStation: getStationForVehicle(vehicle), - Headsign: trip.Headsign, + Headsign: trip_headsign.String, + Route: &pb.VehicleFeed_Route{ + Id: route_id, + Type: pb.VehicleFeed_Route_RouteType(route_type + 1), // lol + Color: route_color.String, + ShortName: route_short_name.String, + LongName: route_long_name.String, + }, }) } return pb.VehicleFeed{ Vehicles: vehicle_feed, + Info: &pb.VehicleFeed_FeedInfo{ + LastUpdate: *header.Timestamp, + }, } } @@ -193,12 +185,7 @@ func main() { log.Fatal(err) } - fmt.Println("Loading trip data...") - scheduleDb = _db - if err := loadTrips(); err != nil { - log.Fatalln(err) - } // vehicles, err := getVehicles() // if err != nil { @@ -217,14 +204,14 @@ func main() { }) http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { - vehicles, err := getVehicles() + vehicles, header, err := getVehicles() if err != nil { log.Println(err) w.WriteHeader(http.StatusInternalServerError) return } - feed := feedifyVehicles(vehicles) + feed := feedifyVehicles(vehicles, header) b, err := proto.Marshal(&feed) if err != nil { log.Println(err) diff --git a/proto/schema.pb.go b/proto/schema.pb.go index f611515..0ab4de9 100644 --- a/proto/schema.pb.go +++ b/proto/schema.pb.go @@ -79,9 +79,65 @@ func (VehicleFeed_Line) EnumDescriptor() ([]byte, []int) { return file_proto_schema_proto_rawDescGZIP(), []int{0, 0} } +type VehicleFeed_Route_RouteType int32 + +const ( + VehicleFeed_Route_UNSPECIFIED VehicleFeed_Route_RouteType = 0 + VehicleFeed_Route_TRAM VehicleFeed_Route_RouteType = 1 + VehicleFeed_Route_SUBWAY VehicleFeed_Route_RouteType = 2 + VehicleFeed_Route_RAIL VehicleFeed_Route_RouteType = 3 + VehicleFeed_Route_BUS VehicleFeed_Route_RouteType = 4 +) + +// Enum value maps for VehicleFeed_Route_RouteType. +var ( + VehicleFeed_Route_RouteType_name = map[int32]string{ + 0: "UNSPECIFIED", + 1: "TRAM", + 2: "SUBWAY", + 3: "RAIL", + 4: "BUS", + } + VehicleFeed_Route_RouteType_value = map[string]int32{ + "UNSPECIFIED": 0, + "TRAM": 1, + "SUBWAY": 2, + "RAIL": 3, + "BUS": 4, + } +) + +func (x VehicleFeed_Route_RouteType) Enum() *VehicleFeed_Route_RouteType { + p := new(VehicleFeed_Route_RouteType) + *p = x + return p +} + +func (x VehicleFeed_Route_RouteType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (VehicleFeed_Route_RouteType) Descriptor() protoreflect.EnumDescriptor { + return file_proto_schema_proto_enumTypes[1].Descriptor() +} + +func (VehicleFeed_Route_RouteType) Type() protoreflect.EnumType { + return &file_proto_schema_proto_enumTypes[1] +} + +func (x VehicleFeed_Route_RouteType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use VehicleFeed_Route_RouteType.Descriptor instead. +func (VehicleFeed_Route_RouteType) EnumDescriptor() ([]byte, []int) { + return file_proto_schema_proto_rawDescGZIP(), []int{0, 1, 0} +} + type VehicleFeed struct { state protoimpl.MessageState `protogen:"open.v1"` Vehicles []*VehicleFeed_Vehicle `protobuf:"bytes,1,rep,name=vehicles,proto3" json:"vehicles,omitempty"` + Info *VehicleFeed_FeedInfo `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -123,6 +179,133 @@ func (x *VehicleFeed) GetVehicles() []*VehicleFeed_Vehicle { return nil } +func (x *VehicleFeed) GetInfo() *VehicleFeed_FeedInfo { + if x != nil { + return x.Info + } + return nil +} + +type VehicleFeed_FeedInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + LastUpdate uint64 `protobuf:"varint,1,opt,name=last_update,json=lastUpdate,proto3" json:"last_update,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VehicleFeed_FeedInfo) Reset() { + *x = VehicleFeed_FeedInfo{} + mi := &file_proto_schema_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VehicleFeed_FeedInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VehicleFeed_FeedInfo) ProtoMessage() {} + +func (x *VehicleFeed_FeedInfo) ProtoReflect() protoreflect.Message { + mi := &file_proto_schema_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VehicleFeed_FeedInfo.ProtoReflect.Descriptor instead. +func (*VehicleFeed_FeedInfo) Descriptor() ([]byte, []int) { + return file_proto_schema_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *VehicleFeed_FeedInfo) GetLastUpdate() uint64 { + if x != nil { + return x.LastUpdate + } + return 0 +} + +type VehicleFeed_Route struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type VehicleFeed_Route_RouteType `protobuf:"varint,1,opt,name=type,proto3,enum=VehicleFeed_Route_RouteType" json:"type,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + Color string `protobuf:"bytes,3,opt,name=color,proto3" json:"color,omitempty"` + ShortName string `protobuf:"bytes,4,opt,name=short_name,json=shortName,proto3" json:"short_name,omitempty"` + LongName string `protobuf:"bytes,5,opt,name=long_name,json=longName,proto3" json:"long_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VehicleFeed_Route) Reset() { + *x = VehicleFeed_Route{} + mi := &file_proto_schema_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VehicleFeed_Route) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VehicleFeed_Route) ProtoMessage() {} + +func (x *VehicleFeed_Route) ProtoReflect() protoreflect.Message { + mi := &file_proto_schema_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VehicleFeed_Route.ProtoReflect.Descriptor instead. +func (*VehicleFeed_Route) Descriptor() ([]byte, []int) { + return file_proto_schema_proto_rawDescGZIP(), []int{0, 1} +} + +func (x *VehicleFeed_Route) GetType() VehicleFeed_Route_RouteType { + if x != nil { + return x.Type + } + return VehicleFeed_Route_UNSPECIFIED +} + +func (x *VehicleFeed_Route) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *VehicleFeed_Route) GetColor() string { + if x != nil { + return x.Color + } + return "" +} + +func (x *VehicleFeed_Route) GetShortName() string { + if x != nil { + return x.ShortName + } + return "" +} + +func (x *VehicleFeed_Route) GetLongName() string { + if x != nil { + return x.LongName + } + return "" +} + type VehicleFeed_Station struct { state protoimpl.MessageState `protogen:"open.v1"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` @@ -135,7 +318,7 @@ type VehicleFeed_Station struct { func (x *VehicleFeed_Station) Reset() { *x = VehicleFeed_Station{} - mi := &file_proto_schema_proto_msgTypes[1] + mi := &file_proto_schema_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -147,7 +330,7 @@ func (x *VehicleFeed_Station) String() string { func (*VehicleFeed_Station) ProtoMessage() {} func (x *VehicleFeed_Station) ProtoReflect() protoreflect.Message { - mi := &file_proto_schema_proto_msgTypes[1] + mi := &file_proto_schema_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -160,7 +343,7 @@ func (x *VehicleFeed_Station) ProtoReflect() protoreflect.Message { // Deprecated: Use VehicleFeed_Station.ProtoReflect.Descriptor instead. func (*VehicleFeed_Station) Descriptor() ([]byte, []int) { - return file_proto_schema_proto_rawDescGZIP(), []int{0, 0} + return file_proto_schema_proto_rawDescGZIP(), []int{0, 2} } func (x *VehicleFeed_Station) GetId() string { @@ -195,18 +378,20 @@ type VehicleFeed_Vehicle struct { state protoimpl.MessageState `protogen:"open.v1"` Lat float32 `protobuf:"fixed32,1,opt,name=lat,proto3" json:"lat,omitempty"` Lon float32 `protobuf:"fixed32,2,opt,name=lon,proto3" json:"lon,omitempty"` + Bearing float32 `protobuf:"fixed32,9,opt,name=bearing,proto3" json:"bearing,omitempty"` Line VehicleFeed_Line `protobuf:"varint,3,opt,name=line,proto3,enum=VehicleFeed_Line" json:"line,omitempty"` Direction int32 `protobuf:"varint,4,opt,name=direction,proto3" json:"direction,omitempty"` Id string `protobuf:"bytes,5,opt,name=id,proto3" json:"id,omitempty"` NearestStation *VehicleFeed_Station `protobuf:"bytes,6,opt,name=nearest_station,json=nearestStation,proto3" json:"nearest_station,omitempty"` Headsign string `protobuf:"bytes,7,opt,name=headsign,proto3" json:"headsign,omitempty"` + Route *VehicleFeed_Route `protobuf:"bytes,8,opt,name=route,proto3" json:"route,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *VehicleFeed_Vehicle) Reset() { *x = VehicleFeed_Vehicle{} - mi := &file_proto_schema_proto_msgTypes[2] + mi := &file_proto_schema_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -218,7 +403,7 @@ func (x *VehicleFeed_Vehicle) String() string { func (*VehicleFeed_Vehicle) ProtoMessage() {} func (x *VehicleFeed_Vehicle) ProtoReflect() protoreflect.Message { - mi := &file_proto_schema_proto_msgTypes[2] + mi := &file_proto_schema_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -231,7 +416,7 @@ func (x *VehicleFeed_Vehicle) ProtoReflect() protoreflect.Message { // Deprecated: Use VehicleFeed_Vehicle.ProtoReflect.Descriptor instead. func (*VehicleFeed_Vehicle) Descriptor() ([]byte, []int) { - return file_proto_schema_proto_rawDescGZIP(), []int{0, 1} + return file_proto_schema_proto_rawDescGZIP(), []int{0, 3} } func (x *VehicleFeed_Vehicle) GetLat() float32 { @@ -248,6 +433,13 @@ func (x *VehicleFeed_Vehicle) GetLon() float32 { return 0 } +func (x *VehicleFeed_Vehicle) GetBearing() float32 { + if x != nil { + return x.Bearing + } + return 0 +} + func (x *VehicleFeed_Vehicle) GetLine() VehicleFeed_Line { if x != nil { return x.Line @@ -283,26 +475,53 @@ func (x *VehicleFeed_Vehicle) GetHeadsign() string { return "" } +func (x *VehicleFeed_Vehicle) GetRoute() *VehicleFeed_Route { + if x != nil { + return x.Route + } + return nil +} + var File_proto_schema_proto protoreflect.FileDescriptor const file_proto_schema_proto_rawDesc = "" + "\n" + - "\x12proto/schema.proto\"\xce\x03\n" + + "\x12proto/schema.proto\"\xcf\x06\n" + "\vVehicleFeed\x120\n" + - "\bvehicles\x18\x01 \x03(\v2\x14.VehicleFeed.VehicleR\bvehicles\x1aQ\n" + + "\bvehicles\x18\x01 \x03(\v2\x14.VehicleFeed.VehicleR\bvehicles\x12)\n" + + "\x04info\x18\x02 \x01(\v2\x15.VehicleFeed.FeedInfoR\x04info\x1a+\n" + + "\bFeedInfo\x12\x1f\n" + + "\vlast_update\x18\x01 \x01(\x04R\n" + + "lastUpdate\x1a\xe2\x01\n" + + "\x05Route\x120\n" + + "\x04type\x18\x01 \x01(\x0e2\x1c.VehicleFeed.Route.RouteTypeR\x04type\x12\x0e\n" + + "\x02id\x18\x02 \x01(\tR\x02id\x12\x14\n" + + "\x05color\x18\x03 \x01(\tR\x05color\x12\x1d\n" + + "\n" + + "short_name\x18\x04 \x01(\tR\tshortName\x12\x1b\n" + + "\tlong_name\x18\x05 \x01(\tR\blongName\"E\n" + + "\tRouteType\x12\x0f\n" + + "\vUNSPECIFIED\x10\x00\x12\b\n" + + "\x04TRAM\x10\x01\x12\n" + + "\n" + + "\x06SUBWAY\x10\x02\x12\b\n" + + "\x04RAIL\x10\x03\x12\a\n" + + "\x03BUS\x10\x04\x1aQ\n" + "\aStation\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12\x10\n" + "\x03lat\x18\x03 \x01(\x02R\x03lat\x12\x10\n" + - "\x03lon\x18\x04 \x01(\x02R\x03lon\x1a\xdd\x01\n" + + "\x03lon\x18\x04 \x01(\x02R\x03lon\x1a\xa1\x02\n" + "\aVehicle\x12\x10\n" + "\x03lat\x18\x01 \x01(\x02R\x03lat\x12\x10\n" + - "\x03lon\x18\x02 \x01(\x02R\x03lon\x12%\n" + + "\x03lon\x18\x02 \x01(\x02R\x03lon\x12\x18\n" + + "\abearing\x18\t \x01(\x02R\abearing\x12%\n" + "\x04line\x18\x03 \x01(\x0e2\x11.VehicleFeed.LineR\x04line\x12\x1c\n" + "\tdirection\x18\x04 \x01(\x05R\tdirection\x12\x0e\n" + "\x02id\x18\x05 \x01(\tR\x02id\x12=\n" + "\x0fnearest_station\x18\x06 \x01(\v2\x14.VehicleFeed.StationR\x0enearestStation\x12\x1a\n" + - "\bheadsign\x18\a \x01(\tR\bheadsign\"Z\n" + + "\bheadsign\x18\a \x01(\tR\bheadsign\x12(\n" + + "\x05route\x18\b \x01(\v2\x12.VehicleFeed.RouteR\x05route\"Z\n" + "\x04Line\x12\x14\n" + "\x10LINE_UNSPECIFIED\x10\x00\x12\t\n" + "\x05GREEN\x10\x01\x12\a\n" + @@ -323,23 +542,29 @@ func file_proto_schema_proto_rawDescGZIP() []byte { return file_proto_schema_proto_rawDescData } -var file_proto_schema_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_proto_schema_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_proto_schema_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_proto_schema_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_proto_schema_proto_goTypes = []any{ - (VehicleFeed_Line)(0), // 0: VehicleFeed.Line - (*VehicleFeed)(nil), // 1: VehicleFeed - (*VehicleFeed_Station)(nil), // 2: VehicleFeed.Station - (*VehicleFeed_Vehicle)(nil), // 3: VehicleFeed.Vehicle + (VehicleFeed_Line)(0), // 0: VehicleFeed.Line + (VehicleFeed_Route_RouteType)(0), // 1: VehicleFeed.Route.RouteType + (*VehicleFeed)(nil), // 2: VehicleFeed + (*VehicleFeed_FeedInfo)(nil), // 3: VehicleFeed.FeedInfo + (*VehicleFeed_Route)(nil), // 4: VehicleFeed.Route + (*VehicleFeed_Station)(nil), // 5: VehicleFeed.Station + (*VehicleFeed_Vehicle)(nil), // 6: VehicleFeed.Vehicle } var file_proto_schema_proto_depIdxs = []int32{ - 3, // 0: VehicleFeed.vehicles:type_name -> VehicleFeed.Vehicle - 0, // 1: VehicleFeed.Vehicle.line:type_name -> VehicleFeed.Line - 2, // 2: VehicleFeed.Vehicle.nearest_station:type_name -> VehicleFeed.Station - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 6, // 0: VehicleFeed.vehicles:type_name -> VehicleFeed.Vehicle + 3, // 1: VehicleFeed.info:type_name -> VehicleFeed.FeedInfo + 1, // 2: VehicleFeed.Route.type:type_name -> VehicleFeed.Route.RouteType + 0, // 3: VehicleFeed.Vehicle.line:type_name -> VehicleFeed.Line + 5, // 4: VehicleFeed.Vehicle.nearest_station:type_name -> VehicleFeed.Station + 4, // 5: VehicleFeed.Vehicle.route:type_name -> VehicleFeed.Route + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_proto_schema_proto_init() } @@ -352,8 +577,8 @@ func file_proto_schema_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_schema_proto_rawDesc), len(file_proto_schema_proto_rawDesc)), - NumEnums: 1, - NumMessages: 3, + NumEnums: 2, + NumMessages: 5, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/schema.proto b/proto/schema.proto index 2ec2d54..7883f13 100644 --- a/proto/schema.proto +++ b/proto/schema.proto @@ -11,6 +11,26 @@ message VehicleFeed { FRONTRUNNER = 5; } + message FeedInfo { + uint64 last_update = 1; + } + + message Route { + enum RouteType { + UNSPECIFIED = 0; + TRAM = 1; + SUBWAY = 2; + RAIL = 3; + BUS = 4; + } + + RouteType type = 1; + string id = 2; + string color = 3; + string short_name = 4; + string long_name = 5; + } + message Station { string id = 1; string name = 2; @@ -21,12 +41,15 @@ message VehicleFeed { message Vehicle { float lat = 1; float lon = 2; + float bearing = 9; Line line = 3; int32 direction = 4; string id = 5; Station nearest_station = 6; string headsign = 7; + Route route = 8; } repeated Vehicle vehicles = 1; + FeedInfo info = 2; } diff --git a/static/index.html b/static/index.html index 41765a8..30b75e0 100644 --- a/static/index.html +++ b/static/index.html @@ -1,3 +1,5 @@ + + @@ -14,73 +16,108 @@ body { margin: 0; } + + #sidebar { + flex-basis: 300px; + flex-shrink: 0; + padding: 10px; + } + + .vehicle { + border-radius: 999px; + width: 20px; + height: 20px; + margin-left: -10px; + margin-top: -10px; + padding: 8px; + fill: white; + /* box-shadow: 0px 0px 10px black; */ + border: 1px solid black; + position: relative; + background-color: var(--color); + } + + .vehicle-plain { + /* bus */ + background-color: white; + border-color: var(--color); + fill: var(--color); + } + .vehicle-small { + width: 15px; + height: 15px; + margin-left: -7px; + margin-top: -7px; + }
- +