first commit
Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped

This commit is contained in:
Rogee
2025-09-28 10:05:07 +08:00
commit 7fcabe0225
481 changed files with 125127 additions and 0 deletions

View File

@@ -0,0 +1,332 @@
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
}