Commit 690a5499635a21b2a46e2d15b04d5de1152033d8

Authored by YunaiV
1 parent 27685b99

```

✨ feat(im): RTC 通话逻辑收口(displayName / inviteeIds 校验 / 配置化阈值)

- fix: pushCallInviteNotification 给被邀请人签 token 时 displayName 改用 invitee 自己的昵称(原来错用 inviter)
- feat: 群通话发起 / 追加邀请均强制 inviteeIds 非空,对齐微信交互;超量改抛 RTC_GROUP_INVITEE_OVER_LIMIT,不再静默截断
- refactor: ImGroupMemberService 抽 validateMembersInGroup(groupId, ids) 批量校验,inviteMoreCall / resolveInvitees 复用
- refactor: 僵尸通话清理阈值从 ImRtcCallCleanupJob 静态常量挪到 ImProperties.rtc.cleanupZombieThresholdMinutes
- perf: createCall / inviteMoreCall 推 INVITE 前一次 getUserMap 批量拉用户,省 N 次 RPC
- refactor: inviteMoreCall 参与者构造改 CollectionUtils.convertList;trim 多余注释
- docs: 补齐 RTC service / controller / job / LiveKitClient 私有方法的 @param / @return
- chore: 错误码新增 RTC_GROUP_INVITEE_REQUIRED / RTC_GROUP_INVITEE_OVER_LIMIT
```
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcCallController.java
@@ -109,6 +109,13 @@ public class ImRtcCallController { @@ -109,6 +109,13 @@ public class ImRtcCallController {
109 109
110 // ========== VO 拼装 ========== 110 // ========== VO 拼装 ==========
111 111
  112 + /**
  113 + * 拼装 invite / join / accept / refresh-token 的响应 VO;含 token + 参与者分桶
  114 + *
  115 + * @param call 通话主表
  116 + * @param userId 当前用户编号;token 按该用户签发
  117 + * @return 响应 VO;call 为空返回 null
  118 + */
112 private ImRtcCallRespVO buildCallResp(ImRtcCallDO call, Long userId) { 119 private ImRtcCallRespVO buildCallResp(ImRtcCallDO call, Long userId) {
113 if (call == null) { 120 if (call == null) {
114 return null; 121 return null;
@@ -125,6 +132,12 @@ public class ImRtcCallController { @@ -125,6 +132,12 @@ public class ImRtcCallController {
125 .setJoinedUserIds(filterUserIds(participants, ImRtcParticipantStatusEnum.JOINED)); 132 .setJoinedUserIds(filterUserIds(participants, ImRtcParticipantStatusEnum.JOINED));
126 } 133 }
127 134
  135 + /**
  136 + * 拼装 get-active-call 的响应 VO;只用于群聊胶囊条,不含 token
  137 + *
  138 + * @param call 通话主表
  139 + * @return 响应 VO;call 为空返回 null
  140 + */
128 private ImRtcGroupCallRespVO buildGroupActiveResp(ImRtcCallDO call) { 141 private ImRtcGroupCallRespVO buildGroupActiveResp(ImRtcCallDO call) {
129 if (call == null) { 142 if (call == null) {
130 return null; 143 return null;
@@ -140,6 +153,10 @@ public class ImRtcCallController { @@ -140,6 +153,10 @@ public class ImRtcCallController {
140 153
141 /** 154 /**
142 * 按状态过滤参与者 userId;用 LinkedHashSet 保留前端展示顺序 155 * 按状态过滤参与者 userId;用 LinkedHashSet 保留前端展示顺序
  156 + *
  157 + * @param participants 参与者列表
  158 + * @param status 目标状态
  159 + * @return userId 集合
143 */ 160 */
144 private static Set<Long> filterUserIds(List<ImRtcParticipantDO> participants, 161 private static Set<Long> filterUserIds(List<ImRtcParticipantDO> participants,
145 ImRtcParticipantStatusEnum status) { 162 ImRtcParticipantStatusEnum status) {
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcLiveKitController.java
@@ -39,6 +39,13 @@ public class ImRtcLiveKitController { @@ -39,6 +39,13 @@ public class ImRtcLiveKitController {
39 @Resource 39 @Resource
40 private ImRtcCallService rtcCallService; 40 private ImRtcCallService rtcCallService;
41 41
  42 + /**
  43 + * LiveKit Webhook 回调入口
  44 + *
  45 + * @param request HTTP 请求;用于取 Authorization 头做签名校验
  46 + * @param rawBody 原始 JSON body;签名校验需要原始字节
  47 + * @return 是否处理成功;伪造 / 非法事件返回 false
  48 + */
42 @PostMapping(value = "/webhook", consumes = MediaType.APPLICATION_JSON_VALUE) 49 @PostMapping(value = "/webhook", consumes = MediaType.APPLICATION_JSON_VALUE)
43 @Operation(summary = "LiveKit Webhook 回调;接收成员离开 / 房间结束等事件做业务态兜底清理") 50 @Operation(summary = "LiveKit Webhook 回调;接收成员离开 / 房间结束等事件做业务态兜底清理")
44 @PermitAll 51 @PermitAll
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitClient.java
@@ -54,6 +54,9 @@ public class LiveKitClient { @@ -54,6 +54,9 @@ public class LiveKitClient {
54 54
55 private final ImProperties imProperties; 55 private final ImProperties imProperties;
56 56
  57 + /**
  58 + * @param imProperties IM 全局配置;从中读 livekitUrl / apiKey / apiSecret / tokenTtlHours
  59 + */
57 public LiveKitClient(ImProperties imProperties) { 60 public LiveKitClient(ImProperties imProperties) {
58 this.imProperties = imProperties; 61 this.imProperties = imProperties;
59 } 62 }