You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
9.4 KiB
Go
303 lines
9.4 KiB
Go
package main
|
|
|
|
import (
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/autotls"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// Message resp struct
|
|
type Message struct {
|
|
Status int `json:"status"`
|
|
Payload interface{} `json:"payload"`
|
|
}
|
|
|
|
// HTTPAPIServer start http server routes
|
|
func HTTPAPIServer() {
|
|
//Set HTTP API mode
|
|
log.WithFields(logrus.Fields{
|
|
"module": "http_server",
|
|
"func": "RTSPServer",
|
|
"call": "Start",
|
|
}).Infoln("Server HTTP start")
|
|
var public *gin.Engine
|
|
if !Storage.ServerHTTPDebug() {
|
|
gin.SetMode(gin.ReleaseMode)
|
|
public = gin.New()
|
|
} else {
|
|
gin.SetMode(gin.DebugMode)
|
|
public = gin.Default()
|
|
}
|
|
|
|
public.Use(CrossOrigin())
|
|
//Add private login password protect methods
|
|
privat := public.Group("/")
|
|
if Storage.ServerHTTPLogin() != "" && Storage.ServerHTTPPassword() != "" {
|
|
privat.Use(gin.BasicAuth(gin.Accounts{Storage.ServerHTTPLogin(): Storage.ServerHTTPPassword()}))
|
|
}
|
|
|
|
/*
|
|
Static HTML Files Demo Mode
|
|
*/
|
|
|
|
if Storage.ServerHTTPDemo() {
|
|
public.LoadHTMLGlob(Storage.ServerHTTPDir() + "/templates/*")
|
|
public.GET("/", HTTPAPIServerIndex)
|
|
public.GET("/pages/stream/list", HTTPAPIStreamList)
|
|
public.GET("/pages/stream/add", HTTPAPIAddStream)
|
|
public.GET("/pages/stream/edit/:uuid", HTTPAPIEditStream)
|
|
public.GET("/pages/player/hls/:uuid/:channel", HTTPAPIPlayHls)
|
|
public.GET("/pages/player/mse/:uuid/:channel", HTTPAPIPlayMse)
|
|
public.GET("/pages/player/webrtc/:uuid/:channel", HTTPAPIPlayWebrtc)
|
|
public.GET("/pages/multiview", HTTPAPIMultiview)
|
|
public.Any("/pages/multiview/full", HTTPAPIFullScreenMultiView)
|
|
public.GET("/pages/documentation", HTTPAPIServerDocumentation)
|
|
public.GET("/pages/player/all/:uuid/:channel", HTTPAPIPlayAll)
|
|
public.StaticFS("/static", http.Dir(Storage.ServerHTTPDir()+"/static"))
|
|
}
|
|
|
|
/*
|
|
Stream Control elements
|
|
*/
|
|
|
|
privat.GET("/streams", HTTPAPIServerStreams)
|
|
privat.POST("/stream/:uuid/add", HTTPAPIServerStreamAdd)
|
|
privat.POST("/stream/:uuid/edit", HTTPAPIServerStreamEdit)
|
|
privat.GET("/stream/:uuid/delete", HTTPAPIServerStreamDelete)
|
|
privat.GET("/stream/:uuid/reload", HTTPAPIServerStreamReload)
|
|
privat.GET("/stream/:uuid/info", HTTPAPIServerStreamInfo)
|
|
|
|
/*
|
|
Streams Multi Control elements
|
|
*/
|
|
|
|
privat.POST("/streams/multi/control/add", HTTPAPIServerStreamsMultiControlAdd)
|
|
privat.POST("/streams/multi/control/delete", HTTPAPIServerStreamsMultiControlDelete)
|
|
|
|
/*
|
|
Stream Channel elements
|
|
*/
|
|
|
|
privat.POST("/stream/:uuid/channel/:channel/add", HTTPAPIServerStreamChannelAdd)
|
|
privat.POST("/stream/:uuid/channel/:channel/edit", HTTPAPIServerStreamChannelEdit)
|
|
privat.GET("/stream/:uuid/channel/:channel/delete", HTTPAPIServerStreamChannelDelete)
|
|
privat.GET("/stream/:uuid/channel/:channel/codec", HTTPAPIServerStreamChannelCodec)
|
|
privat.GET("/stream/:uuid/channel/:channel/reload", HTTPAPIServerStreamChannelReload)
|
|
privat.GET("/stream/:uuid/channel/:channel/info", HTTPAPIServerStreamChannelInfo)
|
|
|
|
/*
|
|
Stream video elements
|
|
*/
|
|
//HLS
|
|
public.GET("/stream/:uuid/channel/:channel/hls/live/index.m3u8", HTTPAPIServerStreamHLSM3U8)
|
|
public.GET("/stream/:uuid/channel/:channel/hls/live/segment/:seq/file.ts", HTTPAPIServerStreamHLSTS)
|
|
//HLS remote record
|
|
//public.GET("/stream/:uuid/channel/:channel/hls/rr/:s/:e/index.m3u8", HTTPAPIServerStreamRRM3U8)
|
|
//public.GET("/stream/:uuid/channel/:channel/hls/rr/:s/:e/:seq/file.ts", HTTPAPIServerStreamRRTS)
|
|
//HLS LL
|
|
public.GET("/stream/:uuid/channel/:channel/hlsll/live/index.m3u8", HTTPAPIServerStreamHLSLLM3U8)
|
|
public.GET("/stream/:uuid/channel/:channel/hlsll/live/init.mp4", HTTPAPIServerStreamHLSLLInit)
|
|
public.GET("/stream/:uuid/channel/:channel/hlsll/live/segment/:segment/:any", HTTPAPIServerStreamHLSLLM4Segment)
|
|
public.GET("/stream/:uuid/channel/:channel/hlsll/live/fragment/:segment/:fragment/:any", HTTPAPIServerStreamHLSLLM4Fragment)
|
|
//MSE
|
|
public.GET("/stream/:uuid/channel/:channel/mse", HTTPAPIServerStreamMSE)
|
|
public.POST("/stream/:uuid/channel/:channel/webrtc", HTTPAPIServerStreamWebRTC)
|
|
//Save fragment to mp4
|
|
public.GET("/stream/:uuid/channel/:channel/save/mp4/fragment/:duration", HTTPAPIServerStreamSaveToMP4)
|
|
/*
|
|
HTTPS Mode Cert
|
|
# Key considerations for algorithm "RSA" ≥ 2048-bit
|
|
openssl genrsa -out server.key 2048
|
|
|
|
# Key considerations for algorithm "ECDSA" ≥ secp384r1
|
|
# List ECDSA the supported curves (openssl ecparam -list_curves)
|
|
#openssl ecparam -genkey -name secp384r1 -out server.key
|
|
#Generation of self-signed(x509) public key (PEM-encodings .pem|.crt) based on the private (.key)
|
|
|
|
openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650
|
|
*/
|
|
if Storage.ServerHTTPS() {
|
|
if Storage.ServerHTTPSAutoTLSEnable() {
|
|
go func() {
|
|
err := autotls.Run(public, Storage.ServerHTTPSAutoTLSName()+Storage.ServerHTTPSPort())
|
|
if err != nil {
|
|
log.Println("Start HTTPS Server Error", err)
|
|
}
|
|
}()
|
|
} else {
|
|
go func() {
|
|
err := public.RunTLS(Storage.ServerHTTPSPort(), Storage.ServerHTTPSCert(), Storage.ServerHTTPSKey())
|
|
if err != nil {
|
|
log.WithFields(logrus.Fields{
|
|
"module": "http_router",
|
|
"func": "HTTPSAPIServer",
|
|
"call": "ServerHTTPSPort",
|
|
}).Fatalln(err.Error())
|
|
os.Exit(1)
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
err := public.Run(Storage.ServerHTTPPort())
|
|
if err != nil {
|
|
log.WithFields(logrus.Fields{
|
|
"module": "http_router",
|
|
"func": "HTTPAPIServer",
|
|
"call": "ServerHTTPPort",
|
|
}).Fatalln(err.Error())
|
|
os.Exit(1)
|
|
}
|
|
|
|
}
|
|
|
|
// HTTPAPIServerIndex index file
|
|
func HTTPAPIServerIndex(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "index.tmpl", gin.H{
|
|
"port": Storage.ServerHTTPPort(),
|
|
"streams": Storage.Streams,
|
|
"version": time.Now().String(),
|
|
"page": "index",
|
|
})
|
|
|
|
}
|
|
|
|
func HTTPAPIServerDocumentation(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "documentation.tmpl", gin.H{
|
|
"port": Storage.ServerHTTPPort(),
|
|
"streams": Storage.Streams,
|
|
"version": time.Now().String(),
|
|
"page": "documentation",
|
|
})
|
|
}
|
|
|
|
func HTTPAPIStreamList(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "stream_list.tmpl", gin.H{
|
|
"port": Storage.ServerHTTPPort(),
|
|
"streams": Storage.Streams,
|
|
"version": time.Now().String(),
|
|
"page": "stream_list",
|
|
})
|
|
}
|
|
|
|
func HTTPAPIPlayHls(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "play_hls.tmpl", gin.H{
|
|
"port": Storage.ServerHTTPPort(),
|
|
"streams": Storage.Streams,
|
|
"version": time.Now().String(),
|
|
"page": "play_hls",
|
|
"uuid": c.Param("uuid"),
|
|
"channel": c.Param("channel"),
|
|
})
|
|
}
|
|
func HTTPAPIPlayMse(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "play_mse.tmpl", gin.H{
|
|
"port": Storage.ServerHTTPPort(),
|
|
"streams": Storage.Streams,
|
|
"version": time.Now().String(),
|
|
"page": "play_mse",
|
|
"uuid": c.Param("uuid"),
|
|
"channel": c.Param("channel"),
|
|
})
|
|
}
|
|
func HTTPAPIPlayWebrtc(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "play_webrtc.tmpl", gin.H{
|
|
"port": Storage.ServerHTTPPort(),
|
|
"streams": Storage.Streams,
|
|
"version": time.Now().String(),
|
|
"page": "play_webrtc",
|
|
"uuid": c.Param("uuid"),
|
|
"channel": c.Param("channel"),
|
|
})
|
|
}
|
|
func HTTPAPIAddStream(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "add_stream.tmpl", gin.H{
|
|
"port": Storage.ServerHTTPPort(),
|
|
"streams": Storage.Streams,
|
|
"version": time.Now().String(),
|
|
"page": "add_stream",
|
|
})
|
|
}
|
|
func HTTPAPIEditStream(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "edit_stream.tmpl", gin.H{
|
|
"port": Storage.ServerHTTPPort(),
|
|
"streams": Storage.Streams,
|
|
"version": time.Now().String(),
|
|
"page": "edit_stream",
|
|
"uuid": c.Param("uuid"),
|
|
})
|
|
}
|
|
|
|
func HTTPAPIMultiview(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "multiview.tmpl", gin.H{
|
|
"port": Storage.ServerHTTPPort(),
|
|
"streams": Storage.Streams,
|
|
"version": time.Now().String(),
|
|
"page": "multiview",
|
|
})
|
|
}
|
|
|
|
func HTTPAPIPlayAll(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "play_all.tmpl", gin.H{
|
|
"port": Storage.ServerHTTPPort(),
|
|
"streams": Storage.Streams,
|
|
"version": time.Now().String(),
|
|
"page": "play_all",
|
|
"uuid": c.Param("uuid"),
|
|
"channel": c.Param("channel"),
|
|
})
|
|
}
|
|
|
|
type MultiViewOptions struct {
|
|
Grid int `json:"grid"`
|
|
Player map[string]MultiViewOptionsGrid `json:"player"`
|
|
}
|
|
type MultiViewOptionsGrid struct {
|
|
UUID string `json:"uuid"`
|
|
Channel int `json:"channel"`
|
|
PlayerType string `json:"playerType"`
|
|
}
|
|
|
|
func HTTPAPIFullScreenMultiView(c *gin.Context) {
|
|
var createParams MultiViewOptions
|
|
err := c.ShouldBindJSON(&createParams)
|
|
if err != nil {
|
|
log.WithFields(logrus.Fields{
|
|
"module": "http_page",
|
|
"func": "HTTPAPIFullScreenMultiView",
|
|
"call": "BindJSON",
|
|
}).Errorln(err.Error())
|
|
}
|
|
log.WithFields(logrus.Fields{
|
|
"module": "http_page",
|
|
"func": "HTTPAPIFullScreenMultiView",
|
|
"call": "Options",
|
|
}).Debugln(createParams)
|
|
c.HTML(http.StatusOK, "fullscreenmulti.tmpl", gin.H{
|
|
"port": Storage.ServerHTTPPort(),
|
|
"streams": Storage.Streams,
|
|
"version": time.Now().String(),
|
|
"options": createParams,
|
|
"page": "fullscreenmulti",
|
|
"query": c.Request.URL.Query(),
|
|
})
|
|
}
|
|
|
|
// CrossOrigin Access-Control-Allow-Origin any methods
|
|
func CrossOrigin() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
|
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
|
|
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
|
|
if c.Request.Method == "OPTIONS" {
|
|
c.AbortWithStatus(204)
|
|
return
|
|
}
|
|
c.Next()
|
|
}
|
|
}
|