142 lines
3.2 KiB
Go
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)
|
|
}
|