Ready-to-use SRT / WebRTC / RTSP / RTMP / LL-HLS media server and media proxy that allows to read, publish, proxy, record and playback video and audio streams.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

990 lines
22 KiB

package core
import (
"encoding/json"
"fmt"
"net/http"
"reflect"
"sort"
"strconv"
"sync"
"time"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/defs"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/protocols/httpserv"
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
)
func interfaceIsEmpty(i interface{}) bool {
return reflect.ValueOf(i).Kind() != reflect.Ptr || reflect.ValueOf(i).IsNil()
}
func paginate2(itemsPtr interface{}, itemsPerPage int, page int) int {
ritems := reflect.ValueOf(itemsPtr).Elem()
itemsLen := ritems.Len()
if itemsLen == 0 {
return 0
}
pageCount := (itemsLen / itemsPerPage)
if (itemsLen % itemsPerPage) != 0 {
pageCount++
}
min := page * itemsPerPage
if min > itemsLen {
min = itemsLen
}
max := (page + 1) * itemsPerPage
if max > itemsLen {
max = itemsLen
}
ritems.Set(ritems.Slice(min, max))
return pageCount
}
func paginate(itemsPtr interface{}, itemsPerPageStr string, pageStr string) (int, error) {
itemsPerPage := 100
if itemsPerPageStr != "" {
tmp, err := strconv.ParseUint(itemsPerPageStr, 10, 31)
if err != nil {
return 0, err
}
itemsPerPage = int(tmp)
}
page := 0
if pageStr != "" {
tmp, err := strconv.ParseUint(pageStr, 10, 31)
if err != nil {
return 0, err
}
page = int(tmp)
}
return paginate2(itemsPtr, itemsPerPage, page), nil
}
func sortedKeys(paths map[string]*conf.Path) []string {
ret := make([]string, len(paths))
i := 0
for name := range paths {
ret[i] = name
i++
}
sort.Strings(ret)
return ret
}
func paramName(ctx *gin.Context) (string, bool) {
name := ctx.Param("name")
if len(name) < 2 || name[0] != '/' {
return "", false
}
return name[1:], true
}
type apiPathManager interface {
apiPathsList() (*defs.APIPathList, error)
apiPathsGet(string) (*defs.APIPath, error)
}
type apiHLSManager interface {
apiMuxersList() (*defs.APIHLSMuxerList, error)
apiMuxersGet(string) (*defs.APIHLSMuxer, error)
}
type apiRTSPServer interface {
apiConnsList() (*defs.APIRTSPConnsList, error)
apiConnsGet(uuid.UUID) (*defs.APIRTSPConn, error)
apiSessionsList() (*defs.APIRTSPSessionList, error)
apiSessionsGet(uuid.UUID) (*defs.APIRTSPSession, error)
apiSessionsKick(uuid.UUID) error
}
type apiRTMPServer interface {
apiConnsList() (*defs.APIRTMPConnList, error)
apiConnsGet(uuid.UUID) (*defs.APIRTMPConn, error)
apiConnsKick(uuid.UUID) error
}
type apiWebRTCManager interface {
apiSessionsList() (*defs.APIWebRTCSessionList, error)
apiSessionsGet(uuid.UUID) (*defs.APIWebRTCSession, error)
apiSessionsKick(uuid.UUID) error
}
type apiSRTServer interface {
apiConnsList() (*defs.APISRTConnList, error)
apiConnsGet(uuid.UUID) (*defs.APISRTConn, error)
apiConnsKick(uuid.UUID) error
}
type apiParent interface {
logger.Writer
apiConfigSet(conf *conf.Conf)
}
type api struct {
conf *conf.Conf
pathManager apiPathManager
rtspServer apiRTSPServer
rtspsServer apiRTSPServer
rtmpServer apiRTMPServer
rtmpsServer apiRTMPServer
hlsManager apiHLSManager
webRTCManager apiWebRTCManager
srtServer apiSRTServer
parent apiParent
httpServer *httpserv.WrappedServer
mutex sync.Mutex
}
func newAPI(
address string,
readTimeout conf.StringDuration,
conf *conf.Conf,
pathManager apiPathManager,
rtspServer apiRTSPServer,
rtspsServer apiRTSPServer,
rtmpServer apiRTMPServer,
rtmpsServer apiRTMPServer,
hlsManager apiHLSManager,
webRTCManager apiWebRTCManager,
srtServer apiSRTServer,
parent apiParent,
) (*api, error) {
a := &api{
conf: conf,
pathManager: pathManager,
rtspServer: rtspServer,
rtspsServer: rtspsServer,
rtmpServer: rtmpServer,
rtmpsServer: rtmpsServer,
hlsManager: hlsManager,
webRTCManager: webRTCManager,
srtServer: srtServer,
parent: parent,
}
router := gin.New()
router.SetTrustedProxies(nil) //nolint:errcheck
group := router.Group("/")
group.GET("/v3/config/global/get", a.onConfigGlobalGet)
group.PATCH("/v3/config/global/patch", a.onConfigGlobalPatch)
group.GET("/v3/config/pathdefaults/get", a.onConfigPathDefaultsGet)
group.PATCH("/v3/config/pathdefaults/patch", a.onConfigPathDefaultsPatch)
group.GET("/v3/config/paths/list", a.onConfigPathsList)
group.GET("/v3/config/paths/get/*name", a.onConfigPathsGet)
group.POST("/v3/config/paths/add/*name", a.onConfigPathsAdd)
group.PATCH("/v3/config/paths/patch/*name", a.onConfigPathsPatch)
group.POST("/v3/config/paths/replace/*name", a.onConfigPathsReplace)
group.DELETE("/v3/config/paths/delete/*name", a.onConfigPathsDelete)
group.GET("/v3/paths/list", a.onPathsList)
group.GET("/v3/paths/get/*name", a.onPathsGet)
if !interfaceIsEmpty(a.hlsManager) {
group.GET("/v3/hlsmuxers/list", a.onHLSMuxersList)
group.GET("/v3/hlsmuxers/get/*name", a.onHLSMuxersGet)
}
if !interfaceIsEmpty(a.rtspServer) {
group.GET("/v3/rtspconns/list", a.onRTSPConnsList)
group.GET("/v3/rtspconns/get/:id", a.onRTSPConnsGet)
group.GET("/v3/rtspsessions/list", a.onRTSPSessionsList)
group.GET("/v3/rtspsessions/get/:id", a.onRTSPSessionsGet)
group.POST("/v3/rtspsessions/kick/:id", a.onRTSPSessionsKick)
}
if !interfaceIsEmpty(a.rtspsServer) {
group.GET("/v3/rtspsconns/list", a.onRTSPSConnsList)
group.GET("/v3/rtspsconns/get/:id", a.onRTSPSConnsGet)
group.GET("/v3/rtspssessions/list", a.onRTSPSSessionsList)
group.GET("/v3/rtspssessions/get/:id", a.onRTSPSSessionsGet)
group.POST("/v3/rtspssessions/kick/:id", a.onRTSPSSessionsKick)
}
if !interfaceIsEmpty(a.rtmpServer) {
group.GET("/v3/rtmpconns/list", a.onRTMPConnsList)
group.GET("/v3/rtmpconns/get/:id", a.onRTMPConnsGet)
group.POST("/v3/rtmpconns/kick/:id", a.onRTMPConnsKick)
}
if !interfaceIsEmpty(a.rtmpsServer) {
group.GET("/v3/rtmpsconns/list", a.onRTMPSConnsList)
group.GET("/v3/rtmpsconns/get/:id", a.onRTMPSConnsGet)
group.POST("/v3/rtmpsconns/kick/:id", a.onRTMPSConnsKick)
}
if !interfaceIsEmpty(a.webRTCManager) {
group.GET("/v3/webrtcsessions/list", a.onWebRTCSessionsList)
group.GET("/v3/webrtcsessions/get/:id", a.onWebRTCSessionsGet)
group.POST("/v3/webrtcsessions/kick/:id", a.onWebRTCSessionsKick)
}
if !interfaceIsEmpty(a.srtServer) {
group.GET("/v3/srtconns/list", a.onSRTConnsList)
group.GET("/v3/srtconns/get/:id", a.onSRTConnsGet)
group.POST("/v3/srtconns/kick/:id", a.onSRTConnsKick)
}
network, address := restrictnetwork.Restrict("tcp", address)
var err error
a.httpServer, err = httpserv.NewWrappedServer(
network,
address,
time.Duration(readTimeout),
"",
"",
router,
a,
)
if err != nil {
return nil, err
}
a.Log(logger.Info, "listener opened on "+address)
return a, nil
}
func (a *api) close() {
a.Log(logger.Info, "listener is closing")
a.httpServer.Close()
}
func (a *api) Log(level logger.Level, format string, args ...interface{}) {
a.parent.Log(level, "[API] "+format, args...)
}
// error coming from something the user inserted into the request.
func (a *api) writeError(ctx *gin.Context, status int, err error) {
// show error in logs
a.Log(logger.Error, err.Error())
// send error in response
ctx.JSON(status, &defs.APIError{
Error: err.Error(),
})
}
func (a *api) onConfigGlobalGet(ctx *gin.Context) {
a.mutex.Lock()
c := a.conf
a.mutex.Unlock()
ctx.JSON(http.StatusOK, c.Global())
}
func (a *api) onConfigGlobalPatch(ctx *gin.Context) {
var c conf.OptionalGlobal
err := json.NewDecoder(ctx.Request.Body).Decode(&c)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.mutex.Lock()
defer a.mutex.Unlock()
newConf := a.conf.Clone()
newConf.PatchGlobal(&c)
err = newConf.Check()
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.conf = newConf
// since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine
go a.parent.apiConfigSet(newConf)
ctx.Status(http.StatusOK)
}
func (a *api) onConfigPathDefaultsGet(ctx *gin.Context) {
a.mutex.Lock()
c := a.conf
a.mutex.Unlock()
ctx.JSON(http.StatusOK, c.PathDefaults)
}
func (a *api) onConfigPathDefaultsPatch(ctx *gin.Context) {
var p conf.OptionalPath
err := json.NewDecoder(ctx.Request.Body).Decode(&p)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.mutex.Lock()
defer a.mutex.Unlock()
newConf := a.conf.Clone()
newConf.PatchPathDefaults(&p)
err = newConf.Check()
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.conf = newConf
a.parent.apiConfigSet(newConf)
ctx.Status(http.StatusOK)
}
func (a *api) onConfigPathsList(ctx *gin.Context) {
a.mutex.Lock()
c := a.conf
a.mutex.Unlock()
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) {
name, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
a.mutex.Lock()
c := a.conf
a.mutex.Unlock()
p, ok := c.Paths[name]
if !ok {
a.writeError(ctx, http.StatusInternalServerError, fmt.Errorf("path configuration not found"))
return
}
ctx.JSON(http.StatusOK, p)
}
func (a *api) onConfigPathsAdd(ctx *gin.Context) { //nolint:dupl
name, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
var p conf.OptionalPath
err := json.NewDecoder(ctx.Request.Body).Decode(&p)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.mutex.Lock()
defer a.mutex.Unlock()
newConf := a.conf.Clone()
err = newConf.AddPath(name, &p)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = newConf.Check()
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.conf = newConf
a.parent.apiConfigSet(newConf)
ctx.Status(http.StatusOK)
}
func (a *api) onConfigPathsPatch(ctx *gin.Context) { //nolint:dupl
name, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
var p conf.OptionalPath
err := json.NewDecoder(ctx.Request.Body).Decode(&p)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.mutex.Lock()
defer a.mutex.Unlock()
newConf := a.conf.Clone()
err = newConf.PatchPath(name, &p)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = newConf.Check()
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.conf = newConf
a.parent.apiConfigSet(newConf)
ctx.Status(http.StatusOK)
}
func (a *api) onConfigPathsReplace(ctx *gin.Context) { //nolint:dupl
name, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
var p conf.OptionalPath
err := json.NewDecoder(ctx.Request.Body).Decode(&p)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.mutex.Lock()
defer a.mutex.Unlock()
newConf := a.conf.Clone()
err = newConf.ReplacePath(name, &p)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = newConf.Check()
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.conf = newConf
a.parent.apiConfigSet(newConf)
ctx.Status(http.StatusOK)
}
func (a *api) onConfigPathsDelete(ctx *gin.Context) {
name, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
a.mutex.Lock()
defer a.mutex.Unlock()
newConf := a.conf.Clone()
err := newConf.RemovePath(name)
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = newConf.Check()
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
a.conf = newConf
a.parent.apiConfigSet(newConf)
ctx.Status(http.StatusOK)
}
func (a *api) onPathsList(ctx *gin.Context) {
data, err := a.pathManager.apiPathsList()
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
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) onPathsGet(ctx *gin.Context) {
name, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
data, err := a.pathManager.apiPathsGet(name)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.JSON(http.StatusOK, data)
}
func (a *api) onRTSPConnsList(ctx *gin.Context) {
data, err := a.rtspServer.apiConnsList()
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
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) onRTSPConnsGet(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
data, err := a.rtspServer.apiConnsGet(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.JSON(http.StatusOK, data)
}
func (a *api) onRTSPSessionsList(ctx *gin.Context) {
data, err := a.rtspServer.apiSessionsList()
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
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) onRTSPSessionsGet(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
data, err := a.rtspServer.apiSessionsGet(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.JSON(http.StatusOK, data)
}
func (a *api) onRTSPSessionsKick(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = a.rtspServer.apiSessionsKick(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.Status(http.StatusOK)
}
func (a *api) onRTSPSConnsList(ctx *gin.Context) {
data, err := a.rtspsServer.apiConnsList()
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
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) onRTSPSConnsGet(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
data, err := a.rtspsServer.apiConnsGet(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.JSON(http.StatusOK, data)
}
func (a *api) onRTSPSSessionsList(ctx *gin.Context) {
data, err := a.rtspsServer.apiSessionsList()
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
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) onRTSPSSessionsGet(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
data, err := a.rtspsServer.apiSessionsGet(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.JSON(http.StatusOK, data)
}
func (a *api) onRTSPSSessionsKick(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = a.rtspsServer.apiSessionsKick(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.Status(http.StatusOK)
}
func (a *api) onRTMPConnsList(ctx *gin.Context) {
data, err := a.rtmpServer.apiConnsList()
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
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) onRTMPConnsGet(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
data, err := a.rtmpServer.apiConnsGet(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.JSON(http.StatusOK, data)
}
func (a *api) onRTMPConnsKick(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = a.rtmpServer.apiConnsKick(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.Status(http.StatusOK)
}
func (a *api) onRTMPSConnsList(ctx *gin.Context) {
data, err := a.rtmpsServer.apiConnsList()
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
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) onRTMPSConnsGet(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
data, err := a.rtmpsServer.apiConnsGet(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.JSON(http.StatusOK, data)
}
func (a *api) onRTMPSConnsKick(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = a.rtmpsServer.apiConnsKick(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.Status(http.StatusOK)
}
func (a *api) onHLSMuxersList(ctx *gin.Context) {
data, err := a.hlsManager.apiMuxersList()
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
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) onHLSMuxersGet(ctx *gin.Context) {
name, ok := paramName(ctx)
if !ok {
a.writeError(ctx, http.StatusBadRequest, fmt.Errorf("invalid name"))
return
}
data, err := a.hlsManager.apiMuxersGet(name)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.JSON(http.StatusOK, data)
}
func (a *api) onWebRTCSessionsList(ctx *gin.Context) {
data, err := a.webRTCManager.apiSessionsList()
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
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) onWebRTCSessionsGet(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
data, err := a.webRTCManager.apiSessionsGet(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.JSON(http.StatusOK, data)
}
func (a *api) onWebRTCSessionsKick(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = a.webRTCManager.apiSessionsKick(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.Status(http.StatusOK)
}
func (a *api) onSRTConnsList(ctx *gin.Context) {
data, err := a.srtServer.apiConnsList()
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
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) onSRTConnsGet(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
data, err := a.srtServer.apiConnsGet(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.JSON(http.StatusOK, data)
}
func (a *api) onSRTConnsKick(ctx *gin.Context) {
uuid, err := uuid.Parse(ctx.Param("id"))
if err != nil {
a.writeError(ctx, http.StatusBadRequest, err)
return
}
err = a.srtServer.apiConnsKick(uuid)
if err != nil {
a.writeError(ctx, http.StatusInternalServerError, err)
return
}
ctx.Status(http.StatusOK)
}
// confReload is called by core.
func (a *api) confReload(conf *conf.Conf) {
a.mutex.Lock()
defer a.mutex.Unlock()
a.conf = conf
}