修复:weblive 协程 panic 防护、Mongo 空指针防护、直播状态轮询退避

Made-with: Cursor
This commit is contained in:
whm
2026-03-25 16:45:22 +08:00
parent 70e6782713
commit 7e24a965bc
6 changed files with 70 additions and 12 deletions

View File

@@ -47,6 +47,11 @@ func GetWebHomepage(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if config.MongoClient == nil {
c.JSON(http.StatusOK, defaultHomepageData())
return
}
siteID := getOfficialSiteID(ctx)
if siteID == "" {
c.JSON(http.StatusOK, defaultHomepageData())

View File

@@ -35,6 +35,11 @@ func GetWebRoutes(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if config.MongoClient == nil {
c.JSON(http.StatusOK, gin.H{"site_id": "", "routes": []any{}})
return
}
siteID := c.Query("site_id")
if siteID == "" {
siteID = getOfficialSiteID(ctx)
@@ -84,6 +89,11 @@ func GetWebPageByPath(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if config.MongoClient == nil {
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "服务暂不可用"})
return
}
siteID := c.Query("site_id")
if siteID == "" {
siteID = getOfficialSiteID(ctx)

View File

@@ -154,7 +154,7 @@ func (h *Hub) onPublisherTrack(track *webrtc.TrackRemote) {
h.mu.Lock()
h.forwarders = append(h.forwarders, tf)
h.mu.Unlock()
go tf.runReadLoop()
goSafe("trackRead", tf.runReadLoop)
// 观众仅在「已开播」后拉流:首次协商时 attachForwardersToViewerPC 会带上当前全部轨,无需在此重协商
}
@@ -173,14 +173,14 @@ func (h *Hub) attachForwardersToViewerPC(v *viewerSession) {
continue
}
// Drain RTCP feedback to keep interceptors/senders healthy.
go func() {
goSafe("viewerRTCP", func() {
rtcpBuf := make([]byte, 1500)
for {
if _, _, e := rtpSender.Read(rtcpBuf); e != nil {
return
}
}
}()
})
tf.addViewer(v.id, lt)
}
}

View File

@@ -0,0 +1,15 @@
package weblive
import "log"
// goSafe 在独立 goroutine 中运行 fnpanic 只记录日志,避免拖垮整个 HTTP 进程(否则 Nginx 会看到 502
func goSafe(label string, fn func()) {
go func() {
defer func() {
if r := recover(); r != nil {
log.Printf("weblive: panic in %s: %v", label, r)
}
}()
fn()
}()
}

View File

@@ -120,7 +120,8 @@ func handlePublisherWS(c *gin.Context, h *Hub) {
log.Printf("weblive: publisher track kind=%s", track.Kind().String())
h.onPublisherTrack(track)
if track.Kind() == webrtc.RTPCodecTypeVideo {
go func(ssrc uint32) {
ssrc := uint32(track.SSRC())
goSafe("publisherPLI", func() {
_ = pc.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: ssrc}})
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
@@ -131,7 +132,7 @@ func handlePublisherWS(c *gin.Context, h *Hub) {
}
_ = pc.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: ssrc}})
}
}(uint32(track.SSRC()))
})
}
})