Add the initial PoC for the app
Should have committed while creating this, but here we are ...main
parent
2fe4a2a313
commit
6d211b5a1e
|
@ -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
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="nl">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Busvertrektijden</title>
|
||||||
|
<style>
|
||||||
|
h2 { margin-bottom: 2px; }
|
||||||
|
dt { font-weight: bold; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{{ range .Quays }}
|
||||||
|
<article>
|
||||||
|
<h2>{{ .Name }}</h2>
|
||||||
|
<p>{{ .Town }}</p>
|
||||||
|
|
||||||
|
{{ range .Departures }}
|
||||||
|
<dl>
|
||||||
|
<dt>{{ .RouteShortName }} | {{ .StopHeadsign }}</dt>
|
||||||
|
<dd><time>{{ .DepartureTime }}</time></dd>
|
||||||
|
</dl>
|
||||||
|
{{ end }}
|
||||||
|
</article>
|
||||||
|
{{ end }}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -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()
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue