211 lines
8.1 KiB
Go
211 lines
8.1 KiB
Go
// Filename: internal/router/router.go
|
|
package router
|
|
|
|
import (
|
|
"gemini-balancer/internal/config"
|
|
"gemini-balancer/internal/domain/proxy"
|
|
"gemini-balancer/internal/domain/upstream"
|
|
"gemini-balancer/internal/handlers"
|
|
"gemini-balancer/internal/middleware"
|
|
"gemini-balancer/internal/pongo"
|
|
"gemini-balancer/internal/service"
|
|
"gemini-balancer/internal/settings"
|
|
"gemini-balancer/internal/webhandlers"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/gin-contrib/cors"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func NewRouter(
|
|
// Core Services
|
|
cfg *config.Config,
|
|
securityService *service.SecurityService,
|
|
settingsManager *settings.SettingsManager,
|
|
// Core Handlers
|
|
proxyHandler *handlers.ProxyHandler,
|
|
apiAuthHandler *handlers.APIAuthHandler,
|
|
// Admin API Handlers
|
|
keyGroupHandler *handlers.KeyGroupHandler,
|
|
apiKeyHandler *handlers.APIKeyHandler,
|
|
tokensHandler *handlers.TokensHandler,
|
|
logHandler *handlers.LogHandler,
|
|
settingHandler *handlers.SettingHandler,
|
|
dashboardHandler *handlers.DashboardHandler,
|
|
taskHandler *handlers.TaskHandler,
|
|
// Web Page Handlers
|
|
webAuthHandler *webhandlers.WebAuthHandler,
|
|
pageHandler *webhandlers.PageHandler,
|
|
// === Domain Modules ===
|
|
upstreamModule *upstream.Module,
|
|
proxyModule *proxy.Module,
|
|
) *gin.Engine {
|
|
if cfg.Log.Level != "debug" {
|
|
gin.SetMode(gin.ReleaseMode)
|
|
}
|
|
router := gin.Default()
|
|
|
|
router.Static("/static", "./web/static")
|
|
// CORS 配置
|
|
config := cors.Config{
|
|
// 允许前端的来源。在生产环境中,需改为实际域名
|
|
AllowOrigins: []string{"http://localhost:9000"},
|
|
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
|
|
AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization"},
|
|
ExposeHeaders: []string{"Content-Length"},
|
|
AllowCredentials: true,
|
|
MaxAge: 12 * time.Hour,
|
|
}
|
|
router.Use(cors.New(config))
|
|
isDebug := gin.Mode() != gin.ReleaseMode
|
|
router.HTMLRender = pongo.New("web/templates", isDebug)
|
|
|
|
// --- 基础设施 ---
|
|
router.GET("/", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "/dashboard") })
|
|
router.GET("/health", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"status": "ok"}) })
|
|
// --- 统一的认证管道 ---
|
|
apiAdminAuth := middleware.APIAdminAuthMiddleware(securityService)
|
|
webAdminAuth := middleware.WebAdminAuthMiddleware(securityService)
|
|
|
|
router.Use(gin.RecoveryWithWriter(os.Stdout))
|
|
// --- 将正确的依赖和中间件管道传递下去 ---
|
|
registerProxyRoutes(router, proxyHandler, securityService)
|
|
registerAdminRoutes(router, apiAdminAuth, keyGroupHandler, tokensHandler, apiKeyHandler, logHandler, settingHandler, dashboardHandler, taskHandler, upstreamModule, proxyModule)
|
|
registerPublicAPIRoutes(router, apiAuthHandler, securityService, settingsManager)
|
|
registerWebRoutes(router, webAdminAuth, webAuthHandler, pageHandler)
|
|
return router
|
|
}
|
|
|
|
func registerProxyRoutes(
|
|
router *gin.Engine, proxyHandler *handlers.ProxyHandler, securityService *service.SecurityService,
|
|
) {
|
|
// 通用的代理认证中间件
|
|
proxyAuthMiddleware := middleware.ProxyAuthMiddleware(securityService)
|
|
// --- 模式一: 智能聚合模式 (根路径) ---
|
|
// /v1 和 /v1beta 路径作为默认入口,服务于 BasePool 聚合逻辑
|
|
v1 := router.Group("/v1")
|
|
v1.Use(proxyAuthMiddleware)
|
|
{
|
|
v1.Any("/*path", proxyHandler.HandleProxy)
|
|
}
|
|
v1beta := router.Group("/v1beta")
|
|
v1beta.Use(proxyAuthMiddleware)
|
|
{
|
|
v1beta.Any("/*path", proxyHandler.HandleProxy)
|
|
}
|
|
// --- 模式二: 精确路由模式 (/proxy/:group_name) ---
|
|
// 创建一个新的、物理隔离的路由组,用于按组名精确路由
|
|
proxyGroup := router.Group("/proxy/:group_name")
|
|
proxyGroup.Use(proxyAuthMiddleware)
|
|
{
|
|
// 捕获所有子路径 (例如 /v1/chat/completions),并全部交给同一个 ProxyHandler。
|
|
proxyGroup.Any("/*path", proxyHandler.HandleProxy)
|
|
}
|
|
}
|
|
|
|
// registerAdminRoutes
|
|
func registerAdminRoutes(
|
|
router *gin.Engine,
|
|
authMiddleware gin.HandlerFunc,
|
|
keyGroupHandler *handlers.KeyGroupHandler,
|
|
tokensHandler *handlers.TokensHandler,
|
|
apiKeyHandler *handlers.APIKeyHandler,
|
|
logHandler *handlers.LogHandler,
|
|
settingHandler *handlers.SettingHandler,
|
|
dashboardHandler *handlers.DashboardHandler,
|
|
taskHandler *handlers.TaskHandler,
|
|
upstreamModule *upstream.Module,
|
|
proxyModule *proxy.Module,
|
|
) {
|
|
admin := router.Group("/admin", authMiddleware)
|
|
{
|
|
// --- KeyGroup Base Routes ---
|
|
admin.POST("/keygroups", keyGroupHandler.CreateKeyGroup)
|
|
admin.GET("/keygroups", keyGroupHandler.GetKeyGroups)
|
|
admin.PUT("/keygroups/order", keyGroupHandler.UpdateKeyGroupOrder)
|
|
// --- KeyGroup Specific Routes (by :id) ---
|
|
admin.GET("/keygroups/:id", keyGroupHandler.GetKeyGroups)
|
|
admin.PUT("/keygroups/:id", keyGroupHandler.UpdateKeyGroup)
|
|
admin.DELETE("/keygroups/:id", keyGroupHandler.DeleteKeyGroup)
|
|
admin.POST("/keygroups/:id/clone", keyGroupHandler.CloneKeyGroup)
|
|
admin.GET("/keygroups/:id/stats", keyGroupHandler.GetKeyGroupStats)
|
|
admin.POST("/keygroups/:id/bulk-actions", apiKeyHandler.HandleBulkAction)
|
|
// --- APIKey Sub-resource Routes under a KeyGroup ---
|
|
keyGroupAPIKeys := admin.Group("/keygroups/:id/apikeys")
|
|
{
|
|
keyGroupAPIKeys.GET("", apiKeyHandler.ListKeysForGroup)
|
|
keyGroupAPIKeys.GET("/export", apiKeyHandler.ExportKeysForGroup)
|
|
keyGroupAPIKeys.POST("/bulk", apiKeyHandler.AddMultipleKeysToGroup)
|
|
keyGroupAPIKeys.DELETE("/bulk", apiKeyHandler.UnlinkMultipleKeysFromGroup)
|
|
keyGroupAPIKeys.POST("/test", apiKeyHandler.TestKeysForGroup)
|
|
keyGroupAPIKeys.PUT("/:keyId", apiKeyHandler.UpdateGroupAPIKeyMapping)
|
|
}
|
|
|
|
// Global key operations
|
|
admin.GET("/apikeys", apiKeyHandler.ListAPIKeys)
|
|
// admin.PUT("/apikeys/:id", apiKeyHandler.UpdateAPIKey) // DEPRECATED: Status is now contextual
|
|
admin.POST("/apikeys/test", apiKeyHandler.TestMultipleKeys) // Test keys globally
|
|
admin.DELETE("/apikeys/:id", apiKeyHandler.HardDeleteAPIKey) // Hard delete a single key
|
|
admin.DELETE("/apikeys/bulk", apiKeyHandler.HardDeleteMultipleKeys) // Hard delete multiple keys
|
|
admin.PUT("/apikeys/bulk/restore", apiKeyHandler.RestoreMultipleKeys) // Restore multiple keys globally
|
|
|
|
// --- Global Routes ---
|
|
admin.GET("/tokens", tokensHandler.GetAllTokens)
|
|
admin.PUT("/tokens", tokensHandler.UpdateTokens)
|
|
admin.GET("/logs", logHandler.GetLogs)
|
|
admin.GET("/settings", settingHandler.GetSettings)
|
|
admin.PUT("/settings", settingHandler.UpdateSettings)
|
|
admin.PUT("/settings/reset", settingHandler.ResetSettingsToDefaults)
|
|
|
|
// 用于查询异步任务的状态
|
|
admin.GET("/tasks/:id", taskHandler.GetTaskStatus)
|
|
|
|
// 领域模块
|
|
upstreamModule.RegisterRoutes(admin)
|
|
proxyModule.RegisterRoutes(admin)
|
|
// --- 全局仪表盘路由 ---
|
|
dashboard := admin.Group("/dashboard")
|
|
{
|
|
dashboard.GET("/overview", dashboardHandler.GetOverview)
|
|
dashboard.GET("/chart", dashboardHandler.GetChart)
|
|
dashboard.GET("/stats/:period", dashboardHandler.GetRequestStats) // 点击详情
|
|
}
|
|
}
|
|
}
|
|
|
|
// registerWebRoutes
|
|
func registerWebRoutes(
|
|
router *gin.Engine,
|
|
authMiddleware gin.HandlerFunc,
|
|
webAuthHandler *webhandlers.WebAuthHandler,
|
|
pageHandler *webhandlers.PageHandler,
|
|
) {
|
|
router.GET("/login", webAuthHandler.ShowLoginPage)
|
|
router.POST("/login", webAuthHandler.HandleLogin)
|
|
router.GET("/logout", webAuthHandler.HandleLogout)
|
|
// For Test only router.Run("127.0.0.1:9000")
|
|
// 受保护的Admin Web界面
|
|
webGroup := router.Group("/", authMiddleware)
|
|
webGroup.Use(authMiddleware)
|
|
{
|
|
webGroup.GET("/keys", pageHandler.ShowKeysPage)
|
|
webGroup.GET("/settings", pageHandler.ShowConfigEditorPage)
|
|
webGroup.GET("/logs", pageHandler.ShowErrorLogsPage)
|
|
webGroup.GET("/dashboard", pageHandler.ShowDashboardPage)
|
|
webGroup.GET("/tasks", pageHandler.ShowTasksPage)
|
|
webGroup.GET("/chat", pageHandler.ShowChatPage)
|
|
}
|
|
|
|
}
|
|
|
|
// registerPublicAPIRoutes 无需后台登录的公共API路由
|
|
func registerPublicAPIRoutes(router *gin.Engine, apiAuthHandler *handlers.APIAuthHandler, securityService *service.SecurityService, settingsManager *settings.SettingsManager) {
|
|
ipBanMiddleware := middleware.IPBanMiddleware(securityService, settingsManager)
|
|
publicAPIGroup := router.Group("/api")
|
|
{
|
|
publicAPIGroup.POST("/login", ipBanMiddleware, apiAuthHandler.HandleLogin)
|
|
}
|
|
}
|