// fleet serves the read-only luxd fleet overview the lux.cloud dashboard polls. // // It runs inside the cluster that hosts the fleet, reads every luxd pod over // that node's own /v1 HTTP RPC, and answers one document: // // GET /health liveness // GET /v1/fleets/lux/overview the fleet, optionally ?networks=a,b // // The response is public chain state — node IDs, versions, heights, peer // counts — so it carries no auth and no secrets: the lux.cloud landing page // renders it for signed-out visitors. package main import ( "os" "strings" luxlog "github.com/luxfi/log" "github.com/zap-proto/zip" "github.com/zap-proto/zip/middleware" "github.com/hanzoai/bootnode/fleet" ) func main() { log := luxlog.New("module", "fleet") cluster, err := fleet.NewInCluster() if err != nil { log.Error("cluster unreachable", "err", err) os.Exit(1) } app := newApp(log, &fleet.Collector{Cluster: cluster, Prober: fleet.NewRPC(), Markets: fleet.NewGraph()}) // The scheme picks the transport: a bare address would serve ZAP, and the // dashboard and the kubelet both speak HTTP. addr := os.Getenv("FLEET_ADDR") if addr == "" { addr = "http://:8000" } log.Info("lux fleet listening", "addr", addr) if err := app.Listen(addr); err != nil { log.Error("serve failed", "err", err) os.Exit(1) } } // newApp is the whole HTTP surface: two routes, one of them a Group. func newApp(log luxlog.Logger, c *fleet.Collector) *zip.App { app := zip.New(zip.Config{Logger: log, AppName: "lux-fleet"}) app.Use( middleware.Recover(), middleware.RequestID(), middleware.CORS(middleware.CORSConfig{AllowMethods: []string{"GET", "OPTIONS"}}), ) app.Get("/health", func(ctx *zip.Ctx) error { return ctx.JSON(200, map[string]any{"status": "ok", "k8s_enrichment": fleet.Available()}) }) app.Group("/v1/fleets/lux").Get("/overview", func(ctx *zip.Ctx) error { return ctx.JSON(200, c.Overview(ctx.Context(), networks(ctx.Query("networks")))) }) return app } // networks parses the comma-separated ?networks= filter; empty means all. func networks(q string) []string { var out []string for _, n := range strings.Split(q, ",") { if n = strings.TrimSpace(n); n != "" { out = append(out, n) } } return out }