mirror of
https://github.com/cjdenio/uta-trax-api.git
synced 2026-10-03 16:06:19 +00:00
initial commit
This commit is contained in:
9 files changed
+5730
No files matched your search
@@ -0,0 +1,2 @@
|
|||||||
|
/gtfs/
|
||||||
|
/gtfs.zip
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
proto:
|
||||||
|
protoc --go_out=. --go_opt=paths=source_relative --go_opt=Mproto/gtfs-realtime.proto=github.com/cjdenio/uta-trax-api/proto proto/*.proto
|
||||||
+132
@@ -0,0 +1,132 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
pb "github.com/cjdenio/uta-trax-api/proto"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getVehicles() ([]*pb.VehiclePosition, error) {
|
||||||
|
resp, err := http.Get("https://apps.rideuta.com/tms/gtfs/Vehicle")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
feed := pb.FeedMessage{}
|
||||||
|
err = proto.Unmarshal(bytes, &feed)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
vehicles := make([]*pb.VehiclePosition, 0, len(feed.Entity))
|
||||||
|
for _, v := range feed.Entity {
|
||||||
|
if v.Vehicle != nil {
|
||||||
|
vehicles = append(vehicles, v.Vehicle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vehicles, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TripInfo struct {
|
||||||
|
Line pb.VehicleFeed_Line
|
||||||
|
Direction int
|
||||||
|
}
|
||||||
|
|
||||||
|
var trips = make(map[string]*TripInfo)
|
||||||
|
|
||||||
|
func loadTrips() error {
|
||||||
|
f, err := os.Open("gtfs/trips.txt")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
r := csv.NewReader(f)
|
||||||
|
|
||||||
|
header, err := r.Read()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
route_id := slices.Index(header, "route_id")
|
||||||
|
trip_id := slices.Index(header, "trip_id")
|
||||||
|
// direction_id := slices.Index(header, "direction_id")
|
||||||
|
|
||||||
|
for {
|
||||||
|
if record, err := r.Read(); err == nil {
|
||||||
|
trip_info := new(TripInfo)
|
||||||
|
|
||||||
|
switch record[route_id] {
|
||||||
|
case "8246":
|
||||||
|
trip_info.Line = pb.VehicleFeed_RED
|
||||||
|
trips[record[trip_id]] = trip_info
|
||||||
|
case "39020":
|
||||||
|
trip_info.Line = pb.VehicleFeed_GREEN
|
||||||
|
trips[record[trip_id]] = trip_info
|
||||||
|
case "5907":
|
||||||
|
trip_info.Line = pb.VehicleFeed_BLUE
|
||||||
|
trips[record[trip_id]] = trip_info
|
||||||
|
case "45389":
|
||||||
|
trip_info.Line = pb.VehicleFeed_STREETCAR
|
||||||
|
trips[record[trip_id]] = trip_info
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func feedifyVehicles(vehicles []*pb.VehiclePosition) pb.VehicleFeed {
|
||||||
|
|
||||||
|
vehicle_feed := make([]*pb.VehicleFeed_Vehicle, 0, len(vehicles))
|
||||||
|
|
||||||
|
for _, vehicle := range vehicles {
|
||||||
|
trip, ok := trips[*vehicle.Trip.TripId]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
vehicle_feed = append(vehicle_feed, &pb.VehicleFeed_Vehicle{
|
||||||
|
Lat: *vehicle.Position.Latitude,
|
||||||
|
Lon: *vehicle.Position.Longitude,
|
||||||
|
Line: trip.Line,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return pb.VehicleFeed{
|
||||||
|
Vehicles: vehicle_feed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := loadTrips(); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
http.DefaultServeMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vehicles, err := getVehicles()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
feed := feedifyVehicles(vehicles)
|
||||||
|
b, _ := proto.Marshal(&feed)
|
||||||
|
w.Header().Add("Content-Type", "application/protobuf")
|
||||||
|
w.Write(b)
|
||||||
|
})
|
||||||
|
|
||||||
|
http.ListenAndServe(":3000", nil)
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module github.com/cjdenio/uta-trax-api
|
||||||
|
|
||||||
|
go 1.24.2
|
||||||
|
|
||||||
|
require google.golang.org/protobuf v1.36.6 // indirect
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,262 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.6
|
||||||
|
// protoc v5.29.3
|
||||||
|
// source: proto/schema.proto
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type VehicleFeed_Line int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
VehicleFeed_LINE_UNSPECIFIED VehicleFeed_Line = 0
|
||||||
|
VehicleFeed_GREEN VehicleFeed_Line = 1
|
||||||
|
VehicleFeed_RED VehicleFeed_Line = 2
|
||||||
|
VehicleFeed_BLUE VehicleFeed_Line = 3
|
||||||
|
VehicleFeed_STREETCAR VehicleFeed_Line = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for VehicleFeed_Line.
|
||||||
|
var (
|
||||||
|
VehicleFeed_Line_name = map[int32]string{
|
||||||
|
0: "LINE_UNSPECIFIED",
|
||||||
|
1: "GREEN",
|
||||||
|
2: "RED",
|
||||||
|
3: "BLUE",
|
||||||
|
4: "STREETCAR",
|
||||||
|
}
|
||||||
|
VehicleFeed_Line_value = map[string]int32{
|
||||||
|
"LINE_UNSPECIFIED": 0,
|
||||||
|
"GREEN": 1,
|
||||||
|
"RED": 2,
|
||||||
|
"BLUE": 3,
|
||||||
|
"STREETCAR": 4,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x VehicleFeed_Line) Enum() *VehicleFeed_Line {
|
||||||
|
p := new(VehicleFeed_Line)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x VehicleFeed_Line) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (VehicleFeed_Line) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_proto_schema_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (VehicleFeed_Line) Type() protoreflect.EnumType {
|
||||||
|
return &file_proto_schema_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x VehicleFeed_Line) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use VehicleFeed_Line.Descriptor instead.
|
||||||
|
func (VehicleFeed_Line) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_proto_schema_proto_rawDescGZIP(), []int{0, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
type VehicleFeed struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Vehicles []*VehicleFeed_Vehicle `protobuf:"bytes,1,rep,name=vehicles,proto3" json:"vehicles,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VehicleFeed) Reset() {
|
||||||
|
*x = VehicleFeed{}
|
||||||
|
mi := &file_proto_schema_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VehicleFeed) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*VehicleFeed) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *VehicleFeed) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_proto_schema_proto_msgTypes[0]
|
||||||
|
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.ProtoReflect.Descriptor instead.
|
||||||
|
func (*VehicleFeed) Descriptor() ([]byte, []int) {
|
||||||
|
return file_proto_schema_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VehicleFeed) GetVehicles() []*VehicleFeed_Vehicle {
|
||||||
|
if x != nil {
|
||||||
|
return x.Vehicles
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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"`
|
||||||
|
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"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VehicleFeed_Vehicle) Reset() {
|
||||||
|
*x = VehicleFeed_Vehicle{}
|
||||||
|
mi := &file_proto_schema_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VehicleFeed_Vehicle) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*VehicleFeed_Vehicle) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *VehicleFeed_Vehicle) 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_Vehicle.ProtoReflect.Descriptor instead.
|
||||||
|
func (*VehicleFeed_Vehicle) Descriptor() ([]byte, []int) {
|
||||||
|
return file_proto_schema_proto_rawDescGZIP(), []int{0, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VehicleFeed_Vehicle) GetLat() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Lat
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VehicleFeed_Vehicle) GetLon() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Lon
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VehicleFeed_Vehicle) GetLine() VehicleFeed_Line {
|
||||||
|
if x != nil {
|
||||||
|
return x.Line
|
||||||
|
}
|
||||||
|
return VehicleFeed_LINE_UNSPECIFIED
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *VehicleFeed_Vehicle) GetDirection() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Direction
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_proto_schema_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
const file_proto_schema_proto_rawDesc = "" +
|
||||||
|
"\n" +
|
||||||
|
"\x12proto/schema.proto\"\xfe\x01\n" +
|
||||||
|
"\vVehicleFeed\x120\n" +
|
||||||
|
"\bvehicles\x18\x01 \x03(\v2\x14.VehicleFeed.VehicleR\bvehicles\x1ar\n" +
|
||||||
|
"\aVehicle\x12\x10\n" +
|
||||||
|
"\x03lat\x18\x01 \x01(\x02R\x03lat\x12\x10\n" +
|
||||||
|
"\x03lon\x18\x02 \x01(\x02R\x03lon\x12%\n" +
|
||||||
|
"\x04line\x18\x03 \x01(\x0e2\x11.VehicleFeed.LineR\x04line\x12\x1c\n" +
|
||||||
|
"\tdirection\x18\x04 \x01(\x05R\tdirection\"I\n" +
|
||||||
|
"\x04Line\x12\x14\n" +
|
||||||
|
"\x10LINE_UNSPECIFIED\x10\x00\x12\t\n" +
|
||||||
|
"\x05GREEN\x10\x01\x12\a\n" +
|
||||||
|
"\x03RED\x10\x02\x12\b\n" +
|
||||||
|
"\x04BLUE\x10\x03\x12\r\n" +
|
||||||
|
"\tSTREETCAR\x10\x04B'Z%github.com/cjdenio/uta-trax-api/protob\x06proto3"
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_proto_schema_proto_rawDescOnce sync.Once
|
||||||
|
file_proto_schema_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_proto_schema_proto_rawDescGZIP() []byte {
|
||||||
|
file_proto_schema_proto_rawDescOnce.Do(func() {
|
||||||
|
file_proto_schema_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_schema_proto_rawDesc), len(file_proto_schema_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
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, 2)
|
||||||
|
var file_proto_schema_proto_goTypes = []any{
|
||||||
|
(VehicleFeed_Line)(0), // 0: VehicleFeed.Line
|
||||||
|
(*VehicleFeed)(nil), // 1: VehicleFeed
|
||||||
|
(*VehicleFeed_Vehicle)(nil), // 2: VehicleFeed.Vehicle
|
||||||
|
}
|
||||||
|
var file_proto_schema_proto_depIdxs = []int32{
|
||||||
|
2, // 0: VehicleFeed.vehicles:type_name -> VehicleFeed.Vehicle
|
||||||
|
0, // 1: VehicleFeed.Vehicle.line:type_name -> VehicleFeed.Line
|
||||||
|
2, // [2:2] is the sub-list for method output_type
|
||||||
|
2, // [2:2] is the sub-list for method input_type
|
||||||
|
2, // [2:2] is the sub-list for extension type_name
|
||||||
|
2, // [2:2] is the sub-list for extension extendee
|
||||||
|
0, // [0:2] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_proto_schema_proto_init() }
|
||||||
|
func file_proto_schema_proto_init() {
|
||||||
|
if File_proto_schema_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
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: 2,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_proto_schema_proto_goTypes,
|
||||||
|
DependencyIndexes: file_proto_schema_proto_depIdxs,
|
||||||
|
EnumInfos: file_proto_schema_proto_enumTypes,
|
||||||
|
MessageInfos: file_proto_schema_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_proto_schema_proto = out.File
|
||||||
|
file_proto_schema_proto_goTypes = nil
|
||||||
|
file_proto_schema_proto_depIdxs = nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
option go_package = "github.com/cjdenio/uta-trax-api/proto";
|
||||||
|
|
||||||
|
message VehicleFeed {
|
||||||
|
enum Line {
|
||||||
|
LINE_UNSPECIFIED = 0;
|
||||||
|
GREEN = 1;
|
||||||
|
RED = 2;
|
||||||
|
BLUE = 3;
|
||||||
|
STREETCAR = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Vehicle {
|
||||||
|
float lat = 1;
|
||||||
|
float lon = 2;
|
||||||
|
Line line = 3;
|
||||||
|
int32 direction = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated Vehicle vehicles = 1;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user