main.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "net/http"
  6. "os"
  7. "os/signal"
  8. "syscall"
  9. "time"
  10. "github.com/ding113/claude-code-hub/internal/config"
  11. "github.com/ding113/claude-code-hub/internal/database"
  12. "github.com/ding113/claude-code-hub/internal/pkg/logger"
  13. "github.com/ding113/claude-code-hub/internal/pkg/validator"
  14. "github.com/gin-gonic/gin"
  15. "github.com/uptrace/bun"
  16. )
  17. func main() {
  18. // 加载配置
  19. cfg, err := config.Load()
  20. if err != nil {
  21. fmt.Printf("Failed to load config: %v\n", err)
  22. os.Exit(1)
  23. }
  24. // 初始化日志
  25. logger.Init(logger.Config{
  26. Level: cfg.Log.Level,
  27. Format: cfg.Log.Format,
  28. })
  29. logger.Info().Msg("Starting Claude Code Hub...")
  30. // 初始化验证器
  31. validator.Init()
  32. // 连接数据库
  33. db, err := database.NewPostgres(cfg.Database)
  34. if err != nil {
  35. logger.Fatal().Err(err).Msg("Failed to connect to PostgreSQL")
  36. }
  37. defer database.ClosePostgres(db)
  38. // 连接 Redis
  39. rdb, err := database.NewRedis(cfg.Redis)
  40. if err != nil {
  41. logger.Fatal().Err(err).Msg("Failed to connect to Redis")
  42. }
  43. defer database.CloseRedis(rdb)
  44. // 创建 Gin 引擎
  45. if cfg.Log.Level != "debug" {
  46. gin.SetMode(gin.ReleaseMode)
  47. }
  48. router := setupRouter(db, rdb)
  49. // 创建 HTTP 服务器
  50. srv := &http.Server{
  51. Addr: fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port),
  52. Handler: router,
  53. ReadTimeout: cfg.Server.ReadTimeout,
  54. WriteTimeout: cfg.Server.WriteTimeout,
  55. }
  56. // 启动服务器
  57. go func() {
  58. logger.Info().
  59. Str("host", cfg.Server.Host).
  60. Int("port", cfg.Server.Port).
  61. Msg("Server listening")
  62. if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
  63. logger.Fatal().Err(err).Msg("Server failed")
  64. }
  65. }()
  66. // 等待中断信号
  67. quit := make(chan os.Signal, 1)
  68. signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
  69. <-quit
  70. logger.Info().Msg("Shutting down server...")
  71. // 优雅关闭
  72. ctx, cancel := context.WithTimeout(context.Background(), cfg.Server.ShutdownTimeout)
  73. defer cancel()
  74. if err := srv.Shutdown(ctx); err != nil {
  75. logger.Error().Err(err).Msg("Server forced to shutdown")
  76. }
  77. logger.Info().Msg("Server exited")
  78. }
  79. // setupRouter 设置路由
  80. func setupRouter(db *bun.DB, rdb *database.RedisClient) *gin.Engine {
  81. router := gin.New()
  82. // 添加中间件
  83. router.Use(gin.Recovery())
  84. router.Use(requestLogger())
  85. // 健康检查
  86. router.GET("/health", healthCheck(db, rdb))
  87. // API v1 路由组 (代理 API)
  88. v1 := router.Group("/v1")
  89. {
  90. // TODO: Phase 5 实现
  91. v1.POST("/messages", notImplemented)
  92. v1.POST("/chat/completions", notImplemented)
  93. v1.POST("/responses", notImplemented)
  94. v1.GET("/models", notImplemented)
  95. }
  96. // 管理 API 路由组
  97. api := router.Group("/api/actions")
  98. {
  99. // TODO: Phase 5 实现
  100. api.GET("/users", notImplemented)
  101. api.GET("/users/:id", notImplemented)
  102. api.POST("/users", notImplemented)
  103. api.PUT("/users/:id", notImplemented)
  104. api.DELETE("/users/:id", notImplemented)
  105. api.GET("/keys", notImplemented)
  106. api.GET("/keys/:id", notImplemented)
  107. api.POST("/keys", notImplemented)
  108. api.PUT("/keys/:id", notImplemented)
  109. api.DELETE("/keys/:id", notImplemented)
  110. api.GET("/providers", notImplemented)
  111. api.GET("/providers/:id", notImplemented)
  112. api.POST("/providers", notImplemented)
  113. api.PUT("/providers/:id", notImplemented)
  114. api.DELETE("/providers/:id", notImplemented)
  115. }
  116. return router
  117. }
  118. // requestLogger 请求日志中间件
  119. func requestLogger() gin.HandlerFunc {
  120. return func(c *gin.Context) {
  121. start := time.Now()
  122. path := c.Request.URL.Path
  123. c.Next()
  124. latency := time.Since(start)
  125. status := c.Writer.Status()
  126. logger.Info().
  127. Str("method", c.Request.Method).
  128. Str("path", path).
  129. Int("status", status).
  130. Dur("latency", latency).
  131. Str("client_ip", c.ClientIP()).
  132. Msg("Request")
  133. }
  134. }
  135. // healthCheck 健康检查处理器
  136. func healthCheck(db *bun.DB, rdb *database.RedisClient) gin.HandlerFunc {
  137. return func(c *gin.Context) {
  138. ctx := c.Request.Context()
  139. // 检查数据库连接
  140. if err := db.PingContext(ctx); err != nil {
  141. c.JSON(http.StatusServiceUnavailable, gin.H{
  142. "status": "unhealthy",
  143. "database": "disconnected",
  144. "error": err.Error(),
  145. })
  146. return
  147. }
  148. // 检查 Redis 连接
  149. redisStatus := "disabled"
  150. if rdb != nil {
  151. if err := rdb.Ping(ctx).Err(); err != nil {
  152. c.JSON(http.StatusServiceUnavailable, gin.H{
  153. "status": "unhealthy",
  154. "redis": "disconnected",
  155. "database": "connected",
  156. "error": err.Error(),
  157. })
  158. return
  159. }
  160. redisStatus = "connected"
  161. }
  162. c.JSON(http.StatusOK, gin.H{
  163. "status": "healthy",
  164. "database": "connected",
  165. "redis": redisStatus,
  166. })
  167. }
  168. }
  169. // notImplemented 未实现的处理器
  170. func notImplemented(c *gin.Context) {
  171. c.JSON(http.StatusNotImplemented, gin.H{
  172. "error": gin.H{
  173. "type": "not_implemented",
  174. "message": "This endpoint is not yet implemented",
  175. },
  176. })
  177. }