Files
mediamtx/internal/api/api_config_paths.go
T
Alessandro RosandGitHub a56c635f8e fix deadlock when changing configuration through file and API (#6077) (#6101)
When changing configuration in parallel by editing the configuration
file and calling the API, the server could get into a deadlock that
prevented any further action. This is fixed.
2026-08-17 11:14:01 +00:00

151 lines
3.3 KiB
Go

package api //nolint:revive
import (
"errors"
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/conf/jsonwrapper"
"github.com/bluenviron/mediamtx/internal/defs"
)
func (a *API) onConfigPathsList(ctx *gin.Context) {
c := a.Parent.APIConfigSnapshot()
data := &defs.APIPathConfList{
Items: make([]conf.Path, len(c.Paths)),
}
for i, key := range sortedKeys(c.Paths) {
data.Items[i] = *c.Paths[key]
}
data.ItemCount = len(data.Items)
pageCount, err := paginate(&data.Items, ctx.Query("itemsPerPage"), ctx.Query("page"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
data.PageCount = pageCount
ctx.JSON(http.StatusOK, data)
}
func (a *API) onConfigPathsGet(ctx *gin.Context) {
confName, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
c := a.Parent.APIConfigSnapshot()
p, ok := c.Paths[confName]
if !ok {
a.writeError(ctx, http.StatusNotFound, fmt.Errorf("path configuration not found"))
return
}
ctx.JSON(http.StatusOK, p)
}
func (a *API) onConfigPathsAdd(ctx *gin.Context) { //nolint:dupl
confName, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
var p conf.OptionalPath
err := jsonwrapper.Decode(&customLimitReader{ctx.Request.Body, maxInboundConfigSize}, &p)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = a.Parent.APIConfigPathsAdd(confName, p)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.writeOK(ctx)
}
func (a *API) onConfigPathsPatch(ctx *gin.Context) { //nolint:dupl
confName, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
var p conf.OptionalPath
err := jsonwrapper.Decode(&customLimitReader{ctx.Request.Body, maxInboundConfigSize}, &p)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = a.Parent.APIConfigPathsPatch(confName, p)
if err != nil {
if errors.Is(err, conf.ErrPathNotFound) {
a.writeError(ctx, http.StatusNotFound, err)
} else {
a.writeError(ctx, http.StatusBadRequest, err)
}
return
}
a.writeOK(ctx)
}
func (a *API) onConfigPathsReplace(ctx *gin.Context) { //nolint:dupl
confName, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
var p conf.OptionalPath
err := jsonwrapper.Decode(&customLimitReader{ctx.Request.Body, maxInboundConfigSize}, &p)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = a.Parent.APIConfigPathsReplace(confName, p)
if err != nil {
if errors.Is(err, conf.ErrPathNotFound) {
a.writeError(ctx, http.StatusNotFound, err)
} else {
a.writeError(ctx, http.StatusBadRequest, err)
}
return
}
a.writeOK(ctx)
}
func (a *API) onConfigPathsDelete(ctx *gin.Context) {
confName, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
err := a.Parent.APIConfigPathsDelete(confName)
if err != nil {
if errors.Is(err, conf.ErrPathNotFound) {
a.writeError(ctx, http.StatusNotFound, err)
} else {
a.writeError(ctx, http.StatusBadRequest, err)
}
return
}
a.writeOK(ctx)
}