package server import ( "fmt" "log" "os" "os/signal" "path/filepath" "syscall" "dk/internal/auth" "dk/internal/database" "dk/internal/middleware" "dk/internal/router" "dk/internal/routes" "dk/internal/template" "github.com/valyala/fasthttp" ) func Start(port string) error { cwd, err := os.Getwd() if err != nil { return fmt.Errorf("failed to get current working directory: %w", err) } // Initialize template singleton template.InitializeCache(cwd) // Initialize database singleton if err := database.Init("dk.db"); err != nil { return fmt.Errorf("failed to initialize database: %w", err) } defer database.Close() auth.Init("sessions.json") // Initialize auth.Manager r := router.New() r.Use(middleware.Timing()) r.Use(middleware.Auth(auth.Manager)) r.Use(middleware.CSRF(auth.Manager)) r.Get("/", routes.Index) routes.RegisterAuthRoutes(r) routes.RegisterTownRoutes(r) // Use current working directory for static files assetsDir := filepath.Join(cwd, "assets") // Static file server for /assets fs := &fasthttp.FS{ Root: assetsDir, Compress: false, } assetsHandler := fs.NewRequestHandler() // Combined handler requestHandler := func(ctx *fasthttp.RequestCtx) { path := string(ctx.Path()) // Handle static assets - strip /assets prefix if len(path) >= 7 && path[:7] == "/assets" { // Strip the /assets prefix for the file system handler originalPath := ctx.Path() ctx.Request.URI().SetPath(path[7:]) // Remove "/assets" prefix assetsHandler(ctx) ctx.Request.URI().SetPathBytes(originalPath) // Restore original path return } // Handle routes r.ServeHTTP(ctx) } addr := ":" + port log.Printf("Server starting on %s", addr) // Setup graceful shutdown server := &fasthttp.Server{ Handler: requestHandler, } // Channel to listen for interrupt signal c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) // Start server in a goroutine go func() { if err := server.ListenAndServe(addr); err != nil { log.Printf("Server error: %v", err) } }() // Wait for interrupt signal <-c log.Println("Received shutdown signal, shutting down gracefully...") // Save sessions before shutdown log.Println("Saving sessions...") if err := auth.Manager.Close(); err != nil { log.Printf("Error saving sessions: %v", err) } // FastHTTP doesn't have a graceful Shutdown method like net/http // We just let the server stop naturally when the main function exits log.Println("Server stopped") return nil }