package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/haopengzhan/rsspipe/internal/api" "github.com/haopengzhan/rsspipe/internal/auth" "github.com/haopengzhan/rsspipe/internal/config" "github.com/haopengzhan/rsspipe/internal/crawler" "github.com/haopengzhan/rsspipe/internal/db" ) func main() { log.Println("==================================================") log.Println(" Starting RSSPipe Server ") log.Println("==================================================") cfg := config.LoadConfig() // 1. Initialize SQLite Database database, err := db.InitDB(cfg.DBPath) if err != nil { log.Fatalf("Fatal: Database initialization failed: %v", err) } defer database.Close() log.Printf("==> Database connected: %s (WAL mode enabled)\n", cfg.DBPath) // 2. Initialize Auth Service & Bootstrap Admin authService := auth.NewAuthService(database, cfg) if err := authService.BootstrapAdmin(); err != nil { log.Fatalf("Fatal: Admin bootstrap failed: %v", err) } // 3. Start Background Crawler Pool ctx, cancel := context.WithCancel(context.Background()) defer cancel() cr := crawler.NewCrawler(database, cfg.CrawlerIntervalMinutes, cfg.CrawlerWorkers) cr.Start(ctx) // 4. Mount API Routes handler := api.NewHandler(database, authService, cr) router := api.NewRouter(handler, authService, "./web/dist") server := &http.Server{ Addr: ":" + cfg.Port, Handler: router, ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, IdleTimeout: 120 * time.Second, } // 5. Graceful shutdown handler go func() { sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) <-sigChan log.Println("\n==> Shutting down RSSPipe gracefully...") cancel() shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second) defer shutdownCancel() if err := server.Shutdown(shutdownCtx); err != nil { log.Printf("Error during server shutdown: %v\n", err) } }() log.Printf("==> RSSPipe HTTP Server listening at http://localhost:%s\n", cfg.Port) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("Fatal: Server error: %v", err) } log.Println("==> RSSPipe Server stopped.") }