[patch] HTTPAPI: 1. 完善relay pull回源相关的功能 2. kick_session支持踢掉pull session

pull/170/head
q191201771 3 years ago
parent 8e01a3d419
commit 56543378d0

@ -22,8 +22,8 @@
"gop_num": 0 "gop_num": 0
}, },
"hls": { "hls": {
"enable": true, "enable": false,
"enable_https": true, "enable_https": false,
"url_pattern": "/hls/", "url_pattern": "/hls/",
"out_path": "./lal_record/hls/", "out_path": "./lal_record/hls/",
"fragment_duration_ms": 3000, "fragment_duration_ms": 3000,
@ -54,7 +54,7 @@
"addr_list":[ "addr_list":[
] ]
}, },
"relay_pull": { "static_relay_pull": {
"enable": false, "enable": false,
"addr": "" "addr": ""
}, },

@ -8,9 +8,9 @@
package base package base
// 文档见: https://pengrl.com/p/20100/ // 文档见: https://pengrl.com/lal/#/HTTPAPI
const HttpApiVersion = "v0.2.0" const HttpApiVersion = "v0.3.0"
const ( const (
ErrorCodeSucc = 0 ErrorCodeSucc = 0
@ -64,7 +64,8 @@ type ApiStatGroup struct {
type ApiCtrlStartRelayPull struct { type ApiCtrlStartRelayPull struct {
HttpResponseBasic HttpResponseBasic
Data struct { Data struct {
SessionId string `json:"session_id"` StreamName string `json:"stream_name"`
SessionId string `json:"session_id"`
} `json:"data"` } `json:"data"`
} }
@ -85,7 +86,7 @@ type ApiCtrlStartRelayPullReq struct {
AutoStopPullAfterNoOutMs int `json:"auto_stop_pull_after_no_out_ms"` AutoStopPullAfterNoOutMs int `json:"auto_stop_pull_after_no_out_ms"`
} }
type ApiCtrlKickOutSession struct { type ApiCtrlKickSession struct {
StreamName string `json:"stream_name"` StreamName string `json:"stream_name"`
SessionId string `json:"session_id"` SessionId string `json:"session_id"`
} }

@ -355,10 +355,6 @@ func getAllHttpApi(addr string) {
var b []byte var b []byte
var err error var err error
b, err = httpGet(fmt.Sprintf("http://%s/api/list", addr))
Log.Assert(nil, err)
Log.Debugf("%s", string(b))
b, err = httpGet(fmt.Sprintf("http://%s/api/stat/lal_info", addr)) b, err = httpGet(fmt.Sprintf("http://%s/api/stat/lal_info", addr))
Log.Assert(nil, err) Log.Assert(nil, err)
Log.Debugf("%s", string(b)) Log.Debugf("%s", string(b))
@ -376,8 +372,8 @@ func getAllHttpApi(addr string) {
Log.Assert(nil, err) Log.Assert(nil, err)
Log.Debugf("%s", string(b)) Log.Debugf("%s", string(b))
var ackos base.ApiCtrlKickOutSession var ackos base.ApiCtrlKickSession
b, err = httpPost(fmt.Sprintf("http://%s/api/ctrl/kick_out_session", addr), &ackos) b, err = httpPost(fmt.Sprintf("http://%s/api/ctrl/kick_session", addr), &ackos)
Log.Assert(nil, err) Log.Assert(nil, err)
Log.Debugf("%s", string(b)) Log.Debugf("%s", string(b))
} }

@ -232,19 +232,27 @@ func (group *Group) GetStat(maxsub int) base.StatGroup {
return group.stat return group.stat
} }
func (group *Group) KickOutSession(sessionId string) bool { func (group *Group) KickSession(sessionId string) bool {
group.mutex.Lock() group.mutex.Lock()
defer group.mutex.Unlock() defer group.mutex.Unlock()
Log.Infof("[%s] kick out session. session id=%s", group.UniqueKey, sessionId) Log.Infof("[%s] kick out session. session id=%s", group.UniqueKey, sessionId)
if strings.HasPrefix(sessionId, base.UkPreRtmpServerSession) { if strings.HasPrefix(sessionId, base.UkPreRtmpServerSession) {
if group.rtmpPubSession != nil { if group.rtmpPubSession != nil && group.rtmpPubSession.UniqueKey() == sessionId {
group.rtmpPubSession.Dispose() group.rtmpPubSession.Dispose()
return true return true
} }
for s := range group.rtmpSubSessionSet {
if s.UniqueKey() == sessionId {
s.Dispose()
return true
}
}
} else if strings.HasPrefix(sessionId, base.UkPreRtmpPullSession) || strings.HasPrefix(sessionId, base.UkPreRtspPullSession) {
return group.kickPull(sessionId)
} else if strings.HasPrefix(sessionId, base.UkPreRtspPubSession) { } else if strings.HasPrefix(sessionId, base.UkPreRtspPubSession) {
if group.rtspPubSession != nil { if group.rtspPubSession != nil && group.rtspPubSession.UniqueKey() == sessionId {
group.rtspPubSession.Dispose() group.rtspPubSession.Dispose()
return true return true
} }
@ -271,16 +279,16 @@ func (group *Group) KickOutSession(sessionId string) bool {
} }
} }
} else { } else {
Log.Errorf("[%s] kick out session while session id format invalid. %s", group.UniqueKey, sessionId) Log.Errorf("[%s] kick session while session id format invalid. %s", group.UniqueKey, sessionId)
} }
return false return false
} }
func (group *Group) IsTotalEmpty() bool { func (group *Group) IsInactive() bool {
group.mutex.Lock() group.mutex.Lock()
defer group.mutex.Unlock() defer group.mutex.Unlock()
return group.isTotalEmpty() return group.isTotalEmpty() && !group.isPullModuleAlive()
} }
func (group *Group) HasInSession() bool { func (group *Group) HasInSession() bool {

@ -12,6 +12,7 @@ import (
"fmt" "fmt"
"github.com/q191201771/lal/pkg/base" "github.com/q191201771/lal/pkg/base"
"github.com/q191201771/lal/pkg/rtsp" "github.com/q191201771/lal/pkg/rtsp"
"github.com/q191201771/naza/pkg/nazalog"
"strings" "strings"
"time" "time"
@ -38,6 +39,9 @@ func (group *Group) StartPull(info base.ApiCtrlStartRelayPullReq) (string, error
// @return 如果PullSession存在返回它的unique key // @return 如果PullSession存在返回它的unique key
// //
func (group *Group) StopPull() string { func (group *Group) StopPull() string {
group.mutex.Lock()
defer group.mutex.Unlock()
group.pullProxy.apiEnable = false group.pullProxy.apiEnable = false
return group.stopPull() return group.stopPull()
} }
@ -60,7 +64,8 @@ type pullProxy struct {
rtspSession *rtsp.PullSession rtspSession *rtsp.PullSession
} }
// 根据配置文件中的静态回源配置来初始化回源设置 // initRelayPullByConfig 根据配置文件中的静态回源配置来初始化回源设置
//
func (group *Group) initRelayPullByConfig() { func (group *Group) initRelayPullByConfig() {
const ( const (
staticRelayPullTimeoutMs = 5000 // staticRelayPullTimeoutMs = 5000 //
@ -73,7 +78,9 @@ func (group *Group) initRelayPullByConfig() {
appName := group.appName appName := group.appName
streamName := group.streamName streamName := group.streamName
group.pullProxy = &pullProxy{} group.pullProxy = &pullProxy{
lastHasOutTs: time.Now().UnixNano() / 1e6,
}
var pullUrl string var pullUrl string
if enable { if enable {
@ -149,6 +156,24 @@ func (group *Group) pullSessionUniqueKey() string {
return "" return ""
} }
func (group *Group) isPullModuleAlive() bool {
return group.hasPullSession() || group.pullProxy.isSessionPulling || !group.shouldAutoStopPull()
}
// kickPull
//
// @return 返回true表示找到对应的session并关闭
//
func (group *Group) kickPull(sessionId string) bool {
if (group.pullProxy.rtmpSession != nil && group.pullProxy.rtmpSession.UniqueKey() == sessionId) ||
(group.pullProxy.rtspSession != nil && group.pullProxy.rtspSession.UniqueKey() == sessionId) {
group.pullProxy.apiEnable = false
group.stopPull()
return true
}
return false
}
// 判断是否需要pull从远端拉流至本地如果需要则触发pull // 判断是否需要pull从远端拉流至本地如果需要则触发pull
// //
// 当前调用时机: // 当前调用时机:
@ -162,7 +187,7 @@ func (group *Group) pullIfNeeded() (string, error) {
} }
// 如果没有从本地拉流的就不需要pull了 // 如果没有从本地拉流的就不需要pull了
if group.ShouldAutoStop() { if group.shouldAutoStopPull() {
return "", nil return "", nil
} }
@ -254,35 +279,35 @@ func (group *Group) pullIfNeeded() (string, error) {
} }
func (group *Group) stopPull() string { func (group *Group) stopPull() string {
Log.Infof("[%s] stop pull since no sub session.", group.UniqueKey)
// 关闭时,清空用于重试的计数 // 关闭时,清空用于重试的计数
group.pullProxy.startCount = 0 group.pullProxy.startCount = 0
if group.pullProxy.rtmpSession != nil { if group.pullProxy.rtmpSession != nil {
Log.Infof("[%s] stop pull session.", group.UniqueKey)
group.pullProxy.rtmpSession.Dispose() group.pullProxy.rtmpSession.Dispose()
return group.pullProxy.rtspSession.UniqueKey() return group.pullProxy.rtmpSession.UniqueKey()
} }
if group.pullProxy.rtspSession != nil { if group.pullProxy.rtspSession != nil {
Log.Infof("[%s] stop pull session.", group.UniqueKey)
group.pullProxy.rtspSession.Dispose() group.pullProxy.rtspSession.Dispose()
return group.pullProxy.rtmpSession.UniqueKey() return group.pullProxy.rtspSession.UniqueKey()
} }
return "" return ""
} }
func (group *Group) tickPullModule() { func (group *Group) tickPullModule() {
if group.hasSubSession() { if group.hasSubSession() {
group.pullProxy.lastHasOutTs = time.Now().Unix() group.pullProxy.lastHasOutTs = time.Now().UnixNano() / 1e6
} }
if group.ShouldAutoStop() { if group.shouldAutoStopPull() {
group.stopPull() group.stopPull()
} else { } else {
group.pullIfNeeded() group.pullIfNeeded()
} }
} }
func (group *Group) ShouldAutoStop() bool { func (group *Group) shouldAutoStopPull() bool {
if group.pullProxy.autoStopPullAfterNoOutMs < 0 { if group.pullProxy.autoStopPullAfterNoOutMs < 0 {
return false return false
} else if group.pullProxy.autoStopPullAfterNoOutMs == 0 { } else if group.pullProxy.autoStopPullAfterNoOutMs == 0 {
@ -291,6 +316,7 @@ func (group *Group) ShouldAutoStop() bool {
if group.hasOutSession() { if group.hasOutSession() {
return false return false
} }
return time.Now().Unix()-group.pullProxy.lastHasOutTs >= int64(group.pullProxy.autoStopPullAfterNoOutMs) nazalog.Debugf("%d %d %d", group.pullProxy.lastHasOutTs, time.Now().UnixNano(), group.pullProxy.autoStopPullAfterNoOutMs)
return group.pullProxy.lastHasOutTs != -1 && time.Now().UnixNano()/1e6-group.pullProxy.lastHasOutTs >= int64(group.pullProxy.autoStopPullAfterNoOutMs)
} }
} }

@ -50,7 +50,7 @@ func (h *HttpApiServer) RunLoop() error {
mux.HandleFunc("/api/stat/all_group", h.statAllGroupHandler) mux.HandleFunc("/api/stat/all_group", h.statAllGroupHandler)
mux.HandleFunc("/api/ctrl/start_relay_pull", h.ctrlStartRelayPullHandler) mux.HandleFunc("/api/ctrl/start_relay_pull", h.ctrlStartRelayPullHandler)
mux.HandleFunc("/api/ctrl/stop_relay_pull", h.ctrlStopRelayPullHandler) mux.HandleFunc("/api/ctrl/stop_relay_pull", h.ctrlStopRelayPullHandler)
mux.HandleFunc("/api/ctrl/kick_out_session", h.ctrlKickOutSessionHandler) mux.HandleFunc("/api/ctrl/kick_session", h.ctrlKickSessionHandler)
var srv http.Server var srv http.Server
srv.Handler = mux srv.Handler = mux
@ -126,7 +126,7 @@ func (h *HttpApiServer) ctrlStartRelayPullHandler(w http.ResponseWriter, req *ht
info.PullRetryNum = -1 info.PullRetryNum = -1
} }
if !j.Exist("auto_stop_pull_after_no_out_ms") { if !j.Exist("auto_stop_pull_after_no_out_ms") {
info.AutoStopPullAfterNoOutMs = 10000 info.AutoStopPullAfterNoOutMs = -1
} }
return nil return nil
} }
@ -141,17 +141,8 @@ func (h *HttpApiServer) ctrlStartRelayPullHandler(w http.ResponseWriter, req *ht
} }
Log.Infof("http api start pull. req info=%+v", info) Log.Infof("http api start pull. req info=%+v", info)
var sessionId string resp := h.sm.CtrlStartRelayPull(info)
sessionId, err = h.sm.CtrlStartRelayPull(info) feedback(resp, w)
if err != nil {
v.ErrorCode = base.ErrorCodeStartRelayPullFail
v.Desp = err.Error()
} else {
v.ErrorCode = base.ErrorCodeSucc
v.Desp = base.DespSucc
v.Data.SessionId = sessionId
}
feedback(v, w)
return return
} }
@ -174,9 +165,9 @@ func (h *HttpApiServer) ctrlStopRelayPullHandler(w http.ResponseWriter, req *htt
return return
} }
func (h *HttpApiServer) ctrlKickOutSessionHandler(w http.ResponseWriter, req *http.Request) { func (h *HttpApiServer) ctrlKickSessionHandler(w http.ResponseWriter, req *http.Request) {
var v base.HttpResponseBasic var v base.HttpResponseBasic
var info base.ApiCtrlKickOutSession var info base.ApiCtrlKickSession
err := nazahttp.UnmarshalRequestJsonBody(req, &info, "stream_name", "session_id") err := nazahttp.UnmarshalRequestJsonBody(req, &info, "stream_name", "session_id")
if err != nil { if err != nil {
@ -188,7 +179,7 @@ func (h *HttpApiServer) ctrlKickOutSessionHandler(w http.ResponseWriter, req *ht
} }
Log.Infof("http api kick out session. req info=%+v", info) Log.Infof("http api kick out session. req info=%+v", info)
resp := h.sm.CtrlKickOutSession(info) resp := h.sm.CtrlKickSession(info)
feedback(resp, w) feedback(resp, w)
return return
} }

@ -39,9 +39,9 @@ type ILalServer interface {
StatLalInfo() base.LalInfo StatLalInfo() base.LalInfo
StatAllGroup() (sgs []base.StatGroup) StatAllGroup() (sgs []base.StatGroup)
StatGroup(streamName string) *base.StatGroup StatGroup(streamName string) *base.StatGroup
CtrlStartRelayPull(info base.ApiCtrlStartRelayPullReq) (string, error) CtrlStartRelayPull(info base.ApiCtrlStartRelayPullReq) base.ApiCtrlStartRelayPull
CtrlStopRelayPull(streamName string) base.ApiCtrlStopRelayPull CtrlStopRelayPull(streamName string) base.ApiCtrlStopRelayPull
CtrlKickOutSession(info base.ApiCtrlKickOutSession) base.HttpResponseBasic CtrlKickSession(info base.ApiCtrlKickSession) base.HttpResponseBasic
} }
// NewLalServer 创建一个lal server // NewLalServer 创建一个lal server

@ -263,8 +263,8 @@ func (sm *ServerManager) RunLoop() error {
// 关闭空闲的group // 关闭空闲的group
sm.groupManager.Iterate(func(group *Group) bool { sm.groupManager.Iterate(func(group *Group) bool {
if group.IsTotalEmpty() { if group.IsInactive() {
Log.Infof("erase empty group. [%s]", group.UniqueKey) Log.Infof("erase inactive group. [%s]", group.UniqueKey)
group.Dispose() group.Dispose()
return false return false
} }
@ -367,7 +367,7 @@ func (sm *ServerManager) StatGroup(streamName string) *base.StatGroup {
return &ret return &ret
} }
func (sm *ServerManager) CtrlStartRelayPull(info base.ApiCtrlStartRelayPullReq) (string, error) { func (sm *ServerManager) CtrlStartRelayPull(info base.ApiCtrlStartRelayPullReq) (ret base.ApiCtrlStartRelayPull) {
sm.mutex.Lock() sm.mutex.Lock()
defer sm.mutex.Unlock() defer sm.mutex.Unlock()
@ -375,7 +375,9 @@ func (sm *ServerManager) CtrlStartRelayPull(info base.ApiCtrlStartRelayPullReq)
if streamName == "" { if streamName == "" {
ctx, err := base.ParseUrl(info.Url, -1) ctx, err := base.ParseUrl(info.Url, -1)
if err != nil { if err != nil {
return "", err ret.ErrorCode = base.ErrorCodeStartRelayPullFail
ret.Desp = err.Error()
return
} }
streamName = ctx.LastItemOfPath streamName = ctx.LastItemOfPath
} }
@ -383,7 +385,17 @@ func (sm *ServerManager) CtrlStartRelayPull(info base.ApiCtrlStartRelayPullReq)
// 注意如果group不存在我们依然relay pull // 注意如果group不存在我们依然relay pull
g := sm.getOrCreateGroup("", streamName) g := sm.getOrCreateGroup("", streamName)
return g.StartPull(info) sessionId, err := g.StartPull(info)
if err != nil {
ret.ErrorCode = base.ErrorCodeStartRelayPullFail
ret.Desp = err.Error()
} else {
ret.ErrorCode = base.ErrorCodeSucc
ret.Desp = base.DespSucc
ret.Data.StreamName = streamName
ret.Data.SessionId = sessionId
}
return
} }
// CtrlStopRelayPull // CtrlStopRelayPull
@ -413,11 +425,11 @@ func (sm *ServerManager) CtrlStopRelayPull(streamName string) (ret base.ApiCtrlS
return return
} }
// CtrlKickOutSession // CtrlKickSession
// //
// TODO(chef): refactor 不要返回http结果返回error吧 // TODO(chef): refactor 不要返回http结果返回error吧
// //
func (sm *ServerManager) CtrlKickOutSession(info base.ApiCtrlKickOutSession) base.HttpResponseBasic { func (sm *ServerManager) CtrlKickSession(info base.ApiCtrlKickSession) base.HttpResponseBasic {
sm.mutex.Lock() sm.mutex.Lock()
defer sm.mutex.Unlock() defer sm.mutex.Unlock()
g := sm.getGroup("", info.StreamName) g := sm.getGroup("", info.StreamName)
@ -427,7 +439,7 @@ func (sm *ServerManager) CtrlKickOutSession(info base.ApiCtrlKickOutSession) bas
Desp: base.DespGroupNotFound, Desp: base.DespGroupNotFound,
} }
} }
if !g.KickOutSession(info.SessionId) { if !g.KickSession(info.SessionId) {
return base.HttpResponseBasic{ return base.HttpResponseBasic{
ErrorCode: base.ErrorCodeSessionNotFound, ErrorCode: base.ErrorCodeSessionNotFound,
Desp: base.DespSessionNotFound, Desp: base.DespSessionNotFound,

Loading…
Cancel
Save