From ce689db0078ee6b5c675acbc03244a2c6dc95270 Mon Sep 17 00:00:00 2001 From: hawklin2017 <32898629+hawklin2017@users.noreply.github.com> Date: Tue, 19 May 2026 19:50:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0busy=20line?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/rpc/rtc/signal.go | 103 ++++++++++++++++++++++------- pkg/common/servererrs/code.go | 3 + pkg/common/servererrs/predefine.go | 2 + 3 files changed, 84 insertions(+), 24 deletions(-) diff --git a/internal/rpc/rtc/signal.go b/internal/rpc/rtc/signal.go index 7ffb40507..62bc457f4 100644 --- a/internal/rpc/rtc/signal.go +++ b/internal/rpc/rtc/signal.go @@ -23,6 +23,7 @@ import ( "github.com/google/uuid" "github.com/livekit/protocol/auth" 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/protocol/constant" 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) } - for _, inviteeID := range inv.InviteeUserIDList { - allowed, err := s.isCallAllowed(ctx, req.UserID, inviteeID) - if err != nil { - log.ZError(ctx, "handleInvite: isCallAllowed failed", err, "inviteeID", inviteeID) - return nil, err - } - if !allowed { - return nil, errs.ErrNoPermission.WrapMsg("the invitee does not accept calls from you", "inviteeID", inviteeID) - } + 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 @@ -123,8 +123,8 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq, } inv.BusyLineUserIDList = busyUserIDs - if len(inv.InviteeUserIDList) == len(busyUserIDs) { - return nil, errs.ErrNoPermission.WrapMsg("all invitees are busy", "inviteeUserIDList", inv.InviteeUserIDList) + if len(busyUserIDs) == len(inv.InviteeUserIDList) { + return nil, servererrs.ErrAllUserBusy.WrapMsg("all invitees are busy", "inviteeUserIDList", inv.InviteeUserIDList) } // 从主叫用户资料获取铃声 URL,注入到邀请信息中,被叫方收到后播放主叫方铃声 @@ -134,10 +134,17 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq, // 查询被叫方铃声 URL,供主叫方在等待时播放 var calleeRingtoneURL string - if len(inv.InviteeUserIDList) > 0 { - if inviteeInfo, err := s.userClient.GetUserInfo(ctx, inv.InviteeUserIDList[0]); err == nil { + for _, inviteeID := range inv.InviteeUserIDList { + 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 } + break } 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 { + if _, notAllow := notAllowSet[inviteeID]; notAllow { + log.ZInfo(ctx, "handleInvite: skip not-allowed invitee", "inviteeID", inviteeID) + continue + } if _, busy := busySet[inviteeID]; busy { log.ZInfo(ctx, "handleInvite: skip busy invitee", "inviteeID", inviteeID) continue @@ -187,6 +198,7 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq, RoomID: inv.RoomID, LiveURL: s.config.RpcConfig.LiveKit.ExternalAddress, BusyLineUserIDList: busyUserIDs, + NotAllowUserIDList: notAllowUserIDs, CalleeRingtoneURL: calleeRingtoneURL, }, nil } @@ -205,6 +217,16 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi inv.InviterUserID = req.UserID 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 busyUserIDs, err := s.db.GetBusyUserIDs(ctx, inv.InviteeUserIDList) if err != nil { @@ -216,8 +238,8 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi } inv.BusyLineUserIDList = busyUserIDs - if len(inv.InviteeUserIDList) == len(busyUserIDs) { - return nil, errs.ErrNoPermission.WrapMsg("all invitees are busy", "inviteeUserIDList", inv.InviteeUserIDList) + if len(busyUserIDs) == len(inv.InviteeUserIDList) { + return nil, servererrs.ErrAllUserBusy.WrapMsg("all invitees are busy", "inviteeUserIDList", inv.InviteeUserIDList) } // 从主叫用户资料获取铃声 URL,注入到邀请s信息中,被叫方收到后播放主叫方铃声 @@ -225,12 +247,19 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi inv.CallerRingtoneURL = inviterInfo.CallRingtoneURL } - // 查询第一位被叫的铃声 URL,供主叫方在等待时播放 + // 查询第一位可邀请被叫的铃声 URL,供主叫方在等待时播放 var calleeRingtoneURL string - if len(inv.InviteeUserIDList) > 0 { - if inviteeInfo, err := s.userClient.GetUserInfo(ctx, inv.InviteeUserIDList[0]); err == nil { + for _, inviteeID := range inv.InviteeUserIDList { + 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 } + break } 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 } for _, inviteeID := range inv.InviteeUserIDList { - allowed, err := s.isCallAllowed(ctx, req.UserID, inviteeID) - if err != nil { - log.ZWarn(ctx, "handleInviteInGroup: isCallAllowed failed, skipping invitee", err, "inviteeID", inviteeID) - continue - } - if !allowed { + if _, notAllow := notAllowSet[inviteeID]; notAllow { log.ZInfo(ctx, "handleInviteInGroup: skipping invitee (call setting blocked)", "inviteeID", inviteeID) continue } @@ -283,6 +307,7 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi RoomID: inv.RoomID, LiveURL: s.config.RpcConfig.LiveKit.ExternalAddress, BusyLineUserIDList: busyUserIDs, + NotAllowUserIDList: notAllowUserIDs, CalleeRingtoneURL: calleeRingtoneURL, } @@ -291,6 +316,36 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi 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 发起音视频通话。 // 规则: // - CallAcceptSettingPublic(0) → 所有人均可 diff --git a/pkg/common/servererrs/code.go b/pkg/common/servererrs/code.go index 7c8fcf616..ace05826f 100644 --- a/pkg/common/servererrs/code.go +++ b/pkg/common/servererrs/code.go @@ -95,4 +95,7 @@ const ( // S3 error codes. FileUploadedExpiredError = 1701 // Upload expired + + // RTC error codes. + AllUserBusyError = 1801 // All invitees are busy on another call ) diff --git a/pkg/common/servererrs/predefine.go b/pkg/common/servererrs/predefine.go index 08debfb86..320834af4 100644 --- a/pkg/common/servererrs/predefine.go +++ b/pkg/common/servererrs/predefine.go @@ -68,4 +68,6 @@ var ( ErrIOSBackgroundPushErr = errs.NewCodeError(IOSBackgroundPushErr, "ios background push err") ErrFileUploadedExpired = errs.NewCodeError(FileUploadedExpiredError, "FileUploadedExpiredError") + + ErrAllUserBusy = errs.NewCodeError(AllUserBusyError, "AllUserBusyError") )