package handlers
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"github.com/bestruirui/octopus/internal/op"
"github.com/bestruirui/octopus/internal/server/middleware"
"github.com/bestruirui/octopus/internal/server/resp"
"github.com/bestruirui/octopus/internal/server/router"
"github.com/gin-gonic/gin"
)
func init() {
router.NewGroupRouter("/api/v1/log").
Use(middleware.Auth()).
AddRoute(
router.NewRoute("/list", http.MethodGet).
Handle(listLog),
).
AddRoute(
router.NewRoute("/clear", http.MethodDelete).
Handle(clearLog),
).
AddRoute(
router.NewRoute("/stream-token", http.MethodGet).
Handle(getStreamToken),
)
router.NewGroupRouter("/api/v1/log").
AddRoute(
router.NewRoute("/stream", http.MethodGet).
Handle(streamLog),
)
}
func listLog(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
startTimeStr := c.Query("start_time")
endTimeStr := c.Query("end_time")
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 20
}
var startTime, endTime *int
if startTimeStr != "" && endTimeStr != "" {
st, err := strconv.Atoi(startTimeStr)
if err != nil {
resp.Error(c, http.StatusBadRequest, err.Error())
return
}
et, err := strconv.Atoi(endTimeStr)
if err != nil {
resp.Error(c, http.StatusBadRequest, err.Error())
return
}
startTime = &st
endTime = &et
}
logs, err := op.RelayLogList(c.Request.Context(), startTime, endTime, page, pageSize)
if err != nil {
resp.Error(c, http.StatusInternalServerError, err.Error())
return
}
resp.Success(c, logs)
}
func clearLog(c *gin.Context) {
if err := op.RelayLogClear(c.Request.Context()); err != nil {
resp.Error(c, http.StatusInternalServerError, err.Error())
return
}
resp.Success(c, nil)
}
func getStreamToken(c *gin.Context) {
token, err := op.RelayLogStreamTokenCreate()
if err != nil {
resp.Error(c, http.StatusInternalServerError, err.Error())
return
}
resp.Success(c, gin.H{"token": token})
}
func streamLog(c *gin.Context) {
token := c.Query("token")
if token == "" || !op.RelayLogStreamTokenVerify(token) {
resp.Error(c, http.StatusUnauthorized, "invalid stream token")
return
}
op.RelayLogStreamTokenRevoke(token)
c.Header("Content-Type", "text/event-stream")
c.Header("Cache-Control", "no-cache")
c.Header("Connection", "keep-alive")
c.Header("X-Accel-Buffering", "no")
logChan := op.RelayLogSubscribe()
defer op.RelayLogUnsubscribe(logChan)
ctx := c.Request.Context()
for {
select {
case <-ctx.Done():
return
case log, ok := <-logChan:
if !ok {
return
}
data, err := json.Marshal(log)
if err != nil {
continue
}
c.Writer.Write([]byte(fmt.Sprintf("data: %s\n\n", data)))
c.Writer.Flush()
}
}
}