package service import ( "fmt" "net/http" "os" "os/signal" "syscall" "time" "github.com/gofiber/fiber/v2" "github.com/subconverter-go/internal/cache" "github.com/subconverter-go/internal/config" "github.com/subconverter-go/internal/conversion" "github.com/subconverter-go/internal/generator" "github.com/subconverter-go/internal/handler" "github.com/subconverter-go/internal/logging" "github.com/subconverter-go/internal/middleware" "github.com/subconverter-go/internal/parser" ) // Application 应用程序主服务 // 整合所有组件并提供统一的启动和管理接口 type Application struct { config *config.ConfigManager logger *logging.Logger httpServer *fiber.App cacheMgr *cache.CacheManager convEngine *conversion.ConversionEngine parserMgr *parser.ParserManager generatorMgr *generator.GeneratorManager conversionHandler *handler.ConversionHandler health *handler.HealthHandler version *handler.VersionHandler templateHandler *handler.TemplateHandler } // NewApplication 创建新的应用程序实例 func NewApplication(configPath string) (*Application, error) { // 创建日志记录器 logger, err := logging.NewDefaultLogger() if err != nil { return nil, fmt.Errorf("failed to create logger: %v", err) } // 加载配置 configMgr, err := config.NewConfigManager(configPath) if err != nil { return nil, fmt.Errorf("failed to load config: %v", err) } // 创建解析器管理器 parserMgr := parser.NewParserManager(logger, configMgr) // 创建生成器管理器 generatorMgr := generator.NewGeneratorManager(logger) // 创建缓存管理器 appConfig := configMgr.GetConfig() cacheConfig := &cache.CacheConfig{ Enabled: appConfig.Conversion.CacheTimeout > 0, // 如果超时时间大于0则启用缓存 TTL: time.Duration(appConfig.Conversion.CacheTimeout) * time.Minute, MaxSize: appConfig.Conversion.MaxNodes, Cleanup: time.Minute, // 固定清理间隔 } cacheMgr := cache.NewCacheManager(cacheConfig, logger) // 创建转换引擎 convEngine := conversion.NewConversionEngine(logger, parserMgr, generatorMgr) // 创建处理器 health := handler.NewHealthHandler(logger, configMgr) version := handler.NewVersionHandler(logger, configMgr) conversionHandler := handler.NewConversionHandler(convEngine, cacheMgr, configMgr, logger) // 创建模板处理器(如果配置管理器支持) var templateHandler *handler.TemplateHandler if configMgr.HasTemplateManager() { templateHandler = handler.NewTemplateHandler(configMgr.GetTemplateManager(), logger, configMgr) logger.Info("Template handler initialized") } else { logger.Warn("Template manager not available, template features disabled") } // 创建HTTP服务器 httpServer := createHTTPServer(configMgr, logger, conversionHandler, health, version, templateHandler) app := &Application{ config: configMgr, logger: logger, httpServer: httpServer, cacheMgr: cacheMgr, convEngine: convEngine, parserMgr: parserMgr, generatorMgr: generatorMgr, conversionHandler: conversionHandler, health: health, version: version, templateHandler: templateHandler, } return app, nil } // createHTTPServer 创建HTTP服务器 func createHTTPServer( configMgr *config.ConfigManager, logger *logging.Logger, conversionHandler *handler.ConversionHandler, health *handler.HealthHandler, version *handler.VersionHandler, templateHandler *handler.TemplateHandler, ) *fiber.App { // 获取服务器配置 serverConfig := configMgr.GetServerConfig() securityConfig := configMgr.GetSecurityConfig() // 创建Fiber应用 app := fiber.New(fiber.Config{ AppName: "SubConverter-Go", ServerHeader: "", ReadTimeout: time.Duration(serverConfig.ReadTimeout) * time.Second, WriteTimeout: time.Duration(serverConfig.WriteTimeout) * time.Second, BodyLimit: int(serverConfig.MaxRequestSize), }) // 设置中间件 app.Use(middleware.SetupRecovery(logger)) app.Use(middleware.SetupRequestID()) app.Use(middleware.SetupSecurity()) app.Use(middleware.SetupLogging(logger)) app.Use(middleware.SetupCORS()) app.Use(middleware.SetupCompression()) // 设置限流中间件(如果启用) if securityConfig.RateLimit > 0 { app.Use(middleware.SetupRateLimit(securityConfig.RateLimit, 60)) } // 预备认证中间件(仅对需要保护的路由使用) var authMiddleware fiber.Handler if len(securityConfig.AccessTokens) > 0 { authMiddleware = middleware.SetupAuthentication(logger, securityConfig.AccessTokens) } // 注册路由 setupRoutes(app, conversionHandler, health, version, templateHandler, configMgr, authMiddleware) return app } // setupRoutes 设置路由 func setupRoutes( app *fiber.App, conversionHandler *handler.ConversionHandler, health *handler.HealthHandler, version *handler.VersionHandler, templateHandler *handler.TemplateHandler, configMgr *config.ConfigManager, auth fiber.Handler, ) { register := func(method, path string, handler fiber.Handler, protected bool) { handlers := make([]fiber.Handler, 0, 2) if protected && auth != nil { handlers = append(handlers, auth) } handlers = append(handlers, handler) app.Add(method, path, handlers...) } // 健康检查路由 register(fiber.MethodGet, "/health", health.HandleHealth, false) register(fiber.MethodGet, "/healthz", health.HandleHealth, false) register(fiber.MethodGet, "/ready", health.HandleReady, false) register(fiber.MethodGet, "/live", health.HandleLive, false) register(fiber.MethodGet, "/metrics", health.HandleMetrics, false) register(fiber.MethodGet, "/ping", health.HandlePing, false) // 版本信息路由 register(fiber.MethodGet, "/version", version.HandleVersion, false) // 维护类路由(兼容C++实现) register(fiber.MethodGet, "/refreshrules", conversionHandler.HandleRefreshRules, true) register(fiber.MethodGet, "/readconf", conversionHandler.HandleReadConf, true) register(fiber.MethodPost, "/updateconf", conversionHandler.HandleUpdateConfig, true) register(fiber.MethodGet, "/flushcache", conversionHandler.HandleFlushCache, true) // API路由组 api := app.Group("/api") // 转换路由 api.Get("/convert", conversionHandler.HandleConversion) api.Post("/convert", conversionHandler.HandleConversion) api.Get("/sub", conversionHandler.HandleSubscription) // 兼容性路由(与原始SubConverter兼容) register(fiber.MethodGet, "/sub", conversionHandler.HandleSubscription, false) register(fiber.MethodHead, "/sub", conversionHandler.HandleSubscription, false) register(fiber.MethodGet, "/sub2clashr", conversionHandler.HandleSubToClashR, false) register(fiber.MethodGet, "/surge2clash", conversionHandler.HandleSurgeToClash, false) register(fiber.MethodGet, "/getruleset", conversionHandler.HandleGetRulesetLegacy, false) register(fiber.MethodGet, "/getprofile", conversionHandler.HandleGetProfile, true) register(fiber.MethodGet, "/get", conversionHandler.HandleGetRemote, false) register(fiber.MethodGet, "/getlocal", conversionHandler.HandleGetLocal, false) // 缓存管理路由 cache := app.Group("/cache") if auth != nil { cache.Use(auth) } cache.Get("/stats", conversionHandler.HandleCacheStats) cache.Delete("/clear", conversionHandler.HandleCacheClear) // 配置管理路由 config := app.Group("/config") if auth != nil { config.Use(auth) } config.Get("/", conversionHandler.HandleGetConfig) config.Post("/", conversionHandler.HandleUpdateConfig) // 模板管理路由(如果模板处理器可用) if templateHandler != nil { templateHandler.RegisterRoutes(app) } // 404处理 app.Use(func(c *fiber.Ctx) error { return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ "success": false, "error": "Not Found", "message": "The requested resource was not found", }) }) } // Start 启动应用程序 func (app *Application) Start() error { // 获取服务器配置 serverConfig := app.config.GetServerConfig() addr := fmt.Sprintf("%s:%d", serverConfig.Host, serverConfig.Port) // 启动HTTP服务器 go func() { app.logger.Infof("Starting HTTP server on %s", addr) if err := app.httpServer.Listen(addr); err != nil && err != http.ErrServerClosed { app.logger.WithError(err).Error("Failed to start HTTP server") } }() // 等待服务器启动 time.Sleep(100 * time.Millisecond) app.logger.Info("Application started successfully") app.logger.Infof("Server is listening on %s", addr) app.logger.Infof("Health check: http://%s/health", addr) app.logger.Infof("API documentation: http://%s/api", addr) return nil } // Stop 停止应用程序 func (app *Application) Stop() error { app.logger.Info("Shutting down application...") // 关闭HTTP服务器 if err := app.httpServer.Shutdown(); err != nil { app.logger.WithError(err).Error("Failed to shutdown HTTP server") } // 关闭缓存管理器 if app.cacheMgr != nil { app.cacheMgr.Close() } // 关闭配置管理器 if app.config != nil { app.config.Close() } app.logger.Info("Application stopped successfully") return nil } // WaitForShutdown 等待关闭信号 func (app *Application) WaitForShutdown() { // 设置信号处理 quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit app.logger.Info("Received shutdown signal") // 优雅关闭 if err := app.Stop(); err != nil { app.logger.WithError(err).Error("Failed to stop application") os.Exit(1) } } // GetLogger 获取日志记录器 func (app *Application) GetLogger() *logging.Logger { return app.logger } // GetConfig 获取配置管理器 func (app *Application) GetConfig() *config.ConfigManager { return app.config } // GetCacheStats 获取缓存统计信息 func (app *Application) GetCacheStats() *cache.CacheStats { if app.cacheMgr == nil { return &cache.CacheStats{} } return app.cacheMgr.GetStats() } // GetHTTPServer 获取HTTP服务器实例 func (app *Application) GetHTTPServer() *fiber.App { return app.httpServer } // GetConversionEngine exposes the conversion engine instance (primarily for testing). func (app *Application) GetConversionEngine() *conversion.ConversionEngine { return app.convEngine } // IsRunning 检查应用是否正在运行 func (app *Application) IsRunning() bool { return app.httpServer != nil }