// Commande server : point d'entrée du backend PdfEditor. package main import ( "context" "errors" "log" "net/http" "os" "os/signal" "syscall" "time" "pdfeditor/internal/auth" "pdfeditor/internal/config" "pdfeditor/internal/db" "pdfeditor/internal/handlers" "pdfeditor/internal/storage" ) func main() { // Chargement de la configuration depuis l'environnement. cfg, err := config.Load() if err != nil { log.Fatalf("configuration : %v", err) } ctx := context.Background() // Application des migrations au démarrage. log.Println("application des migrations...") if err := db.Migrate(cfg.DatabaseURL); err != nil { log.Fatalf("migrations : %v", err) } // Connexion à la base (pool pgx). pool, err := db.Connect(ctx, cfg.DatabaseURL) if err != nil { log.Fatalf("base de données : %v", err) } defer pool.Close() // Initialisation du stockage des fichiers. store, err := storage.New(cfg.StoragePath) if err != nil { log.Fatalf("stockage : %v", err) } // Gestionnaire d'authentification. authMgr := auth.NewManager(cfg.JWTSecret, cfg.JWTAccessTTL, cfg.JWTRefreshTTL) // Construction de l'API et du routeur. api := handlers.New(pool, authMgr, store) router := api.Router(cfg.CORSOrigin) srv := &http.Server{ Addr: ":" + cfg.Port, Handler: router, ReadHeaderTimeout: 10 * time.Second, // Pas de WriteTimeout court : upload/download de PDF peuvent être longs. } // Démarrage du serveur dans une goroutine pour permettre l'arrêt propre. go func() { log.Printf("serveur à l'écoute sur le port %s", cfg.Port) if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalf("serveur : %v", err) } }() // Attente d'un signal d'arrêt. stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt, syscall.SIGTERM) <-stop log.Println("arrêt en cours...") shutdownCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() if err := srv.Shutdown(shutdownCtx); err != nil { log.Printf("arrêt forcé : %v", err) } log.Println("serveur arrêté") }