package main import ( "context" "errors" "flag" "fmt" "log" "net/http" "os" "os/signal" "syscall" "time" ) const defaultAddress = ":9105" const defaultDatabasePath = "/var/lib/proxmox-dashboard/dashboard.db" var version = "dev" func main() { showVersion := flag.Bool("version", false, "show version") agentMode := flag.Bool("agent", false, "run as a read-only guest agent") agentServer := flag.String("agent-server", "", "dashboard URL used by the guest agent") agentEnrollToken := flag.String("agent-enroll-token", "", "one-time enrollment token") agentName := flag.String("agent-name", "", "agent display name") agentVMID := flag.Int("agent-vmid", 0, "Proxmox VM/LXC ID") agentConfig := flag.String("agent-config", "/var/lib/proxmox-dashboard-agent/agent.json", "agent configuration path") flag.Parse() if *showVersion { fmt.Println(version) return } if *agentMode { if err := runGuestAgent(agentOptions{Server: *agentServer, EnrollmentToken: *agentEnrollToken, Name: *agentName, VMID: *agentVMID, ConfigPath: *agentConfig}); err != nil { log.Fatalf("Ошибка агента: %v", err) } return } address := os.Getenv("DASHBOARD_ADDR") if address == "" { address = defaultAddress } collector, err := newCPUCollector(cpuInfoPath, procStatPath) if err != nil { log.Fatalf("Не удалось запустить сборщик CPU: %v", err) } databasePath := os.Getenv("DASHBOARD_DB_PATH") if databasePath == "" { databasePath = defaultDatabasePath } store, err := openStore(databasePath) if err != nil { log.Fatalf("Не удалось открыть базу данных: %v", err) } defer store.Close() server := &http.Server{ Addr: address, Handler: routes(collector, store), ReadHeaderTimeout: 5 * time.Second, } runSystemdWatchdog() go func() { log.Printf("Proxmox Dashboard %s запущен на http://0.0.0.0%s", version, address) if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { log.Fatalf("Ошибка веб-сервера: %v", err) } }() stop := make(chan os.Signal, 1) signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM) <-stop ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := server.Shutdown(ctx); err != nil { fmt.Fprintf(os.Stderr, "Ошибка остановки сервера: %v\n", err) } }