Commit 3e38e77ee6f68da490e27f86111ecbbc865bc809
1 parent
3dd71793
refactor: 扁平化 IM WebSocket 通知推送 API
- 将 WebSocket 推送入口统一为 userId/userIds + conversationType + contentType + payload - 移除业务侧 ImNotificationWebSocketDTO 构造和无会话专用发送入口 - 收敛私聊、群聊、频道、好友、加群申请、RTC 通知调用路径 - 精简 ImNotificationWebSocketDTO,仅保留统一外壳字段 - 保留群消息 payload 的 receiptStatus、readCount、receiverUserIds - 更新相关单元测试,覆盖群消息通知 payload 字段
Showing
18 changed files
with
221 additions
and
185 deletions
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/mq/consumer/friend/AdminUserProfileUpdateConsumer.java
| @@ -2,11 +2,11 @@ package cn.iocoder.yudao.module.im.mq.consumer.friend; | @@ -2,11 +2,11 @@ package cn.iocoder.yudao.module.im.mq.consumer.friend; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO; | 4 | import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO; |
| 5 | -import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; | 5 | +import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum; |
| 6 | +import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum; | ||
| 6 | import cn.iocoder.yudao.module.im.service.friend.ImFriendService; | 7 | import cn.iocoder.yudao.module.im.service.friend.ImFriendService; |
| 7 | import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService; | 8 | import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService; |
| 8 | -import cn.iocoder.yudao.module.im.service.websocket.dto.ImPrivateMessageDTO; | ||
| 9 | -import cn.iocoder.yudao.module.im.service.websocket.dto.notification.friend.FriendInfoUpdatedNotification; | 9 | +import cn.iocoder.yudao.module.im.service.websocket.notification.friend.FriendInfoUpdatedNotification; |
| 10 | import cn.iocoder.yudao.module.system.api.message.user.AdminUserProfileUpdateMessage; | 10 | import cn.iocoder.yudao.module.system.api.message.user.AdminUserProfileUpdateMessage; |
| 11 | import jakarta.annotation.Resource; | 11 | import jakarta.annotation.Resource; |
| 12 | import lombok.extern.slf4j.Slf4j; | 12 | import lombok.extern.slf4j.Slf4j; |
| @@ -52,8 +52,9 @@ public class AdminUserProfileUpdateConsumer { | @@ -52,8 +52,9 @@ public class AdminUserProfileUpdateConsumer { | ||
| 52 | try { | 52 | try { |
| 53 | FriendInfoUpdatedNotification payload = (FriendInfoUpdatedNotification) new FriendInfoUpdatedNotification() | 53 | FriendInfoUpdatedNotification payload = (FriendInfoUpdatedNotification) new FriendInfoUpdatedNotification() |
| 54 | .setOperatorUserId(userId).setFriendUserId(userId); | 54 | .setOperatorUserId(userId).setFriendUserId(userId); |
| 55 | - websocketService.sendPrivateMessageAsync(friend.getFriendUserId(), ImPrivateMessageDTO.ofFriendNotification( | ||
| 56 | - ImMessageTypeEnum.FRIEND_INFO_UPDATED.getType(), userId, friend.getFriendUserId(), payload)); | 55 | + websocketService.sendNotificationAsync(friend.getFriendUserId(), |
| 56 | + ImConversationTypeEnum.NONE.getType(), | ||
| 57 | + ImContentTypeEnum.FRIEND_INFO_UPDATED.getType(), payload); | ||
| 57 | successCount++; | 58 | successCount++; |
| 58 | } catch (Exception e) { | 59 | } catch (Exception e) { |
| 59 | log.warn("[onMessage][userId({}) friendUserId({}) 推送失败]", | 60 | log.warn("[onMessage][userId({}) friendUserId({}) 推送失败]", |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestServiceImpl.java
| @@ -14,7 +14,8 @@ import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO; | @@ -14,7 +14,8 @@ import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO; | ||
| 14 | import cn.iocoder.yudao.module.im.dal.mysql.friend.ImFriendRequestMapper; | 14 | import cn.iocoder.yudao.module.im.dal.mysql.friend.ImFriendRequestMapper; |
| 15 | import cn.iocoder.yudao.module.im.enums.friend.ImFriendRequestHandleResultEnum; | 15 | import cn.iocoder.yudao.module.im.enums.friend.ImFriendRequestHandleResultEnum; |
| 16 | import cn.iocoder.yudao.module.im.enums.friend.ImFriendStateEnum; | 16 | import cn.iocoder.yudao.module.im.enums.friend.ImFriendStateEnum; |
| 17 | -import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; | 17 | +import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum; |
| 18 | +import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum; | ||
| 18 | import cn.iocoder.yudao.module.im.framework.config.ImProperties; | 19 | import cn.iocoder.yudao.module.im.framework.config.ImProperties; |
| 19 | import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService; | 20 | import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService; |
| 20 | import cn.iocoder.yudao.module.im.service.websocket.notification.friend.FriendRequestApprovedNotification; | 21 | import cn.iocoder.yudao.module.im.service.websocket.notification.friend.FriendRequestApprovedNotification; |
| @@ -104,8 +105,8 @@ public class ImFriendRequestServiceImpl implements ImFriendRequestService { | @@ -104,8 +105,8 @@ public class ImFriendRequestServiceImpl implements ImFriendRequestService { | ||
| 104 | if (fromUser != null) { | 105 | if (fromUser != null) { |
| 105 | payload.setFromNickname(fromUser.getNickname()).setFromAvatar(fromUser.getAvatar()); | 106 | payload.setFromNickname(fromUser.getNickname()).setFromAvatar(fromUser.getAvatar()); |
| 106 | } | 107 | } |
| 107 | - websocketService.sendPrivateMessageAsync(toUserId, ImPrivateMessageDTO.ofFriendNotification( | ||
| 108 | - ImMessageTypeEnum.FRIEND_REQUEST_RECEIVED.getType(), fromUserId, toUserId, payload)); | 108 | + websocketService.sendNotificationAsync(toUserId, ImConversationTypeEnum.NONE.getType(), |
| 109 | + ImContentTypeEnum.FRIEND_REQUEST_RECEIVED.getType(), payload); | ||
| 109 | 110 | ||
| 110 | // 4. 全局自动通过开关:注册 afterCommit 回调,事务提交后再走同意流程 | 111 | // 4. 全局自动通过开关:注册 afterCommit 回调,事务提交后再走同意流程 |
| 111 | // 回调内 try/catch 兜底 —— afterCommit 异常会被 Spring 静默吞掉,否则同意失败时申请方永远等不到 APPROVED | 112 | // 回调内 try/catch 兜底 —— afterCommit 异常会被 Spring 静默吞掉,否则同意失败时申请方永远等不到 APPROVED |
| @@ -191,8 +192,8 @@ public class ImFriendRequestServiceImpl implements ImFriendRequestService { | @@ -191,8 +192,8 @@ public class ImFriendRequestServiceImpl implements ImFriendRequestService { | ||
| 191 | FriendRequestApprovedNotification payload = (FriendRequestApprovedNotification) | 192 | FriendRequestApprovedNotification payload = (FriendRequestApprovedNotification) |
| 192 | new FriendRequestApprovedNotification().setRequestId(request.getId()) | 193 | new FriendRequestApprovedNotification().setRequestId(request.getId()) |
| 193 | .setOperatorUserId(userId).setFriendUserId(userId); | 194 | .setOperatorUserId(userId).setFriendUserId(userId); |
| 194 | - websocketService.sendPrivateMessageAsync(request.getFromUserId(), ImPrivateMessageDTO.ofFriendNotification( | ||
| 195 | - ImMessageTypeEnum.FRIEND_REQUEST_APPROVED.getType(), userId, request.getFromUserId(), payload)); | 195 | + websocketService.sendNotificationAsync(request.getFromUserId(), ImConversationTypeEnum.NONE.getType(), |
| 196 | + ImContentTypeEnum.FRIEND_REQUEST_APPROVED.getType(), payload); | ||
| 196 | } | 197 | } |
| 197 | 198 | ||
| 198 | @Override | 199 | @Override |
| @@ -216,8 +217,8 @@ public class ImFriendRequestServiceImpl implements ImFriendRequestService { | @@ -216,8 +217,8 @@ public class ImFriendRequestServiceImpl implements ImFriendRequestService { | ||
| 216 | new FriendRequestRejectedNotification().setRequestId(request.getId()) | 217 | new FriendRequestRejectedNotification().setRequestId(request.getId()) |
| 217 | .setHandleContent(handleContent) | 218 | .setHandleContent(handleContent) |
| 218 | .setOperatorUserId(userId).setFriendUserId(userId); | 219 | .setOperatorUserId(userId).setFriendUserId(userId); |
| 219 | - websocketService.sendPrivateMessageAsync(request.getFromUserId(), ImPrivateMessageDTO.ofFriendNotification( | ||
| 220 | - ImMessageTypeEnum.FRIEND_REQUEST_REJECTED.getType(), userId, request.getFromUserId(), payload)); | 220 | + websocketService.sendNotificationAsync(request.getFromUserId(), ImConversationTypeEnum.NONE.getType(), |
| 221 | + ImContentTypeEnum.FRIEND_REQUEST_REJECTED.getType(), payload); | ||
| 221 | } | 222 | } |
| 222 | 223 | ||
| 223 | @Override | 224 | @Override |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java
| @@ -11,12 +11,12 @@ import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO; | @@ -11,12 +11,12 @@ import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO; | ||
| 11 | import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO; | 11 | import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO; |
| 12 | import cn.iocoder.yudao.module.im.dal.mysql.friend.ImFriendMapper; | 12 | import cn.iocoder.yudao.module.im.dal.mysql.friend.ImFriendMapper; |
| 13 | import cn.iocoder.yudao.module.im.enums.friend.ImFriendStateEnum; | 13 | import cn.iocoder.yudao.module.im.enums.friend.ImFriendStateEnum; |
| 14 | -import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; | 14 | +import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum; |
| 15 | +import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum; | ||
| 15 | import cn.iocoder.yudao.module.im.service.message.ImPrivateMessageService; | 16 | import cn.iocoder.yudao.module.im.service.message.ImPrivateMessageService; |
| 16 | import cn.iocoder.yudao.module.im.service.message.dto.ImPrivateMessageSendDTO; | 17 | import cn.iocoder.yudao.module.im.service.message.dto.ImPrivateMessageSendDTO; |
| 17 | import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService; | 18 | import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService; |
| 18 | -import cn.iocoder.yudao.module.im.service.websocket.dto.ImPrivateMessageDTO; | ||
| 19 | -import cn.iocoder.yudao.module.im.service.websocket.dto.notification.friend.*; | 19 | +import cn.iocoder.yudao.module.im.service.websocket.notification.friend.*; |
| 20 | import jakarta.annotation.Resource; | 20 | import jakarta.annotation.Resource; |
| 21 | import lombok.extern.slf4j.Slf4j; | 21 | import lombok.extern.slf4j.Slf4j; |
| 22 | import org.springframework.cache.annotation.CacheEvict; | 22 | import org.springframework.cache.annotation.CacheEvict; |
| @@ -160,8 +160,8 @@ public class ImFriendServiceImpl implements ImFriendService { | @@ -160,8 +160,8 @@ public class ImFriendServiceImpl implements ImFriendService { | ||
| 160 | FriendUpdateNotification payload = (FriendUpdateNotification) new FriendUpdateNotification() | 160 | FriendUpdateNotification payload = (FriendUpdateNotification) new FriendUpdateNotification() |
| 161 | .setDisplayName(reqVO.getDisplayName()).setSilent(reqVO.getSilent()).setPinned(reqVO.getPinned()) | 161 | .setDisplayName(reqVO.getDisplayName()).setSilent(reqVO.getSilent()).setPinned(reqVO.getPinned()) |
| 162 | .setOperatorUserId(userId).setFriendUserId(reqVO.getFriendUserId()); | 162 | .setOperatorUserId(userId).setFriendUserId(reqVO.getFriendUserId()); |
| 163 | - websocketService.sendPrivateMessageAsync(userId, ImPrivateMessageDTO.ofFriendNotification( | ||
| 164 | - ImMessageTypeEnum.FRIEND_UPDATE.getType(), userId, userId, payload)); | 163 | + websocketService.sendNotificationAsync(userId, ImConversationTypeEnum.NONE.getType(), |
| 164 | + ImContentTypeEnum.FRIEND_UPDATE.getType(), payload); | ||
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | @Override | 167 | @Override |
| @@ -183,7 +183,7 @@ public class ImFriendServiceImpl implements ImFriendService { | @@ -183,7 +183,7 @@ public class ImFriendServiceImpl implements ImFriendService { | ||
| 183 | FriendAddNotification payload = (FriendAddNotification) new FriendAddNotification() | 183 | FriendAddNotification payload = (FriendAddNotification) new FriendAddNotification() |
| 184 | .setOperatorUserId(fromUserId).setFriendUserId(toUserId); | 184 | .setOperatorUserId(fromUserId).setFriendUserId(toUserId); |
| 185 | privateMessageService.sendPrivateMessage(fromUserId, new ImPrivateMessageSendDTO() | 185 | privateMessageService.sendPrivateMessage(fromUserId, new ImPrivateMessageSendDTO() |
| 186 | - .setReceiverId(toUserId).setType(ImMessageTypeEnum.FRIEND_ADD.getType()).setContent(payload)); | 186 | + .setReceiverId(toUserId).setType(ImContentTypeEnum.FRIEND_ADD.getType()).setContent(payload)); |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | @Override | 189 | @Override |
| @@ -202,7 +202,7 @@ public class ImFriendServiceImpl implements ImFriendService { | @@ -202,7 +202,7 @@ public class ImFriendServiceImpl implements ImFriendService { | ||
| 202 | FriendAddNotification payload = (FriendAddNotification) new FriendAddNotification() | 202 | FriendAddNotification payload = (FriendAddNotification) new FriendAddNotification() |
| 203 | .setOperatorUserId(friendUserId).setFriendUserId(friendUserId); | 203 | .setOperatorUserId(friendUserId).setFriendUserId(friendUserId); |
| 204 | privateMessageService.sendPrivateMessage(userId, new ImPrivateMessageSendDTO() | 204 | privateMessageService.sendPrivateMessage(userId, new ImPrivateMessageSendDTO() |
| 205 | - .setReceiverId(friendUserId).setType(ImMessageTypeEnum.FRIEND_ADD.getType()) | 205 | + .setReceiverId(friendUserId).setType(ImContentTypeEnum.FRIEND_ADD.getType()) |
| 206 | .setContent(payload).setPersistent(false)); | 206 | .setContent(payload).setPersistent(false)); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| @@ -224,7 +224,7 @@ public class ImFriendServiceImpl implements ImFriendService { | @@ -224,7 +224,7 @@ public class ImFriendServiceImpl implements ImFriendService { | ||
| 224 | FriendDeleteNotification payload = ((FriendDeleteNotification) new FriendDeleteNotification() | 224 | FriendDeleteNotification payload = ((FriendDeleteNotification) new FriendDeleteNotification() |
| 225 | .setOperatorUserId(userId).setFriendUserId(friendUserId)).setClear(clear); | 225 | .setOperatorUserId(userId).setFriendUserId(friendUserId)).setClear(clear); |
| 226 | privateMessageService.sendPrivateMessage(userId, new ImPrivateMessageSendDTO() | 226 | privateMessageService.sendPrivateMessage(userId, new ImPrivateMessageSendDTO() |
| 227 | - .setReceiverId(friendUserId).setType(ImMessageTypeEnum.FRIEND_DELETE.getType()) | 227 | + .setReceiverId(friendUserId).setType(ImContentTypeEnum.FRIEND_DELETE.getType()) |
| 228 | .setContent(payload).setPersistent(false)); | 228 | .setContent(payload).setPersistent(false)); |
| 229 | } | 229 | } |
| 230 | 230 | ||
| @@ -250,8 +250,8 @@ public class ImFriendServiceImpl implements ImFriendService { | @@ -250,8 +250,8 @@ public class ImFriendServiceImpl implements ImFriendService { | ||
| 250 | // 3. 推 FRIEND_BLOCK 给 A 多端 | 250 | // 3. 推 FRIEND_BLOCK 给 A 多端 |
| 251 | FriendBlockNotification payload = (FriendBlockNotification) new FriendBlockNotification() | 251 | FriendBlockNotification payload = (FriendBlockNotification) new FriendBlockNotification() |
| 252 | .setOperatorUserId(userId).setFriendUserId(friendUserId); | 252 | .setOperatorUserId(userId).setFriendUserId(friendUserId); |
| 253 | - websocketService.sendPrivateMessageAsync(userId, ImPrivateMessageDTO.ofFriendNotification( | ||
| 254 | - ImMessageTypeEnum.FRIEND_BLOCK.getType(), userId, userId, payload)); | 253 | + websocketService.sendNotificationAsync(userId, ImConversationTypeEnum.NONE.getType(), |
| 254 | + ImContentTypeEnum.FRIEND_BLOCK.getType(), payload); | ||
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | @Override | 257 | @Override |
| @@ -276,8 +276,8 @@ public class ImFriendServiceImpl implements ImFriendService { | @@ -276,8 +276,8 @@ public class ImFriendServiceImpl implements ImFriendService { | ||
| 276 | // 3. 推 FRIEND_UNBLOCK 给 A 多端 | 276 | // 3. 推 FRIEND_UNBLOCK 给 A 多端 |
| 277 | FriendUnblockNotification payload = (FriendUnblockNotification) new FriendUnblockNotification() | 277 | FriendUnblockNotification payload = (FriendUnblockNotification) new FriendUnblockNotification() |
| 278 | .setOperatorUserId(userId).setFriendUserId(friendUserId); | 278 | .setOperatorUserId(userId).setFriendUserId(friendUserId); |
| 279 | - websocketService.sendPrivateMessageAsync(userId, ImPrivateMessageDTO.ofFriendNotification( | ||
| 280 | - ImMessageTypeEnum.FRIEND_UNBLOCK.getType(), userId, userId, payload)); | 279 | + websocketService.sendNotificationAsync(userId, ImConversationTypeEnum.NONE.getType(), |
| 280 | + ImContentTypeEnum.FRIEND_UNBLOCK.getType(), payload); | ||
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | /** | 283 | /** |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestServiceImpl.java
| @@ -13,7 +13,8 @@ import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupRequestMapper; | @@ -13,7 +13,8 @@ import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupRequestMapper; | ||
| 13 | import cn.iocoder.yudao.module.im.enums.group.ImGroupAddSourceEnum; | 13 | import cn.iocoder.yudao.module.im.enums.group.ImGroupAddSourceEnum; |
| 14 | import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum; | 14 | import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum; |
| 15 | import cn.iocoder.yudao.module.im.enums.group.ImGroupRequestHandleResultEnum; | 15 | import cn.iocoder.yudao.module.im.enums.group.ImGroupRequestHandleResultEnum; |
| 16 | -import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; | 16 | +import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum; |
| 17 | +import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum; | ||
| 17 | import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService; | 18 | import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService; |
| 18 | import cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO; | 19 | import cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO; |
| 19 | import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService; | 20 | import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService; |
| @@ -100,8 +101,8 @@ public class ImGroupRequestServiceImpl implements ImGroupRequestService { | @@ -100,8 +101,8 @@ public class ImGroupRequestServiceImpl implements ImGroupRequestService { | ||
| 100 | AdminUserRespDTO applyUser = adminUserApi.getUser(userId); | 101 | AdminUserRespDTO applyUser = adminUserApi.getUser(userId); |
| 101 | GroupRequestReceivedNotification payload = buildRequestNotification(group, request, applyUser); | 102 | GroupRequestReceivedNotification payload = buildRequestNotification(group, request, applyUser); |
| 102 | for (Long receiverUserId : getGroupMemberListByOwnerAndAdminUserIds(group)) { | 103 | for (Long receiverUserId : getGroupMemberListByOwnerAndAdminUserIds(group)) { |
| 103 | - websocketService.sendPrivateMessageAsync(receiverUserId, ImPrivateMessageDTO.ofGroupNotification( | ||
| 104 | - ImMessageTypeEnum.GROUP_REQUEST_RECEIVED.getType(), userId, receiverUserId, payload)); | 104 | + websocketService.sendNotificationAsync(receiverUserId, ImConversationTypeEnum.NONE.getType(), |
| 105 | + ImContentTypeEnum.GROUP_REQUEST_RECEIVED.getType(), payload); | ||
| 105 | } | 106 | } |
| 106 | return request; | 107 | return request; |
| 107 | } | 108 | } |
| @@ -200,8 +201,8 @@ public class ImGroupRequestServiceImpl implements ImGroupRequestService { | @@ -200,8 +201,8 @@ public class ImGroupRequestServiceImpl implements ImGroupRequestService { | ||
| 200 | AdminUserRespDTO applyUser = userMap.get(request.getUserId()); | 201 | AdminUserRespDTO applyUser = userMap.get(request.getUserId()); |
| 201 | GroupRequestReceivedNotification payload = buildRequestNotification(group, request, applyUser); | 202 | GroupRequestReceivedNotification payload = buildRequestNotification(group, request, applyUser); |
| 202 | for (Long receiverUserId : ownerAndAdmins) { | 203 | for (Long receiverUserId : ownerAndAdmins) { |
| 203 | - websocketService.sendPrivateMessageAsync(receiverUserId, ImPrivateMessageDTO.ofGroupNotification( | ||
| 204 | - ImMessageTypeEnum.GROUP_REQUEST_RECEIVED.getType(), inviterUserId, receiverUserId, payload)); | 204 | + websocketService.sendNotificationAsync(receiverUserId, ImConversationTypeEnum.NONE.getType(), |
| 205 | + ImContentTypeEnum.GROUP_REQUEST_RECEIVED.getType(), payload); | ||
| 205 | } | 206 | } |
| 206 | } | 207 | } |
| 207 | } | 208 | } |
| @@ -405,8 +406,8 @@ public class ImGroupRequestServiceImpl implements ImGroupRequestService { | @@ -405,8 +406,8 @@ public class ImGroupRequestServiceImpl implements ImGroupRequestService { | ||
| 405 | Set<Long> receivers = new LinkedHashSet<>(getGroupMemberListByOwnerAndAdminUserIds(group)); | 406 | Set<Long> receivers = new LinkedHashSet<>(getGroupMemberListByOwnerAndAdminUserIds(group)); |
| 406 | receivers.add(applicantUserId); | 407 | receivers.add(applicantUserId); |
| 407 | for (Long receiverUserId : receivers) { | 408 | for (Long receiverUserId : receivers) { |
| 408 | - websocketService.sendPrivateMessageAsync(receiverUserId, ImPrivateMessageDTO.ofGroupNotification( | ||
| 409 | - messageType, operatorUserId, receiverUserId, payload)); | 409 | + websocketService.sendNotificationAsync(receiverUserId, ImConversationTypeEnum.NONE.getType(), |
| 410 | + messageType, payload); | ||
| 410 | } | 411 | } |
| 411 | } | 412 | } |
| 412 | 413 |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageServiceImpl.java
| @@ -97,7 +97,8 @@ public class ImChannelMessageServiceImpl implements ImChannelMessageService { | @@ -97,7 +97,8 @@ public class ImChannelMessageServiceImpl implements ImChannelMessageService { | ||
| 97 | */ | 97 | */ |
| 98 | @Async | 98 | @Async |
| 99 | public void readChannelMessageEvent(Long userId, Long channelId, Long readId) { | 99 | public void readChannelMessageEvent(Long userId, Long channelId, Long readId) { |
| 100 | - webSocketService.sendChannelMessageAsync(userId, ImChannelMessageDTO.ofRead(channelId, readId)); | 100 | + webSocketService.sendNotificationAsync(userId, ImConversationTypeEnum.CHANNEL.getType(), |
| 101 | + ImContentTypeEnum.READ.getType(), ImMessageReadNotification.ofChannel(channelId, readId)); | ||
| 101 | } | 102 | } |
| 102 | 103 | ||
| 103 | private ImChannelMessageServiceImpl getSelf() { | 104 | private ImChannelMessageServiceImpl getSelf() { |
| @@ -121,11 +122,12 @@ public class ImChannelMessageServiceImpl implements ImChannelMessageService { | @@ -121,11 +122,12 @@ public class ImChannelMessageServiceImpl implements ImChannelMessageService { | ||
| 121 | channelMessageMapper.insert(message); | 122 | channelMessageMapper.insert(message); |
| 122 | 123 | ||
| 123 | // 3. 异步推 WebSocket:指定用户走点对点;全员(receiverUserIds 为空)走广播 | 124 | // 3. 异步推 WebSocket:指定用户走点对点;全员(receiverUserIds 为空)走广播 |
| 124 | - ImChannelMessageDTO dto = ImChannelMessageDTO.ofSend(message); | 125 | + ImChannelMessageNotification dto = ImChannelMessageNotification.ofSend(message); |
| 125 | if (CollUtil.isNotEmpty(reqVO.getReceiverUserIds())) { | 126 | if (CollUtil.isNotEmpty(reqVO.getReceiverUserIds())) { |
| 126 | - webSocketService.sendChannelMessageAsync(reqVO.getReceiverUserIds(), dto); | 127 | + webSocketService.sendNotificationAsync(reqVO.getReceiverUserIds(), ImConversationTypeEnum.CHANNEL.getType(), |
| 128 | + dto.getType(), dto); | ||
| 127 | } else { | 129 | } else { |
| 128 | - webSocketService.broadcastChannelMessageAsync(dto); | 130 | + webSocketService.broadcastNotificationAsync(ImConversationTypeEnum.CHANNEL.getType(), dto.getType(), dto); |
| 129 | } | 131 | } |
| 130 | return message.getId(); | 132 | return message.getId(); |
| 131 | } | 133 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImpl.java
| @@ -118,7 +118,9 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { | @@ -118,7 +118,9 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { | ||
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | // 3. WebSocket 异步推送(快照内可见成员 + 发送方多端同步) | 120 | // 3. WebSocket 异步推送(快照内可见成员 + 发送方多端同步) |
| 121 | - imWebSocketService.sendGroupMessageAsync(receiverUserIds, ImGroupMessageDTO.ofSend(message)); | 121 | + ImGroupMessageNotification notification = ImGroupMessageNotification.ofSend(message); |
| 122 | + imWebSocketService.sendNotificationAsync(receiverUserIds, ImConversationTypeEnum.GROUP.getType(), | ||
| 123 | + notification.getType(), notification); | ||
| 122 | return message; | 124 | return message; |
| 123 | } | 125 | } |
| 124 | 126 | ||
| @@ -149,7 +151,9 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { | @@ -149,7 +151,9 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { | ||
| 149 | } | 151 | } |
| 150 | 152 | ||
| 151 | // 2. WebSocket 异步推送 | 153 | // 2. WebSocket 异步推送 |
| 152 | - imWebSocketService.sendGroupMessageAsync(receiverUserIds, ImGroupMessageDTO.ofSend(message)); | 154 | + ImGroupMessageNotification notification = ImGroupMessageNotification.ofSend(message); |
| 155 | + imWebSocketService.sendNotificationAsync(receiverUserIds, ImConversationTypeEnum.GROUP.getType(), | ||
| 156 | + notification.getType(), notification); | ||
| 153 | return message; | 157 | return message; |
| 154 | } | 158 | } |
| 155 | 159 | ||
| @@ -347,8 +351,9 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { | @@ -347,8 +351,9 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { | ||
| 347 | @SuppressWarnings("DataFlowIssue") | 351 | @SuppressWarnings("DataFlowIssue") |
| 348 | public void readGroupMessageEvent(Long userId, Long groupId, Long prevMaxMessageId, Long newMaxMessageId) { | 352 | public void readGroupMessageEvent(Long userId, Long groupId, Long prevMaxMessageId, Long newMaxMessageId) { |
| 349 | // 1. 发送 READ 事件给自己的其他终端(多端同步) | 353 | // 1. 发送 READ 事件给自己的其他终端(多端同步) |
| 350 | - imWebSocketService.sendGroupMessageAsync(userId, | ||
| 351 | - ImGroupMessageDTO.ofRead(userId, groupId, newMaxMessageId)); | 354 | + imWebSocketService.sendNotificationAsync(userId, ImConversationTypeEnum.GROUP.getType(), |
| 355 | + ImContentTypeEnum.READ.getType(), | ||
| 356 | + ImMessageReadNotification.ofGroup(userId, groupId, newMaxMessageId)); | ||
| 352 | 357 | ||
| 353 | // 2. 刷新 (prevMaxMessageId, newMaxMessageId] 区间内的待回执消息 | 358 | // 2. 刷新 (prevMaxMessageId, newMaxMessageId] 区间内的待回执消息 |
| 354 | List<ImGroupMessageDO> pendingMessages = groupMessageMapper.selectListByGroupIdAndPendingReceipt( | 359 | List<ImGroupMessageDO> pendingMessages = groupMessageMapper.selectListByGroupIdAndPendingReceipt( |
| @@ -378,8 +383,9 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { | @@ -378,8 +383,9 @@ public class ImGroupMessageServiceImpl implements ImGroupMessageService { | ||
| 378 | } | 383 | } |
| 379 | 384 | ||
| 380 | // 2.2 发送 RECEIPT 事件给消息发送方(只有 ta 关心已读进度) | 385 | // 2.2 发送 RECEIPT 事件给消息发送方(只有 ta 关心已读进度) |
| 381 | - imWebSocketService.sendGroupMessageAsync(message.getSenderId(), | ||
| 382 | - ImGroupMessageDTO.ofReceipt(message.getId(), groupId, readCount, newReceiptStatus)); | 386 | + imWebSocketService.sendNotificationAsync(message.getSenderId(), ImConversationTypeEnum.GROUP.getType(), |
| 387 | + ImContentTypeEnum.RECEIPT.getType(), | ||
| 388 | + ImMessageReceiptNotification.ofGroup(message.getId(), groupId, readCount, newReceiptStatus)); | ||
| 383 | } | 389 | } |
| 384 | } | 390 | } |
| 385 | 391 |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImpl.java
| @@ -103,9 +103,11 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { | @@ -103,9 +103,11 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { | ||
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | // 3. WebSocket 异步推送:接收方 + 发送方多端同步 | 105 | // 3. WebSocket 异步推送:接收方 + 发送方多端同步 |
| 106 | - ImPrivateMessageDTO websocketMessage = ImPrivateMessageDTO.ofSend(message); | ||
| 107 | - imWebSocketService.sendPrivateMessageAsync(message.getReceiverId(), websocketMessage); | ||
| 108 | - imWebSocketService.sendPrivateMessageAsync(senderId, websocketMessage); | 106 | + ImPrivateMessageNotification notification = ImPrivateMessageNotification.ofSend(message); |
| 107 | + imWebSocketService.sendNotificationAsync(message.getReceiverId(), ImConversationTypeEnum.PRIVATE.getType(), | ||
| 108 | + notification.getType(), notification); | ||
| 109 | + imWebSocketService.sendNotificationAsync(senderId, ImConversationTypeEnum.PRIVATE.getType(), | ||
| 110 | + notification.getType(), notification); | ||
| 109 | return message; | 111 | return message; |
| 110 | } | 112 | } |
| 111 | 113 | ||
| @@ -131,11 +133,13 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { | @@ -131,11 +133,13 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { | ||
| 131 | } | 133 | } |
| 132 | 134 | ||
| 133 | // 2. WebSocket 异步推送:双向(默认);单边语义(persistent=false)下仅推 sender 多端,对方不感知 | 135 | // 2. WebSocket 异步推送:双向(默认);单边语义(persistent=false)下仅推 sender 多端,对方不感知 |
| 134 | - ImPrivateMessageDTO websocketMessage = ImPrivateMessageDTO.ofSend(message); | 136 | + ImPrivateMessageNotification notification = ImPrivateMessageNotification.ofSend(message); |
| 135 | if (persistent) { | 137 | if (persistent) { |
| 136 | - imWebSocketService.sendPrivateMessageAsync(dto.getReceiverId(), websocketMessage); | 138 | + imWebSocketService.sendNotificationAsync(dto.getReceiverId(), ImConversationTypeEnum.PRIVATE.getType(), |
| 139 | + notification.getType(), notification); | ||
| 137 | } | 140 | } |
| 138 | - imWebSocketService.sendPrivateMessageAsync(senderId, websocketMessage); | 141 | + imWebSocketService.sendNotificationAsync(senderId, ImConversationTypeEnum.PRIVATE.getType(), |
| 142 | + notification.getType(), notification); | ||
| 139 | return message; | 143 | return message; |
| 140 | } | 144 | } |
| 141 | 145 | ||
| @@ -256,10 +260,11 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { | @@ -256,10 +260,11 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { | ||
| 256 | } | 260 | } |
| 257 | 261 | ||
| 258 | // 4. 异步发送 READ + RECEIPT 事件(已读位置以前端上报为准,与多端 / 对方 UI 显示一致) | 262 | // 4. 异步发送 READ + RECEIPT 事件(已读位置以前端上报为准,与多端 / 对方 UI 显示一致) |
| 259 | - imWebSocketService.sendPrivateMessageAsync(userId, | ||
| 260 | - ImPrivateMessageDTO.ofRead(userId, receiverId, messageId)); | ||
| 261 | - imWebSocketService.sendPrivateMessageAsync(receiverId, | ||
| 262 | - ImPrivateMessageDTO.ofReceipt(userId, receiverId, messageId)); | 263 | + imWebSocketService.sendNotificationAsync(userId, ImConversationTypeEnum.PRIVATE.getType(), |
| 264 | + ImContentTypeEnum.READ.getType(), ImMessageReadNotification.ofPrivate(userId, receiverId, messageId)); | ||
| 265 | + imWebSocketService.sendNotificationAsync(receiverId, ImConversationTypeEnum.PRIVATE.getType(), | ||
| 266 | + ImContentTypeEnum.RECEIPT.getType(), | ||
| 267 | + ImMessageReceiptNotification.ofPrivate(userId, receiverId, messageId)); | ||
| 263 | } | 268 | } |
| 264 | 269 | ||
| 265 | @Override | 270 | @Override |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImpl.java
| @@ -56,7 +56,7 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*; | @@ -56,7 +56,7 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*; | ||
| 56 | * 并发幂等:同好友对 / 同群活跃唯一性走 {@link ImRtcCallLockRedisDAO} 分布式锁 + 锁内 SELECT 兜底;webhook 兜底走条件 UPDATE; | 56 | * 并发幂等:同好友对 / 同群活跃唯一性走 {@link ImRtcCallLockRedisDAO} 分布式锁 + 锁内 SELECT 兜底;webhook 兜底走条件 UPDATE; |
| 57 | * <p> | 57 | * <p> |
| 58 | * 推送通道分流: | 58 | * 推送通道分流: |
| 59 | - * 1601 RTC_CALL(INVITING / JOINED / REJECTED / NO_ANSWER / LEFT 子类型)→ {@link ImWebSocketService#sendPrivateMessageAsync} 仅推参与方; | 59 | + * 1601 RTC_CALL(INVITING / JOINED / REJECTED / NO_ANSWER / LEFT 子类型)→ {@link ImWebSocketService#sendNotificationAsync} 仅推参与方; |
| 60 | * 1602 / 1603 PARTICIPANT_CONNECTED / DISCONNECTED → {@link ImWebSocketService} 推参与方 + 群通话场景广播全群; | 60 | * 1602 / 1603 PARTICIPANT_CONNECTED / DISCONNECTED → {@link ImWebSocketService} 推参与方 + 群通话场景广播全群; |
| 61 | * 1610 RTC_CALL_START + 1611 RTC_CALL_END → {@link ImPrivateMessageService} / {@link ImGroupMessageService} 入消息流当聊天 tip | 61 | * 1610 RTC_CALL_START + 1611 RTC_CALL_END → {@link ImPrivateMessageService} / {@link ImGroupMessageService} 入消息流当聊天 tip |
| 62 | * (START 仅群通话;两者分别在 invite / cancel(leave) 事务里 INSERT,自增 id 自然保证顺序) | 62 | * (START 仅群通话;两者分别在 invite / cancel(leave) 事务里 INSERT,自增 id 自然保证顺序) |
| @@ -1001,8 +1001,8 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { | @@ -1001,8 +1001,8 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { | ||
| 1001 | String token = signToken(inviteeId, resolveDisplayName(invitee, inviteeId), call.getRoom()); | 1001 | String token = signToken(inviteeId, resolveDisplayName(invitee, inviteeId), call.getRoom()); |
| 1002 | ImRtcCallNotification payload = ImRtcCallNotification.ofInvite( | 1002 | ImRtcCallNotification payload = ImRtcCallNotification.ofInvite( |
| 1003 | call, inviter, imProperties.getRtc().getLivekitUrl(), token, inviteeIds); | 1003 | call, inviter, imProperties.getRtc().getLivekitUrl(), token, inviteeIds); |
| 1004 | - webSocketService.sendPrivateMessageAsync(inviteeId, ImPrivateMessageDTO.ofRtcNotification( | ||
| 1005 | - ImMessageTypeEnum.RTC_CALL.getType(), call.getInviterUserId(), inviteeId, payload)); | 1004 | + webSocketService.sendNotificationAsync(inviteeId, ImConversationTypeEnum.NONE.getType(), |
| 1005 | + ImContentTypeEnum.RTC_CALL.getType(), payload); | ||
| 1006 | } | 1006 | } |
| 1007 | 1007 | ||
| 1008 | /** | 1008 | /** |
| @@ -1017,8 +1017,8 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { | @@ -1017,8 +1017,8 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { | ||
| 1017 | AdminUserRespDTO operator = operatorUserId != null ? adminUserApi.getUser(operatorUserId) : null; | 1017 | AdminUserRespDTO operator = operatorUserId != null ? adminUserApi.getUser(operatorUserId) : null; |
| 1018 | ImRtcCallNotification payload = ImRtcCallNotification.ofReject(call, operatorUserId, operator); | 1018 | ImRtcCallNotification payload = ImRtcCallNotification.ofReject(call, operatorUserId, operator); |
| 1019 | for (Long receiverUserId : getCallAudienceUserIdList(call)) { | 1019 | for (Long receiverUserId : getCallAudienceUserIdList(call)) { |
| 1020 | - webSocketService.sendPrivateMessageAsync(receiverUserId, ImPrivateMessageDTO.ofRtcNotification( | ||
| 1021 | - ImMessageTypeEnum.RTC_CALL.getType(), operatorUserId, receiverUserId, payload)); | 1020 | + webSocketService.sendNotificationAsync(receiverUserId, ImConversationTypeEnum.NONE.getType(), |
| 1021 | + ImContentTypeEnum.RTC_CALL.getType(), payload); | ||
| 1022 | } | 1022 | } |
| 1023 | } | 1023 | } |
| 1024 | 1024 | ||
| @@ -1034,8 +1034,8 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { | @@ -1034,8 +1034,8 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { | ||
| 1034 | private void pushCallNoAnswerNotification(ImRtcCallDO call, Long operatorUserId, AdminUserRespDTO operator) { | 1034 | private void pushCallNoAnswerNotification(ImRtcCallDO call, Long operatorUserId, AdminUserRespDTO operator) { |
| 1035 | ImRtcCallNotification payload = ImRtcCallNotification.ofNoAnswer(call, operatorUserId, operator); | 1035 | ImRtcCallNotification payload = ImRtcCallNotification.ofNoAnswer(call, operatorUserId, operator); |
| 1036 | for (Long receiverUserId : getCallAudienceUserIdList(call)) { | 1036 | for (Long receiverUserId : getCallAudienceUserIdList(call)) { |
| 1037 | - webSocketService.sendPrivateMessageAsync(receiverUserId, ImPrivateMessageDTO.ofRtcNotification( | ||
| 1038 | - ImMessageTypeEnum.RTC_CALL.getType(), operatorUserId, receiverUserId, payload)); | 1037 | + webSocketService.sendNotificationAsync(receiverUserId, ImConversationTypeEnum.NONE.getType(), |
| 1038 | + ImContentTypeEnum.RTC_CALL.getType(), payload); | ||
| 1039 | } | 1039 | } |
| 1040 | } | 1040 | } |
| 1041 | 1041 | ||
| @@ -1074,8 +1074,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { | @@ -1074,8 +1074,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { | ||
| 1074 | if (CollUtil.isEmpty(receivers)) { | 1074 | if (CollUtil.isEmpty(receivers)) { |
| 1075 | return; | 1075 | return; |
| 1076 | } | 1076 | } |
| 1077 | - ImPrivateMessageDTO dto = ImPrivateMessageDTO.ofRtcNotification(type, actorUserId, null, payload); | ||
| 1078 | - webSocketService.sendPrivateMessageAsync(receivers, dto); | 1077 | + webSocketService.sendNotificationAsync(receivers, ImConversationTypeEnum.NONE.getType(), type, payload); |
| 1079 | } | 1078 | } |
| 1080 | 1079 | ||
| 1081 | /** | 1080 | /** |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketServiceImpl.java
| @@ -34,55 +34,24 @@ public class ImWebSocketServiceImpl implements ImWebSocketService { | @@ -34,55 +34,24 @@ public class ImWebSocketServiceImpl implements ImWebSocketService { | ||
| 34 | private WebSocketSenderApi webSocketSenderApi; | 34 | private WebSocketSenderApi webSocketSenderApi; |
| 35 | 35 | ||
| 36 | @Override | 36 | @Override |
| 37 | - public void sendPrivateMessageAsync(Collection<Long> userIds, ImPrivateMessageDTO dto) { | ||
| 38 | - // 说明:通过 executeAfterTransaction 保证事务提交后再推送,避免客户端收到消息后查询数据库时事务尚未提交 | ||
| 39 | - // 通过 getSelf() 获取 Spring 代理对象调用 @Async 方法,确保异步 AOP 生效(直接 this 调用会绕过代理) | ||
| 40 | - executeAfterTransaction(() -> getSelf().doSendPrivateMessage(userIds, dto)); | 37 | + public void sendNotificationAsync(Collection<Long> userIds, Integer conversationType, Integer contentType, |
| 38 | + Object payload) { | ||
| 39 | + ImNotificationWebSocketDTO notification = buildNotification(conversationType, contentType, payload); | ||
| 40 | + executeAfterTransaction(() -> getSelf().doSendNotification(userIds, notification)); | ||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | @Override | 43 | @Override |
| 44 | - public void sendGroupMessageAsync(Collection<Long> userIds, ImGroupMessageDTO dto) { | ||
| 45 | - executeAfterTransaction(() -> getSelf().doSendGroupMessage(userIds, dto)); | 44 | + public void broadcastNotificationAsync(Integer conversationType, Integer contentType, Object payload) { |
| 45 | + ImNotificationWebSocketDTO notification = buildNotification(conversationType, contentType, payload); | ||
| 46 | + executeAfterTransaction(() -> getSelf().doBroadcastNotification(notification)); | ||
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | - @Override | ||
| 49 | - public void sendChannelMessageAsync(Collection<Long> userIds, ImChannelMessageDTO dto) { | ||
| 50 | - executeAfterTransaction(() -> getSelf().doSendChannelMessage(userIds, dto)); | ||
| 51 | - } | ||
| 52 | - | ||
| 53 | - @Override | ||
| 54 | - public void broadcastChannelMessageAsync(ImChannelMessageDTO dto) { | ||
| 55 | - executeAfterTransaction(() -> getSelf().doBroadcastChannelMessage(dto)); | ||
| 56 | - } | ||
| 57 | - | ||
| 58 | - /** | ||
| 59 | - * 异步发送私聊 WebSocket 消息;多收件人共享同一 dto,避免按收件人重复注册 afterCommit 回调 | ||
| 60 | - */ | ||
| 61 | - @Async | ||
| 62 | - public void doSendPrivateMessage(Collection<Long> userIds, ImPrivateMessageDTO dto) { | ||
| 63 | - for (Long userId : getDistinctUserIds(userIds)) { | ||
| 64 | - try { | ||
| 65 | - webSocketSenderApi.sendObject(UserTypeEnum.ADMIN.getValue(), userId, | ||
| 66 | - ImPrivateMessageDTO.TYPE, dto); | ||
| 67 | - } catch (Exception e) { | ||
| 68 | - log.error("[doSendPrivateMessage][userId({}) dto({}) 发送失败]", userId, dto, e); | ||
| 69 | - } | ||
| 70 | - } | ||
| 71 | - } | ||
| 72 | - | ||
| 73 | - /** | ||
| 74 | - * 异步发送群聊 WebSocket 消息 | ||
| 75 | - */ | ||
| 76 | - @Async | ||
| 77 | - public void doSendGroupMessage(Collection<Long> userIds, ImGroupMessageDTO dto) { | ||
| 78 | - for (Long userId : getDistinctUserIds(userIds)) { | ||
| 79 | - try { | ||
| 80 | - webSocketSenderApi.sendObject(UserTypeEnum.ADMIN.getValue(), userId, | ||
| 81 | - ImGroupMessageDTO.TYPE, dto); | ||
| 82 | - } catch (Exception e) { | ||
| 83 | - log.error("[doSendGroupMessage][userId({}) dto({}) 发送失败]", userId, dto, e); | ||
| 84 | - } | ||
| 85 | - } | 49 | + private static ImNotificationWebSocketDTO buildNotification(Integer conversationType, Integer contentType, |
| 50 | + Object payload) { | ||
| 51 | + return new ImNotificationWebSocketDTO() | ||
| 52 | + .setConversationType(conversationType) | ||
| 53 | + .setContentType(contentType) | ||
| 54 | + .setPayload(payload); | ||
| 86 | } | 55 | } |
| 87 | 56 | ||
| 88 | /** | 57 | /** |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestServiceImplTest.java
| @@ -112,7 +112,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -112,7 +112,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 112 | assertNull(result); | 112 | assertNull(result); |
| 113 | verify(friendService).silentReAddFriend(eq(1L), eq(2L), eq("老张"), eq(1)); | 113 | verify(friendService).silentReAddFriend(eq(1L), eq(2L), eq("老张"), eq(1)); |
| 114 | verify(friendRequestMapper, never()).insert(any(ImFriendRequestDO.class)); | 114 | verify(friendRequestMapper, never()).insert(any(ImFriendRequestDO.class)); |
| 115 | - verify(websocketService, never()).sendPrivateMessageAsync(anyLong(), any(ImPrivateMessageDTO.class)); | 115 | + verify(websocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | @Test | 118 | @Test |
| @@ -157,7 +157,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -157,7 +157,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 157 | assertEquals(ImFriendRequestHandleResultEnum.UNHANDLED.getResult(), saved.getHandleResult()); | 157 | assertEquals(ImFriendRequestHandleResultEnum.UNHANDLED.getResult(), saved.getHandleResult()); |
| 158 | assertSame(saved, result); | 158 | assertSame(saved, result); |
| 159 | // 断言:推送给接收方 | 159 | // 断言:推送给接收方 |
| 160 | - verify(websocketService).sendPrivateMessageAsync(eq(2L), any(ImPrivateMessageDTO.class)); | 160 | + verify(websocketService).sendNotificationAsync(eq(2L), anyInt(), anyInt(), any()); |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | @Test | 163 | @Test |
| @@ -210,7 +210,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -210,7 +210,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 210 | any(LocalDateTime.class)); | 210 | any(LocalDateTime.class)); |
| 211 | assertEquals(100L, result.getId()); | 211 | assertEquals(100L, result.getId()); |
| 212 | assertEquals(ImFriendRequestHandleResultEnum.UNHANDLED.getResult(), result.getHandleResult()); | 212 | assertEquals(ImFriendRequestHandleResultEnum.UNHANDLED.getResult(), result.getHandleResult()); |
| 213 | - verify(websocketService).sendPrivateMessageAsync(eq(2L), any(ImPrivateMessageDTO.class)); | 213 | + verify(websocketService).sendNotificationAsync(eq(2L), anyInt(), anyInt(), any()); |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | // ========== agreeFriendRequest ========== | 216 | // ========== agreeFriendRequest ========== |
| @@ -230,7 +230,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -230,7 +230,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 230 | // 断言:双向建立好友 + 推 APPROVED 给发起方 | 230 | // 断言:双向建立好友 + 推 APPROVED 给发起方 |
| 231 | verify(adminUserApi).validateUserList(ListUtil.of(1L, 2L)); | 231 | verify(adminUserApi).validateUserList(ListUtil.of(1L, 2L)); |
| 232 | verify(friendService).becomeFriends(request); | 232 | verify(friendService).becomeFriends(request); |
| 233 | - verify(websocketService).sendPrivateMessageAsync(eq(1L), any(ImPrivateMessageDTO.class)); | 233 | + verify(websocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any()); |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | @Test | 236 | @Test |
| @@ -305,7 +305,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -305,7 +305,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 305 | eq(ImFriendRequestHandleResultEnum.UNHANDLED.getResult()), captor.capture()); | 305 | eq(ImFriendRequestHandleResultEnum.UNHANDLED.getResult()), captor.capture()); |
| 306 | assertEquals(ImFriendRequestHandleResultEnum.REFUSED.getResult(), captor.getValue().getHandleResult()); | 306 | assertEquals(ImFriendRequestHandleResultEnum.REFUSED.getResult(), captor.getValue().getHandleResult()); |
| 307 | assertEquals("不认识", captor.getValue().getHandleContent()); | 307 | assertEquals("不认识", captor.getValue().getHandleContent()); |
| 308 | - verify(websocketService).sendPrivateMessageAsync(eq(1L), any(ImPrivateMessageDTO.class)); | 308 | + verify(websocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any()); |
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | @Test | 311 | @Test |
| @@ -320,7 +320,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -320,7 +320,7 @@ public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 320 | ServiceException exception = assertThrows(ServiceException.class, | 320 | ServiceException exception = assertThrows(ServiceException.class, |
| 321 | () -> friendRequestService.refuseFriendRequest(2L, 100L, "x")); | 321 | () -> friendRequestService.refuseFriendRequest(2L, 100L, "x")); |
| 322 | assertEquals(FRIEND_REQUEST_HANDLED.getCode(), exception.getCode()); | 322 | assertEquals(FRIEND_REQUEST_HANDLED.getCode(), exception.getCode()); |
| 323 | - verify(websocketService, never()).sendPrivateMessageAsync(anyLong(), any(ImPrivateMessageDTO.class)); | 323 | + verify(websocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | // ========== getMyFriendRequestList ========== | 326 | // ========== getMyFriendRequestList ========== |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImplTest.java
| @@ -68,7 +68,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | @@ -68,7 +68,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | ||
| 68 | assertEquals(100L, captor.getValue().getId()); | 68 | assertEquals(100L, captor.getValue().getId()); |
| 69 | assertTrue(captor.getValue().getSilent()); | 69 | assertTrue(captor.getValue().getSilent()); |
| 70 | // 断言:推送了好友更新通知 | 70 | // 断言:推送了好友更新通知 |
| 71 | - verify(imWebSocketService).sendPrivateMessageAsync(eq(1L), any(ImPrivateMessageDTO.class)); | 71 | + verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any()); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | @Test | 74 | @Test |
| @@ -100,7 +100,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | @@ -100,7 +100,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | ||
| 100 | () -> friendService.updateFriend(1L, reqVO)); | 100 | () -> friendService.updateFriend(1L, reqVO)); |
| 101 | assertEquals(FRIEND_NOT_FRIEND.getCode(), exception.getCode()); | 101 | assertEquals(FRIEND_NOT_FRIEND.getCode(), exception.getCode()); |
| 102 | verify(imFriendMapper, never()).updateById(any(ImFriendDO.class)); | 102 | verify(imFriendMapper, never()).updateById(any(ImFriendDO.class)); |
| 103 | - verify(imWebSocketService, never()).sendPrivateMessageAsync(any(Long.class), any(ImPrivateMessageDTO.class)); | 103 | + verify(imWebSocketService, never()).sendNotificationAsync(any(Long.class), anyInt(), anyInt(), any()); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | @Test | 106 | @Test |
| @@ -123,7 +123,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | @@ -123,7 +123,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | ||
| 123 | assertEquals("老张", captor.getValue().getDisplayName()); | 123 | assertEquals("老张", captor.getValue().getDisplayName()); |
| 124 | assertNull(captor.getValue().getSilent()); | 124 | assertNull(captor.getValue().getSilent()); |
| 125 | // 断言:推送好友更新通知 | 125 | // 断言:推送好友更新通知 |
| 126 | - verify(imWebSocketService).sendPrivateMessageAsync(eq(1L), any(ImPrivateMessageDTO.class)); | 126 | + verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any()); |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | @Test | 129 | @Test |
| @@ -138,7 +138,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | @@ -138,7 +138,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | ||
| 138 | // 断言:没查记录、没触发 SQL 更新 / 没发 WebSocket 推送 | 138 | // 断言:没查记录、没触发 SQL 更新 / 没发 WebSocket 推送 |
| 139 | verify(imFriendMapper, never()).selectByUserIdAndFriendUserId(anyLong(), anyLong()); | 139 | verify(imFriendMapper, never()).selectByUserIdAndFriendUserId(anyLong(), anyLong()); |
| 140 | verify(imFriendMapper, never()).updateById(any(ImFriendDO.class)); | 140 | verify(imFriendMapper, never()).updateById(any(ImFriendDO.class)); |
| 141 | - verify(imWebSocketService, never()).sendPrivateMessageAsync(any(Long.class), any(ImPrivateMessageDTO.class)); | 141 | + verify(imWebSocketService, never()).sendNotificationAsync(any(Long.class), anyInt(), anyInt(), any()); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | // ========== addFriend0(内部方法,被 becomeFriends / silentReAddFriend 调用) ========== | 144 | // ========== addFriend0(内部方法,被 becomeFriends / silentReAddFriend 调用) ========== |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestServiceImplTest.java
| @@ -116,7 +116,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -116,7 +116,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 116 | verify(groupMemberService, never()).addGroupMember(anyLong(), anyLong(), anyInt(), anyInt(), anyLong()); | 116 | verify(groupMemberService, never()).addGroupMember(anyLong(), anyLong(), anyInt(), anyInt(), anyLong()); |
| 117 | verify(groupRequestMapper).insert(any(ImGroupRequestDO.class)); | 117 | verify(groupRequestMapper).insert(any(ImGroupRequestDO.class)); |
| 118 | // 1503 推送给 owner(99) + admin(98),去重后两条 | 118 | // 1503 推送给 owner(99) + admin(98),去重后两条 |
| 119 | - verify(websocketService, times(2)).sendPrivateMessageAsync(anyLong(), any(ImPrivateMessageDTO.class)); | 119 | + verify(websocketService, times(2)).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | @Test | 122 | @Test |
| @@ -149,7 +149,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -149,7 +149,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 149 | eq(ImGroupAddSourceEnum.SEARCH.getSource()), any()); | 149 | eq(ImGroupAddSourceEnum.SEARCH.getSource()), any()); |
| 150 | assertEquals(50L, result.getId()); | 150 | assertEquals(50L, result.getId()); |
| 151 | assertEquals(ImGroupRequestHandleResultEnum.UNHANDLED.getResult(), result.getHandleResult()); | 151 | assertEquals(ImGroupRequestHandleResultEnum.UNHANDLED.getResult(), result.getHandleResult()); |
| 152 | - verify(websocketService).sendPrivateMessageAsync(eq(99L), any(ImPrivateMessageDTO.class)); | 152 | + verify(websocketService).sendNotificationAsync(eq(99L), anyInt(), anyInt(), any()); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | @Test | 155 | @Test |
| @@ -208,7 +208,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -208,7 +208,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 208 | verify(groupMessageService).sendGroupMessage(eq(1L), dtoCaptor.capture()); | 208 | verify(groupMessageService).sendGroupMessage(eq(1L), dtoCaptor.capture()); |
| 209 | assertEquals(ImContentTypeEnum.GROUP_MEMBER_ENTER.getType(), dtoCaptor.getValue().getType()); | 209 | assertEquals(ImContentTypeEnum.GROUP_MEMBER_ENTER.getType(), dtoCaptor.getValue().getType()); |
| 210 | // 1505 推送给申请人 + owner,去重后两条 | 210 | // 1505 推送给申请人 + owner,去重后两条 |
| 211 | - verify(websocketService, times(2)).sendPrivateMessageAsync(anyLong(), any(ImPrivateMessageDTO.class)); | 211 | + verify(websocketService, times(2)).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | @Test | 214 | @Test |
| @@ -278,7 +278,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -278,7 +278,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 278 | 278 | ||
| 279 | // 不写群成员;推 1506 给申请人 + 群主(同一人 1L 时去重为 1 + 申请人 2L = 2 条) | 279 | // 不写群成员;推 1506 给申请人 + 群主(同一人 1L 时去重为 1 + 申请人 2L = 2 条) |
| 280 | verify(groupMemberService, never()).addGroupMember(anyLong(), anyLong(), anyInt(), any(), any()); | 280 | verify(groupMemberService, never()).addGroupMember(anyLong(), anyLong(), anyInt(), any(), any()); |
| 281 | - verify(websocketService, times(2)).sendPrivateMessageAsync(anyLong(), any(ImPrivateMessageDTO.class)); | 281 | + verify(websocketService, times(2)).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | // ==================== createInviteRequestList ==================== | 284 | // ==================== createInviteRequestList ==================== |
| @@ -305,7 +305,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -305,7 +305,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 305 | // 断言:插入 2 条 + 推 1503 给 owner(每条 1 帧)共 2 帧 | 305 | // 断言:插入 2 条 + 推 1503 给 owner(每条 1 帧)共 2 帧 |
| 306 | ArgumentCaptor<ImGroupRequestDO> captor = ArgumentCaptor.forClass(ImGroupRequestDO.class); | 306 | ArgumentCaptor<ImGroupRequestDO> captor = ArgumentCaptor.forClass(ImGroupRequestDO.class); |
| 307 | verify(groupRequestMapper, times(2)).insert(captor.capture()); | 307 | verify(groupRequestMapper, times(2)).insert(captor.capture()); |
| 308 | - verify(websocketService, times(2)).sendPrivateMessageAsync(anyLong(), any(ImPrivateMessageDTO.class)); | 308 | + verify(websocketService, times(2)).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 309 | // 断言:每条记录 inviterUserId=1 + addSource=INVITE,避免审批通过后回写群成员留痕的来源为空 / 脏带旧值 | 309 | // 断言:每条记录 inviterUserId=1 + addSource=INVITE,避免审批通过后回写群成员留痕的来源为空 / 脏带旧值 |
| 310 | Collection<ImGroupRequestDO> inserted = captor.getAllValues(); | 310 | Collection<ImGroupRequestDO> inserted = captor.getAllValues(); |
| 311 | assertEquals(2, inserted.size()); | 311 | assertEquals(2, inserted.size()); |
| @@ -337,7 +337,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | @@ -337,7 +337,7 @@ public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest { | ||
| 337 | // 断言:复用并重置旧邀请申请 | 337 | // 断言:复用并重置旧邀请申请 |
| 338 | verify(groupRequestMapper).updateInviteByIdReset(eq(50L), eq(1L), | 338 | verify(groupRequestMapper).updateInviteByIdReset(eq(50L), eq(1L), |
| 339 | eq(ImGroupAddSourceEnum.INVITE.getSource()), any()); | 339 | eq(ImGroupAddSourceEnum.INVITE.getSource()), any()); |
| 340 | - verify(websocketService).sendPrivateMessageAsync(eq(99L), any(ImPrivateMessageDTO.class)); | 340 | + verify(websocketService).sendNotificationAsync(eq(99L), anyInt(), anyInt(), any()); |
| 341 | } | 341 | } |
| 342 | 342 | ||
| 343 | private AdminUserRespDTO buildUser(Long id, String nickname) { | 343 | private AdminUserRespDTO buildUser(Long id, String nickname) { |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImplTest.java
| @@ -342,7 +342,7 @@ public class ImGroupServiceImplTest extends BaseMockitoUnitTest { | @@ -342,7 +342,7 @@ public class ImGroupServiceImplTest extends BaseMockitoUnitTest { | ||
| 342 | verify(groupMemberService).addGroupMembers(eq(10L), anyCollection(), | 342 | verify(groupMemberService).addGroupMembers(eq(10L), anyCollection(), |
| 343 | eq(ImGroupAddSourceEnum.INVITE.getSource()), eq(1L)); | 343 | eq(ImGroupAddSourceEnum.INVITE.getSource()), eq(1L)); |
| 344 | verify(groupRequestService, never()).createInviteRequestList(anyLong(), anyLong(), anyCollection()); | 344 | verify(groupRequestService, never()).createInviteRequestList(anyLong(), anyLong(), anyCollection()); |
| 345 | - verify(webSocketService, never()).sendGroupMessageAsync(anyCollection(), any(ImGroupMessageDTO.class)); | 345 | + verify(webSocketService, never()).sendNotificationAsync(anyCollection(), anyInt(), anyInt(), any()); |
| 346 | ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class); | 346 | ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class); |
| 347 | verify(groupMessageService).sendGroupMessage(eq(1L), anyCollection(), dtoCaptor.capture()); | 347 | verify(groupMessageService).sendGroupMessage(eq(1L), anyCollection(), dtoCaptor.capture()); |
| 348 | assertEquals(ImContentTypeEnum.GROUP_MEMBER_INVITE.getType(), dtoCaptor.getValue().getType()); | 348 | assertEquals(ImContentTypeEnum.GROUP_MEMBER_INVITE.getType(), dtoCaptor.getValue().getType()); |
| @@ -526,7 +526,7 @@ public class ImGroupServiceImplTest extends BaseMockitoUnitTest { | @@ -526,7 +526,7 @@ public class ImGroupServiceImplTest extends BaseMockitoUnitTest { | ||
| 526 | 526 | ||
| 527 | // 断言:不会触发添加、不会推送 | 527 | // 断言:不会触发添加、不会推送 |
| 528 | verify(groupMemberService, never()).addGroupMembers(anyLong(), anyCollection()); | 528 | verify(groupMemberService, never()).addGroupMembers(anyLong(), anyCollection()); |
| 529 | - verify(webSocketService, never()).sendGroupMessageAsync(anyCollection(), any(ImGroupMessageDTO.class)); | 529 | + verify(webSocketService, never()).sendNotificationAsync(anyCollection(), anyInt(), anyInt(), any()); |
| 530 | } | 530 | } |
| 531 | } | 531 | } |
| 532 | 532 |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageServiceImplTest.java
| @@ -88,7 +88,7 @@ public class ImChannelMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -88,7 +88,7 @@ public class ImChannelMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 88 | channelMessageService.readChannelMessages(1L, 10L, 100L); | 88 | channelMessageService.readChannelMessages(1L, 10L, 100L); |
| 89 | 89 | ||
| 90 | // 断言:读位置未前进 → 不推 READ 事件 | 90 | // 断言:读位置未前进 → 不推 READ 事件 |
| 91 | - verify(webSocketService, never()).sendChannelMessageAsync(anyLong(), any()); | 91 | + verify(webSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | } | 94 | } |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImplTest.java
| @@ -116,9 +116,16 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -116,9 +116,16 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 116 | assertEquals(ImMessageReceiptStatusEnum.PENDING.getStatus(), result.getReceiptStatus()); | 116 | assertEquals(ImMessageReceiptStatusEnum.PENDING.getStatus(), result.getReceiptStatus()); |
| 117 | 117 | ||
| 118 | // 验证推送给 3 个群成员(含发送者自己,用于多端同步) | 118 | // 验证推送给 3 个群成员(含发送者自己,用于多端同步) |
| 119 | - verify(imWebSocketService).sendGroupMessageAsync(argThat((Collection<Long> ids) -> | 119 | + ArgumentCaptor<ImGroupMessageNotification> payloadCaptor = |
| 120 | + ArgumentCaptor.forClass(ImGroupMessageNotification.class); | ||
| 121 | + verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) -> | ||
| 120 | ids.size() == 3 && ids.contains(1L) && ids.contains(2L) && ids.contains(3L)), | 122 | ids.size() == 3 && ids.contains(1L) && ids.contains(2L) && ids.contains(3L)), |
| 121 | - any(ImGroupMessageDTO.class)); | 123 | + eq(ImConversationTypeEnum.GROUP.getType()), eq(ImContentTypeEnum.TEXT.getType()), |
| 124 | + payloadCaptor.capture()); | ||
| 125 | + ImGroupMessageNotification payload = payloadCaptor.getValue(); | ||
| 126 | + assertEquals(ImMessageReceiptStatusEnum.PENDING.getStatus(), payload.getReceiptStatus()); | ||
| 127 | + assertEquals(0, payload.getReadCount()); | ||
| 128 | + assertEquals(List.of(1L, 2L, 3L), payload.getReceiverUserIds()); | ||
| 122 | } | 129 | } |
| 123 | } | 130 | } |
| 124 | 131 | ||
| @@ -152,9 +159,9 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -152,9 +159,9 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 152 | 159 | ||
| 153 | // 断言:固化快照必含发送者,推送目标补回发送者 = {1,2,3} | 160 | // 断言:固化快照必含发送者,推送目标补回发送者 = {1,2,3} |
| 154 | assertTrue(result.getReceiverUserIds().contains(1L), "发送者必须在 receiver_user_ids 快照内"); | 161 | assertTrue(result.getReceiverUserIds().contains(1L), "发送者必须在 receiver_user_ids 快照内"); |
| 155 | - verify(imWebSocketService).sendGroupMessageAsync(argThat((Collection<Long> ids) -> | 162 | + verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) -> |
| 156 | ids.size() == 3 && ids.contains(1L) && ids.contains(2L) && ids.contains(3L)), | 163 | ids.size() == 3 && ids.contains(1L) && ids.contains(2L) && ids.contains(3L)), |
| 157 | - any(ImGroupMessageDTO.class)); | 164 | + anyInt(), anyInt(), any()); |
| 158 | } | 165 | } |
| 159 | } | 166 | } |
| 160 | 167 | ||
| @@ -211,7 +218,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -211,7 +218,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 211 | // 被引用原消息:定向给 {1,2}(对发送人 1 可见,但不覆盖广播受众 {1,2,3}) | 218 | // 被引用原消息:定向给 {1,2}(对发送人 1 可见,但不覆盖广播受众 {1,2,3}) |
| 212 | ImGroupMessageDO original = ImGroupMessageDO.builder().id(500L).groupId(10L).senderId(2L) | 219 | ImGroupMessageDO original = ImGroupMessageDO.builder().id(500L).groupId(10L).senderId(2L) |
| 213 | .status(ImMessageStatusEnum.NORMAL.getStatus()).receiverUserIds(List.of(1L, 2L)) | 220 | .status(ImMessageStatusEnum.NORMAL.getStatus()).receiverUserIds(List.of(1L, 2L)) |
| 214 | - .type(ImMessageTypeEnum.TEXT.getType()).content("{\"content\":\"密\"}") | 221 | + .type(ImContentTypeEnum.TEXT.getType()).content("{\"content\":\"密\"}") |
| 215 | .sendTime(LocalDateTime.now()).build(); | 222 | .sendTime(LocalDateTime.now()).build(); |
| 216 | when(groupMessageMapper.selectById(500L)).thenReturn(original); | 223 | when(groupMessageMapper.selectById(500L)).thenReturn(original); |
| 217 | 224 | ||
| @@ -237,7 +244,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -237,7 +244,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 237 | when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)).thenReturn(List.of(1L, 2L, 3L)); | 244 | when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)).thenReturn(List.of(1L, 2L, 3L)); |
| 238 | ImGroupMessageDO original = ImGroupMessageDO.builder().id(500L).groupId(10L).senderId(2L) | 245 | ImGroupMessageDO original = ImGroupMessageDO.builder().id(500L).groupId(10L).senderId(2L) |
| 239 | .status(ImMessageStatusEnum.NORMAL.getStatus()).receiverUserIds(List.of(1L, 2L, 3L)) | 246 | .status(ImMessageStatusEnum.NORMAL.getStatus()).receiverUserIds(List.of(1L, 2L, 3L)) |
| 240 | - .type(ImMessageTypeEnum.TEXT.getType()).content("{\"content\":\"公开\"}") | 247 | + .type(ImContentTypeEnum.TEXT.getType()).content("{\"content\":\"公开\"}") |
| 241 | .sendTime(LocalDateTime.now()).build(); | 248 | .sendTime(LocalDateTime.now()).build(); |
| 242 | when(groupMessageMapper.selectById(500L)).thenReturn(original); | 249 | when(groupMessageMapper.selectById(500L)).thenReturn(original); |
| 243 | when(groupMessageMapper.insert(any(ImGroupMessageDO.class))).thenAnswer(invocation -> { | 250 | when(groupMessageMapper.insert(any(ImGroupMessageDO.class))).thenAnswer(invocation -> { |
| @@ -390,9 +397,9 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -390,9 +397,9 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 390 | verify(groupMessageMapper).updateById(any(ImGroupMessageDO.class)); | 397 | verify(groupMessageMapper).updateById(any(ImGroupMessageDO.class)); |
| 391 | verify(groupMessageMapper).insert(any(ImGroupMessageDO.class)); | 398 | verify(groupMessageMapper).insert(any(ImGroupMessageDO.class)); |
| 392 | // 验证:给 2 个活跃成员推送撤回提示 | 399 | // 验证:给 2 个活跃成员推送撤回提示 |
| 393 | - verify(imWebSocketService).sendGroupMessageAsync(argThat((Collection<Long> ids) -> | 400 | + verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) -> |
| 394 | ids.size() == 2 && ids.contains(1L) && ids.contains(2L)), | 401 | ids.size() == 2 && ids.contains(1L) && ids.contains(2L)), |
| 395 | - any(ImGroupMessageDTO.class)); | 402 | + anyInt(), anyInt(), any()); |
| 396 | } | 403 | } |
| 397 | } | 404 | } |
| 398 | 405 | ||
| @@ -588,7 +595,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -588,7 +595,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 588 | assertEquals(MESSAGE_SENSITIVE_WORD_BLOCKED.getCode(), exception.getCode()); | 595 | assertEquals(MESSAGE_SENSITIVE_WORD_BLOCKED.getCode(), exception.getCode()); |
| 589 | // 断言:不入库、不推送 | 596 | // 断言:不入库、不推送 |
| 590 | verify(groupMessageMapper, never()).insert(any(ImGroupMessageDO.class)); | 597 | verify(groupMessageMapper, never()).insert(any(ImGroupMessageDO.class)); |
| 591 | - verify(imWebSocketService, never()).sendGroupMessageAsync(anyCollection(), any(ImGroupMessageDTO.class)); | 598 | + verify(imWebSocketService, never()).sendNotificationAsync(anyCollection(), anyInt(), anyInt(), any()); |
| 592 | } | 599 | } |
| 593 | 600 | ||
| 594 | // ========== 撤回:补充边界 ========== | 601 | // ========== 撤回:补充边界 ========== |
| @@ -649,7 +656,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -649,7 +656,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 649 | 656 | ||
| 650 | // 断言:已读位置更新 + READ 事件 | 657 | // 断言:已读位置更新 + READ 事件 |
| 651 | verify(conversationReadService).updateConversationReadPosition(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 100L); | 658 | verify(conversationReadService).updateConversationReadPosition(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 100L); |
| 652 | - verify(imWebSocketService).sendGroupMessageAsync(eq(1L), any(ImGroupMessageDTO.class)); | 659 | + verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any()); |
| 653 | } | 660 | } |
| 654 | } | 661 | } |
| 655 | 662 | ||
| @@ -664,7 +671,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -664,7 +671,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 664 | assertEquals(MESSAGE_GROUP_READ_DISABLED.getCode(), exception.getCode()); | 671 | assertEquals(MESSAGE_GROUP_READ_DISABLED.getCode(), exception.getCode()); |
| 665 | // 断言:已读位置不写、不推送 | 672 | // 断言:已读位置不写、不推送 |
| 666 | verify(conversationReadService, never()).updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong()); | 673 | verify(conversationReadService, never()).updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong()); |
| 667 | - verify(imWebSocketService, never()).sendGroupMessageAsync(anyLong(), any(ImGroupMessageDTO.class)); | 674 | + verify(imWebSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 668 | } | 675 | } |
| 669 | 676 | ||
| 670 | @Test | 677 | @Test |
| @@ -726,7 +733,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -726,7 +733,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 726 | 733 | ||
| 727 | // 断言:调用了 CAS 更新但读位置未前进 → 不推送 | 734 | // 断言:调用了 CAS 更新但读位置未前进 → 不推送 |
| 728 | verify(conversationReadService).updateConversationReadPosition(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 100L); | 735 | verify(conversationReadService).updateConversationReadPosition(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 100L); |
| 729 | - verify(imWebSocketService, never()).sendGroupMessageAsync(anyLong(), any(ImGroupMessageDTO.class)); | 736 | + verify(imWebSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 730 | } | 737 | } |
| 731 | 738 | ||
| 732 | @Test | 739 | @Test |
| @@ -787,7 +794,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -787,7 +794,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 787 | assertEquals(100L, captor.getValue().getId()); | 794 | assertEquals(100L, captor.getValue().getId()); |
| 788 | assertEquals(ImMessageReceiptStatusEnum.DONE.getStatus(), captor.getValue().getReceiptStatus()); | 795 | assertEquals(ImMessageReceiptStatusEnum.DONE.getStatus(), captor.getValue().getReceiptStatus()); |
| 789 | // 断言:给消息发送方(5)推送 RECEIPT 事件 | 796 | // 断言:给消息发送方(5)推送 RECEIPT 事件 |
| 790 | - verify(imWebSocketService).sendGroupMessageAsync(eq(5L), any(ImGroupMessageDTO.class)); | 797 | + verify(imWebSocketService).sendNotificationAsync(eq(5L), anyInt(), anyInt(), any()); |
| 791 | } | 798 | } |
| 792 | 799 | ||
| 793 | @Test | 800 | @Test |
| @@ -824,7 +831,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -824,7 +831,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 824 | // 断言:回执状态保持 PENDING,不更新 DB | 831 | // 断言:回执状态保持 PENDING,不更新 DB |
| 825 | verify(groupMessageMapper, never()).updateById(any(ImGroupMessageDO.class)); | 832 | verify(groupMessageMapper, never()).updateById(any(ImGroupMessageDO.class)); |
| 826 | // 仍然推送 RECEIPT 事件给发送方(携带已读人数) | 833 | // 仍然推送 RECEIPT 事件给发送方(携带已读人数) |
| 827 | - verify(imWebSocketService).sendGroupMessageAsync(eq(5L), any(ImGroupMessageDTO.class)); | 834 | + verify(imWebSocketService).sendNotificationAsync(eq(5L), anyInt(), anyInt(), any()); |
| 828 | } | 835 | } |
| 829 | 836 | ||
| 830 | // ========== sendGroupMessage(senderId, dto):receiverUserIds 定向过滤 ========== | 837 | // ========== sendGroupMessage(senderId, dto):receiverUserIds 定向过滤 ========== |
| @@ -833,17 +840,17 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -833,17 +840,17 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 833 | public void testSendGroupMessage_noReceiverUserIds_broadcastsToAllMembers() { | 840 | public void testSendGroupMessage_noReceiverUserIds_broadcastsToAllMembers() { |
| 834 | // 准备:无定向 → 应发给所有 ENABLE 成员(含发送者自己,多端同步) | 841 | // 准备:无定向 → 应发给所有 ENABLE 成员(含发送者自己,多端同步) |
| 835 | ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO() | 842 | ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO() |
| 836 | - .setGroupId(10L).setType(ImMessageTypeEnum.RECALL.getType()) | 843 | + .setGroupId(10L).setType(ImContentTypeEnum.RECALL.getType()) |
| 837 | .setContent("{\"messageId\":1}"); | 844 | .setContent("{\"messageId\":1}"); |
| 838 | when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)) | 845 | when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)) |
| 839 | .thenReturn(List.of(1L, 2L, 3L, 4L)); | 846 | .thenReturn(List.of(1L, 2L, 3L, 4L)); |
| 840 | 847 | ||
| 841 | groupMessageService.sendGroupMessage(1L, dto); | 848 | groupMessageService.sendGroupMessage(1L, dto); |
| 842 | 849 | ||
| 843 | - verify(imWebSocketService).sendGroupMessageAsync(argThat((Collection<Long> ids) -> | 850 | + verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) -> |
| 844 | ids.size() == 4 && ids.contains(1L) && ids.contains(2L) | 851 | ids.size() == 4 && ids.contains(1L) && ids.contains(2L) |
| 845 | && ids.contains(3L) && ids.contains(4L)), | 852 | && ids.contains(3L) && ids.contains(4L)), |
| 846 | - any(ImGroupMessageDTO.class)); | 853 | + anyInt(), anyInt(), any()); |
| 847 | } | 854 | } |
| 848 | 855 | ||
| 849 | @Test | 856 | @Test |
| @@ -851,7 +858,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -851,7 +858,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 851 | // 准备:定向给 {2,3},发送者 1;群成员 {1,2,3,4} | 858 | // 准备:定向给 {2,3},发送者 1;群成员 {1,2,3,4} |
| 852 | // 预期推送目标:{1,2,3}(发送者自己多端同步 + 定向列表);4 被过滤 | 859 | // 预期推送目标:{1,2,3}(发送者自己多端同步 + 定向列表);4 被过滤 |
| 853 | ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO() | 860 | ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO() |
| 854 | - .setGroupId(10L).setType(ImMessageTypeEnum.RECALL.getType()) | 861 | + .setGroupId(10L).setType(ImContentTypeEnum.RECALL.getType()) |
| 855 | .setContent("{\"messageId\":1}") | 862 | .setContent("{\"messageId\":1}") |
| 856 | .setReceiverUserIds(List.of(2L, 3L)); | 863 | .setReceiverUserIds(List.of(2L, 3L)); |
| 857 | when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)) | 864 | when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)) |
| @@ -859,10 +866,10 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -859,10 +866,10 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 859 | 866 | ||
| 860 | groupMessageService.sendGroupMessage(1L, dto); | 867 | groupMessageService.sendGroupMessage(1L, dto); |
| 861 | 868 | ||
| 862 | - verify(imWebSocketService).sendGroupMessageAsync(argThat((Collection<Long> ids) -> | 869 | + verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) -> |
| 863 | ids.size() == 3 && ids.contains(1L) && ids.contains(2L) | 870 | ids.size() == 3 && ids.contains(1L) && ids.contains(2L) |
| 864 | && ids.contains(3L) && !ids.contains(4L)), | 871 | && ids.contains(3L) && !ids.contains(4L)), |
| 865 | - any(ImGroupMessageDTO.class)); | 872 | + anyInt(), anyInt(), any()); |
| 866 | } | 873 | } |
| 867 | 874 | ||
| 868 | @Test | 875 | @Test |
| @@ -870,7 +877,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -870,7 +877,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 870 | // 边界:发送者不在群成员缓存里(理论上应先被 validateMemberInGroup 挡住,这里纯防御) | 877 | // 边界:发送者不在群成员缓存里(理论上应先被 validateMemberInGroup 挡住,这里纯防御) |
| 871 | // 预期:定向用户 + 发送者自己(始终纳入快照保证多端同步);非定向成员 4 被过滤 | 878 | // 预期:定向用户 + 发送者自己(始终纳入快照保证多端同步);非定向成员 4 被过滤 |
| 872 | ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO() | 879 | ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO() |
| 873 | - .setGroupId(10L).setType(ImMessageTypeEnum.RECALL.getType()) | 880 | + .setGroupId(10L).setType(ImContentTypeEnum.RECALL.getType()) |
| 874 | .setContent("{\"messageId\":1}") | 881 | .setContent("{\"messageId\":1}") |
| 875 | .setReceiverUserIds(List.of(2L, 3L)); | 882 | .setReceiverUserIds(List.of(2L, 3L)); |
| 876 | when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)) | 883 | when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)) |
| @@ -878,10 +885,10 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -878,10 +885,10 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 878 | 885 | ||
| 879 | groupMessageService.sendGroupMessage(99L, dto); | 886 | groupMessageService.sendGroupMessage(99L, dto); |
| 880 | 887 | ||
| 881 | - verify(imWebSocketService).sendGroupMessageAsync(argThat((Collection<Long> ids) -> | 888 | + verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) -> |
| 882 | ids.size() == 3 && ids.contains(2L) && ids.contains(3L) | 889 | ids.size() == 3 && ids.contains(2L) && ids.contains(3L) |
| 883 | && ids.contains(99L) && !ids.contains(4L)), | 890 | && ids.contains(99L) && !ids.contains(4L)), |
| 884 | - any(ImGroupMessageDTO.class)); | 891 | + anyInt(), anyInt(), any()); |
| 885 | } | 892 | } |
| 886 | 893 | ||
| 887 | // ========== sendGroupMessage(senderId, dto):helper 行为 ========== | 894 | // ========== sendGroupMessage(senderId, dto):helper 行为 ========== |
| @@ -935,7 +942,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -935,7 +942,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 935 | groupMessageService.sendGroupMessage(1L, dto); | 942 | groupMessageService.sendGroupMessage(1L, dto); |
| 936 | 943 | ||
| 937 | verify(groupMessageMapper, never()).insert(any(ImGroupMessageDO.class)); | 944 | verify(groupMessageMapper, never()).insert(any(ImGroupMessageDO.class)); |
| 938 | - verify(imWebSocketService).sendGroupMessageAsync(anyCollection(), any(ImGroupMessageDTO.class)); | 945 | + verify(imWebSocketService).sendNotificationAsync(anyCollection(), anyInt(), anyInt(), any()); |
| 939 | } | 946 | } |
| 940 | 947 | ||
| 941 | @Test | 948 | @Test |
| @@ -949,7 +956,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -949,7 +956,7 @@ public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 949 | 956 | ||
| 950 | // 断言:不读取 active members,按调用方 targets 推送 | 957 | // 断言:不读取 active members,按调用方 targets 推送 |
| 951 | verify(groupMemberService, never()).getActiveGroupMemberUserIdsByGroupId(anyLong()); | 958 | verify(groupMemberService, never()).getActiveGroupMemberUserIdsByGroupId(anyLong()); |
| 952 | - verify(imWebSocketService).sendGroupMessageAsync(eq(targets), any(ImGroupMessageDTO.class)); | 959 | + verify(imWebSocketService).sendNotificationAsync(eq(targets), anyInt(), anyInt(), any()); |
| 953 | } | 960 | } |
| 954 | 961 | ||
| 955 | // ========== getGroupMessageList ========== | 962 | // ========== getGroupMessageList ========== |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImplTest.java
| @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivate | @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivate | ||
| 7 | import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageSendReqVO; | 7 | import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageSendReqVO; |
| 8 | import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO; | 8 | import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO; |
| 9 | import cn.iocoder.yudao.module.im.dal.mysql.message.ImPrivateMessageMapper; | 9 | import cn.iocoder.yudao.module.im.dal.mysql.message.ImPrivateMessageMapper; |
| 10 | +import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum; | ||
| 10 | import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum; | 11 | import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum; |
| 11 | import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum; | 12 | import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum; |
| 12 | import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum; | 13 | import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum; |
| @@ -16,8 +17,10 @@ import cn.iocoder.yudao.module.im.service.friend.ImFriendService; | @@ -16,8 +17,10 @@ import cn.iocoder.yudao.module.im.service.friend.ImFriendService; | ||
| 16 | import cn.iocoder.yudao.module.im.service.sensitiveword.ImSensitiveWordService; | 17 | import cn.iocoder.yudao.module.im.service.sensitiveword.ImSensitiveWordService; |
| 17 | import cn.iocoder.yudao.module.im.service.message.dto.ImPrivateMessageSendDTO; | 18 | import cn.iocoder.yudao.module.im.service.message.dto.ImPrivateMessageSendDTO; |
| 18 | import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService; | 19 | import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService; |
| 19 | -import cn.iocoder.yudao.module.im.service.websocket.dto.ImPrivateMessageDTO; | ||
| 20 | -import cn.iocoder.yudao.module.im.service.websocket.dto.message.RecallMessage; | 20 | +import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImMessageReadNotification; |
| 21 | +import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImMessageReceiptNotification; | ||
| 22 | +import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImPrivateMessageNotification; | ||
| 23 | +import cn.iocoder.yudao.module.im.dal.dataobject.message.content.RecallMessage; | ||
| 21 | import org.junit.jupiter.api.Test; | 24 | import org.junit.jupiter.api.Test; |
| 22 | import org.mockito.ArgumentCaptor; | 25 | import org.mockito.ArgumentCaptor; |
| 23 | import org.mockito.InjectMocks; | 26 | import org.mockito.InjectMocks; |
| @@ -61,7 +64,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -61,7 +64,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 61 | ImPrivateMessageSendReqVO reqVO = new ImPrivateMessageSendReqVO(); | 64 | ImPrivateMessageSendReqVO reqVO = new ImPrivateMessageSendReqVO(); |
| 62 | reqVO.setClientMessageId("test-uuid-001"); | 65 | reqVO.setClientMessageId("test-uuid-001"); |
| 63 | reqVO.setReceiverId(2L); | 66 | reqVO.setReceiverId(2L); |
| 64 | - reqVO.setType(ImMessageTypeEnum.TEXT.getType()); | 67 | + reqVO.setType(ImContentTypeEnum.TEXT.getType()); |
| 65 | reqVO.setContent("{\"content\":\"你好\"}"); | 68 | reqVO.setContent("{\"content\":\"你好\"}"); |
| 66 | return reqVO; | 69 | return reqVO; |
| 67 | } | 70 | } |
| @@ -87,7 +90,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -87,7 +90,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 87 | assertNotNull(result); | 90 | assertNotNull(result); |
| 88 | assertEquals(1L, result.getSenderId()); | 91 | assertEquals(1L, result.getSenderId()); |
| 89 | assertEquals(2L, result.getReceiverId()); | 92 | assertEquals(2L, result.getReceiverId()); |
| 90 | - assertEquals(ImMessageTypeEnum.TEXT.getType(), result.getType()); | 93 | + assertEquals(ImContentTypeEnum.TEXT.getType(), result.getType()); |
| 91 | assertEquals(ImMessageStatusEnum.NORMAL.getStatus(), result.getStatus()); | 94 | assertEquals(ImMessageStatusEnum.NORMAL.getStatus(), result.getStatus()); |
| 92 | assertEquals(ImMessageReceiptStatusEnum.PENDING.getStatus(), result.getReceiptStatus(), | 95 | assertEquals(ImMessageReceiptStatusEnum.PENDING.getStatus(), result.getReceiptStatus(), |
| 93 | "用户私聊消息默认需要回执(PENDING)"); | 96 | "用户私聊消息默认需要回执(PENDING)"); |
| @@ -98,8 +101,8 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -98,8 +101,8 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 98 | verify(sensitiveWordService).validateText(reqVO.getContent()); | 101 | verify(sensitiveWordService).validateText(reqVO.getContent()); |
| 99 | verify(privateMessageMapper).insert(any(ImPrivateMessageDO.class)); | 102 | verify(privateMessageMapper).insert(any(ImPrivateMessageDO.class)); |
| 100 | // 验证推送给接收方和发送方 | 103 | // 验证推送给接收方和发送方 |
| 101 | - verify(imWebSocketService).sendPrivateMessageAsync(eq(2L), any(ImPrivateMessageDTO.class)); | ||
| 102 | - verify(imWebSocketService).sendPrivateMessageAsync(eq(1L), any(ImPrivateMessageDTO.class)); | 104 | + verify(imWebSocketService).sendNotificationAsync(eq(2L), anyInt(), anyInt(), any()); |
| 105 | + verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any()); | ||
| 103 | } | 106 | } |
| 104 | 107 | ||
| 105 | @Test | 108 | @Test |
| @@ -187,22 +190,25 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -187,22 +190,25 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 187 | 190 | ||
| 188 | // 断言:发送了 READ + RECEIPT 事件,payload 字段正确 | 191 | // 断言:发送了 READ + RECEIPT 事件,payload 字段正确 |
| 189 | ArgumentCaptor<Long> userCaptor = ArgumentCaptor.forClass(Long.class); | 192 | ArgumentCaptor<Long> userCaptor = ArgumentCaptor.forClass(Long.class); |
| 190 | - ArgumentCaptor<ImPrivateMessageDTO> contentCaptor = ArgumentCaptor.forClass(ImPrivateMessageDTO.class); | ||
| 191 | - verify(imWebSocketService, times(2)).sendPrivateMessageAsync( | ||
| 192 | - userCaptor.capture(), contentCaptor.capture()); | 193 | + ArgumentCaptor<Integer> contentTypeCaptor = ArgumentCaptor.forClass(Integer.class); |
| 194 | + ArgumentCaptor<Object> payloadCaptor = ArgumentCaptor.forClass(Object.class); | ||
| 195 | + verify(imWebSocketService, times(2)).sendNotificationAsync( | ||
| 196 | + userCaptor.capture(), eq(ImConversationTypeEnum.PRIVATE.getType()), | ||
| 197 | + contentTypeCaptor.capture(), payloadCaptor.capture()); | ||
| 193 | 198 | ||
| 194 | // 第一次:发给自己的 READ 事件 | 199 | // 第一次:发给自己的 READ 事件 |
| 195 | assertEquals(1L, userCaptor.getAllValues().get(0)); | 200 | assertEquals(1L, userCaptor.getAllValues().get(0)); |
| 196 | - ImPrivateMessageDTO readPayload = contentCaptor.getAllValues().get(0); | ||
| 197 | - assertEquals(ImMessageTypeEnum.READ.getType(), readPayload.getType()); | 201 | + assertEquals(ImContentTypeEnum.READ.getType(), contentTypeCaptor.getAllValues().get(0)); |
| 202 | + ImMessageReadNotification readPayload = (ImMessageReadNotification) payloadCaptor.getAllValues().get(0); | ||
| 198 | assertEquals(1L, readPayload.getSenderId()); | 203 | assertEquals(1L, readPayload.getSenderId()); |
| 199 | assertEquals(2L, readPayload.getReceiverId()); | 204 | assertEquals(2L, readPayload.getReceiverId()); |
| 200 | assertEquals(5L, readPayload.getId(), "READ id 应为前端上报的 messageId"); | 205 | assertEquals(5L, readPayload.getId(), "READ id 应为前端上报的 messageId"); |
| 201 | 206 | ||
| 202 | // 第二次:发给对方的 RECEIPT 事件 | 207 | // 第二次:发给对方的 RECEIPT 事件 |
| 203 | assertEquals(2L, userCaptor.getAllValues().get(1)); | 208 | assertEquals(2L, userCaptor.getAllValues().get(1)); |
| 204 | - ImPrivateMessageDTO receiptPayload = contentCaptor.getAllValues().get(1); | ||
| 205 | - assertEquals(ImMessageTypeEnum.RECEIPT.getType(), receiptPayload.getType()); | 209 | + assertEquals(ImContentTypeEnum.RECEIPT.getType(), contentTypeCaptor.getAllValues().get(1)); |
| 210 | + ImMessageReceiptNotification receiptPayload = | ||
| 211 | + (ImMessageReceiptNotification) payloadCaptor.getAllValues().get(1); | ||
| 206 | assertEquals(5L, receiptPayload.getId(), "RECEIPT id 应为前端上报的 messageId"); | 212 | assertEquals(5L, receiptPayload.getId(), "RECEIPT id 应为前端上报的 messageId"); |
| 207 | } | 213 | } |
| 208 | 214 | ||
| @@ -228,7 +234,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -228,7 +234,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 228 | verify(privateMessageMapper).updateById(any(ImPrivateMessageDO.class)); | 234 | verify(privateMessageMapper).updateById(any(ImPrivateMessageDO.class)); |
| 229 | verify(privateMessageMapper).insert(any(ImPrivateMessageDO.class)); | 235 | verify(privateMessageMapper).insert(any(ImPrivateMessageDO.class)); |
| 230 | // 验证推送了消息(给接收方和发送方) | 236 | // 验证推送了消息(给接收方和发送方) |
| 231 | - verify(imWebSocketService, times(2)).sendPrivateMessageAsync(anyLong(), any(ImPrivateMessageDTO.class)); | 237 | + verify(imWebSocketService, times(2)).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 232 | } | 238 | } |
| 233 | 239 | ||
| 234 | @Test | 240 | @Test |
| @@ -304,7 +310,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -304,7 +310,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 304 | assertEquals(MESSAGE_SENSITIVE_WORD_BLOCKED.getCode(), exception.getCode()); | 310 | assertEquals(MESSAGE_SENSITIVE_WORD_BLOCKED.getCode(), exception.getCode()); |
| 305 | // 断言:不入库、不推送 | 311 | // 断言:不入库、不推送 |
| 306 | verify(privateMessageMapper, never()).insert(any(ImPrivateMessageDO.class)); | 312 | verify(privateMessageMapper, never()).insert(any(ImPrivateMessageDO.class)); |
| 307 | - verify(imWebSocketService, never()).sendPrivateMessageAsync(anyLong(), any(ImPrivateMessageDTO.class)); | 313 | + verify(imWebSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 308 | } | 314 | } |
| 309 | 315 | ||
| 310 | @Test | 316 | @Test |
| @@ -319,7 +325,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -319,7 +325,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 319 | // 断言:不更新消息状态、不推送 | 325 | // 断言:不更新消息状态、不推送 |
| 320 | verify(privateMessageMapper, never()).updateBySenderIdAndReceiverIdAndIdLeAndReceiptStatus( | 326 | verify(privateMessageMapper, never()).updateBySenderIdAndReceiverIdAndIdLeAndReceiptStatus( |
| 321 | anyLong(), anyLong(), anyLong(), anyInt(), any(ImPrivateMessageDO.class)); | 327 | anyLong(), anyLong(), anyLong(), anyInt(), any(ImPrivateMessageDO.class)); |
| 322 | - verify(imWebSocketService, never()).sendPrivateMessageAsync(anyLong(), any(ImPrivateMessageDTO.class)); | 328 | + verify(imWebSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 323 | } | 329 | } |
| 324 | 330 | ||
| 325 | @Test | 331 | @Test |
| @@ -332,7 +338,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -332,7 +338,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 332 | privateMessageService.readPrivateMessages(1L, 2L, 5L); | 338 | privateMessageService.readPrivateMessages(1L, 2L, 5L); |
| 333 | 339 | ||
| 334 | // 断言:读位置没前进,不推送 READ / RECEIPT | 340 | // 断言:读位置没前进,不推送 READ / RECEIPT |
| 335 | - verify(imWebSocketService, never()).sendPrivateMessageAsync(anyLong(), any(ImPrivateMessageDTO.class)); | 341 | + verify(imWebSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any()); |
| 336 | } | 342 | } |
| 337 | 343 | ||
| 338 | // ========== getMaxReadMessageId 测试 ========== | 344 | // ========== getMaxReadMessageId 测试 ========== |
| @@ -397,8 +403,8 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -397,8 +403,8 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 397 | assertNotNull(message.getClientMessageId()); | 403 | assertNotNull(message.getClientMessageId()); |
| 398 | assertNotNull(message.getSendTime()); | 404 | assertNotNull(message.getSendTime()); |
| 399 | // 断言:sender + receiver 双端推送 | 405 | // 断言:sender + receiver 双端推送 |
| 400 | - verify(imWebSocketService).sendPrivateMessageAsync(eq(1L), any(ImPrivateMessageDTO.class)); | ||
| 401 | - verify(imWebSocketService).sendPrivateMessageAsync(eq(2L), any(ImPrivateMessageDTO.class)); | 406 | + verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any()); |
| 407 | + verify(imWebSocketService).sendNotificationAsync(eq(2L), anyInt(), anyInt(), any()); | ||
| 402 | } | 408 | } |
| 403 | 409 | ||
| 404 | @Test | 410 | @Test |
| @@ -410,8 +416,8 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -410,8 +416,8 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 410 | privateMessageService.sendPrivateMessage(1L, dto); | 416 | privateMessageService.sendPrivateMessage(1L, dto); |
| 411 | 417 | ||
| 412 | verify(privateMessageMapper, never()).insert(any(ImPrivateMessageDO.class)); | 418 | verify(privateMessageMapper, never()).insert(any(ImPrivateMessageDO.class)); |
| 413 | - verify(imWebSocketService).sendPrivateMessageAsync(eq(1L), any(ImPrivateMessageDTO.class)); | ||
| 414 | - verify(imWebSocketService, never()).sendPrivateMessageAsync(eq(2L), any(ImPrivateMessageDTO.class)); | 419 | + verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any()); |
| 420 | + verify(imWebSocketService, never()).sendNotificationAsync(eq(2L), anyInt(), anyInt(), any()); | ||
| 415 | } | 421 | } |
| 416 | 422 | ||
| 417 | // ========== getPrivateMessageList ========== | 423 | // ========== getPrivateMessageList ========== |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImplTest.java
| @@ -143,7 +143,7 @@ public class ImRtcCallServiceImplTest extends BaseMockitoUnitTest { | @@ -143,7 +143,7 @@ public class ImRtcCallServiceImplTest extends BaseMockitoUnitTest { | ||
| 143 | 143 | ||
| 144 | // 断言:成功 1 个;NO_ANSWER 信令推到主叫;不触发 endSession | 144 | // 断言:成功 1 个;NO_ANSWER 信令推到主叫;不触发 endSession |
| 145 | assertEquals(1, result); | 145 | assertEquals(1, result); |
| 146 | - verify(webSocketService).sendPrivateMessageAsync(eq(200L), any(ImPrivateMessageDTO.class)); | 146 | + verify(webSocketService).sendNotificationAsync(eq(200L), anyInt(), anyInt(), any()); |
| 147 | verify(rtcCallMapper, never()).updateByIdAndStatusIn(any(), anyCollection(), any()); | 147 | verify(rtcCallMapper, never()).updateByIdAndStatusIn(any(), anyCollection(), any()); |
| 148 | } | 148 | } |
| 149 | 149 | ||
| @@ -238,7 +238,7 @@ public class ImRtcCallServiceImplTest extends BaseMockitoUnitTest { | @@ -238,7 +238,7 @@ public class ImRtcCallServiceImplTest extends BaseMockitoUnitTest { | ||
| 238 | rtcCallService.noAnswerCallCheck(100L, "r1"); | 238 | rtcCallService.noAnswerCallCheck(100L, "r1"); |
| 239 | 239 | ||
| 240 | // 断言:NO_ANSWER 信令推到主叫 200L;不触发 endSession | 240 | // 断言:NO_ANSWER 信令推到主叫 200L;不触发 endSession |
| 241 | - verify(webSocketService).sendPrivateMessageAsync(eq(200L), any(ImPrivateMessageDTO.class)); | 241 | + verify(webSocketService).sendNotificationAsync(eq(200L), anyInt(), anyInt(), any()); |
| 242 | verify(rtcCallMapper, never()).updateByIdAndStatusIn(any(), anyCollection(), any()); | 242 | verify(rtcCallMapper, never()).updateByIdAndStatusIn(any(), anyCollection(), any()); |
| 243 | } | 243 | } |
| 244 | 244 |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketServiceImplTest.java
| @@ -57,10 +57,12 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | @@ -57,10 +57,12 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | ||
| 57 | .thenReturn(imWebSocketService); | 57 | .thenReturn(imWebSocketService); |
| 58 | 58 | ||
| 59 | // 准备 | 59 | // 准备 |
| 60 | - ImPrivateMessageDTO dto = new ImPrivateMessageDTO().setSenderId(1L).setReceiverId(2L); | 60 | + ImPrivateMessageNotification dto = new ImPrivateMessageNotification().setSenderId(1L).setReceiverId(2L) |
| 61 | + .setType(ImContentTypeEnum.TEXT.getType()); | ||
| 61 | 62 | ||
| 62 | // 调用:无事务,应立即发送 | 63 | // 调用:无事务,应立即发送 |
| 63 | - imWebSocketService.sendPrivateMessageAsync(2L, dto); | 64 | + imWebSocketService.sendNotificationAsync(2L, ImConversationTypeEnum.PRIVATE.getType(), |
| 65 | + ImContentTypeEnum.TEXT.getType(), dto); | ||
| 64 | 66 | ||
| 65 | // 断言 | 67 | // 断言 |
| 66 | verify(webSocketSenderApi).sendObject( | 68 | verify(webSocketSenderApi).sendObject( |
| @@ -79,10 +81,12 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | @@ -79,10 +81,12 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | ||
| 79 | // 准备:开启事务同步 | 81 | // 准备:开启事务同步 |
| 80 | TransactionSynchronizationManager.initSynchronization(); | 82 | TransactionSynchronizationManager.initSynchronization(); |
| 81 | try { | 83 | try { |
| 82 | - ImPrivateMessageDTO dto = new ImPrivateMessageDTO().setSenderId(1L).setReceiverId(2L); | 84 | + ImPrivateMessageNotification dto = new ImPrivateMessageNotification().setSenderId(1L).setReceiverId(2L) |
| 85 | + .setType(ImContentTypeEnum.TEXT.getType()); | ||
| 83 | 86 | ||
| 84 | // 调用 | 87 | // 调用 |
| 85 | - imWebSocketService.sendPrivateMessageAsync(2L, dto); | 88 | + imWebSocketService.sendNotificationAsync(2L, ImConversationTypeEnum.PRIVATE.getType(), |
| 89 | + ImContentTypeEnum.TEXT.getType(), dto); | ||
| 86 | 90 | ||
| 87 | // 断言:事务未提交,未推送 | 91 | // 断言:事务未提交,未推送 |
| 88 | verify(webSocketSenderApi, never()).sendObject(anyInt(), anyLong(), anyString(), any()); | 92 | verify(webSocketSenderApi, never()).sendObject(anyInt(), anyLong(), anyString(), any()); |
| @@ -115,8 +119,10 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | @@ -115,8 +119,10 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | ||
| 115 | ImGroupMessageNotification dto = new ImGroupMessageNotification(); | 119 | ImGroupMessageNotification dto = new ImGroupMessageNotification(); |
| 116 | dto.setGroupId(10L); | 120 | dto.setGroupId(10L); |
| 117 | dto.setSenderId(1L); | 121 | dto.setSenderId(1L); |
| 122 | + dto.setType(ImContentTypeEnum.TEXT.getType()); | ||
| 118 | 123 | ||
| 119 | - imWebSocketService.sendGroupMessageAsync(ListUtil.of(1L, 2L, 3L), dto); | 124 | + imWebSocketService.sendNotificationAsync(ListUtil.of(1L, 2L, 3L), |
| 125 | + ImConversationTypeEnum.GROUP.getType(), ImContentTypeEnum.TEXT.getType(), dto); | ||
| 120 | 126 | ||
| 121 | verify(webSocketSenderApi).sendObject( | 127 | verify(webSocketSenderApi).sendObject( |
| 122 | eq(UserTypeEnum.ADMIN.getValue()), eq(1L), eq(ImNotificationWebSocketDTO.TYPE), | 128 | eq(UserTypeEnum.ADMIN.getValue()), eq(1L), eq(ImNotificationWebSocketDTO.TYPE), |
| @@ -145,7 +151,8 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | @@ -145,7 +151,8 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | ||
| 145 | doThrow(new RuntimeException("user offline")) | 151 | doThrow(new RuntimeException("user offline")) |
| 146 | .when(webSocketSenderApi).sendObject(anyInt(), eq(1L), anyString(), any()); | 152 | .when(webSocketSenderApi).sendObject(anyInt(), eq(1L), anyString(), any()); |
| 147 | 153 | ||
| 148 | - imWebSocketService.sendGroupMessageAsync(ListUtil.of(1L, 2L, 3L), dto); | 154 | + imWebSocketService.sendNotificationAsync(ListUtil.of(1L, 2L, 3L), |
| 155 | + ImConversationTypeEnum.GROUP.getType(), ImContentTypeEnum.TEXT.getType(), dto); | ||
| 149 | 156 | ||
| 150 | // 2L 和 3L 也都被推送 | 157 | // 2L 和 3L 也都被推送 |
| 151 | verify(webSocketSenderApi).sendObject(anyInt(), eq(2L), anyString(), any()); | 158 | verify(webSocketSenderApi).sendObject(anyInt(), eq(2L), anyString(), any()); |
| @@ -154,8 +161,12 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | @@ -154,8 +161,12 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | ||
| 154 | } | 161 | } |
| 155 | 162 | ||
| 156 | @Test | 163 | @Test |
| 157 | - public void testDoSendGroupMessage_emptyUserIds_noSend() { | ||
| 158 | - ImGroupMessageDTO dto = new ImGroupMessageDTO().setGroupId(10L); | 164 | + public void testDoSendNotification_emptyUserIds_noSend() { |
| 165 | + ImGroupMessageNotification dto = new ImGroupMessageNotification(); | ||
| 166 | + dto.setGroupId(10L); | ||
| 167 | + dto.setType(ImContentTypeEnum.TEXT.getType()); | ||
| 168 | + ImNotificationWebSocketDTO notification = buildNotification(ImConversationTypeEnum.GROUP, | ||
| 169 | + ImContentTypeEnum.TEXT, dto); | ||
| 159 | 170 | ||
| 160 | imWebSocketService.doSendNotification(Collections.emptyList(), notification); | 171 | imWebSocketService.doSendNotification(Collections.emptyList(), notification); |
| 161 | imWebSocketService.doSendNotification(null, notification); | 172 | imWebSocketService.doSendNotification(null, notification); |
| @@ -164,8 +175,12 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | @@ -164,8 +175,12 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | ||
| 164 | } | 175 | } |
| 165 | 176 | ||
| 166 | @Test | 177 | @Test |
| 167 | - public void testDoSendGroupMessage_distinctUserIds() { | ||
| 168 | - ImGroupMessageDTO dto = new ImGroupMessageDTO().setGroupId(10L); | 178 | + public void testDoSendNotification_distinctUserIds() { |
| 179 | + ImGroupMessageNotification dto = new ImGroupMessageNotification(); | ||
| 180 | + dto.setGroupId(10L); | ||
| 181 | + dto.setType(ImContentTypeEnum.TEXT.getType()); | ||
| 182 | + ImNotificationWebSocketDTO notification = buildNotification(ImConversationTypeEnum.GROUP, | ||
| 183 | + ImContentTypeEnum.TEXT, dto); | ||
| 169 | 184 | ||
| 170 | imWebSocketService.doSendNotification(Arrays.asList(1L, 2L, 1L, null), notification); | 185 | imWebSocketService.doSendNotification(Arrays.asList(1L, 2L, 1L, null), notification); |
| 171 | 186 | ||
| @@ -187,12 +202,14 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | @@ -187,12 +202,14 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | ||
| 187 | .thenReturn(imWebSocketService); | 202 | .thenReturn(imWebSocketService); |
| 188 | 203 | ||
| 189 | // 准备:sender 抛异常 | 204 | // 准备:sender 抛异常 |
| 190 | - ImPrivateMessageDTO dto = new ImPrivateMessageDTO().setSenderId(1L).setReceiverId(2L); | 205 | + ImPrivateMessageNotification dto = new ImPrivateMessageNotification().setSenderId(1L).setReceiverId(2L) |
| 206 | + .setType(ImContentTypeEnum.TEXT.getType()); | ||
| 191 | doThrow(new RuntimeException("user offline")) | 207 | doThrow(new RuntimeException("user offline")) |
| 192 | .when(webSocketSenderApi).sendObject(anyInt(), anyLong(), anyString(), any()); | 208 | .when(webSocketSenderApi).sendObject(anyInt(), anyLong(), anyString(), any()); |
| 193 | 209 | ||
| 194 | // 调用:异常应被吞掉,不向上抛 | 210 | // 调用:异常应被吞掉,不向上抛 |
| 195 | - imWebSocketService.sendPrivateMessageAsync(2L, dto); | 211 | + imWebSocketService.sendNotificationAsync(2L, ImConversationTypeEnum.PRIVATE.getType(), |
| 212 | + ImContentTypeEnum.TEXT.getType(), dto); | ||
| 196 | 213 | ||
| 197 | verify(webSocketSenderApi).sendObject(anyInt(), eq(2L), anyString(), any()); | 214 | verify(webSocketSenderApi).sendObject(anyInt(), eq(2L), anyString(), any()); |
| 198 | } | 215 | } |
| @@ -206,12 +223,34 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | @@ -206,12 +223,34 @@ public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest { | ||
| 206 | 223 | ||
| 207 | ImGroupMessageNotification dto = new ImGroupMessageNotification(); | 224 | ImGroupMessageNotification dto = new ImGroupMessageNotification(); |
| 208 | dto.setGroupId(10L); | 225 | dto.setGroupId(10L); |
| 226 | + dto.setType(ImContentTypeEnum.TEXT.getType()); | ||
| 209 | 227 | ||
| 210 | - imWebSocketService.sendGroupMessageAsync(42L, dto); | 228 | + imWebSocketService.sendNotificationAsync(42L, ImConversationTypeEnum.GROUP.getType(), |
| 229 | + ImContentTypeEnum.TEXT.getType(), dto); | ||
| 211 | 230 | ||
| 212 | verify(webSocketSenderApi).sendObject( | 231 | verify(webSocketSenderApi).sendObject( |
| 213 | - eq(UserTypeEnum.ADMIN.getValue()), eq(42L), eq(ImGroupMessageDTO.TYPE), eq(dto)); | 232 | + eq(UserTypeEnum.ADMIN.getValue()), eq(42L), eq(ImNotificationWebSocketDTO.TYPE), |
| 233 | + argThat(actual -> isNotification(actual, ImConversationTypeEnum.GROUP, | ||
| 234 | + ImContentTypeEnum.TEXT, dto))); | ||
| 214 | } | 235 | } |
| 215 | } | 236 | } |
| 216 | 237 | ||
| 238 | + private static boolean isNotification(Object object, ImConversationTypeEnum conversationType, | ||
| 239 | + ImContentTypeEnum contentType, Object payload) { | ||
| 240 | + if (!(object instanceof ImNotificationWebSocketDTO notification)) { | ||
| 241 | + return false; | ||
| 242 | + } | ||
| 243 | + return conversationType.getType().equals(notification.getConversationType()) | ||
| 244 | + && contentType.getType().equals(notification.getContentType()) | ||
| 245 | + && payload == notification.getPayload(); | ||
| 246 | + } | ||
| 247 | + | ||
| 248 | + private static ImNotificationWebSocketDTO buildNotification(ImConversationTypeEnum conversationType, | ||
| 249 | + ImContentTypeEnum contentType, Object payload) { | ||
| 250 | + return new ImNotificationWebSocketDTO() | ||
| 251 | + .setConversationType(conversationType.getType()) | ||
| 252 | + .setContentType(contentType.getType()) | ||
| 253 | + .setPayload(payload); | ||
| 254 | + } | ||
| 255 | + | ||
| 217 | } | 256 | } |