Files
2026-07-13 13:39:47 +08:00

68 lines
2.0 KiB
Go

package handler
import (
"fmt"
"net/http"
"caorushizi.cn/mediago/internal/api/dto"
"caorushizi.cn/mediago/internal/api/sse"
"caorushizi.cn/mediago/internal/i18n"
"caorushizi.cn/mediago/internal/logger"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// EventHandler handles SSE event streaming.
type EventHandler struct {
hub *sse.Hub
}
// NewEventHandler creates an EventHandler.
func NewEventHandler(hub *sse.Hub) *EventHandler {
return &EventHandler{hub: hub}
}
// Stream serves the SSE event stream.
// @Summary SSE event stream
// @Description Subscribe to Server-Sent Events (SSE) to receive real-time download task status change notifications
// @Description Event types include: download-start (task started), download-success (task succeeded), download-failed (task failed), download-stop (task stopped)
// @Description Note: progress update events are not included; poll GET /api/tasks/{id} to retrieve download progress
// @Tags Events
// @Produce text/event-stream
// @Success 200 {string} string "SSE event stream"
// @Router /events [get]
func (h *EventHandler) Stream(c *gin.Context) {
logger.Info("SSE client connected", zap.String("clientIP", c.ClientIP()))
c.Header("Content-Type", "text/event-stream")
c.Header("Cache-Control", "no-cache")
c.Header("Connection", "keep-alive")
c.Header("X-Accel-Buffering", "no")
client := h.hub.Subscribe()
defer func() {
h.hub.Unsubscribe(client)
logger.Info("SSE client disconnected", zap.String("clientIP", c.ClientIP()))
}()
flusher, ok := c.Writer.(http.Flusher)
if !ok {
logger.Error("SSE streaming not supported")
c.JSON(http.StatusInternalServerError, dto.ErrorResponse{Success: false, Code: http.StatusInternalServerError, Message: i18n.T(c, i18n.MsgEventStreamFailed)})
return
}
notify := c.Request.Context().Done()
for {
select {
case <-notify:
return
case evt := <-client:
fmt.Fprintf(c.Writer, "event: %s\n", evt.Name)
fmt.Fprintf(c.Writer, "data: %s\n\n", evt.JSON())
flusher.Flush()
}
}
}