2021-07-04 16:13:49 +00:00
|
|
|
package core
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"net/http"
|
|
|
|
"reflect"
|
2023-05-16 17:48:13 +00:00
|
|
|
"strconv"
|
2021-07-04 16:13:49 +00:00
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
2023-05-16 13:59:37 +00:00
|
|
|
"github.com/google/uuid"
|
2021-07-04 16:13:49 +00:00
|
|
|
|
2023-05-16 14:14:20 +00:00
|
|
|
"github.com/bluenviron/mediamtx/internal/conf"
|
|
|
|
"github.com/bluenviron/mediamtx/internal/logger"
|
2021-07-04 16:13:49 +00:00
|
|
|
)
|
|
|
|
|
2021-08-12 09:48:47 +00:00
|
|
|
func interfaceIsEmpty(i interface{}) bool {
|
|
|
|
return reflect.ValueOf(i).Kind() != reflect.Ptr || reflect.ValueOf(i).IsNil()
|
|
|
|
}
|
|
|
|
|
2021-07-04 16:13:49 +00:00
|
|
|
func fillStruct(dest interface{}, source interface{}) {
|
2022-10-23 16:01:51 +00:00
|
|
|
rvsource := reflect.ValueOf(source).Elem()
|
2021-07-04 16:13:49 +00:00
|
|
|
rvdest := reflect.ValueOf(dest)
|
|
|
|
nf := rvsource.NumField()
|
|
|
|
for i := 0; i < nf; i++ {
|
|
|
|
fnew := rvsource.Field(i)
|
|
|
|
if !fnew.IsNil() {
|
|
|
|
f := rvdest.Elem().FieldByName(rvsource.Type().Field(i).Name)
|
|
|
|
if f.Kind() == reflect.Ptr {
|
|
|
|
f.Set(fnew)
|
|
|
|
} else {
|
|
|
|
f.Set(fnew.Elem())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-23 16:01:51 +00:00
|
|
|
func generateStructWithOptionalFields(model interface{}) interface{} {
|
|
|
|
var fields []reflect.StructField
|
|
|
|
|
|
|
|
rt := reflect.TypeOf(model)
|
|
|
|
nf := rt.NumField()
|
|
|
|
for i := 0; i < nf; i++ {
|
|
|
|
f := rt.Field(i)
|
|
|
|
j := f.Tag.Get("json")
|
|
|
|
|
|
|
|
if j != "-" && j != "paths" {
|
|
|
|
fields = append(fields, reflect.StructField{
|
|
|
|
Name: f.Name,
|
|
|
|
Type: reflect.PtrTo(f.Type),
|
|
|
|
Tag: f.Tag,
|
|
|
|
})
|
|
|
|
}
|
2021-07-04 16:13:49 +00:00
|
|
|
}
|
2022-10-23 16:01:51 +00:00
|
|
|
|
|
|
|
return reflect.New(reflect.StructOf(fields)).Interface()
|
|
|
|
}
|
|
|
|
|
|
|
|
func loadConfData(ctx *gin.Context) (interface{}, error) {
|
|
|
|
in := generateStructWithOptionalFields(conf.Conf{})
|
|
|
|
err := json.NewDecoder(ctx.Request.Body).Decode(in)
|
2021-07-04 16:13:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return in, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func loadConfPathData(ctx *gin.Context) (interface{}, error) {
|
2022-10-23 16:01:51 +00:00
|
|
|
in := generateStructWithOptionalFields(conf.PathConf{})
|
|
|
|
err := json.NewDecoder(ctx.Request.Body).Decode(in)
|
2021-07-04 16:13:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return in, err
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:48:13 +00:00
|
|
|
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) + 1
|
|
|
|
|
|
|
|
min := page * itemsPerPage
|
|
|
|
if min >= itemsLen {
|
|
|
|
min = itemsLen - 1
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-08-11 10:45:53 +00:00
|
|
|
type apiPathManager interface {
|
2022-11-09 17:31:31 +00:00
|
|
|
apiPathsList() pathAPIPathsListRes
|
2021-08-11 10:45:53 +00:00
|
|
|
}
|
|
|
|
|
2023-05-16 13:59:37 +00:00
|
|
|
type apiHLSManager interface {
|
|
|
|
apiMuxersList() hlsManagerAPIMuxersListRes
|
2022-12-15 23:50:47 +00:00
|
|
|
}
|
|
|
|
|
2021-08-11 10:45:53 +00:00
|
|
|
type apiRTSPServer interface {
|
2022-11-09 17:31:31 +00:00
|
|
|
apiConnsList() rtspServerAPIConnsListRes
|
|
|
|
apiSessionsList() rtspServerAPISessionsListRes
|
2023-05-16 13:59:37 +00:00
|
|
|
apiSessionsKick(uuid.UUID) rtspServerAPISessionsKickRes
|
2021-08-11 10:45:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type apiRTMPServer interface {
|
2022-11-09 17:31:31 +00:00
|
|
|
apiConnsList() rtmpServerAPIConnsListRes
|
2023-05-16 13:59:37 +00:00
|
|
|
apiConnsKick(uuid.UUID) rtmpServerAPIConnsKickRes
|
2021-08-11 10:45:53 +00:00
|
|
|
}
|
|
|
|
|
2021-07-04 16:13:49 +00:00
|
|
|
type apiParent interface {
|
2023-05-04 18:16:41 +00:00
|
|
|
logger.Writer
|
2022-08-04 19:07:17 +00:00
|
|
|
apiConfigSet(conf *conf.Conf)
|
2021-07-04 16:13:49 +00:00
|
|
|
}
|
|
|
|
|
2023-05-16 13:59:37 +00:00
|
|
|
type apiWebRTCManager interface {
|
|
|
|
apiSessionsList() webRTCManagerAPISessionsListRes
|
|
|
|
apiSessionsKick(uuid.UUID) webRTCManagerAPISessionsKickRes
|
2022-12-15 23:50:47 +00:00
|
|
|
}
|
|
|
|
|
2021-07-04 16:13:49 +00:00
|
|
|
type api struct {
|
2023-05-16 13:59:37 +00:00
|
|
|
conf *conf.Conf
|
|
|
|
pathManager apiPathManager
|
|
|
|
rtspServer apiRTSPServer
|
|
|
|
rtspsServer apiRTSPServer
|
|
|
|
rtmpServer apiRTMPServer
|
|
|
|
rtmpsServer apiRTMPServer
|
|
|
|
hlsManager apiHLSManager
|
|
|
|
webRTCManager apiWebRTCManager
|
|
|
|
parent apiParent
|
2021-07-04 16:13:49 +00:00
|
|
|
|
2023-05-16 18:12:45 +00:00
|
|
|
httpServer *httpServer
|
2023-04-11 18:42:40 +00:00
|
|
|
mutex sync.Mutex
|
2021-07-04 16:13:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func newAPI(
|
|
|
|
address string,
|
2023-04-11 18:47:19 +00:00
|
|
|
readTimeout conf.StringDuration,
|
2021-07-04 16:13:49 +00:00
|
|
|
conf *conf.Conf,
|
2021-08-11 10:45:53 +00:00
|
|
|
pathManager apiPathManager,
|
|
|
|
rtspServer apiRTSPServer,
|
|
|
|
rtspsServer apiRTSPServer,
|
|
|
|
rtmpServer apiRTMPServer,
|
2022-08-16 11:53:04 +00:00
|
|
|
rtmpsServer apiRTMPServer,
|
2023-05-16 13:59:37 +00:00
|
|
|
hlsManager apiHLSManager,
|
|
|
|
webRTCManager apiWebRTCManager,
|
2021-07-04 16:13:49 +00:00
|
|
|
parent apiParent,
|
|
|
|
) (*api, error) {
|
|
|
|
a := &api{
|
2023-05-16 13:59:37 +00:00
|
|
|
conf: conf,
|
|
|
|
pathManager: pathManager,
|
|
|
|
rtspServer: rtspServer,
|
|
|
|
rtspsServer: rtspsServer,
|
|
|
|
rtmpServer: rtmpServer,
|
|
|
|
rtmpsServer: rtmpsServer,
|
|
|
|
hlsManager: hlsManager,
|
|
|
|
webRTCManager: webRTCManager,
|
|
|
|
parent: parent,
|
2021-07-04 16:13:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
router := gin.New()
|
2022-06-21 11:41:15 +00:00
|
|
|
router.SetTrustedProxies(nil)
|
2023-04-09 15:12:50 +00:00
|
|
|
|
2022-12-15 23:50:47 +00:00
|
|
|
mwLog := httpLoggerMiddleware(a)
|
2023-04-09 15:12:50 +00:00
|
|
|
router.NoRoute(mwLog, httpServerHeaderMiddleware)
|
|
|
|
group := router.Group("/", mwLog, httpServerHeaderMiddleware)
|
2021-11-05 16:18:21 +00:00
|
|
|
|
2021-08-07 16:28:27 +00:00
|
|
|
group.GET("/v1/config/get", a.onConfigGet)
|
|
|
|
group.POST("/v1/config/set", a.onConfigSet)
|
2021-09-23 07:07:36 +00:00
|
|
|
group.POST("/v1/config/paths/add/*name", a.onConfigPathsAdd)
|
|
|
|
group.POST("/v1/config/paths/edit/*name", a.onConfigPathsEdit)
|
|
|
|
group.POST("/v1/config/paths/remove/*name", a.onConfigPathsDelete)
|
2021-11-05 16:53:24 +00:00
|
|
|
|
2023-05-16 13:59:37 +00:00
|
|
|
if !interfaceIsEmpty(a.hlsManager) {
|
2022-12-15 23:50:47 +00:00
|
|
|
group.GET("/v1/hlsmuxers/list", a.onHLSMuxersList)
|
|
|
|
}
|
|
|
|
|
2021-08-07 16:28:27 +00:00
|
|
|
group.GET("/v1/paths/list", a.onPathsList)
|
2021-11-05 16:18:21 +00:00
|
|
|
|
|
|
|
if !interfaceIsEmpty(a.rtspServer) {
|
2022-11-09 17:31:31 +00:00
|
|
|
group.GET("/v1/rtspconns/list", a.onRTSPConnsList)
|
2021-11-05 16:18:21 +00:00
|
|
|
group.GET("/v1/rtspsessions/list", a.onRTSPSessionsList)
|
|
|
|
group.POST("/v1/rtspsessions/kick/:id", a.onRTSPSessionsKick)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !interfaceIsEmpty(a.rtspsServer) {
|
2022-11-09 17:31:31 +00:00
|
|
|
group.GET("/v1/rtspsconns/list", a.onRTSPSConnsList)
|
2021-11-05 16:18:21 +00:00
|
|
|
group.GET("/v1/rtspssessions/list", a.onRTSPSSessionsList)
|
|
|
|
group.POST("/v1/rtspssessions/kick/:id", a.onRTSPSSessionsKick)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !interfaceIsEmpty(a.rtmpServer) {
|
|
|
|
group.GET("/v1/rtmpconns/list", a.onRTMPConnsList)
|
|
|
|
group.POST("/v1/rtmpconns/kick/:id", a.onRTMPConnsKick)
|
|
|
|
}
|
|
|
|
|
2022-08-16 11:53:04 +00:00
|
|
|
if !interfaceIsEmpty(a.rtmpsServer) {
|
|
|
|
group.GET("/v1/rtmpsconns/list", a.onRTMPSConnsList)
|
|
|
|
group.POST("/v1/rtmpsconns/kick/:id", a.onRTMPSConnsKick)
|
|
|
|
}
|
|
|
|
|
2023-05-16 13:59:37 +00:00
|
|
|
if !interfaceIsEmpty(a.webRTCManager) {
|
|
|
|
group.GET("/v1/webrtcsessions/list", a.onWebRTCSessionsList)
|
|
|
|
group.POST("/v1/webrtcsessions/kick/:id", a.onWebRTCSessionsKick)
|
2021-11-05 16:18:21 +00:00
|
|
|
}
|
2021-07-04 16:13:49 +00:00
|
|
|
|
2023-05-16 18:12:45 +00:00
|
|
|
var err error
|
|
|
|
a.httpServer, err = newHTTPServer(
|
|
|
|
address,
|
|
|
|
readTimeout,
|
|
|
|
"",
|
|
|
|
"",
|
|
|
|
router,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2023-01-08 12:23:11 +00:00
|
|
|
}
|
2021-07-04 16:13:49 +00:00
|
|
|
|
2023-05-04 18:16:41 +00:00
|
|
|
a.Log(logger.Info, "listener opened on "+address)
|
2021-07-04 16:13:49 +00:00
|
|
|
|
|
|
|
return a, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) close() {
|
2023-05-04 18:16:41 +00:00
|
|
|
a.Log(logger.Info, "listener is closing")
|
2023-05-16 18:12:45 +00:00
|
|
|
a.httpServer.close()
|
2021-07-04 16:13:49 +00:00
|
|
|
}
|
|
|
|
|
2023-05-04 18:16:41 +00:00
|
|
|
func (a *api) Log(level logger.Level, format string, args ...interface{}) {
|
2021-07-04 16:13:49 +00:00
|
|
|
a.parent.Log(level, "[API] "+format, args...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onConfigGet(ctx *gin.Context) {
|
|
|
|
a.mutex.Lock()
|
|
|
|
c := a.conf
|
|
|
|
a.mutex.Unlock()
|
|
|
|
|
|
|
|
ctx.JSON(http.StatusOK, c)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onConfigSet(ctx *gin.Context) {
|
|
|
|
in, err := loadConfData(ctx)
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
a.mutex.Lock()
|
2021-09-06 16:39:15 +00:00
|
|
|
defer a.mutex.Unlock()
|
|
|
|
|
2023-03-31 14:22:08 +00:00
|
|
|
newConf := a.conf.Clone()
|
|
|
|
|
|
|
|
fillStruct(newConf, in)
|
2021-07-04 16:13:49 +00:00
|
|
|
|
2023-05-06 21:00:42 +00:00
|
|
|
err = newConf.Check()
|
2021-07-04 16:13:49 +00:00
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-31 14:22:08 +00:00
|
|
|
a.conf = newConf
|
2021-08-07 14:07:08 +00:00
|
|
|
|
2021-07-04 16:13:49 +00:00
|
|
|
// since reloading the configuration can cause the shutdown of the API,
|
|
|
|
// call it in a goroutine
|
2023-03-31 14:22:08 +00:00
|
|
|
go a.parent.apiConfigSet(newConf)
|
2021-07-04 16:13:49 +00:00
|
|
|
|
|
|
|
ctx.Status(http.StatusOK)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onConfigPathsAdd(ctx *gin.Context) {
|
2021-09-23 07:07:36 +00:00
|
|
|
name := ctx.Param("name")
|
|
|
|
if len(name) < 2 || name[0] != '/' {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
name = name[1:]
|
|
|
|
|
2021-07-04 16:13:49 +00:00
|
|
|
in, err := loadConfPathData(ctx)
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
a.mutex.Lock()
|
2021-09-06 16:39:15 +00:00
|
|
|
defer a.mutex.Unlock()
|
|
|
|
|
2023-03-31 14:22:08 +00:00
|
|
|
newConf := a.conf.Clone()
|
2021-07-04 16:13:49 +00:00
|
|
|
|
|
|
|
if _, ok := newConf.Paths[name]; ok {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-09-27 12:59:27 +00:00
|
|
|
newConfPath := &conf.PathConf{}
|
2021-07-04 16:13:49 +00:00
|
|
|
fillStruct(newConfPath, in)
|
2021-09-27 12:59:27 +00:00
|
|
|
|
2021-07-04 16:13:49 +00:00
|
|
|
newConf.Paths[name] = newConfPath
|
|
|
|
|
2023-05-06 21:00:42 +00:00
|
|
|
err = newConf.Check()
|
2021-07-04 16:13:49 +00:00
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-31 14:22:08 +00:00
|
|
|
a.conf = newConf
|
2021-08-07 14:07:08 +00:00
|
|
|
|
2021-07-04 16:13:49 +00:00
|
|
|
// since reloading the configuration can cause the shutdown of the API,
|
|
|
|
// call it in a goroutine
|
2023-03-31 14:22:08 +00:00
|
|
|
go a.parent.apiConfigSet(newConf)
|
2021-07-04 16:13:49 +00:00
|
|
|
|
|
|
|
ctx.Status(http.StatusOK)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onConfigPathsEdit(ctx *gin.Context) {
|
2021-09-23 07:07:36 +00:00
|
|
|
name := ctx.Param("name")
|
|
|
|
if len(name) < 2 || name[0] != '/' {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
name = name[1:]
|
|
|
|
|
2021-07-04 16:13:49 +00:00
|
|
|
in, err := loadConfPathData(ctx)
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
a.mutex.Lock()
|
2021-09-06 16:39:15 +00:00
|
|
|
defer a.mutex.Unlock()
|
|
|
|
|
2023-03-31 14:22:08 +00:00
|
|
|
newConf := a.conf.Clone()
|
2021-07-04 16:13:49 +00:00
|
|
|
|
|
|
|
newConfPath, ok := newConf.Paths[name]
|
|
|
|
if !ok {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
fillStruct(newConfPath, in)
|
|
|
|
|
2023-05-06 21:00:42 +00:00
|
|
|
err = newConf.Check()
|
2021-07-04 16:13:49 +00:00
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-31 14:22:08 +00:00
|
|
|
a.conf = newConf
|
2021-08-07 14:07:08 +00:00
|
|
|
|
2021-07-04 16:13:49 +00:00
|
|
|
// since reloading the configuration can cause the shutdown of the API,
|
|
|
|
// call it in a goroutine
|
2023-03-31 14:22:08 +00:00
|
|
|
go a.parent.apiConfigSet(newConf)
|
2021-07-04 16:13:49 +00:00
|
|
|
|
|
|
|
ctx.Status(http.StatusOK)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onConfigPathsDelete(ctx *gin.Context) {
|
|
|
|
name := ctx.Param("name")
|
2021-09-23 07:07:36 +00:00
|
|
|
if len(name) < 2 || name[0] != '/' {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
name = name[1:]
|
2021-07-04 16:13:49 +00:00
|
|
|
|
|
|
|
a.mutex.Lock()
|
2021-09-06 16:39:15 +00:00
|
|
|
defer a.mutex.Unlock()
|
|
|
|
|
2023-03-31 14:22:08 +00:00
|
|
|
newConf := a.conf.Clone()
|
2021-07-04 16:13:49 +00:00
|
|
|
|
|
|
|
if _, ok := newConf.Paths[name]; !ok {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
delete(newConf.Paths, name)
|
|
|
|
|
2023-05-06 21:00:42 +00:00
|
|
|
err := newConf.Check()
|
2021-07-04 16:13:49 +00:00
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-31 14:22:08 +00:00
|
|
|
a.conf = newConf
|
2021-08-07 14:07:08 +00:00
|
|
|
|
2021-07-04 16:13:49 +00:00
|
|
|
// since reloading the configuration can cause the shutdown of the API,
|
|
|
|
// call it in a goroutine
|
2023-03-31 14:22:08 +00:00
|
|
|
go a.parent.apiConfigSet(newConf)
|
2021-07-04 16:13:49 +00:00
|
|
|
|
|
|
|
ctx.Status(http.StatusOK)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onPathsList(ctx *gin.Context) {
|
2022-11-09 17:31:31 +00:00
|
|
|
res := a.pathManager.apiPathsList()
|
|
|
|
if res.err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:48:13 +00:00
|
|
|
pageCount, err := paginate(&res.data.Items, ctx.Query("itemsPerPage"), ctx.Query("page"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
res.data.PageCount = pageCount
|
|
|
|
|
2022-11-09 17:31:31 +00:00
|
|
|
ctx.JSON(http.StatusOK, res.data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onRTSPConnsList(ctx *gin.Context) {
|
|
|
|
res := a.rtspServer.apiConnsList()
|
2022-01-14 22:42:41 +00:00
|
|
|
if res.err != nil {
|
2021-07-04 16:13:49 +00:00
|
|
|
ctx.AbortWithStatus(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:48:13 +00:00
|
|
|
pageCount, err := paginate(&res.data.Items, ctx.Query("itemsPerPage"), ctx.Query("page"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
res.data.PageCount = pageCount
|
|
|
|
|
2022-01-14 22:42:41 +00:00
|
|
|
ctx.JSON(http.StatusOK, res.data)
|
2021-07-04 16:13:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onRTSPSessionsList(ctx *gin.Context) {
|
2022-11-09 17:31:31 +00:00
|
|
|
res := a.rtspServer.apiSessionsList()
|
2022-01-14 22:42:41 +00:00
|
|
|
if res.err != nil {
|
2021-08-11 15:32:47 +00:00
|
|
|
ctx.AbortWithStatus(http.StatusInternalServerError)
|
|
|
|
return
|
2021-07-04 16:13:49 +00:00
|
|
|
}
|
|
|
|
|
2023-05-16 17:48:13 +00:00
|
|
|
pageCount, err := paginate(&res.data.Items, ctx.Query("itemsPerPage"), ctx.Query("page"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
res.data.PageCount = pageCount
|
|
|
|
|
2022-01-14 22:42:41 +00:00
|
|
|
ctx.JSON(http.StatusOK, res.data)
|
2021-07-04 16:13:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onRTSPSessionsKick(ctx *gin.Context) {
|
2023-05-16 13:59:37 +00:00
|
|
|
uuid, err := uuid.Parse(ctx.Param("id"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
2021-07-04 16:13:49 +00:00
|
|
|
|
2023-05-16 13:59:37 +00:00
|
|
|
res := a.rtspServer.apiSessionsKick(uuid)
|
2022-01-14 22:42:41 +00:00
|
|
|
if res.err != nil {
|
2021-08-11 15:32:47 +00:00
|
|
|
return
|
2021-07-04 16:13:49 +00:00
|
|
|
}
|
|
|
|
|
2021-08-11 15:32:47 +00:00
|
|
|
ctx.Status(http.StatusOK)
|
|
|
|
}
|
|
|
|
|
2022-11-09 17:31:31 +00:00
|
|
|
func (a *api) onRTSPSConnsList(ctx *gin.Context) {
|
|
|
|
res := a.rtspsServer.apiConnsList()
|
|
|
|
if res.err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:48:13 +00:00
|
|
|
pageCount, err := paginate(&res.data.Items, ctx.Query("itemsPerPage"), ctx.Query("page"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
res.data.PageCount = pageCount
|
|
|
|
|
2022-11-09 17:31:31 +00:00
|
|
|
ctx.JSON(http.StatusOK, res.data)
|
|
|
|
}
|
|
|
|
|
2021-08-11 15:32:47 +00:00
|
|
|
func (a *api) onRTSPSSessionsList(ctx *gin.Context) {
|
2022-11-09 17:31:31 +00:00
|
|
|
res := a.rtspsServer.apiSessionsList()
|
2022-01-14 22:42:41 +00:00
|
|
|
if res.err != nil {
|
2021-08-11 15:32:47 +00:00
|
|
|
ctx.AbortWithStatus(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:48:13 +00:00
|
|
|
pageCount, err := paginate(&res.data.Items, ctx.Query("itemsPerPage"), ctx.Query("page"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
res.data.PageCount = pageCount
|
|
|
|
|
2022-01-14 22:42:41 +00:00
|
|
|
ctx.JSON(http.StatusOK, res.data)
|
2021-08-11 15:32:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onRTSPSSessionsKick(ctx *gin.Context) {
|
2023-05-16 13:59:37 +00:00
|
|
|
uuid, err := uuid.Parse(ctx.Param("id"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
2021-08-11 15:32:47 +00:00
|
|
|
|
2023-05-16 13:59:37 +00:00
|
|
|
res := a.rtspsServer.apiSessionsKick(uuid)
|
2022-01-14 22:42:41 +00:00
|
|
|
if res.err != nil {
|
2021-08-11 15:32:47 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Status(http.StatusOK)
|
2021-07-04 16:13:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onRTMPConnsList(ctx *gin.Context) {
|
2022-11-09 17:31:31 +00:00
|
|
|
res := a.rtmpServer.apiConnsList()
|
2022-01-14 22:42:41 +00:00
|
|
|
if res.err != nil {
|
2021-07-04 16:13:49 +00:00
|
|
|
ctx.AbortWithStatus(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:48:13 +00:00
|
|
|
pageCount, err := paginate(&res.data.Items, ctx.Query("itemsPerPage"), ctx.Query("page"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
res.data.PageCount = pageCount
|
|
|
|
|
2022-01-14 22:42:41 +00:00
|
|
|
ctx.JSON(http.StatusOK, res.data)
|
2021-07-04 16:13:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onRTMPConnsKick(ctx *gin.Context) {
|
2023-05-16 13:59:37 +00:00
|
|
|
uuid, err := uuid.Parse(ctx.Param("id"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
2021-07-04 16:13:49 +00:00
|
|
|
|
2023-05-16 13:59:37 +00:00
|
|
|
res := a.rtmpServer.apiConnsKick(uuid)
|
2022-01-14 22:42:41 +00:00
|
|
|
if res.err != nil {
|
2021-07-04 16:13:49 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Status(http.StatusOK)
|
|
|
|
}
|
2021-11-05 16:14:31 +00:00
|
|
|
|
2022-08-16 11:53:04 +00:00
|
|
|
func (a *api) onRTMPSConnsList(ctx *gin.Context) {
|
2022-11-09 17:31:31 +00:00
|
|
|
res := a.rtmpsServer.apiConnsList()
|
2022-08-16 11:53:04 +00:00
|
|
|
if res.err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:48:13 +00:00
|
|
|
pageCount, err := paginate(&res.data.Items, ctx.Query("itemsPerPage"), ctx.Query("page"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
res.data.PageCount = pageCount
|
|
|
|
|
2022-08-16 11:53:04 +00:00
|
|
|
ctx.JSON(http.StatusOK, res.data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *api) onRTMPSConnsKick(ctx *gin.Context) {
|
2023-05-16 13:59:37 +00:00
|
|
|
uuid, err := uuid.Parse(ctx.Param("id"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
2022-08-16 11:53:04 +00:00
|
|
|
|
2023-05-16 13:59:37 +00:00
|
|
|
res := a.rtmpsServer.apiConnsKick(uuid)
|
2022-08-16 11:53:04 +00:00
|
|
|
if res.err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Status(http.StatusOK)
|
|
|
|
}
|
|
|
|
|
2021-11-05 16:14:31 +00:00
|
|
|
func (a *api) onHLSMuxersList(ctx *gin.Context) {
|
2023-05-16 13:59:37 +00:00
|
|
|
res := a.hlsManager.apiMuxersList()
|
2022-12-15 23:50:47 +00:00
|
|
|
if res.err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:48:13 +00:00
|
|
|
pageCount, err := paginate(&res.data.Items, ctx.Query("itemsPerPage"), ctx.Query("page"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
res.data.PageCount = pageCount
|
|
|
|
|
2022-12-15 23:50:47 +00:00
|
|
|
ctx.JSON(http.StatusOK, res.data)
|
|
|
|
}
|
|
|
|
|
2023-05-16 13:59:37 +00:00
|
|
|
func (a *api) onWebRTCSessionsList(ctx *gin.Context) {
|
|
|
|
res := a.webRTCManager.apiSessionsList()
|
2022-01-14 22:42:41 +00:00
|
|
|
if res.err != nil {
|
2021-11-05 16:14:31 +00:00
|
|
|
ctx.AbortWithStatus(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:48:13 +00:00
|
|
|
pageCount, err := paginate(&res.data.Items, ctx.Query("itemsPerPage"), ctx.Query("page"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
res.data.PageCount = pageCount
|
|
|
|
|
2022-01-14 22:42:41 +00:00
|
|
|
ctx.JSON(http.StatusOK, res.data)
|
2021-11-05 16:14:31 +00:00
|
|
|
}
|
|
|
|
|
2023-05-16 13:59:37 +00:00
|
|
|
func (a *api) onWebRTCSessionsKick(ctx *gin.Context) {
|
|
|
|
uuid, err := uuid.Parse(ctx.Param("id"))
|
|
|
|
if err != nil {
|
|
|
|
ctx.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
2022-12-15 23:50:47 +00:00
|
|
|
|
2023-05-16 13:59:37 +00:00
|
|
|
res := a.webRTCManager.apiSessionsKick(uuid)
|
2022-12-15 23:50:47 +00:00
|
|
|
if res.err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Status(http.StatusOK)
|
|
|
|
}
|
|
|
|
|
2022-08-04 19:07:17 +00:00
|
|
|
// confReload is called by core.
|
|
|
|
func (a *api) confReload(conf *conf.Conf) {
|
2021-11-05 16:14:31 +00:00
|
|
|
a.mutex.Lock()
|
|
|
|
defer a.mutex.Unlock()
|
|
|
|
a.conf = conf
|
|
|
|
}
|