Files
oci-portal/internal/api/router.go
T
2026-07-30 12:23:05 +08:00

61 lines
3.2 KiB
Go

package api
import (
"log"
"github.com/gin-gonic/gin"
"oci-portal/internal/service"
)
// NewRouter 组装 HTTP 路由骨架:中间件链、公开/鉴权分组与各域注册;
// 具体路由按域拆在 routes_*.go。/auth/login 公开,业务路由要求 JWT。
func NewRouter(auth *service.AuthService, oauth *service.OAuthService, passkeys *service.PasskeyService, wallets *service.WalletService, ociConfigs *service.OciConfigService, tasks *service.TaskService, console *service.ConsoleService, settings *service.SettingService, notifier *service.Notifier, systemLogs *service.SystemLogService, logEvents *service.LogEventService, proxies *service.ProxyService, aiGateway *service.AiGatewayService) *gin.Engine {
r := gin.New()
// 禁用 gin 内置代理信任:真实 IP 统一由 RealIPMiddleware 按安全设置解析
_ = r.SetTrustedProxies(nil)
registerWebhook(r, settings, logEvents)
// 访问日志不落 query string:webconsole WS 的 JWT 经 query 传递,默认 Logger 会打进 stdout/journal
accessLog := gin.LoggerWithConfig(gin.LoggerConfig{SkipQueryString: true})
r.Use(accessLog, RealIPMiddleware(settings), IPRateMiddleware(settings), gin.Recovery())
// 面板 API 请求体统一 1MB 上限(S-03);AI 网关按对话体量单独 10MB
v1 := r.Group("/api/v1", bodyLimit(1<<20))
registerAuthPublic(v1, auth, oauth, passkeys, wallets, systemLogs)
// AI 网关对外端点:独立密钥鉴权,挂在全局 Use 之后,仍受 IP 限速与 Recovery 保护
registerAiGateway(r, aiGateway)
// 系统日志中间件挂在鉴权之后,写请求自动留痕(webconsole ws 为 GET,天然跳过)
secured := v1.Group("", RequireAuth(auth), systemLogMiddleware(systemLogs))
registerAuthSecured(secured, auth, oauth, passkeys, settings, systemLogs)
registerConsole(v1, secured, console, auth)
registerSettings(secured, auth, settings, notifier, systemLogs, proxies)
registerTasksAndLogs(secured, tasks, logEvents)
registerOci(secured, ociConfigs)
// 上传类接口独立成组:文件本体上限 1MB,multipart 边界与字段头另占空间,
// 留在统一 1MB 的 v1 组里恰好 1MB 的文件会被截断;超限由 handler 映射 413
uploads := r.Group("/api/v1", bodyLimit(1<<20+64<<10), RequireAuth(auth), systemLogMiddleware(systemLogs))
registerOciUploads(uploads, ociConfigs)
// 对象内容中转 PUT:5MB 文件上限 + 封装余量,精确上限由 handler/service 执行
contentUploads := r.Group("/api/v1", bodyLimit(5<<20+64<<10), RequireAuth(auth), systemLogMiddleware(systemLogs))
registerOciContentUploads(contentUploads, ociConfigs)
registerAiAdmin(secured, aiGateway)
registerSwagger(r)
// 嵌入的前端产物兜底伺服;失败仅降级为纯 API 服务,不阻塞启动
if err := registerWebUI(r); err != nil {
log.Printf("[warn] webui disabled: %v", err)
}
return r
}
// registerWebhook 挂载 ONS 回传入口。必须注册在全局 Logger 之前:
// 访问日志不落含 secret 的路径;不挂系统日志中间件——投递高频且已在回传日志留痕。
func registerWebhook(r *gin.Engine, settings *service.SettingService, logEvents *service.LogEventService) {
wh := &webhookHandler{events: logEvents}
r.POST("/api/v1/webhooks/oci-logs/:secret",
gin.Recovery(), RealIPMiddleware(settings), wh.handle)
}