Files
2026-08-14 23:41:57 +08:00

87 lines
2.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package server
import (
"fmt"
"net/http"
"path/filepath"
"time"
"agent/internal/agent"
"github.com/gin-gonic/gin"
)
// NewRouter 组装全部路由:静态资源、会话直达、/api/v1 REST、/ws WebSocket。
// 返回 (gin.Engine, *Server)*Server 供 main.go 在托管模式下调用 StartBenchmark 自动触发评测。
func NewRouter(cfg agent.Config, store *agent.SessionStore, dockerCfg *agent.DockerConfigStore, apiCfg *agent.APIConfigStore) (*gin.Engine, *Server) {
s := &Server{
cfg: cfg,
store: store,
agent: agent.NewAgent(cfg, store, dockerCfg, apiCfg),
dockerCfg: dockerCfg,
apiCfg: apiCfg,
}
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(gin.Recovery(), requestLogger())
staticDir := filepath.Join(cfg.Workspace, "web", "static")
indexFile := filepath.Join(staticDir, "index.html")
r.Static("/static", staticDir)
r.StaticFile("/", indexFile)
// 会话直达:/<sessionId> 返回前端页面,由前端 JS 从路径解析会话 ID
r.GET("/:sessionId", func(c *gin.Context) {
if !sessionIDPattern.MatchString(c.Param("sessionId")) {
c.Status(http.StatusNotFound)
return
}
c.File(indexFile)
})
v1 := r.Group("/api/v1")
v1.GET("/health", s.health)
// 授权相关接口始终放行:前端据此判断是否需要授权 / 提交授权码。
// 其余 API 与 WebSocket 统一挂 authRequired(未启用授权时自动放行)。
auth := v1.Group("/auth")
auth.GET("/status", s.authStatus)
auth.POST("/login", s.authLogin)
authed := v1.Group("")
authed.Use(s.authRequired)
authed.GET("/config", s.config)
authed.GET("/docker/config", s.dockerConfig)
authed.PUT("/docker/config", s.setDockerConfig)
authed.GET("/llm/config", s.llmConfig)
authed.PUT("/llm/config", s.setLLMConfig)
authed.GET("/sessions", s.listSessions)
authed.POST("/sessions", s.createSession)
authed.GET("/sessions/:id", s.getSession)
authed.GET("/sessions/:id/messages", s.sessionMessages)
authed.DELETE("/sessions/:id", s.deleteSession)
authed.DELETE("/sessions/:id/messages", s.clearSession)
authed.GET("/coop/tasks", s.coopTasks)
// WebSocket 实时通道:Agent 流式输出 / 状态 / 协作通知(同样受授权保护)
r.GET("/ws", s.authRequired, s.ws)
return r, s
}
// requestLogger 轻量请求日志中间件:统一 [http] 前缀,便于与 [coop] 等日志区分。
func requestLogger() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
gin.DefaultWriter.Write([]byte(fmt.Sprintf(
"[http] %s | %s %s | %s | %d\n",
time.Now().Format("2006/01/02 15:04:05"),
c.Request.Method,
c.Request.URL.Path,
time.Since(start).Round(time.Millisecond).String(),
c.Writer.Status(),
)))
}
}