chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
90
internal/rpc/groupcall_sweep_dispatcher.go
Normal file
90
internal/rpc/groupcall_sweep_dispatcher.go
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/sfu"
|
||||
)
|
||||
|
||||
// GroupCallSweepDispatcher 清理群通话幽灵参与者(kill 进程/断电后无人发 leave)。
|
||||
//
|
||||
// ⚠ P0-2 活性契约:客户端只在 Connecting 态发 checkGroupCall(媒体连通后心跳停止),
|
||||
// 单凭 last_check_date 判死会把所有连上媒体的健康参与者踢光。约定的判据是
|
||||
// 「max(心跳, 媒体面活性)」:M0(SFU disabled)客户端恒 Connecting、4s 心跳不断,
|
||||
// 纯水位成立;M1 起 SFU 必须对媒体面存活(ICE consent/近期 SRTP 收包)的 endpoint
|
||||
// 周期性刷新 last_check_date(liveness reporter),使单一水位同时承载两路活性。
|
||||
type GroupCallSweepDispatcher struct {
|
||||
router *Router
|
||||
log *zap.Logger
|
||||
interval time.Duration
|
||||
checkTTL time.Duration
|
||||
batch int
|
||||
}
|
||||
|
||||
func NewGroupCallSweepDispatcher(router *Router, log *zap.Logger, interval, checkTTL time.Duration) *GroupCallSweepDispatcher {
|
||||
if log == nil {
|
||||
log = zap.NewNop()
|
||||
}
|
||||
if interval <= 0 {
|
||||
interval = 10 * time.Second
|
||||
}
|
||||
if checkTTL <= 0 {
|
||||
checkTTL = 45 * time.Second
|
||||
}
|
||||
return &GroupCallSweepDispatcher{router: router, log: log, interval: interval, checkTTL: checkTTL, batch: 100}
|
||||
}
|
||||
|
||||
func (d *GroupCallSweepDispatcher) Run(ctx context.Context) {
|
||||
if d == nil || d.router == nil {
|
||||
return
|
||||
}
|
||||
ticker := time.NewTicker(d.interval)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
d.DispatchOnce(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *GroupCallSweepDispatcher) DispatchOnce(ctx context.Context) {
|
||||
if d == nil || d.router == nil || d.router.deps.GroupCalls == nil {
|
||||
return
|
||||
}
|
||||
now := d.router.clock.Now()
|
||||
cutoff := int(now.Add(-d.checkTTL).Unix())
|
||||
muts, err := d.router.deps.GroupCalls.SweepStale(ctx, cutoff, int(now.Unix()), d.batch)
|
||||
if err != nil {
|
||||
d.log.Warn("sweep group call participants", zap.Error(err))
|
||||
return
|
||||
}
|
||||
for _, mut := range muts {
|
||||
if d.router.deps.SFU != nil {
|
||||
_ = d.router.deps.SFU.Leave(ctx, mut.Call.ID, mut.Participant.UserID, sfu.EndpointMain)
|
||||
}
|
||||
channel, err := d.router.channelForGroupCall(ctx, mut.Call)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
d.router.groupCallMutationFanout(ctx, channel, mut)
|
||||
d.log.Info("group call participant swept",
|
||||
zap.Int64("call_id", mut.Call.ID),
|
||||
zap.Int64("user_id", mut.Participant.UserID))
|
||||
}
|
||||
}
|
||||
|
||||
// channelForGroupCall 取通话所属频道行(推送 hydration 用)。
|
||||
func (r *Router) channelForGroupCall(ctx context.Context, call domain.GroupCall) (domain.Channel, error) {
|
||||
view, err := r.deps.Channels.GetChannel(ctx, call.CreatorUserID, call.ChannelID)
|
||||
if err != nil {
|
||||
return domain.Channel{}, err
|
||||
}
|
||||
return view.Channel, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue