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

346
internal/http/server.go Normal file
View File

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