package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "vdi-cloud/platform/internal/config" "vdi-cloud/platform/internal/server" "vdi-cloud/platform/internal/store" "vdi-cloud/platform/pkg/proxmox" ) func main() { cfg, err := config.Load() if err != nil { log.Fatal(err) } ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() startup, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() db, err := store.Open(startup, cfg.DatabaseURL) if err != nil { log.Fatal("database initialization failed: ", err) } defer db.Close() if err = store.Bootstrap(startup, db, cfg.Mode, cfg.AdminUsername, cfg.AdminPassword); err != nil { log.Fatal("bootstrap failed: ", err) } var pve *proxmox.Client if cfg.PVEURL != "" { pve, err = proxmox.New(cfg.PVEURL, cfg.PVETokenID, cfg.PVETokenSecret, cfg.PVECAFile) if err != nil { log.Fatal(err) } } s := server.New(cfg, db, pve) go s.RunWorker(ctx) if pve != nil { go s.RunSync(ctx) } httpServer := &http.Server{Addr: cfg.Address, Handler: s.Router, ReadHeaderTimeout: 5 * time.Second, ReadTimeout: 20 * time.Second, WriteTimeout: 30 * time.Second, IdleTimeout: 60 * time.Second} go func() { log.Printf("VDI API listening on %s (mode=%s)", cfg.Address, cfg.Mode) if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Print(err) stop() } }() <-ctx.Done() shutdown, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second) defer shutdownCancel() _ = httpServer.Shutdown(shutdown) }