Files
go-gtfs/cmd/planner/main.go
2025-11-15 00:23:48 +01:00

142 lines
3.2 KiB
Go

package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strconv"
"time"
"git.tornberg.me/go-gtfs/pkg/reader"
"git.tornberg.me/go-gtfs/pkg/types"
)
type Edge struct {
To string
TripID string
Time types.SecondsAfterMidnight
DepartureTime types.SecondsAfterMidnight
}
type TripDetail struct {
RouteShortName string `json:"route_short_name"`
AgencyName string `json:"agency_name"`
Stops []string `json:"stops"`
}
type Leg struct {
From *types.StopTime `json:"start"`
To *types.StopTime `json:"end"`
}
type Route struct {
Legs []Leg `json:"legs"`
}
func (r *Route) EndTime() types.SecondsAfterMidnight {
if len(r.Legs) == 0 {
return 0
}
return r.Legs[len(r.Legs)-1].To.ArrivalTime
}
func (r *Route) StartTime() types.SecondsAfterMidnight {
if len(r.Legs) == 0 {
return 0
}
return r.Legs[0].From.DepartureTime
}
func (r *Route) Duration() int {
if len(r.Legs) == 0 {
return 0
}
return int(r.Legs[len(r.Legs)-1].To.ArrivalTime - r.Legs[0].From.DepartureTime)
}
type PathInfo struct {
Prev string
TripID string
DepartureTime time.Time
Transfers int
LastTrip string
WaitDuration time.Duration
}
func main() {
tripData, err := reader.LoadTripData("data")
if err != nil {
log.Fatalf("unable to load data %v", err)
}
tp := NewTripPlanner(tripData)
if err := tp.Preprocess(); err != nil {
fmt.Printf("Failed to preprocess data: %v\n", err)
os.Exit(1)
}
if hosjo, ok := tp.Stops["740025287"]; ok {
trips := hosjo.GetTripsAfter(time.Now())
for trip := range trips {
log.Printf("Trip %s (%s):", trip.TripShortName, trip.TripHeadsign)
for stop := range trip.GetDirectPossibleDestinations(hosjo, time.Now()) {
log.Printf("- Stop %s at %s", stop.Stop.StopName, types.AsTime(stop.ArrivalTime))
}
}
}
http.HandleFunc("/api/stops", func(w http.ResponseWriter, r *http.Request) {
stopList := []types.Stop{}
for _, s := range tp.Stops {
if len(s.Trips) > 0 {
stopList = append(stopList, *s)
}
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(stopList)
})
http.HandleFunc("/api/route", func(w http.ResponseWriter, r *http.Request) {
from := r.URL.Query().Get("from")
to := r.URL.Query().Get("to")
whenStr := r.URL.Query().Get("when")
numStr := r.URL.Query().Get("num")
num := 3
if numStr != "" {
if parsed, err := strconv.Atoi(numStr); err == nil && parsed > 0 {
num = parsed
}
}
when := time.Now()
if whenStr != "" {
if parsed, err := time.Parse(time.DateTime, whenStr); err == nil {
when = parsed
}
}
if from == "" || to == "" {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{"error": "from and to parameters required"})
return
}
log.Printf("using num %v", num)
w.WriteHeader(http.StatusOK)
log.Printf("start time %v", when)
route, err := tp.FindRoute(from, to, when)
if err != nil {
w.WriteHeader(http.StatusNotFound)
json.NewEncoder(w).Encode(map[string]string{"error": "no route found"})
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(route)
})
log.Printf("Listening on 8080")
http.ListenAndServe(":8080", nil)
}