package daemon import ( "context" "errors" "fmt" "net" "net/http" "strings" "time" "banger/internal/model" "banger/internal/paths" "banger/internal/webui" ) func (d *Daemon) startWebServer() error { listenAddr := strings.TrimSpace(d.config.WebListenAddr) if listenAddr == "" { d.webURL = "" return nil } listener, err := net.Listen("tcp", listenAddr) if err != nil { if d.logger != nil { d.logger.Error("web ui listen failed", "addr", listenAddr, "error", err.Error()) } return fmt.Errorf("web ui listen on %s: %w", listenAddr, err) } d.webListener = listener d.webURL = "http://" + listener.Addr().String() d.webServer = &http.Server{ Handler: webui.NewHandler(d), ReadHeaderTimeout: 5 * time.Second, } if d.logger != nil { d.logger.Info("web ui serving", "addr", listener.Addr().String(), "url", d.webURL) } go func() { err := d.webServer.Serve(listener) if err == nil || errors.Is(err, http.ErrServerClosed) { return } if d.logger != nil { d.logger.Error("web ui serve failed", "addr", listener.Addr().String(), "error", err.Error()) } }() return nil } func (d *Daemon) Layout() paths.Layout { return d.layout } func (d *Daemon) Config() model.DaemonConfig { return d.config } func (d *Daemon) ListVMs(ctx context.Context) ([]model.VMRecord, error) { return d.store.ListVMs(ctx) } func (d *Daemon) ListImages(ctx context.Context) ([]model.Image, error) { return d.store.ListImages(ctx) }