131 lines
4.4 KiB
Go
131 lines
4.4 KiB
Go
package router
|
||
|
||
import (
|
||
"os"
|
||
"strings"
|
||
|
||
"github.com/engigu/taskpool/internal/controllers"
|
||
"github.com/engigu/taskpool/internal/middleware"
|
||
"github.com/engigu/taskpool/internal/services"
|
||
|
||
"github.com/gin-contrib/pprof"
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
type Controllers struct {
|
||
Task *controllers.TaskController
|
||
Auth *controllers.AuthController
|
||
Env *controllers.EnvController
|
||
Script *controllers.ScriptController
|
||
Executor *controllers.ExecutorController
|
||
File *controllers.FileController
|
||
Dashboard *controllers.DashboardController
|
||
Log *controllers.LogController
|
||
LogSSE *controllers.LogSSEController
|
||
Terminal *controllers.TerminalController
|
||
Settings *controllers.SettingsController
|
||
Dependency *controllers.DependencyController
|
||
Agent *controllers.AgentController
|
||
Mise *controllers.MiseController
|
||
Notification *controllers.NotificationController
|
||
AppLog *controllers.AppLogController
|
||
SystemWS *controllers.SystemWSController
|
||
WebUI *controllers.WebUIController
|
||
Monitor *controllers.MonitorController
|
||
Interconnect *controllers.InterconnectController
|
||
Data *controllers.DataController
|
||
Install *controllers.InstallController
|
||
MCP *controllers.MCPController
|
||
}
|
||
|
||
func Setup(c *Controllers) *gin.Engine {
|
||
if os.Getenv("GIN_MODE") == "" {
|
||
gin.SetMode(gin.ReleaseMode)
|
||
}
|
||
router := gin.New()
|
||
|
||
// 信任所有反向代理(Docker/Nginx 场景)
|
||
// 使用 CIDR "0.0.0.0/0" 信任所有 IPv4,"::/0" 信任所有 IPv6
|
||
// 避免 "Forbidden: invalid Host header" 错误
|
||
router.SetTrustedProxies([]string{"0.0.0.0/0", "::/0"})
|
||
|
||
router.Use(middleware.GinLogger(), middleware.GinRecovery())
|
||
router.Use(middleware.TravelProxyMiddleware())
|
||
|
||
// 获取 URL 前缀
|
||
cfg := services.GetConfig()
|
||
urlPrefix := strings.TrimSuffix(cfg.Server.URLPrefix, "/")
|
||
|
||
// 创建一个路由组,如果有前缀则使用前缀,否则使用根路径
|
||
var root *gin.RouterGroup
|
||
if urlPrefix != "" {
|
||
root = router.Group(urlPrefix)
|
||
} else {
|
||
root = router.Group("")
|
||
}
|
||
|
||
// 按需绑定 Pprof 调试路由 (注册在 root 下以支持 URLPrefix)
|
||
if cfg.Server.PprofEnabled {
|
||
// pprof.RouteRegister 会在传入的路由组下注册 /debug/pprof 等路由
|
||
pprof.RouteRegister(root)
|
||
}
|
||
|
||
// =========================================================================
|
||
// 路由分类组装 (对应 Nginx 的 location 块分发)
|
||
// =========================================================================
|
||
|
||
// 1. [ location /assets ] 静态资源路由
|
||
initStaticRoutes(root)
|
||
|
||
// 3. [ location /api ] 内部 API 路由组
|
||
apiV1 := root.Group("/api/v1")
|
||
initPublicAPIRoutes(apiV1, c) // 公开接口 (无需认证)
|
||
initAuthorizedAPIRoutes(apiV1, c) // 授权接口 (需 JWT)
|
||
|
||
// 4. [ location /api/agent ] Agent 相关 API 路由组
|
||
initAgentAPIRoutes(root, c)
|
||
initOpenAPIV1Routes(root, c)
|
||
|
||
// 5. [ location /mcp ] MCP Server 路由(供 AI Agent 使用)
|
||
initMCPRoutes(root, c)
|
||
|
||
// =========================================================================
|
||
// [ location / ] 全局 404 兜底与 SPA 渲染
|
||
// 对应 Nginx: try_files $uri $uri/ /index.html;
|
||
// =========================================================================
|
||
router.NoRoute(func(ctx *gin.Context) {
|
||
path := ctx.Request.URL.Path
|
||
|
||
// 如果配置了前缀,只处理带前缀的路径
|
||
if urlPrefix != "" && !strings.HasPrefix(path, urlPrefix) {
|
||
ctx.Status(404)
|
||
return
|
||
}
|
||
|
||
// 解析实际的相对路径
|
||
relPath := strings.TrimPrefix(path, urlPrefix)
|
||
if !strings.HasPrefix(relPath, "/") {
|
||
relPath = "/" + relPath
|
||
}
|
||
|
||
// 拦截器:不该返回 index.html 的情况
|
||
// 如果该请求被识别为 API 请求、静态资源请求,或者是带有明确文件后缀(如 .js / .css / .png)的物理文件请求
|
||
// 都不应该返回 SPA 页面(会报前端 MIME 类型错误),而是直接掐断返回 404
|
||
hasAnyExt := false
|
||
if idx := strings.LastIndex(relPath, "."); idx > 0 && len(relPath)-idx < 6 {
|
||
// 简单判断是否有后缀(如 .js, .css)
|
||
hasAnyExt = true
|
||
}
|
||
|
||
if strings.HasPrefix(relPath, "/api/") || strings.HasPrefix(relPath, "/assets/") || strings.HasPrefix(relPath, "/debug/") || hasAnyExt {
|
||
ctx.String(404, "404 Not Found")
|
||
return
|
||
}
|
||
|
||
// 其他所有有效的前端页面路径(如 /tasks, /settings),都返回 index.html 交给 vue-router 处理
|
||
serveSPA(ctx, urlPrefix, 200)
|
||
})
|
||
|
||
return router
|
||
}
|