Latest Updates done, before integrating
This commit is contained in:
83
main.go
83
main.go
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/tb/ems/internal/actuator"
|
||||
"github.com/tb/ems/internal/auth"
|
||||
"github.com/tb/ems/internal/collector"
|
||||
"github.com/tb/ems/internal/config"
|
||||
"github.com/tb/ems/internal/engine"
|
||||
@@ -134,36 +135,74 @@ func main() {
|
||||
// Build sorted car option list for the status page form
|
||||
carOptions := buildCarOptions(cfg.Cars)
|
||||
|
||||
// Auth manager — loads or generates persistent session and CSRF tokens.
|
||||
// Token files live alongside other persistent state in /var/lib/ems/.
|
||||
tokenDir := filepath.Dir(cfg.EMS.SessionLogFile)
|
||||
authMgr := auth.New(cfg.EMS.HTTPUsername, cfg.EMS.HTTPPassword, tokenDir, logger)
|
||||
if authMgr.Enabled() {
|
||||
logger.Info("web UI authentication enabled", "username", cfg.EMS.HTTPUsername)
|
||||
} else {
|
||||
logger.Warn("web UI authentication disabled — set ems.http_username and ems.http_password to enable")
|
||||
}
|
||||
|
||||
// Status store (shared between HTTP handler and control loop)
|
||||
wwConfigured := cfg.Viessmann.InstallationID != ""
|
||||
statusStore := status.NewStore(*dryRun, wwConfigured, cfg.Strategic, cfg.CarCharging, monitorMode, wwBoostDisabled, tripMgr, carOptions)
|
||||
statusStore := status.NewStore(*dryRun, wwConfigured, cfg.Strategic, cfg.CarCharging, monitorMode, wwBoostDisabled, tripMgr, carOptions, authMgr.CSRFToken(), authMgr.Enabled())
|
||||
|
||||
// Metrics HTTP server
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
|
||||
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
// Web UI server — authenticated, serves status page and control endpoints.
|
||||
uiMux := http.NewServeMux()
|
||||
uiMux.HandleFunc("/login", authMgr.LoginHandler())
|
||||
uiMux.HandleFunc("/logout", authMgr.LogoutHandler())
|
||||
uiMux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("ok"))
|
||||
w.Write([]byte("ok")) //nolint:errcheck
|
||||
})
|
||||
mux.HandleFunc("/override", overrideHandler(act, eng, logger))
|
||||
mux.HandleFunc("/monitor", monitorHandler(monitorMode, logger))
|
||||
mux.HandleFunc("/trip", tripSetHandler(tripMgr, cfg, logger))
|
||||
mux.HandleFunc("/trip/cancel", tripCancelHandler(tripMgr, logger))
|
||||
mux.HandleFunc("/ww/reset", wwResetHandler(act, eng, cfg, logger))
|
||||
mux.HandleFunc("/ww/boost", wwBoostToggleHandler(wwBoostDisabled, logger))
|
||||
mux.HandleFunc("/", statusStore.Handler())
|
||||
uiMux.HandleFunc("/override", overrideHandler(act, eng, logger))
|
||||
uiMux.HandleFunc("/monitor", monitorHandler(monitorMode, logger))
|
||||
uiMux.HandleFunc("/trip", tripSetHandler(tripMgr, cfg, logger))
|
||||
uiMux.HandleFunc("/trip/cancel", tripCancelHandler(tripMgr, logger))
|
||||
uiMux.HandleFunc("/ww/reset", wwResetHandler(act, eng, cfg, logger))
|
||||
uiMux.HandleFunc("/ww/boost", wwBoostToggleHandler(wwBoostDisabled, logger))
|
||||
uiMux.HandleFunc("/", statusStore.Handler())
|
||||
|
||||
srv := &http.Server{
|
||||
var uiHandler http.Handler = authMgr.VerifyCSRF(uiMux)
|
||||
uiHandler = authMgr.RequireAuth(uiHandler)
|
||||
|
||||
uiSrv := &http.Server{
|
||||
Addr: cfg.EMS.ListenAddr,
|
||||
Handler: mux,
|
||||
Handler: uiHandler,
|
||||
}
|
||||
|
||||
// Metrics server — no auth, for Prometheus scraping.
|
||||
// Bind to MetricsAddr; if unset, skip the separate server (metrics stay on UI port).
|
||||
var metricsSrv *http.Server
|
||||
if cfg.EMS.MetricsAddr != "" && cfg.EMS.MetricsAddr != cfg.EMS.ListenAddr {
|
||||
metMux := http.NewServeMux()
|
||||
metMux.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
|
||||
metMux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("ok")) //nolint:errcheck
|
||||
})
|
||||
metricsSrv = &http.Server{Addr: cfg.EMS.MetricsAddr, Handler: metMux}
|
||||
} else {
|
||||
// Fallback: add /metrics to the UI mux (no separate port configured)
|
||||
uiMux.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
|
||||
}
|
||||
|
||||
go func() {
|
||||
logger.Info("metrics server listening", "addr", cfg.EMS.ListenAddr)
|
||||
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
||||
logger.Error("metrics server error", "error", err)
|
||||
logger.Info("web UI listening", "addr", cfg.EMS.ListenAddr)
|
||||
if err := uiSrv.ListenAndServe(); err != http.ErrServerClosed {
|
||||
logger.Error("web UI server error", "error", err)
|
||||
}
|
||||
}()
|
||||
if metricsSrv != nil {
|
||||
go func() {
|
||||
logger.Info("metrics server listening", "addr", cfg.EMS.MetricsAddr)
|
||||
if err := metricsSrv.ListenAndServe(); err != http.ErrServerClosed {
|
||||
logger.Error("metrics server error", "error", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Graceful shutdown
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@@ -192,7 +231,10 @@ func main() {
|
||||
|
||||
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer shutdownCancel()
|
||||
srv.Shutdown(shutdownCtx)
|
||||
uiSrv.Shutdown(shutdownCtx) //nolint:errcheck
|
||||
if metricsSrv != nil {
|
||||
metricsSrv.Shutdown(shutdownCtx) //nolint:errcheck
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -235,7 +277,7 @@ func runCycle(
|
||||
logger.Warn("all Shelly devices unreachable, skipping override detection", "error", err)
|
||||
} else {
|
||||
shellyStates = states
|
||||
eng.SyncHardwareState(shellyStates, now, cfg.EMS.OverrideTimeoutParsed())
|
||||
eng.SyncHardwareState(shellyStates, now, cfg.EMS.OverrideTimeoutParsed(), monitorMode.IsActive())
|
||||
store.SyncDeviceStates(shellyStates)
|
||||
}
|
||||
|
||||
@@ -751,3 +793,4 @@ func writeHeartbeat(stateFile string, logger *slog.Logger) {
|
||||
logger.Warn("could not write heartbeat file", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user