package http import ( "context" "fmt" "net/http" "os" "os/signal" "strings" "syscall" "time" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/limiter" "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/recover" "github.com/subconverter-go/internal/config" "github.com/subconverter-go/internal/logging" ) // Server HTTP服务器封装 // 封装Fiber HTTP服务器功能,提供统一的HTTP服务接口 type Server struct { app *fiber.App config *config.ServerConfig logger *logging.Logger manager *config.ConfigManager startTime time.Time } // NewServer 创建新的HTTP服务器 // 返回初始化好的Server实例 func NewServer(manager *config.ConfigManager) (*Server, error) { if manager == nil { return nil, fmt.Errorf("config manager cannot be nil") } // 获取日志记录器 logger, err := logging.NewDefaultLogger() if err != nil { return nil, fmt.Errorf("failed to create logger: %v", err) } // 获取服务器配置 serverConfig := manager.GetServerConfig() if serverConfig == nil { return nil, fmt.Errorf("server config cannot be nil") } // 创建Fiber应用 app := fiber.New(fiber.Config{ AppName: "subconverter-go", ServerHeader: "subconverter-go", ReadTimeout: time.Duration(serverConfig.ReadTimeout) * time.Second, WriteTimeout: time.Duration(serverConfig.WriteTimeout) * time.Second, IdleTimeout: time.Duration(serverConfig.WriteTimeout) * time.Second, BodyLimit: int(serverConfig.MaxRequestSize), CaseSensitive: false, StrictRouting: false, EnablePrintRoutes: false, }) server := &Server{ app: app, config: serverConfig, logger: logger, manager: manager, startTime: time.Now(), } // 设置中间件 server.setupMiddleware() // 设置路由 server.setupRoutes() return server, nil } // setupMiddleware 设置中间件 func (s *Server) setupMiddleware() { // 恢复中间件 - 处理panic s.app.Use(recover.New(recover.Config{ EnableStackTrace: true, StackTraceHandler: func(c *fiber.Ctx, e any) { s.logger.WithField("error", e).Error("Panic recovered") }, })) // 日志中间件 s.app.Use(logger.New(logger.Config{ Format: "${time} | ${status} | ${latency} | ${ip} | ${method} | ${path} | ${error}\n", Output: s.logger.Logger.Out, })) // CORS中间件 s.setupCORS() // 速率限制中间件 s.setupRateLimiter() } // setupCORS 设置CORS func (s *Server) setupCORS() { securityConfig := s.manager.GetSecurityConfig() if securityConfig == nil { securityConfig = &config.SecurityConfig{ CorsOrigins: []string{"*"}, } } s.app.Use(cors.New(cors.Config{ AllowOrigins: strings.Join(securityConfig.CorsOrigins, ","), AllowMethods: "GET,POST,PUT,DELETE,OPTIONS", AllowHeaders: "*", MaxAge: 86400, // 24 hours })) } // setupRateLimiter 设置速率限制 func (s *Server) setupRateLimiter() { securityConfig := s.manager.GetSecurityConfig() if securityConfig == nil || securityConfig.RateLimit <= 0 { // 不启用速率限制 return } s.app.Use(limiter.New(limiter.Config{ Max: securityConfig.RateLimit, Expiration: 60 * time.Second, // 1分钟窗口 KeyGenerator: func(c *fiber.Ctx) string { return c.IP() }, LimitReached: func(c *fiber.Ctx) error { s.logger.WithField("ip", c.IP()).Warn("Rate limit exceeded") return c.Status(fiber.StatusTooManyRequests).JSON(fiber.Map{ "error": "Rate limit exceeded", }) }, })) } // setupRoutes 设置路由 func (s *Server) setupRoutes() { // 健康检查路由 s.app.Get("/health", s.healthCheck) // 版本信息路由 s.app.Get("/version", s.versionInfo) // 根路由 s.app.Get("/", s.rootHandler) // API路由组 api := s.app.Group("/api") // 转换相关路由 api.Get("/sub", s.convertHandler) api.Post("/sub", s.convertHandler) // 配置相关路由 api.Get("/config", s.getConfigHandler) api.Post("/config", s.updateConfigHandler) // 代理相关路由 api.Get("/proxy/validate", s.validateProxyHandler) api.Post("/proxy/validate", s.validateProxyHandler) // 统计信息路由 api.Get("/stats", s.statsHandler) } // Start 启动HTTP服务器 func (s *Server) Start() error { s.logger.Infof("Starting HTTP server on %s:%d", s.config.Host, s.config.Port) // 创建监听地址 addr := fmt.Sprintf("%s:%d", s.config.Host, s.config.Port) // 启动服务器 go func() { if err := s.app.Listen(addr); err != nil && err != http.ErrServerClosed { s.logger.WithError(err).Error("Failed to start HTTP server") os.Exit(1) } }() s.logger.Infof("HTTP server started successfully") return nil } // Stop 停止HTTP服务器 func (s *Server) Stop() error { s.logger.Info("Stopping HTTP server...") // 创建上下文,设置5秒超时 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // 优雅关闭服务器 if err := s.app.ShutdownWithContext(ctx); err != nil { s.logger.WithError(err).Error("Failed to shutdown HTTP server gracefully") return err } s.logger.Info("HTTP server stopped successfully") return nil } // WaitForShutdown 等待服务器关闭信号 func (s *Server) WaitForShutdown() { // 创建信号通道 quit := make(chan os.Signal, 1) // 监听中断信号 signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // 等待信号 <-quit s.logger.Info("Received shutdown signal, shutting down server...") // 停止服务器 if err := s.Stop(); err != nil { s.logger.WithError(err).Error("Error during server shutdown") } } // GetApp 获取Fiber应用实例 // 用于测试或扩展功能 func (s *Server) GetApp() *fiber.App { return s.app } // GetUptime 获取服务器运行时间 func (s *Server) GetUptime() time.Duration { return time.Since(s.startTime) } // GetStats 获取服务器统计信息 func (s *Server) GetStats() map[string]interface{} { return map[string]interface{}{ "uptime": s.GetUptime().String(), "start_time": s.startTime.Format(time.RFC3339), "host": s.config.Host, "port": s.config.Port, "max_request_size": s.config.MaxRequestSize, "read_timeout": s.config.ReadTimeout, "write_timeout": s.config.WriteTimeout, } } // 健康检查处理器 func (s *Server) healthCheck(c *fiber.Ctx) error { health := map[string]interface{}{ "status": "healthy", "uptime": s.GetUptime().String(), "version": "1.0.0", "host": s.config.Host, "port": s.config.Port, } return c.JSON(health) } // 版本信息处理器 func (s *Server) versionInfo(c *fiber.Ctx) error { version := map[string]interface{}{ "version": "1.0.0", "name": "subconverter-go", "description": "Proxy subscription converter service", "author": "subconverter-go team", "uptime": s.GetUptime().String(), } return c.JSON(version) } // 根路径处理器 func (s *Server) rootHandler(c *fiber.Ctx) error { info := map[string]interface{}{ "service": "subconverter-go", "version": "1.0.0", "status": "running", "endpoints": []string{ "GET /health - Health check", "GET /version - Version information", "GET /api/sub - Convert subscription", "POST /api/sub - Convert subscription", "GET /api/config - Get configuration", "POST /api/config - Update configuration", "GET /api/proxy/validate - Validate proxy", "POST /api/proxy/validate - Validate proxy", "GET /api/stats - Server statistics", }, "uptime": s.GetUptime().String(), } return c.JSON(info) } // 转换处理器(占位符) func (s *Server) convertHandler(c *fiber.Ctx) error { s.logger.Info("Convert handler called (placeholder)") return c.Status(fiber.StatusNotImplemented).JSON(fiber.Map{ "error": "Conversion handler not implemented yet", }) } // 获取配置处理器(占位符) func (s *Server) getConfigHandler(c *fiber.Ctx) error { s.logger.Info("Get config handler called (placeholder)") return c.Status(fiber.StatusNotImplemented).JSON(fiber.Map{ "error": "Get config handler not implemented yet", }) } // 更新配置处理器(占位符) func (s *Server) updateConfigHandler(c *fiber.Ctx) error { s.logger.Info("Update config handler called (placeholder)") return c.Status(fiber.StatusNotImplemented).JSON(fiber.Map{ "error": "Update config handler not implemented yet", }) } // 验证代理处理器(占位符) func (s *Server) validateProxyHandler(c *fiber.Ctx) error { s.logger.Info("Validate proxy handler called (placeholder)") return c.Status(fiber.StatusNotImplemented).JSON(fiber.Map{ "error": "Validate proxy handler not implemented yet", }) } // 统计信息处理器(占位符) func (s *Server) statsHandler(c *fiber.Ctx) error { stats := s.GetStats() stats["requests"] = 0 // 占位符 stats["errors"] = 0 // 占位符 return c.JSON(stats) }