Add the initial PoC for the app

Should have committed while creating this, but here we are ...
main
Jasper Bok 2023-08-06 23:01:13 +02:00
parent 2fe4a2a313
commit 6d211b5a1e
5 changed files with 221 additions and 0 deletions

111
bus.go 100644
View File

@ -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
}

26
index.html 100644
View File

@ -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>

19
main.go 100644
View File

@ -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()
}

47
server.go 100644
View File

@ -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)
}

18
utils.go 100644
View File

@ -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
}