package bootstrap import ( "context" "encoding/json" "html" "log" "net" "net/http" "strings" "time" "gitea.dooplex.hu/admin/felhom-controller/internal/config" "gitea.dooplex.hu/admin/felhom-controller/internal/i18n" ) // ── Not configured yet: wait for the hub (R-554, v0.308.0, `09` §3 decision 222) ─────────────── // // Until v0.308.0 a box whose first boot could not ingest its configuration (no or bad bootstrap.json, a // hub it could not reach, a failed write) entered the first-boot SETUP WIZARD — eight pages built for the // retired docker-setup.sh install. The agent provisions every box now; the wizard is deleted. Such a box // shows ONE page instead — „Felhom has not reached the central service yet", in both languages — and // retries the ingestion every minute. When it succeeds the page goes away and the controller starts // normally on the same listener. Pinned by TestWaitForConfig_ServesWaitingPageThenStarts. // WaitRetryInterval is how often an unconfigured box retries the ingestion. const WaitRetryInterval = time.Minute // Unconfigured reports whether this controller has no customer id — the only state that waits. func Unconfigured(cfg *config.Config) bool { return cfg == nil || cfg.Customer.ID == "" } // WaitingHandler serves the waiting page on every path, and a health answer on /api/health (the // container's health check must keep passing while the box waits — it is not broken, it is early). func WaitingHandler(version string) http.Handler { page := waitingPage() return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/api/health" { w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]interface{}{ "ok": true, "message": "felhom-controller is waiting for its configuration", "waiting_for_hub": true, "setup_mode": true, "version": version, }) return } w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Cache-Control", "no-store") _, _ = w.Write([]byte(page)) }) } // waitingPage is the page in BOTH languages: an unconfigured box has no household setting to choose by. func waitingPage() string { var b strings.Builder b.WriteString("\n\n
\n\n") b.WriteString("\n") b.WriteString("\n" + html.EscapeString(body) + "
\n