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
SUNDIAL - LIVE TRAIN DEPARTURES
Last updated: {{.LastUpdateTime}}

{{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}} {{range .Departures}} {{if .ExpectedTime}}{{.ExpectedTime}}{{else}}{{.ScheduledTime}}{{end}} {{end}}
Time Destination Pl.
{{.Destination}}{{if .Via}} {{.Via}}{{end}} {{.Platform}}
{{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 }