package web
import (
"html/template"
"net/http"
)
// ConvoyFetcher defines the interface for fetching convoy data.
type ConvoyFetcher interface {
FetchConvoys() ([]ConvoyRow, error)
FetchMergeQueue() ([]MergeQueueRow, error)
FetchPolecats() ([]PolecatRow, error)
}
// ConvoyHandler handles HTTP requests for the convoy dashboard.
type ConvoyHandler struct {
fetcher ConvoyFetcher
template *template.Template
}
// NewConvoyHandler creates a new convoy handler with the given fetcher.
func NewConvoyHandler(fetcher ConvoyFetcher) (*ConvoyHandler, error) {
tmpl, err := LoadTemplates()
if err != nil {
return nil, err
}
return &ConvoyHandler{
fetcher: fetcher,
template: tmpl,
}, nil
}
// ServeHTTP handles GET / requests and renders the convoy dashboard.
func (h *ConvoyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
convoys, err := h.fetcher.FetchConvoys()
if err != nil {
http.Error(w, "Failed to fetch convoys", http.StatusInternalServerError)
return
}
mergeQueue, err := h.fetcher.FetchMergeQueue()
if err != nil {
// Non-fatal: show convoys even if merge queue fails
mergeQueue = nil
}
polecats, err := h.fetcher.FetchPolecats()
if err != nil {
// Non-fatal: show convoys even if polecats fail
polecats = nil
}
data := ConvoyData{
Convoys: convoys,
MergeQueue: mergeQueue,
Polecats: polecats,
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := h.template.ExecuteTemplate(w, "convoy.html", data); err != nil {
http.Error(w, "Failed to render template", http.StatusInternalServerError)
return
}
}