| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- package routes
-
- import (
- "fmt"
- "net/http"
- "time"
-
- "git.x2erp.com/qdy/go-base/authbase"
- "git.x2erp.com/qdy/go-base/webx/router"
- "git.x2erp.com/qdy/go-svc-code/internal/opencode"
- )
-
- // RegisterLogStreamRoutes 注册日志流路由
- func RegisterLogStreamRoutes(ws *router.RouterService, process *opencode.Process) {
- // 日志流路由
- // 注意:这个路由需要直接处理 HTTP 流,不能使用标准的 router 包装
- // 我们将注册一个原始的 HTTP 处理器到 gin 引擎
- // 这个函数将由 main.go 中的额外注册调用
- }
-
- // LogStreamHandler 日志流的 HTTP 处理器(已包含TokenAuth认证)
- func LogStreamHandler(process *opencode.Process) http.HandlerFunc {
- // 创建内部处理器
- handler := func(w http.ResponseWriter, r *http.Request) {
- // 设置 SSE 头
- w.Header().Set("Content-Type", "text/event-stream")
- w.Header().Set("Cache-Control", "no-cache")
- w.Header().Set("Connection", "keep-alive")
- w.Header().Set("Access-Control-Allow-Origin", "*")
-
- flusher, ok := w.(http.Flusher)
- if !ok {
- http.Error(w, "Streaming unsupported", http.StatusInternalServerError)
- return
- }
-
- // 获取日志通道
- logChan := process.GetLogs()
- if logChan == nil {
- http.Error(w, "日志通道不可用", http.StatusInternalServerError)
- return
- }
-
- // 发送初始消息
- fmt.Fprintf(w, "data: 连接到 opencode 日志流\n\n")
- flusher.Flush()
-
- // 监听日志通道
- for {
- select {
- case log, ok := <-logChan:
- if !ok {
- // 通道关闭
- fmt.Fprintf(w, "data: 日志流已结束\n\n")
- flusher.Flush()
- return
- }
- // 发送日志
- fmt.Fprintf(w, "data: %s\n\n", log)
- flusher.Flush()
- case <-r.Context().Done():
- // 客户端断开连接
- return
- case <-time.After(30 * time.Second):
- // 发送心跳保持连接
- fmt.Fprintf(w, ": heartbeat\n\n")
- flusher.Flush()
- }
- }
- }
-
- // 包装TokenAuth中间件
- return authbase.TokenAuth(http.HandlerFunc(handler)).ServeHTTP
- }
|