增加busy line

This commit is contained in:
hawklin2017 2026-05-19 19:50:06 +08:00
parent 4b579cafc8
commit ce689db007
3 changed files with 84 additions and 24 deletions

View File

@ -23,6 +23,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/livekit/protocol/auth" "github.com/livekit/protocol/auth"
livekit "github.com/livekit/protocol/livekit" livekit "github.com/livekit/protocol/livekit"
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
pbmsg "github.com/openimsdk/protocol/msg" pbmsg "github.com/openimsdk/protocol/msg"
@ -101,15 +102,14 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq,
return nil, errs.ErrArgs.WrapMsg("no invitees", "inviteeUserIDList", inv.InviteeUserIDList) return nil, errs.ErrArgs.WrapMsg("no invitees", "inviteeUserIDList", inv.InviteeUserIDList)
} }
for _, inviteeID := range inv.InviteeUserIDList { notAllowUserIDs, notAllowSet, err := s.filterNotAllowedInvitees(ctx, req.UserID, inv.InviteeUserIDList)
allowed, err := s.isCallAllowed(ctx, req.UserID, inviteeID) if err != nil {
if err != nil { return nil, err
log.ZError(ctx, "handleInvite: isCallAllowed failed", err, "inviteeID", inviteeID) }
return nil, err inv.NotAllowUserIDList = notAllowUserIDs
}
if !allowed { if len(notAllowUserIDs) == len(inv.InviteeUserIDList) {
return nil, errs.ErrNoPermission.WrapMsg("the invitee does not accept calls from you", "inviteeID", inviteeID) return nil, errs.ErrNoPermission.WrapMsg("all invitees do not accept calls from you", "inviteeUserIDList", inv.InviteeUserIDList)
}
} }
// 检测哪些被叫用户正忙(已在通话中),记录到 BusyLineUserIDList // 检测哪些被叫用户正忙(已在通话中),记录到 BusyLineUserIDList
@ -123,8 +123,8 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq,
} }
inv.BusyLineUserIDList = busyUserIDs inv.BusyLineUserIDList = busyUserIDs
if len(inv.InviteeUserIDList) == len(busyUserIDs) { if len(busyUserIDs) == len(inv.InviteeUserIDList) {
return nil, errs.ErrNoPermission.WrapMsg("all invitees are busy", "inviteeUserIDList", inv.InviteeUserIDList) return nil, servererrs.ErrAllUserBusy.WrapMsg("all invitees are busy", "inviteeUserIDList", inv.InviteeUserIDList)
} }
// 从主叫用户资料获取铃声 URL注入到邀请信息中被叫方收到后播放主叫方铃声 // 从主叫用户资料获取铃声 URL注入到邀请信息中被叫方收到后播放主叫方铃声
@ -134,10 +134,17 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq,
// 查询被叫方铃声 URL供主叫方在等待时播放 // 查询被叫方铃声 URL供主叫方在等待时播放
var calleeRingtoneURL string var calleeRingtoneURL string
if len(inv.InviteeUserIDList) > 0 { for _, inviteeID := range inv.InviteeUserIDList {
if inviteeInfo, err := s.userClient.GetUserInfo(ctx, inv.InviteeUserIDList[0]); err == nil { if _, notAllow := notAllowSet[inviteeID]; notAllow {
continue
}
if _, busy := busySet[inviteeID]; busy {
continue
}
if inviteeInfo, err := s.userClient.GetUserInfo(ctx, inviteeID); err == nil {
calleeRingtoneURL = inviteeInfo.CallRingtoneURL calleeRingtoneURL = inviteeInfo.CallRingtoneURL
} }
break
} }
if _, err := s.roomClient.CreateRoom(ctx, &livekit.CreateRoomRequest{Name: inv.RoomID}); err != nil { if _, err := s.roomClient.CreateRoom(ctx, &livekit.CreateRoomRequest{Name: inv.RoomID}); err != nil {
@ -170,6 +177,10 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq,
} }
for _, inviteeID := range inv.InviteeUserIDList { for _, inviteeID := range inv.InviteeUserIDList {
if _, notAllow := notAllowSet[inviteeID]; notAllow {
log.ZInfo(ctx, "handleInvite: skip not-allowed invitee", "inviteeID", inviteeID)
continue
}
if _, busy := busySet[inviteeID]; busy { if _, busy := busySet[inviteeID]; busy {
log.ZInfo(ctx, "handleInvite: skip busy invitee", "inviteeID", inviteeID) log.ZInfo(ctx, "handleInvite: skip busy invitee", "inviteeID", inviteeID)
continue continue
@ -187,6 +198,7 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq,
RoomID: inv.RoomID, RoomID: inv.RoomID,
LiveURL: s.config.RpcConfig.LiveKit.ExternalAddress, LiveURL: s.config.RpcConfig.LiveKit.ExternalAddress,
BusyLineUserIDList: busyUserIDs, BusyLineUserIDList: busyUserIDs,
NotAllowUserIDList: notAllowUserIDs,
CalleeRingtoneURL: calleeRingtoneURL, CalleeRingtoneURL: calleeRingtoneURL,
}, nil }, nil
} }
@ -205,6 +217,16 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi
inv.InviterUserID = req.UserID inv.InviterUserID = req.UserID
inv.InitiateTime = time.Now().UnixMilli() inv.InitiateTime = time.Now().UnixMilli()
notAllowUserIDs, notAllowSet, err := s.filterNotAllowedInvitees(ctx, req.UserID, inv.InviteeUserIDList)
if err != nil {
return nil, err
}
inv.NotAllowUserIDList = notAllowUserIDs
if len(notAllowUserIDs) == len(inv.InviteeUserIDList) {
return nil, errs.ErrNoPermission.WrapMsg("all invitees do not accept calls from you", "inviteeUserIDList", inv.InviteeUserIDList)
}
// 检测哪些被叫用户正忙(已在通话中),记录到 BusyLineUserIDList // 检测哪些被叫用户正忙(已在通话中),记录到 BusyLineUserIDList
busyUserIDs, err := s.db.GetBusyUserIDs(ctx, inv.InviteeUserIDList) busyUserIDs, err := s.db.GetBusyUserIDs(ctx, inv.InviteeUserIDList)
if err != nil { if err != nil {
@ -216,8 +238,8 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi
} }
inv.BusyLineUserIDList = busyUserIDs inv.BusyLineUserIDList = busyUserIDs
if len(inv.InviteeUserIDList) == len(busyUserIDs) { if len(busyUserIDs) == len(inv.InviteeUserIDList) {
return nil, errs.ErrNoPermission.WrapMsg("all invitees are busy", "inviteeUserIDList", inv.InviteeUserIDList) return nil, servererrs.ErrAllUserBusy.WrapMsg("all invitees are busy", "inviteeUserIDList", inv.InviteeUserIDList)
} }
// 从主叫用户资料获取铃声 URL注入到邀请s信息中被叫方收到后播放主叫方铃声 // 从主叫用户资料获取铃声 URL注入到邀请s信息中被叫方收到后播放主叫方铃声
@ -225,12 +247,19 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi
inv.CallerRingtoneURL = inviterInfo.CallRingtoneURL inv.CallerRingtoneURL = inviterInfo.CallRingtoneURL
} }
// 查询第一位被叫的铃声 URL供主叫方在等待时播放 // 查询第一位可邀请被叫的铃声 URL供主叫方在等待时播放
var calleeRingtoneURL string var calleeRingtoneURL string
if len(inv.InviteeUserIDList) > 0 { for _, inviteeID := range inv.InviteeUserIDList {
if inviteeInfo, err := s.userClient.GetUserInfo(ctx, inv.InviteeUserIDList[0]); err == nil { if _, notAllow := notAllowSet[inviteeID]; notAllow {
continue
}
if _, busy := busySet[inviteeID]; busy {
continue
}
if inviteeInfo, err := s.userClient.GetUserInfo(ctx, inviteeID); err == nil {
calleeRingtoneURL = inviteeInfo.CallRingtoneURL calleeRingtoneURL = inviteeInfo.CallRingtoneURL
} }
break
} }
if _, err := s.roomClient.CreateRoom(ctx, &livekit.CreateRoomRequest{Name: inv.RoomID}); err != nil { if _, err := s.roomClient.CreateRoom(ctx, &livekit.CreateRoomRequest{Name: inv.RoomID}); err != nil {
@ -260,12 +289,7 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi
return nil, err return nil, err
} }
for _, inviteeID := range inv.InviteeUserIDList { for _, inviteeID := range inv.InviteeUserIDList {
allowed, err := s.isCallAllowed(ctx, req.UserID, inviteeID) if _, notAllow := notAllowSet[inviteeID]; notAllow {
if err != nil {
log.ZWarn(ctx, "handleInviteInGroup: isCallAllowed failed, skipping invitee", err, "inviteeID", inviteeID)
continue
}
if !allowed {
log.ZInfo(ctx, "handleInviteInGroup: skipping invitee (call setting blocked)", "inviteeID", inviteeID) log.ZInfo(ctx, "handleInviteInGroup: skipping invitee (call setting blocked)", "inviteeID", inviteeID)
continue continue
} }
@ -283,6 +307,7 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi
RoomID: inv.RoomID, RoomID: inv.RoomID,
LiveURL: s.config.RpcConfig.LiveKit.ExternalAddress, LiveURL: s.config.RpcConfig.LiveKit.ExternalAddress,
BusyLineUserIDList: busyUserIDs, BusyLineUserIDList: busyUserIDs,
NotAllowUserIDList: notAllowUserIDs,
CalleeRingtoneURL: calleeRingtoneURL, CalleeRingtoneURL: calleeRingtoneURL,
} }
@ -291,6 +316,36 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi
return resp, nil return resp, nil
} }
func (s *rtcServer) filterNotAllowedInvitees(ctx context.Context, inviterID string, inviteeIDs []string) ([]string, map[string]struct{}, error) {
notAllowUserIDs := make([]string, 0)
notAllowSet := make(map[string]struct{})
for _, inviteeID := range inviteeIDs {
allowed, err := s.isCallAllowed(ctx, inviterID, inviteeID)
if err != nil {
log.ZError(ctx, "filterNotAllowedInvitees: isCallAllowed failed", err, "inviteeID", inviteeID)
return nil, nil, err
}
if !allowed {
notAllowUserIDs = append(notAllowUserIDs, inviteeID)
notAllowSet[inviteeID] = struct{}{}
}
}
return notAllowUserIDs, notAllowSet, nil
}
func hasReachableInvitee(inviteeIDs []string, notAllowSet, busySet map[string]struct{}) bool {
for _, inviteeID := range inviteeIDs {
if _, notAllow := notAllowSet[inviteeID]; notAllow {
continue
}
if _, busy := busySet[inviteeID]; busy {
continue
}
return true
}
return false
}
// isCallAllowed 判断 inviterID 是否被允许向 inviteeID 发起音视频通话。 // isCallAllowed 判断 inviterID 是否被允许向 inviteeID 发起音视频通话。
// 规则: // 规则:
// - CallAcceptSettingPublic(0) → 所有人均可 // - CallAcceptSettingPublic(0) → 所有人均可

View File

@ -95,4 +95,7 @@ const (
// S3 error codes. // S3 error codes.
FileUploadedExpiredError = 1701 // Upload expired FileUploadedExpiredError = 1701 // Upload expired
// RTC error codes.
AllUserBusyError = 1801 // All invitees are busy on another call
) )

View File

@ -68,4 +68,6 @@ var (
ErrIOSBackgroundPushErr = errs.NewCodeError(IOSBackgroundPushErr, "ios background push err") ErrIOSBackgroundPushErr = errs.NewCodeError(IOSBackgroundPushErr, "ios background push err")
ErrFileUploadedExpired = errs.NewCodeError(FileUploadedExpiredError, "FileUploadedExpiredError") ErrFileUploadedExpired = errs.NewCodeError(FileUploadedExpiredError, "FileUploadedExpiredError")
ErrAllUserBusy = errs.NewCodeError(AllUserBusyError, "AllUserBusyError")
) )