Files
sub-store/cmd/server.go
T

96 lines
2.4 KiB
Go

package cmd
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/gofiber/fiber/v3"
"github.com/sirupsen/logrus"
"github.com/jmoiron/sqlx"
"github.com/peterqiu0516/sub-store/internal/config"
"github.com/peterqiu0516/sub-store/internal/database"
"github.com/peterqiu0516/sub-store/internal/handler"
"github.com/peterqiu0516/sub-store/internal/middleware"
)
func startFiber(cfg *config.Config, db *sqlx.DB) error {
logrus.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
})
logrus.SetLevel(logrus.InfoLevel)
// Start cache cleaner — review-resolution #32
cacheCtx, cacheCancel := context.WithCancel(context.Background())
defer cacheCancel()
cacheInterval := cfg.Fetcher.CacheTTL
if cacheInterval <= 0 {
cacheInterval = 300 * time.Second
}
database.StartCacheCleaner(cacheCtx, db, cacheInterval)
app := fiber.New(fiber.Config{
ReadTimeout: cfg.Server.ReadTimeout,
WriteTimeout: cfg.Server.WriteTimeout,
BodyLimit: cfg.Server.BodyLimit,
ErrorHandler: func(c fiber.Ctx, err error) error {
logrus.WithError(err).WithFields(logrus.Fields{
"method": c.Method(),
"path": c.Path(),
}).Error("request error")
return c.Status(500).JSON(fiber.Map{
"status": "failed",
"error": fiber.Map{"code": 500, "message": "Internal server error"},
})
},
})
// Global middleware
app.Use(middleware.SecurityHeaders())
app.Use(middleware.HandleOptions())
app.Use(middleware.CORS(""))
app.Use(middleware.DownloadHostIsolation(cfg.Auth.DownloadHosts))
// Register routes
handler.RegisterRoutes(app, cfg, db)
// Health check
app.Get("/health", func(c fiber.Ctx) error {
return c.JSON(fiber.Map{"status": "ok"})
})
// Start server
addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)
logrus.Infof("Starting %s on %s", cfg.App.Name, addr)
go func() {
if err := app.Listen(addr); err != nil {
logrus.WithError(err).Error("server failed")
}
}()
// Graceful shutdown — review-resolution #34
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
logrus.Info("Shutting down server...")
cacheCancel()
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer shutdownCancel()
go func() {
<-shutdownCtx.Done()
}()
if err := app.Shutdown(); err != nil {
logrus.WithError(err).Error("shutdown error")
}
logrus.Info("Server stopped")
return nil
}