package main
import (
"html/template"
"log"
"net/http"
"strconv"
"time"
)
type Server struct {
config *Config
data []StationData
}
func NewServer(config *Config) *Server {
return &Server{
config: config,
}
}
func (s *Server) refreshData() {
log.Println("Refreshing station data...")
s.data = FetchAllStationsData(s.config.Stations)
log.Printf("Updated data for %d stations", len(s.data))
}
func (s *Server) indexHandler(w http.ResponseWriter, r *http.Request) {
// Refresh data on page load
s.refreshData()
tmpl := `
Sundial - Live Train Departures
{{range .Stations}}
{{.Station.Name}} ({{.Station.Code}})
{{if .Error}}
ERROR: {{.Error}}
{{else}}
{{if not .Departures}}
No departures found - The National Rail website now uses dynamic JavaScript to load departure data.
This simple HTTP scraper cannot access the live data. Consider using the National Rail API instead.
{{else}}
| Time |
Destination |
Pl. |
{{range .Departures}}
|
{{if .ExpectedTime}}{{.ExpectedTime}}{{else}}{{.ScheduledTime}}{{end}}
|
{{.Destination}}{{if .Via}} {{.Via}}{{end}}
|
{{.Platform}} |
{{end}}
{{end}}
{{end}}
{{end}}
`
t, err := template.New("index").Parse(tmpl)
if err != nil {
http.Error(w, "Template error", http.StatusInternalServerError)
return
}
data := struct {
Stations []StationData
RefreshInterval int
LastUpdateTime string
}{
Stations: s.data,
RefreshInterval: s.config.Server.RefreshInterval,
LastUpdateTime: getLastUpdateTime(s.data).Format("15:04"),
}
w.Header().Set("Content-Type", "text/html")
err = t.Execute(w, data)
if err != nil {
log.Printf("Template execution error: %v", err)
}
}
func (s *Server) Start() error {
http.HandleFunc("/", s.indexHandler)
addr := ":" + strconv.Itoa(s.config.Server.Port)
log.Printf("Starting server on http://localhost%s", addr)
log.Printf("Auto-refresh every %d seconds", s.config.Server.RefreshInterval)
return http.ListenAndServe(addr, nil)
}
// getLastUpdateTime finds the most recent update time from all stations
func getLastUpdateTime(stations []StationData) time.Time {
if len(stations) == 0 {
return time.Now()
}
latest := stations[0].LastUpdate
for _, station := range stations[1:] {
if station.LastUpdate.After(latest) {
latest = station.LastUpdate
}
}
return latest
}