// mosis-portal: Developer portal and app store backend for Mosis package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "omixlab.com/mosis-portal/internal/api" "omixlab.com/mosis-portal/internal/config" "omixlab.com/mosis-portal/internal/database" ) func main() { // Load configuration cfg, err := config.Load() if err != nil { log.Fatalf("failed to load config: %v", err) } // Initialize database sqlDB, err := database.Open(cfg.DatabasePath) if err != nil { log.Fatalf("failed to open database: %v", err) } defer sqlDB.Close() // Run migrations if err := database.Migrate(sqlDB); err != nil { log.Fatalf("failed to run migrations: %v", err) } // Wrap database with business logic db := database.NewDB(sqlDB) // Create router router := api.NewRouter(cfg, db) // Create server server := &http.Server{ Addr: cfg.ListenAddr, Handler: router, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, } // Start server in goroutine go func() { log.Printf("Starting mosis-portal on %s", cfg.ListenAddr) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("server error: %v", err) } }() // Wait for interrupt signal quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("Shutting down server...") // Graceful shutdown with timeout ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := server.Shutdown(ctx); err != nil { log.Fatalf("server forced to shutdown: %v", err) } log.Println("Server stopped") }