diff --git a/bus.go b/bus.go new file mode 100644 index 0000000..8ec9597 --- /dev/null +++ b/bus.go @@ -0,0 +1,111 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "time" +) + +type Departure struct { + TripID int + RealtimeTripId string + StopHeadsign string + ArrivalTime time.Time + DepartureTime time.Time + RouteShortName string +} + +type ResponseDeparture struct { + TripID int `json:"trip_id"` + RealtimeTripId string `json:"realtime_trip_id"` + StopHeadsign string `json:"stop_headsign"` + ArrivalTime string `json:"arrival_time"` + DepartureTime string `json:"departure_time"` + Tripdata struct { + Route struct { + RouteShortName string `json:"route_short_name"` + } `json:"route"` + } `json:"tripdata"` +} + +// ToDeparture transforms the ResponseDeparture struct to a Departure. +func (rd ResponseDeparture) ToDeparture() (Departure, error) { + var departure Departure + + departure.TripID = rd.TripID + departure.RealtimeTripId = rd.RealtimeTripId + departure.StopHeadsign = rd.StopHeadsign + departure.RouteShortName = rd.Tripdata.Route.RouteShortName + + _time, err := parseUnixTimestamp(rd.ArrivalTime) + if err != nil { + return departure, err + } + departure.ArrivalTime = _time + + _time, err = parseUnixTimestamp(rd.DepartureTime) + if err != nil { + return departure, err + } + departure.DepartureTime = _time + + return departure, nil +} + +type QueryResponse struct { + Results []struct { + Departures []ResponseDeparture `json:"departures"` + } `json:"results"` +} + +func getDepartures(quay Quay) ([]Departure, error) { + var stop string + var uri string + var data QueryResponse + var departures []Departure + + q, err := json.Marshal(quay) + if err != nil { + return departures, err + } + + stop = string(q) + uri = fmt.Sprintf("https://www.breng.nl/api/travelplanner/quays/departures?stop=%s", url.QueryEscape(stop)) + + req, err := http.NewRequest("GET", uri, nil) + if err != nil { + return departures, err + } + + resp, err := BusClient.Do(req) + if err != nil { + return departures, err + } + + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return departures, err + } + + err = json.Unmarshal(body, &data) + if err != nil { + return departures, err + } + + for _, r := range data.Results { + for _, rd := range r.Departures { + d, err := rd.ToDeparture() + if err != nil { + return departures, err + } + departures = append(departures, d) + } + } + + return departures, nil +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..f7820dd --- /dev/null +++ b/index.html @@ -0,0 +1,26 @@ + + + + + Busvertrektijden + + + +{{ range .Quays }} +
+

{{ .Name }}

+

{{ .Town }}

+ + {{ range .Departures }} +
+
{{ .RouteShortName }} | {{ .StopHeadsign }}
+
+
+ {{ end }} +
+{{ end }} + + \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..544058f --- /dev/null +++ b/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "net/http" +) + +type Quay struct { + ID string `json:"quayid"` + Name string `json:"name"` + Town string `json:"town"` +} + +var BusClient *http.Client +var Quays []Quay = []Quay{} + +func main() { + BusClient = &http.Client{} + serveHttp() +} diff --git a/server.go b/server.go new file mode 100644 index 0000000..b36d4c0 --- /dev/null +++ b/server.go @@ -0,0 +1,47 @@ +package main + +import ( + "html/template" + "log" + "net/http" +) + +type TemplateQuay struct { + Name string + Town string + Departures []Departure +} + +type TemplateContext struct { + Quays []TemplateQuay +} + +func serveHttp() { + http.HandleFunc("/", handleIndex) + + log.Println("Serving on port 4444") + + err := http.ListenAndServe(":4444", nil) + if err != nil { + log.Fatal(err) + } +} + +func handleIndex(w http.ResponseWriter, r *http.Request) { + var ctxt = TemplateContext{} + + for _, quay := range Quays { + departures, err := getDepartures(quay) + if err != nil { + log.Printf("Error retrieving departures for quay '%s'", quay.ID) + continue + } + + ctxt.Quays = append(ctxt.Quays, TemplateQuay{quay.Name, quay.Town, departures}) + } + + tpl := template.New("index.html") + tpl, _ = tpl.ParseFiles("index.html") + + _ = tpl.Execute(w, ctxt) +} diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..a83e1b2 --- /dev/null +++ b/utils.go @@ -0,0 +1,18 @@ +package main + +import ( + "strconv" + "time" +) + +// parseUnixTimestamp parses a string containing a UNIX timestamp to a time.Time. +func parseUnixTimestamp(timestamp string) (time.Time, error) { + var t = time.Time{} + + i, err := strconv.ParseInt(timestamp, 10, 64) + if err != nil { + return t, err + } + + return time.Unix(i, 0), nil +}