feat(live): add handler endpoints for Go Live (me, key, regenerate, update)

This commit is contained in:
senke 2026-02-24 09:53:01 +01:00
parent 083fe2e50d
commit 8062ec685c
2 changed files with 113 additions and 3 deletions

View file

@ -16,14 +16,19 @@ func (r *APIRouter) setupLiveRoutes(router *gin.RouterGroup) {
live := router.Group("/live")
{
live.GET("/streams", liveStreamHandler.ListLiveStreams)
live.GET("/streams/:id", liveStreamHandler.GetLiveStream)
// Protected routes (me/* MUST come before :id)
if r.config != nil && r.config.AuthMiddleware != nil {
protected := live.Group("")
protected.Use(r.config.AuthMiddleware.RequireAuth())
r.applyCSRFProtection(protected)
protected.GET("/streams/me", liveStreamHandler.GetMyStreams)
protected.GET("/streams/me/key", liveStreamHandler.GetMyStreamKey)
protected.POST("/streams/me/key/regenerate", liveStreamHandler.RegenerateStreamKey)
protected.POST("/streams", liveStreamHandler.CreateLiveStream)
protected.PUT("/streams/:id", liveStreamHandler.UpdateLiveStream)
}
// Public routes (after protected)
live.GET("/streams", liveStreamHandler.ListLiveStreams)
live.GET("/streams/:id", liveStreamHandler.GetLiveStream)
}
}

View file

@ -95,3 +95,108 @@ func (h *LiveStreamHandler) CreateLiveStream(c *gin.Context) {
}
RespondSuccess(c, http.StatusCreated, gin.H{"stream": created})
}
// GetMyStreams returns the authenticated user's streams (including stream_key)
func (h *LiveStreamHandler) GetMyStreams(c *gin.Context) {
userID, ok := GetUserIDUUID(c)
if !ok {
return
}
streams, err := h.service.ListByUser(c.Request.Context(), userID)
if err != nil {
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to list streams", err))
return
}
type streamWithKey struct {
*models.LiveStream
StreamKey string `json:"stream_key"`
}
result := make([]streamWithKey, len(streams))
for i, s := range streams {
result[i] = streamWithKey{LiveStream: s, StreamKey: s.StreamKey}
}
RespondSuccess(c, http.StatusOK, gin.H{"streams": result})
}
// GetMyStreamKey returns the user's stream key (creates draft if none exist)
func (h *LiveStreamHandler) GetMyStreamKey(c *gin.Context) {
userID, ok := GetUserIDUUID(c)
if !ok {
return
}
streams, err := h.service.ListByUser(c.Request.Context(), userID)
if err != nil {
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to get streams", err))
return
}
var streamKey string
if len(streams) > 0 {
streamKey = streams[0].StreamKey
} else {
draft := &models.LiveStream{Title: "My Stream"}
created, createErr := h.service.Create(c.Request.Context(), userID, draft)
if createErr != nil {
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to create stream", createErr))
return
}
streamKey = created.StreamKey
}
RespondSuccess(c, http.StatusOK, gin.H{
"stream_key": streamKey,
"rtmp_url": "rtmp://stream.veza.app/live",
})
}
// RegenerateStreamKey generates a new stream key for the user's first stream
func (h *LiveStreamHandler) RegenerateStreamKey(c *gin.Context) {
userID, ok := GetUserIDUUID(c)
if !ok {
return
}
streams, err := h.service.ListByUser(c.Request.Context(), userID)
if err != nil || len(streams) == 0 {
RespondWithAppError(c, apperrors.NewNotFoundError("no stream found"))
return
}
newKey, err := h.service.RegenerateStreamKey(c.Request.Context(), streams[0].ID, userID)
if err != nil {
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to regenerate key", err))
return
}
RespondSuccess(c, http.StatusOK, gin.H{
"stream_key": newKey,
"rtmp_url": "rtmp://stream.veza.app/live",
})
}
// UpdateLiveStream updates a live stream's metadata (ownership check)
func (h *LiveStreamHandler) UpdateLiveStream(c *gin.Context) {
userID, ok := GetUserIDUUID(c)
if !ok {
return
}
id, err := uuid.Parse(c.Param("id"))
if err != nil {
RespondWithAppError(c, apperrors.NewValidationError("invalid stream ID"))
return
}
var req CreateLiveStreamRequest
if appErr := NewCommonHandler(h.logger).BindAndValidateJSON(c, &req); appErr != nil {
RespondWithAppError(c, appErr)
return
}
stream := &models.LiveStream{
Title: req.Title,
Description: req.Description,
Category: req.Category,
ThumbnailURL: req.ThumbnailURL,
StreamerName: req.StreamerName,
Tags: req.Tags,
}
updated, updateErr := h.service.Update(c.Request.Context(), id, userID, stream)
if updateErr != nil {
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to update stream", updateErr))
return
}
RespondSuccess(c, http.StatusOK, gin.H{"stream": updated})
}