From 9e63599dac8db804a6e4fa895ebd8cbea534c034 Mon Sep 17 00:00:00 2001 From: yanglin Date: Mon, 20 Jan 2025 19:25:16 +0800 Subject: [PATCH 001/201] REQ-3345: backup --- .../cn/axzo/im/center/api/feign/GroupApi.java | 31 ++++ .../center/api/vo/PersonAccountAttribute.java | 48 +++++- .../api/vo/mq/GroupMembersChangeMessage.java | 57 +++++++ .../axzo/im/center/api/vo/mq/MqMessage.java | 33 ++++ .../api/vo/req/GroupAddMembersRequest.java | 48 ++++++ .../center/api/vo/req/GroupCreateRequest.java | 92 ++++++++++ .../api/vo/req/GroupDismissRequest.java | 18 ++ .../api/vo/resp/GroupAddMembersResponse.java | 29 ++++ .../api/vo/resp/GroupCreateResponse.java | 30 ++++ .../im/center/common/enums/AppTypeEnum.java | 3 +- .../im/center/common/enums/GroupType.java | 27 +++ .../common/enums/NimFromClientType.java | 23 +++ .../center/common/enums/NimMessageType.java | 28 ++++ .../im/channel/netease/client/NimClient.java | 70 ++++---- .../netease/dto/DismissGroupResponse.java | 13 -- .../netease/dto/GetGroupInfoResponse.java | 16 -- ... => NimBatchSendCustomMessageRequest.java} | 2 +- ...=> NimBatchSendCustomMessageResponse.java} | 2 +- ...est.java => NimGetAccountInfoRequest.java} | 4 +- ...se.java => NimGetAccountInfoResponse.java} | 2 +- .../dto/NimGroupAddMembersRequest.java | 34 ++++ .../dto/NimGroupAddMembersResponse.java | 22 +++ .../netease/dto/NimGroupCreateRequest.java | 116 +++++++++++++ .../netease/dto/NimGroupCreateResponse.java | 32 ++++ ...quest.java => NimGroupDismissRequest.java} | 4 +- .../netease/dto/NimGroupDismissResponse.java | 22 +++ ...quest.java => NimGroupGetInfoRequest.java} | 9 +- .../netease/dto/NimGroupGetInfoResponse.java | 25 +++ .../im/channel/netease/dto/NimGroupInfo.java | 31 ++++ .../netease/dto/NimGroupMemberInfo.java | 32 ++++ ...Request.java => NimQueryEventRequest.java} | 2 +- ...sponse.java => NimQueryEventResponse.java} | 2 +- ...quest.java => NimQueryMessageRequest.java} | 2 +- ...onse.java => NimQueryMessageResponse.java} | 3 +- ...quest.java => NimRefreshTokenRequest.java} | 2 +- ...onse.java => NimRefreshTokenResponse.java} | 2 +- ...uest.java => NimRevokeMessageRequest.java} | 2 +- ....java => NimSendCustomMessageRequest.java} | 2 +- ...java => NimSendCustomMessageResponse.java} | 2 +- ....java => NimUpdateAccountInfoRequest.java} | 2 +- ...java => NimUpdateAccountInfoResponse.java} | 2 +- .../axzo/im/controller/PrivateController.java | 20 +-- .../im/dao/mapper/GroupAccountMapper.java | 10 ++ .../cn/axzo/im/dao/mapper/GroupMapper.java | 10 ++ .../im/dao/mapper/GroupMessageMapper.java | 10 ++ .../im/dao/repository/GroupAccountDao.java | 28 ++++ .../cn/axzo/im/dao/repository/GroupDao.java | 55 ++++++ .../im/dao/repository/GroupMessageDao.java | 13 ++ .../main/java/cn/axzo/im/entity/Group.java | 55 ++++++ .../java/cn/axzo/im/entity/GroupAccount.java | 28 ++++ .../java/cn/axzo/im/entity/GroupMessage.java | 46 +++++ .../cn/axzo/im/event/inner/EventTypeEnum.java | 4 +- .../cn/axzo/im/group/GroupBroadcaster.java | 54 ++++++ .../cn/axzo/im/group/GroupController.java | 40 +++++ .../java/cn/axzo/im/group/GroupManager.java | 158 ++++++++++++++++++ .../java/cn/axzo/im/group/GroupSupport.java | 119 +++++++++++++ .../im/group/domain/GroupMembersDiff.java | 57 +++++++ ...PersonProfileAvatarUpdateEventHandler.java | 4 +- .../cn/axzo/im/job/RevokeAllMessagesJob.java | 6 +- .../im/job/UpdateImAccountPersonInfoJob.java | 18 +- .../java/cn/axzo/im/send/SendExecutor.java | 4 +- .../java/cn/axzo/im/send/SendManager.java | 4 +- .../send/handler/CustomSendBatchHandler.java | 8 +- .../im/send/handler/CustomSendOneHandler.java | 8 +- .../cn/axzo/im/service/AccountService.java | 65 ++++--- .../im/service/domain/PersonImAccounts.java | 65 +++++++ .../im/service/impl/ChatGroupServiceImpl.java | 12 ++ .../impl/MessageHistoryServiceImpl.java | 7 +- .../cn/axzo/im/updatable/RevokeService.java | 7 +- .../cn/axzo/im/utils/ImAccountParser.java | 32 ++++ .../channel/netease/client/NimClientTest.java | 6 +- .../cn/axzo/im/group/GroupManagerTest.java | 55 ++++++ 72 files changed, 1777 insertions(+), 157 deletions(-) create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupMembersChangeMessage.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/MqMessage.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupDismissRequest.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupAddMembersResponse.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupCreateResponse.java create mode 100644 im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupType.java create mode 100644 im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimFromClientType.java create mode 100644 im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimMessageType.java delete mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/DismissGroupResponse.java delete mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetGroupInfoResponse.java rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{BatchSendCustomMessageRequest.java => NimBatchSendCustomMessageRequest.java} (90%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{BatchSendCustomMessageResponse.java => NimBatchSendCustomMessageResponse.java} (84%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{GetAccountInfoRequest.java => NimGetAccountInfoRequest.java} (91%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{GetAccountInfoResponse.java => NimGetAccountInfoResponse.java} (94%) create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersRequest.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersResponse.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateResponse.java rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{DismissGroupRequest.java => NimGroupDismissRequest.java} (84%) create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupDismissResponse.java rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{GetGroupInfoRequest.java => NimGroupGetInfoRequest.java} (58%) create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetInfoResponse.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupMemberInfo.java rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{QueryEventRequest.java => NimQueryEventRequest.java} (97%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{QueryEventResponse.java => NimQueryEventResponse.java} (94%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{QueryMessageRequest.java => NimQueryMessageRequest.java} (98%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{QueryMessageResponse.java => NimQueryMessageResponse.java} (76%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{RefreshTokenRequest.java => NimRefreshTokenRequest.java} (89%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{RefreshTokenResponse.java => NimRefreshTokenResponse.java} (81%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{RevokeMessageRequest.java => NimRevokeMessageRequest.java} (94%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{SendCustomMessageRequest.java => NimSendCustomMessageRequest.java} (91%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{SendCustomMessageResponse.java => NimSendCustomMessageResponse.java} (80%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{UpdateAccountInfoRequest.java => NimUpdateAccountInfoRequest.java} (95%) rename im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/{UpdateAccountInfoResponse.java => NimUpdateAccountInfoResponse.java} (81%) create mode 100644 im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupAccountMapper.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapper.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMessageMapper.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupAccountDao.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/entity/Group.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/entity/GroupAccount.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/GroupController.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/domain/GroupMembersDiff.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/service/domain/PersonImAccounts.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java create mode 100644 im-center-server/src/test/java/cn/axzo/im/group/GroupManagerTest.java diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java new file mode 100644 index 0000000..10a5d17 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java @@ -0,0 +1,31 @@ +package cn.axzo.im.center.api.feign; + +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; +import cn.axzo.im.center.api.vo.req.GroupCreateRequest; +import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; +import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +/** + * @author yanglin + */ +@FeignClient(name = "im-center", url = "${axzo.service.im-center:http://im-center:8080}") +public interface GroupApi { + + String INTRODUCE_MESSAGE = "邀请您加入群聊"; + + @PostMapping("/api/im/group/createGroup") + ApiResult createGroup(@RequestBody @Validated GroupCreateRequest request); + + @PostMapping("/api/im/group/dismissGroup") + ApiResult dismissGroup(@RequestBody @Validated GroupDismissRequest request); + + @PostMapping("/api/im/group/addMembers") + ApiResult addMembers(@RequestBody @Validated GroupAddMembersRequest request); + +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java index 94aba2b..93a89f9 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java @@ -4,11 +4,12 @@ import cn.axzo.im.center.common.enums.AppTypeEnum; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; -import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import org.apache.commons.lang3.math.NumberUtils; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import java.util.Objects; /** * @author yanglin @@ -17,8 +18,6 @@ import javax.validation.constraints.NotNull; @Builder @AllArgsConstructor @NoArgsConstructor -// IMPORTANT: 不要删除这个注解, 避免@Data被@Setter, @Getter取代 -@EqualsAndHashCode public class PersonAccountAttribute { /** @@ -48,4 +47,45 @@ public class PersonAccountAttribute { @NotNull(message = "appType不能为空") private AppTypeEnum appType; -} + public static PersonAccountAttribute cmp(Long personId, Long ouId) { + return PersonAccountAttribute.builder() + .personId(String.valueOf(personId)) + .ouId(ouId) + .appType(AppTypeEnum.CMP) + .build(); + } + + public static PersonAccountAttribute cm(Long personId) { + return PersonAccountAttribute.builder() + .personId(String.valueOf(personId)) + .appType(AppTypeEnum.CM) + .build(); + } + + public Long personIdAsLong() { + if (NumberUtils.isDigits(personId)) + return Long.valueOf(personId); + return 0L; + } + + public Long ouIdOrDefault() { + return ouId == null ? 0L : ouId; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof PersonAccountAttribute)) return false; + PersonAccountAttribute that = (PersonAccountAttribute) o; + return Objects.equals(personId, that.personId) && Objects.equals(ouId, that.ouId) && appType == that.appType; + } + + @Override + public int hashCode() { + return Objects.hash(personId, ouId, appType); + } + + @Override + public String toString() { + return String.format("[personId:%s,ouId:%s,appType:%s]", personId, ouId, appType); + } +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupMembersChangeMessage.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupMembersChangeMessage.java new file mode 100644 index 0000000..0a98b5f --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupMembersChangeMessage.java @@ -0,0 +1,57 @@ +package cn.axzo.im.center.api.vo.mq; + +import cn.axzo.im.center.common.enums.AppTypeEnum; +import cn.axzo.im.center.common.enums.GroupType; +import cn.axzo.im.center.common.enums.YesOrNo; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * @author yanglin + */ +@Setter @Getter +public class GroupMembersChangeMessage extends MqMessage { + + /** + * 群信息 + */ + private GroupInfo groupInfo; + + /** + * 账号信息 + */ + private AccountInfo account; + + @Setter @Getter + public static class GroupInfo { + private Long id; + private Long tid; + private String name; + private String bizCode; + private GroupType type; + private String avatar; + private Long memberCount; + private Long memberLimit; + private String ownerAccount; + private Long ownerPersonId; + private Long createPersonId; + private YesOrNo isDismissed; + private Date createAt; + private Date updateAt; + } + + @Setter @Getter + public static class AccountInfo { + private Long id; + private Long tid; + private String imAccount; + private Long personId; + private Long personOuId; + private AppTypeEnum appType; + private YesOrNo isRobot; + private Date createAt; + private Date updateAt; + } +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/MqMessage.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/MqMessage.java new file mode 100644 index 0000000..60a4b57 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/MqMessage.java @@ -0,0 +1,33 @@ +package cn.axzo.im.center.api.vo.mq; + +import cn.hutool.core.lang.UUID; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @author yanglin + */ +@Setter +@Getter +public abstract class MqMessage implements Serializable { + + /** + * 消息唯一id + */ + private String messageId = UUID.randomUUID().toString(); + + /** + * 消息发送时间 + */ + private Date messageSendTime = new Date(); + + /** + * 消息发送时间, 字符串格式 + */ + private String messageSendTimeStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(messageSendTime); + +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java new file mode 100644 index 0000000..41a7f2c --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java @@ -0,0 +1,48 @@ +package cn.axzo.im.center.api.vo.req; + +import cn.axzo.im.center.api.feign.GroupApi; +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import com.alibaba.fastjson.JSON; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.HashSet; +import java.util.Set; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupAddMembersRequest { + + @NotNull(message = "群ID不能为空") + private Long tid; + + /** + * 邀请发送的文字,最大长度 150 位字符 + */ + @NotBlank(message = "邀请发送的文字不能为空") + private String introduceMessage = GroupApi.INTRODUCE_MESSAGE; + + /** + * 群成员, 不包含群主. members数量不能超过199 + */ + @NotEmpty(message = "群成员不能为空") + private Set members; + + public void addMember(PersonAccountAttribute member) { + if (members == null) + members = new HashSet<>(); + members.add(member); + } + + @Override + public String toString() { + return JSON.toJSONString(this); + } + +} diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java new file mode 100644 index 0000000..3ee64ad --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java @@ -0,0 +1,92 @@ +package cn.axzo.im.center.api.vo.req; + +import cn.axzo.im.center.api.feign.GroupApi; +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.common.enums.GroupType; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.HashSet; +import java.util.Set; + +/** + * @author yanglin + */ +@Setter @Getter +public class GroupCreateRequest { + + /** + * 群类型. groupType和bizCode一起做幂等控制 + */ + @NotNull(message = "群类型不能为空") + private GroupType groupType; + + /** + * 业务编码. groupType和bizCode一起做幂等控制 + */ + @NotBlank(message = "业务码不能为空") + private String bizCode; + + /** + * 群名称 + */ + @NotBlank(message = "群名称不能为空") + private String name; + + /** + * 群主账号 + */ + @NotNull(message = "群主账号不能为空") + private PersonAccountAttribute owner; + + /** + * 群成员, 不包含群主. members数量不能超过199 + */ + @NotEmpty(message = "群成员不能为空") + private Set members; + + /** + * 群成员上限 + */ + private Long memberLimit; + + /** + * 邀请发送的文字,最大长度 150 位字符 + */ + @NotBlank(message = "邀请发送的文字不能为空") + private String introduceMessage = GroupApi.INTRODUCE_MESSAGE; + + /** + * 群头像,最大长度 1024 位字符 + */ + private String avatar; + + @JSONField(serialize = false, deserialize = false) + public Set getOwnerAndMembers() { + Set ownerAndMembers = new HashSet<>(members); + ownerAndMembers.add(owner); + return ownerAndMembers; + } + + public void addMembers(Set members) { + if (this.members == null) + this.members = new HashSet<>(); + this.members.addAll(members); + } + + public void addMember(PersonAccountAttribute member) { + if (members == null) + members = new HashSet<>(); + members.add(member); + } + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupDismissRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupDismissRequest.java new file mode 100644 index 0000000..ad4a721 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupDismissRequest.java @@ -0,0 +1,18 @@ +package cn.axzo.im.center.api.vo.req; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotNull; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupDismissRequest { + + @NotNull(message = "群id不能为空") + private Long tid; + +} diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupAddMembersResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupAddMembersResponse.java new file mode 100644 index 0000000..634f693 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupAddMembersResponse.java @@ -0,0 +1,29 @@ +package cn.axzo.im.center.api.vo.resp; + +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.Getter; +import lombok.Setter; + +import java.util.Set; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupAddMembersResponse { + + /** + * 未找到IM账号的列表 + */ + private Set accountsNotFound; + + private JSONObject faccid; + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupCreateResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupCreateResponse.java new file mode 100644 index 0000000..3b8ea8c --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupCreateResponse.java @@ -0,0 +1,30 @@ +package cn.axzo.im.center.api.vo.resp; + +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import com.alibaba.fastjson.JSON; +import lombok.Getter; +import lombok.Setter; + +import java.util.Set; + +/** + * @author yanglin + */ +@Setter @Getter +public class GroupCreateResponse { + + /** + * 群id + */ + private Long tid; + + /** + * 未找到IM账号的列表 + */ + private Set accountsNotFound; + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} \ No newline at end of file diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java index 45280df..92fa644 100644 --- a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java @@ -1,6 +1,7 @@ package cn.axzo.im.center.common.enums; import cn.axzo.basics.common.constant.enums.CodeDefinition; +import com.baomidou.mybatisplus.annotation.EnumValue; import lombok.Getter; import org.apache.commons.lang3.StringUtils; @@ -28,7 +29,7 @@ public enum AppTypeEnum implements CodeDefinition { */ SYSTEM("system", "服务器"); - + @EnumValue private final String code; private final String message; diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupType.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupType.java new file mode 100644 index 0000000..a021eed --- /dev/null +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupType.java @@ -0,0 +1,27 @@ +package cn.axzo.im.center.common.enums; + +import cn.axzo.basics.common.constant.enums.CodeDefinition; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * @author yanglin + */ +@Getter +@RequiredArgsConstructor +public enum GroupType implements CodeDefinition { + NONE("随意"), + VISA("变洽签"), + WORKSPACE("项目群"), + WORKSPACE_OU("项目单位群"), + WORKSPACE_TEAM("项目班组群"), + ; + + private final String description; + + @Override + public String getCode() { + return name(); + } + +} \ No newline at end of file diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimFromClientType.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimFromClientType.java new file mode 100644 index 0000000..7644dc0 --- /dev/null +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimFromClientType.java @@ -0,0 +1,23 @@ +package cn.axzo.im.center.common.enums; + +import cn.axzo.basics.common.constant.enums.CodeDefinition; +import lombok.RequiredArgsConstructor; + +/** + * @author yanglin + */ +@RequiredArgsConstructor +public enum NimFromClientType implements CodeDefinition { + ANDROID, + IOS, + PC, + WEB, + REST, + MAC + ; + + @Override + public String getCode() { + return name(); + } +} diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimMessageType.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimMessageType.java new file mode 100644 index 0000000..a61de1e --- /dev/null +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimMessageType.java @@ -0,0 +1,28 @@ +package cn.axzo.im.center.common.enums; + +import cn.axzo.basics.common.constant.enums.CodeDefinition; +import lombok.RequiredArgsConstructor; + +/** + * @author yanglin + */ +@RequiredArgsConstructor +public enum NimMessageType implements CodeDefinition { + TEXT("文本"), + IMAGE("图片"), + SPEECH("语音"), + VIDEO("视频"), + POSITION("地理位置"), + FILE("文件"), + CUSTOM("第三方自定义消息"), + GROUP_NOTIFICATION("群通知"), + CHAT_GROUP_NOTIFICATION("聊天室通知"), + ; + + private final String description; + + @Override + public String getCode() { + return name(); + } +} diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java index c99ebdf..6bc6a17 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java @@ -1,24 +1,28 @@ package cn.axzo.im.channel.netease.client; -import cn.axzo.im.channel.netease.dto.BatchSendCustomMessageRequest; -import cn.axzo.im.channel.netease.dto.BatchSendCustomMessageResponse; -import cn.axzo.im.channel.netease.dto.DismissGroupRequest; -import cn.axzo.im.channel.netease.dto.DismissGroupResponse; -import cn.axzo.im.channel.netease.dto.GetAccountInfoRequest; -import cn.axzo.im.channel.netease.dto.GetAccountInfoResponse; -import cn.axzo.im.channel.netease.dto.GetGroupInfoRequest; -import cn.axzo.im.channel.netease.dto.GetGroupInfoResponse; -import cn.axzo.im.channel.netease.dto.QueryEventRequest; -import cn.axzo.im.channel.netease.dto.QueryEventResponse; -import cn.axzo.im.channel.netease.dto.QueryMessageRequest; -import cn.axzo.im.channel.netease.dto.QueryMessageResponse; -import cn.axzo.im.channel.netease.dto.RefreshTokenRequest; -import cn.axzo.im.channel.netease.dto.RefreshTokenResponse; -import cn.axzo.im.channel.netease.dto.RevokeMessageRequest; -import cn.axzo.im.channel.netease.dto.SendCustomMessageRequest; -import cn.axzo.im.channel.netease.dto.SendCustomMessageResponse; -import cn.axzo.im.channel.netease.dto.UpdateAccountInfoRequest; -import cn.axzo.im.channel.netease.dto.UpdateAccountInfoResponse; +import cn.axzo.im.channel.netease.dto.NimBatchSendCustomMessageRequest; +import cn.axzo.im.channel.netease.dto.NimBatchSendCustomMessageResponse; +import cn.axzo.im.channel.netease.dto.NimGetAccountInfoRequest; +import cn.axzo.im.channel.netease.dto.NimGetAccountInfoResponse; +import cn.axzo.im.channel.netease.dto.NimGroupAddMembersRequest; +import cn.axzo.im.channel.netease.dto.NimGroupAddMembersResponse; +import cn.axzo.im.channel.netease.dto.NimGroupCreateRequest; +import cn.axzo.im.channel.netease.dto.NimGroupCreateResponse; +import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; +import cn.axzo.im.channel.netease.dto.NimGroupDismissResponse; +import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; +import cn.axzo.im.channel.netease.dto.NimGroupGetInfoResponse; +import cn.axzo.im.channel.netease.dto.NimQueryEventRequest; +import cn.axzo.im.channel.netease.dto.NimQueryEventResponse; +import cn.axzo.im.channel.netease.dto.NimQueryMessageRequest; +import cn.axzo.im.channel.netease.dto.NimQueryMessageResponse; +import cn.axzo.im.channel.netease.dto.NimRefreshTokenRequest; +import cn.axzo.im.channel.netease.dto.NimRefreshTokenResponse; +import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; +import cn.axzo.im.channel.netease.dto.NimSendCustomMessageRequest; +import cn.axzo.im.channel.netease.dto.NimSendCustomMessageResponse; +import cn.axzo.im.channel.netease.dto.NimUpdateAccountInfoRequest; +import cn.axzo.im.channel.netease.dto.NimUpdateAccountInfoResponse; import lombok.Data; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; @@ -37,37 +41,43 @@ public interface NimClient { String URL = "https://api.netease.im/nimserver"; @PostMapping(value = "/msg/delMsgOneWay.action") - CodeResponse revoke(RevokeMessageRequest request); + NimCodeResponse revoke(NimRevokeMessageRequest request); @PostMapping(value = "/history/queryUserEvents.action") - QueryEventResponse queryEvents(QueryEventRequest request); + NimQueryEventResponse queryEvents(NimQueryEventRequest request); @PostMapping(value = "/history/querySessionMsg.action") - QueryMessageResponse queryMessages(QueryMessageRequest request); + NimQueryMessageResponse queryMessages(NimQueryMessageRequest request); @PostMapping(value = "/user/refreshToken.action") - RefreshTokenResponse refreshToken(RefreshTokenRequest request); + NimRefreshTokenResponse refreshToken(NimRefreshTokenRequest request); @PostMapping(value = "/msg/sendAttachMsg.action") - SendCustomMessageResponse sendCustomMessage(SendCustomMessageRequest request); + NimSendCustomMessageResponse sendCustomMessage(NimSendCustomMessageRequest request); @PostMapping(value = "/msg/sendBatchAttachMsg.action") - BatchSendCustomMessageResponse batchSendCustomMessage(BatchSendCustomMessageRequest request); + NimBatchSendCustomMessageResponse batchSendCustomMessage(NimBatchSendCustomMessageRequest request); @PostMapping(value = "/user/getUinfos.action") - GetAccountInfoResponse getAccountInfo(GetAccountInfoRequest request); + NimGetAccountInfoResponse getAccountInfo(NimGetAccountInfoRequest request); @PostMapping(value = "/user/updateUinfo.action") - UpdateAccountInfoResponse updateAccountInfo(UpdateAccountInfoRequest request); + NimUpdateAccountInfoResponse updateAccountInfo(NimUpdateAccountInfoRequest request); @PostMapping(value = "/team/remove.action") - DismissGroupResponse dismissGroup(DismissGroupRequest request); + NimGroupDismissResponse dismissGroup(NimGroupDismissRequest request); @PostMapping(value = "/team/queryDetail.action") - GetGroupInfoResponse getGroupInfo(GetGroupInfoRequest request); + NimGroupGetInfoResponse getGroupInfo(NimGroupGetInfoRequest request); + + @PostMapping(value = "/team/create.action") + NimGroupCreateResponse createGroup(NimGroupCreateRequest request); + + @PostMapping(value = "/team/add.action") + NimGroupAddMembersResponse addMembers(NimGroupAddMembersRequest request); @Data - class CodeResponse { + class NimCodeResponse { private Integer code; private String desc; private int size; diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/DismissGroupResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/DismissGroupResponse.java deleted file mode 100644 index cfe6047..0000000 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/DismissGroupResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.axzo.im.channel.netease.dto; - -import cn.axzo.im.channel.netease.client.NimClient; -import lombok.Getter; -import lombok.Setter; - -/** - * @author yanglin - */ -@Setter -@Getter -public class DismissGroupResponse extends NimClient.CodeResponse { -} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetGroupInfoResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetGroupInfoResponse.java deleted file mode 100644 index bd904ac..0000000 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetGroupInfoResponse.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.axzo.im.channel.netease.dto; - -import cn.axzo.im.channel.netease.client.NimClient; -import lombok.Getter; -import lombok.Setter; - -/** - * @author yanglin - */ -@Setter -@Getter -public class GetGroupInfoResponse extends NimClient.CodeResponse { - - private Object tinfo; - -} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/BatchSendCustomMessageRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimBatchSendCustomMessageRequest.java similarity index 90% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/BatchSendCustomMessageRequest.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimBatchSendCustomMessageRequest.java index 9dd9a85..1696ba6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/BatchSendCustomMessageRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimBatchSendCustomMessageRequest.java @@ -9,7 +9,7 @@ import lombok.Data; */ @Data @FormRequest -public class BatchSendCustomMessageRequest implements CustomPushRequest { +public class NimBatchSendCustomMessageRequest implements CustomPushRequest { @JSONField(name = "fromAccid") private String fromAccount; // ["aaa","bbb"] diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/BatchSendCustomMessageResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimBatchSendCustomMessageResponse.java similarity index 84% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/BatchSendCustomMessageResponse.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimBatchSendCustomMessageResponse.java index 08eefb6..8d004fc 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/BatchSendCustomMessageResponse.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimBatchSendCustomMessageResponse.java @@ -13,7 +13,7 @@ import java.util.Set; */ @Setter @Getter -public class BatchSendCustomMessageResponse extends NimClient.CodeResponse { +public class NimBatchSendCustomMessageResponse extends NimClient.NimCodeResponse { private String desc; private Set unregister = Collections.emptySet(); diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetAccountInfoRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGetAccountInfoRequest.java similarity index 91% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetAccountInfoRequest.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGetAccountInfoRequest.java index 1a39e39..b242840 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetAccountInfoRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGetAccountInfoRequest.java @@ -3,10 +3,8 @@ package cn.axzo.im.channel.netease.dto; import cn.axzo.im.channel.netease.client.FormRequest; import com.alibaba.excel.util.StringUtils; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.annotation.JSONField; import lombok.Data; -import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -15,7 +13,7 @@ import java.util.List; */ @Data @FormRequest -public class GetAccountInfoRequest { +public class NimGetAccountInfoRequest { /** * 用户帐号 ID 列表,例如:["id1", "id2", "id3"]。格式错误会返回 414 参数错误。 diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetAccountInfoResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGetAccountInfoResponse.java similarity index 94% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetAccountInfoResponse.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGetAccountInfoResponse.java index 718d005..f9c61a7 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetAccountInfoResponse.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGetAccountInfoResponse.java @@ -15,7 +15,7 @@ import java.util.Optional; */ @Setter @Getter -public class GetAccountInfoResponse extends NimClient.CodeResponse { +public class NimGetAccountInfoResponse extends NimClient.NimCodeResponse { private List uinfos; diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersRequest.java new file mode 100644 index 0000000..6924b90 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersRequest.java @@ -0,0 +1,34 @@ +package cn.axzo.im.channel.netease.dto; + +import cn.axzo.im.channel.netease.client.FormRequest; +import com.alibaba.fastjson.JSON; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collection; + +/** + * @author yanglin + */ +@Data +@FormRequest +public class NimGroupAddMembersRequest { + + private Long tid; + private String owner; + private String members; + private String msg; + + public void addMembers(Collection members) { + if (StringUtils.isBlank(this.members)) + this.members = "[]"; + this.members = JSON.parseArray(this.members) + .fluentAddAll(members) + .toJSONString(); + } + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersResponse.java new file mode 100644 index 0000000..8ff16dc --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersResponse.java @@ -0,0 +1,22 @@ +package cn.axzo.im.channel.netease.dto; + +import cn.axzo.im.channel.netease.client.NimClient; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class NimGroupAddMembersResponse extends NimClient.NimCodeResponse { + + private JSONObject faccid; + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java new file mode 100644 index 0000000..0097886 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java @@ -0,0 +1,116 @@ +package cn.axzo.im.channel.netease.dto; + +import cn.axzo.im.channel.netease.client.FormRequest; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collection; + +/** + * @author yanglin + */ +@Data +@FormRequest +public class NimGroupCreateRequest { + + /** + * 群名称,最大长度 64 位字符 + */ + @JSONField(name = "tname") + private String name; + + /** + * 群主账号,accid,最大长度 32 位字符 + */ + private String owner; + + /** + * 邀请的群成员列表,\["aaa","bbb"\](JSONArray 对应的 accid,如果解析出错会报 414) + * members 与 owner 总和上限为 200。members 中无需再加 owner 自己的账号 + */ + private String members; + + /** + * 群描述,最大长度 512 位字符 + */ + @JSONField(name = "intro") + private String description; + + /** + * 邀请发送的文字,最大长度 150 位字符 + */ + @JSONField(name = "msg") + private String introduceMessage; + + /** + * 创建群时,若 members 不为空,那么邀请其入群是否需要同意 + * 0: 不需要被邀请人同意加入群(默认) + * 1: 需要被邀请人同意才可以加入群 + * 只有当 beinvitemode = 0 时,magree 才能设为 1,即 时,magree =1 才生效。 + */ + @JSONField(name = "magree") + private Integer memberAgree; + + /** + * 群创建完成后,通过 SDK 侧操作申请入群的验证方式 + * 0: 不用验证 + * 1: 需要群主或管理员的验证 + * 2: 不允许任何人加入 + */ + @JSONField(name = "joinmode") + private Integer joinMode = 0; + + /** + * 自定义高级群扩展属性,第三方可以跟据此属性自定义扩展自己的群属性,建议为 JSON,最大长度 1024 位字符 + */ + private String custom; + + /** + * 群头像,最大长度 1024 位字符 + */ + private String icon; + + /** + * 群创建完成后,邀请入群时是否需要被邀请人的同意 + * 0: 需要同意(默认) + * 1: 不需要同意 + */ + @JSONField(name = "beinvitemode") + private Integer beInviteMode = 1; + + /** + * 邀请权限,即谁可以邀请他人入群 + * 0: 群主和管理员(默认) + * 1: 所有人 + */ + @JSONField(name = "invitemode") + private Integer inviteMode = 1; + + /** + * 自定义扩展字段,最大长度 512 位字符 + */ + private String attach; + + public void addMembers(Collection members) { + if (StringUtils.isBlank(this.members)) + this.members = "[]"; + this.members = JSON.parseArray(this.members) + .fluentAddAll(members) + .toJSONString(); + } + + public void addAttachment(String key, Object value) { + if (StringUtils.isBlank(this.attach)) + this.attach = "{}"; + this.attach = JSON.parseObject(this.attach) + .fluentPut(key, value) + .toJSONString(); + } + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateResponse.java new file mode 100644 index 0000000..fcd9fe6 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateResponse.java @@ -0,0 +1,32 @@ +package cn.axzo.im.channel.netease.dto; + +import cn.axzo.im.channel.netease.client.NimClient; +import com.alibaba.fastjson.JSON; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * @author yanglin + */ +@Setter +@Getter +public class NimGroupCreateResponse extends NimClient.NimCodeResponse { + + /** + * 群id + */ + private Long tid; + + /** + * 入群失败的账号(accid)列表 + * 如果创建时邀请的成员中存在加群数量超过限制的情况,会返回入群失败的 accid 以及附言(msg) + */ + private List faccid; + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/DismissGroupRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupDismissRequest.java similarity index 84% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/DismissGroupRequest.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupDismissRequest.java index ecd14f0..6e09ff6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/DismissGroupRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupDismissRequest.java @@ -10,9 +10,9 @@ import javax.validation.constraints.NotBlank; */ @Data @FormRequest -public class DismissGroupRequest { +public class NimGroupDismissRequest { @NotBlank(message = "群id不能为空") - private String tid; + private Long tid; @NotBlank(message = "群主id不能为空") private String owner; } diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupDismissResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupDismissResponse.java new file mode 100644 index 0000000..1a63451 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupDismissResponse.java @@ -0,0 +1,22 @@ +package cn.axzo.im.channel.netease.dto; + +import cn.axzo.im.channel.netease.client.NimClient; +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class NimGroupDismissResponse extends NimClient.NimCodeResponse { + + public boolean isNotGroupOwnerError() { + return getCode() == 403; + } + + public boolean isGroupNotFoundError() { + return getCode() == 803; + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetGroupInfoRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetInfoRequest.java similarity index 58% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetGroupInfoRequest.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetInfoRequest.java index 4ccd917..74a9da3 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GetGroupInfoRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetInfoRequest.java @@ -1,6 +1,7 @@ package cn.axzo.im.channel.netease.dto; import cn.axzo.im.channel.netease.client.FormRequest; +import com.alibaba.fastjson.JSON; import lombok.Data; import javax.validation.constraints.NotBlank; @@ -10,9 +11,13 @@ import javax.validation.constraints.NotBlank; */ @Data @FormRequest -public class GetGroupInfoRequest { +public class NimGroupGetInfoRequest { @NotBlank(message = "群id不能为空") - private String tid; + private Long tid; + @Override + public String toString() { + return JSON.toJSONString(this); + } } diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetInfoResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetInfoResponse.java new file mode 100644 index 0000000..ac4ad2e --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetInfoResponse.java @@ -0,0 +1,25 @@ +package cn.axzo.im.channel.netease.dto; + +import cn.axzo.im.channel.netease.client.NimClient; +import com.alibaba.fastjson.JSON; +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class NimGroupGetInfoResponse extends NimClient.NimCodeResponse { + + private NimGroupInfo tinfo; + + public boolean isGroupNotFoundError() { + return getCode() == 414; + } + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java new file mode 100644 index 0000000..f6b063b --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java @@ -0,0 +1,31 @@ +package cn.axzo.im.channel.netease.dto; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Getter; +import lombok.Setter; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author yanglin + */ +@Setter +@Getter +public class NimGroupInfo { + + private NimGroupMemberInfo owner; + private Set members; + + @JSONField(serialize = false, deserialize = false) + public Set getOwnerAndMembers() { + HashSet ownerAndMembers = new HashSet<>(members); + ownerAndMembers.add(owner); + return ownerAndMembers; + } + + public int memberCount() { + return getOwnerAndMembers().size(); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupMemberInfo.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupMemberInfo.java new file mode 100644 index 0000000..116c66f --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupMemberInfo.java @@ -0,0 +1,32 @@ +package cn.axzo.im.channel.netease.dto; + +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; +import java.util.Objects; + +/** + * @author yanglin + */ +@Setter +@Getter +public class NimGroupMemberInfo { + private String nick; + private Date createtime; + private Date updatetime; + private String accid; + private boolean mute; + + @Override + public boolean equals(Object o) { + if (!(o instanceof NimGroupMemberInfo)) return false; + NimGroupMemberInfo that = (NimGroupMemberInfo) o; + return Objects.equals(accid, that.accid); + } + + @Override + public int hashCode() { + return Objects.hashCode(accid); + } +} diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryEventRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryEventRequest.java similarity index 97% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryEventRequest.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryEventRequest.java index 0e42448..02b3fab 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryEventRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryEventRequest.java @@ -14,7 +14,7 @@ import java.text.SimpleDateFormat; */ @Data @FormRequest -public class QueryEventRequest { +public class NimQueryEventRequest { // 要查询用户的accid @JSONField(name = "accid") @NotBlank diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryEventResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryEventResponse.java similarity index 94% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryEventResponse.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryEventResponse.java index 85caf45..33a4bdf 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryEventResponse.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryEventResponse.java @@ -11,7 +11,7 @@ import java.util.List; */ @Setter @Getter -public class QueryEventResponse extends NimClient.CodeResponse { +public class NimQueryEventResponse extends NimClient.NimCodeResponse { // 总共记录数 private int size; private List events; diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryMessageRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryMessageRequest.java similarity index 98% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryMessageRequest.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryMessageRequest.java index a36147b..985f124 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryMessageRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryMessageRequest.java @@ -14,7 +14,7 @@ import java.text.SimpleDateFormat; */ @Data @FormRequest -public class QueryMessageRequest { +public class NimQueryMessageRequest { // 发送者accid @NotBlank private String from; diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryMessageResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryMessageResponse.java similarity index 76% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryMessageResponse.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryMessageResponse.java index 4f0fe4b..cc57074 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/QueryMessageResponse.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimQueryMessageResponse.java @@ -1,7 +1,6 @@ package cn.axzo.im.channel.netease.dto; import cn.axzo.im.channel.netease.client.NimClient; -import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -13,7 +12,7 @@ import java.util.Map; */ @Setter @Getter -public class QueryMessageResponse extends NimClient.CodeResponse { +public class NimQueryMessageResponse extends NimClient.NimCodeResponse { // 消息集合 private List> msgs; } diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/RefreshTokenRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimRefreshTokenRequest.java similarity index 89% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/RefreshTokenRequest.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimRefreshTokenRequest.java index baa6d88..e5002a7 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/RefreshTokenRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimRefreshTokenRequest.java @@ -11,7 +11,7 @@ import javax.validation.constraints.NotBlank; */ @Data @FormRequest -public class RefreshTokenRequest { +public class NimRefreshTokenRequest { @NotBlank @JSONField(name = "accid") private String accid; diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/RefreshTokenResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimRefreshTokenResponse.java similarity index 81% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/RefreshTokenResponse.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimRefreshTokenResponse.java index 222feff..f06ec3c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/RefreshTokenResponse.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimRefreshTokenResponse.java @@ -10,7 +10,7 @@ import lombok.Setter; */ @Setter @Getter -public class RefreshTokenResponse extends NimClient.CodeResponse { +public class NimRefreshTokenResponse extends NimClient.NimCodeResponse { private Info info; diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/RevokeMessageRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimRevokeMessageRequest.java similarity index 94% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/RevokeMessageRequest.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimRevokeMessageRequest.java index f586542..26f4b0f 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/RevokeMessageRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimRevokeMessageRequest.java @@ -9,7 +9,7 @@ import lombok.Data; */ @Data @FormRequest -public class RevokeMessageRequest { +public class NimRevokeMessageRequest { @JSONField(name = "deleteMsgid") private String messageId; // 消息发送者的云信 IM 账号(accid) diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/SendCustomMessageRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimSendCustomMessageRequest.java similarity index 91% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/SendCustomMessageRequest.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimSendCustomMessageRequest.java index fea09df..e5d7d90 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/SendCustomMessageRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimSendCustomMessageRequest.java @@ -9,7 +9,7 @@ import lombok.Data; */ @Data @FormRequest -public class SendCustomMessageRequest implements CustomPushRequest { +public class NimSendCustomMessageRequest implements CustomPushRequest { @JSONField(name = "from") private String fromAccount; @JSONField(name = "to") diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/SendCustomMessageResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimSendCustomMessageResponse.java similarity index 80% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/SendCustomMessageResponse.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimSendCustomMessageResponse.java index 4219bab..3b42d2b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/SendCustomMessageResponse.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimSendCustomMessageResponse.java @@ -10,7 +10,7 @@ import lombok.Setter; */ @Setter @Getter -public class SendCustomMessageResponse extends NimClient.CodeResponse { +public class NimSendCustomMessageResponse extends NimClient.NimCodeResponse { private String desc; diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/UpdateAccountInfoRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimUpdateAccountInfoRequest.java similarity index 95% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/UpdateAccountInfoRequest.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimUpdateAccountInfoRequest.java index b0d594d..2b85d95 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/UpdateAccountInfoRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimUpdateAccountInfoRequest.java @@ -11,7 +11,7 @@ import lombok.Data; */ @Data @FormRequest -public class UpdateAccountInfoRequest { +public class NimUpdateAccountInfoRequest { @JSONField(name = "accid") private String imAccountId; diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/UpdateAccountInfoResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimUpdateAccountInfoResponse.java similarity index 81% rename from im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/UpdateAccountInfoResponse.java rename to im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimUpdateAccountInfoResponse.java index 7c8914e..81cf8bc 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/UpdateAccountInfoResponse.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimUpdateAccountInfoResponse.java @@ -10,7 +10,7 @@ import lombok.Setter; */ @Setter @Getter -public class UpdateAccountInfoResponse extends NimClient.CodeResponse { +public class NimUpdateAccountInfoResponse extends NimClient.NimCodeResponse { private NimAccountInfo info; @Override diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java index 3f87251..dab47ef 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java @@ -2,11 +2,11 @@ package cn.axzo.im.controller; import cn.axzo.im.center.api.vo.req.SendMessageParam; import cn.axzo.im.channel.netease.client.NimClient; -import cn.axzo.im.channel.netease.dto.DismissGroupRequest; -import cn.axzo.im.channel.netease.dto.GetGroupInfoRequest; -import cn.axzo.im.channel.netease.dto.QueryEventRequest; -import cn.axzo.im.channel.netease.dto.QueryMessageRequest; -import cn.axzo.im.channel.netease.dto.RevokeMessageRequest; +import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; +import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; +import cn.axzo.im.channel.netease.dto.NimQueryEventRequest; +import cn.axzo.im.channel.netease.dto.NimQueryMessageRequest; +import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; import cn.axzo.im.job.CreateMessageHistoryJob; import cn.axzo.im.job.ExpungeImTaskJob; import cn.axzo.im.job.RevokeAllMessagesJob; @@ -36,17 +36,17 @@ public class PrivateController { private final ExpungeImTaskJob expungeImTaskJob; @PostMapping("/private/revoke") - public Object revoke(@Valid @RequestBody RevokeMessageRequest request) { + public Object revoke(@Valid @RequestBody NimRevokeMessageRequest request) { return nimClient.revoke(request); } @PostMapping("/private/queryEvents") - public Object queryEvents(@Valid @RequestBody QueryEventRequest request) { + public Object queryEvents(@Valid @RequestBody NimQueryEventRequest request) { return nimClient.queryEvents(request); } @PostMapping("/private/queryMessages") - public Object queryMessages(@Valid @RequestBody QueryMessageRequest request) { + public Object queryMessages(@Valid @RequestBody NimQueryMessageRequest request) { return nimClient.queryMessages(request); } @@ -77,12 +77,12 @@ public class PrivateController { } @PostMapping("/private/group/dismissGroup") - public Object dismissGroup(@Valid @RequestBody DismissGroupRequest request) { + public Object dismissGroup(@Valid @RequestBody NimGroupDismissRequest request) { return CommonResponse.success(nimClient.dismissGroup(request)); } @PostMapping("/private/group/getGroupInfo") - public Object getGroupInfo(@Valid @RequestBody GetGroupInfoRequest request) { + public Object getGroupInfo(@Valid @RequestBody NimGroupGetInfoRequest request) { return CommonResponse.success(nimClient.getGroupInfo(request)); } diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupAccountMapper.java b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupAccountMapper.java new file mode 100644 index 0000000..ab253f1 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupAccountMapper.java @@ -0,0 +1,10 @@ +package cn.axzo.im.dao.mapper; + +import cn.axzo.im.entity.GroupAccount; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @author yanglin + */ +public interface GroupAccountMapper extends BaseMapper { +} diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapper.java b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapper.java new file mode 100644 index 0000000..2ce6df2 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapper.java @@ -0,0 +1,10 @@ +package cn.axzo.im.dao.mapper; + +import cn.axzo.im.entity.Group; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @author yanglin + */ +public interface GroupMapper extends BaseMapper { +} diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMessageMapper.java b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMessageMapper.java new file mode 100644 index 0000000..de5be8c --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMessageMapper.java @@ -0,0 +1,10 @@ +package cn.axzo.im.dao.mapper; + +import cn.axzo.im.entity.GroupMessage; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @author yanglin + */ +public interface GroupMessageMapper extends BaseMapper { +} diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupAccountDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupAccountDao.java new file mode 100644 index 0000000..b15ab1d --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupAccountDao.java @@ -0,0 +1,28 @@ +package cn.axzo.im.dao.repository; + +import cn.axzo.im.dao.mapper.GroupAccountMapper; +import cn.axzo.im.entity.GroupAccount; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @author yanglin + */ +@Repository("groupAccountDao") +public class GroupAccountDao extends ServiceImpl { + + public List getByTid(Long tid) { + return lambdaQuery() + .eq(GroupAccount::getTid, tid) + .list(); + } + + public void deleteAccounts(Long tid) { + lambdaUpdate() + .eq(GroupAccount::getTid, tid) + .remove(); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java new file mode 100644 index 0000000..8af7f1e --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java @@ -0,0 +1,55 @@ +package cn.axzo.im.dao.repository; + +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.common.enums.YesOrNo; +import cn.axzo.im.dao.mapper.GroupMapper; +import cn.axzo.im.entity.Group; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +/** + * @author yanglin + */ +@Repository("groupDao") +public class GroupDao extends ServiceImpl { + + public void updateMembersCount(Long tid, Integer count) { + lambdaUpdate() + .eq(Group::getTid, tid) + .set(Group::getMemberCount, count) + .update(); + } + + public void updateOwner(Long tid, String imAccount, PersonAccountAttribute person) { + lambdaUpdate() + .eq(Group::getTid, tid) + .set(Group::getOwnerAccount, imAccount) + .set(Group::getOwnerPersonId, person.getPersonId()) + .update(); + } + + public void updateTid(Long id, Long tid) { + lambdaUpdate() + .eq(Group::getId, id) + .set(Group::getTid, tid) + .update(); + } + + public Optional findByTid(Long tid, boolean forUpdate) { + Group group = lambdaQuery() + .eq(Group::getTid, tid) + .last(forUpdate, "FOR UPDATE") + .one(); + return Optional.ofNullable(group); + } + + public void setDismissed(Long tid) { + lambdaUpdate() + .eq(Group::getTid, tid) + .set(Group::getIsDismissed, YesOrNo.YES) + .update(); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java new file mode 100644 index 0000000..88f6c8f --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java @@ -0,0 +1,13 @@ +package cn.axzo.im.dao.repository; + +import cn.axzo.im.dao.mapper.GroupMessageMapper; +import cn.axzo.im.entity.GroupMessage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Repository; + +/** + * @author yanglin + */ +@Repository("groupMessageDao") +public class GroupMessageDao extends ServiceImpl { +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/Group.java b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java new file mode 100644 index 0000000..130faca --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java @@ -0,0 +1,55 @@ +package cn.axzo.im.entity; + +import cn.axzo.im.center.common.enums.GroupType; +import cn.axzo.im.center.common.enums.YesOrNo; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * @author yanglin + */ +@Setter +@Getter +@TableName(value = "im_group", autoResultMap = true) +public class Group { + + public static final String ATTACHMENT_GROUP_TYPE = "groupType"; + + private Long id; + private Long tid; + private String name; + private String bizCode; + private GroupType type; + private String avatar; + private Long memberCount; + private Long memberLimit; + private String ownerAccount; + private Long ownerPersonId; + private Long createPersonId; + private Long isDelete; + private YesOrNo isDismissed; + private Date createAt; + private Date updateAt; + @TableField(typeHandler = FastjsonTypeHandler.class) + private RecordExt recordExt; + + public boolean isMemberLimitReached(int memberCount) { + if (memberLimit <= 0) return false; + return memberCount > memberLimit; + } + + public boolean isDismissed() { + return getIsDismissed() == YesOrNo.YES; + } + + @Setter + @Getter + public static class RecordExt { + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupAccount.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupAccount.java new file mode 100644 index 0000000..c21eae7 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupAccount.java @@ -0,0 +1,28 @@ +package cn.axzo.im.entity; + +import cn.axzo.im.center.common.enums.AppTypeEnum; +import cn.axzo.im.center.common.enums.YesOrNo; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * @author yanglin + */ +@Setter +@Getter +@TableName(value = "im_group_account", autoResultMap = true) +public class GroupAccount { + private Long id; + private Long tid; + private String imAccount; + private Long personId; + private Long personOuId; + private AppTypeEnum appType; + private YesOrNo isRobot; + private Long isDelete; + private Date createAt; + private Date updateAt; +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java new file mode 100644 index 0000000..ca0f9eb --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java @@ -0,0 +1,46 @@ +package cn.axzo.im.entity; + +import cn.axzo.im.center.common.enums.AppTypeEnum; +import cn.axzo.im.center.common.enums.NimFromClientType; +import cn.axzo.im.center.common.enums.NimMessageType; +import cn.axzo.im.center.common.enums.YesOrNo; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import com.dingtalk.api.request.OapiAtsResumeAddRequest; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * @author yanglin + */ +@Setter +@Getter +@TableName(value = "im_group_message", autoResultMap = true) +public class GroupMessage { + private Long id; + private Long tid; + private String fromAccount; + private Long fromPersonId; + private Long fromPersonOuId; + private AppTypeEnum fromPersonAppType; + private YesOrNo isFromRobot; + private NimMessageType messageType; + private NimFromClientType fromClientType; + private Date sendTime; + @TableField(typeHandler = FastjsonTypeHandler.class) + private JSONObject body; + @TableField(typeHandler = FastjsonTypeHandler.class) + private RecordExt recordExt; + private Long isDelete; + private Date createAt; + private Date updateAt; + + @Setter + @Getter + public static class RecordExt { + } +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java b/im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java index a56f97e..3e5ee66 100644 --- a/im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java +++ b/im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java @@ -13,7 +13,9 @@ public enum EventTypeEnum { MESSAGE_HISTORY_CREATED("message-history", "message-history-created", "发送记录创建"), MESSAGE_HISTORY_UPDATED("message-history", "message-history-updated", "发送记录修改"), - MESSAGE_CHAT_GROUP_CREATE("chat-group", "chat-group-create", "群聊创建"), + MESSAGE_CHAT_GROUP_CREATE("chat-group", "chat-group-create", "群聊创建[项目]"), + GROUP_ADD_MEMBERS("group", "group-add-members", "添加群聊成员"), + GROUP_REMOVE_MEMBERS("group", "group-remove-members", "移除群聊成员"), UPDATE_AVATAR("profile", "update-avatar", "头像更新"), NODE_USER_CREATE("node-user", "node-user-create", "节点用户创建"), NODE_USER_UPDATE("node-user", "node-user-update", "节点用户修改"), diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java new file mode 100644 index 0000000..b147ea3 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java @@ -0,0 +1,54 @@ +package cn.axzo.im.group; + +import cn.axzo.basics.common.BeanMapper; +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.im.center.api.vo.mq.GroupMembersChangeMessage; +import cn.axzo.im.config.MqProducer; +import cn.axzo.im.dao.repository.GroupDao; +import cn.axzo.im.entity.Group; +import cn.axzo.im.entity.GroupAccount; +import cn.axzo.im.event.inner.EventTypeEnum; +import cn.axzo.im.group.domain.GroupMembersDiff; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Collection; + +/** + * @author yanglin + */ +@Service +@RequiredArgsConstructor +class GroupBroadcaster { + + private final MqProducer mqProducer; + private final GroupDao groupDao; + + void fireMembersAdded(Group group, GroupMembersDiff diff) { + diff.diff(); + fireMembersChanged(group, diff.getAdded(), EventTypeEnum.GROUP_ADD_MEMBERS); + } + + void fireMembersRemoved(Group group, GroupMembersDiff diff) { + diff.diff(); + fireMembersChanged(group, diff.getRemoved(), EventTypeEnum.GROUP_REMOVE_MEMBERS); + } + + private void fireMembersChanged(Group group, Collection accounts, EventTypeEnum eventType) { + if (accounts.isEmpty()) return; + Group effectiveGroup = groupDao.getById(group.getId()); + for (GroupAccount account : accounts) { + GroupMembersChangeMessage message = new GroupMembersChangeMessage(); + message.setGroupInfo(BeanMapper.copyBean(effectiveGroup, GroupMembersChangeMessage.GroupInfo.class)); + message.setAccount(BeanMapper.copyBean(account, GroupMembersChangeMessage.AccountInfo.class)); + Event event = Event.builder() + .targetId(account.getImAccount()) + .targetType(eventType.getModel()) + .eventCode(eventType.getEventCode()) + .data(message) + .build(); + mqProducer.send(event); + } + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java new file mode 100644 index 0000000..888c082 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java @@ -0,0 +1,40 @@ +package cn.axzo.im.group; + +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.im.center.api.feign.GroupApi; +import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; +import cn.axzo.im.center.api.vo.req.GroupCreateRequest; +import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; +import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author yanglin + */ +@Slf4j +@RestController +@RequiredArgsConstructor +public class GroupController implements GroupApi { + + private final GroupManager groupManager; + + @Override + public ApiResult createGroup(GroupCreateRequest request) { + return ApiResult.ok(groupManager.createGroup(request)); + } + + @Override + public ApiResult dismissGroup(GroupDismissRequest request) { + groupManager.dismissGroup(request); + return ApiResult.ok(); + } + + @Override + public ApiResult addMembers(GroupAddMembersRequest request) { + return ApiResult.ok(groupManager.addMembers(request)); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java new file mode 100644 index 0000000..5d04b2b --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -0,0 +1,158 @@ +package cn.axzo.im.group; + +import cn.axzo.basics.common.exception.ServiceException; +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; +import cn.axzo.im.center.api.vo.req.GroupCreateRequest; +import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; +import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; +import cn.axzo.im.channel.netease.client.NimClient; +import cn.axzo.im.channel.netease.dto.NimGroupAddMembersRequest; +import cn.axzo.im.channel.netease.dto.NimGroupAddMembersResponse; +import cn.axzo.im.channel.netease.dto.NimGroupCreateRequest; +import cn.axzo.im.channel.netease.dto.NimGroupCreateResponse; +import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; +import cn.axzo.im.channel.netease.dto.NimGroupDismissResponse; +import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; +import cn.axzo.im.channel.netease.dto.NimGroupGetInfoResponse; +import cn.axzo.im.channel.netease.dto.NimGroupInfo; +import cn.axzo.im.dao.repository.GroupAccountDao; +import cn.axzo.im.dao.repository.GroupDao; +import cn.axzo.im.entity.Group; +import cn.axzo.im.entity.GroupAccount; +import cn.axzo.im.group.domain.GroupMembersDiff; +import cn.axzo.im.service.AccountService; +import cn.axzo.im.service.domain.PersonImAccounts; +import cn.axzo.im.utils.BizAssertions; +import cn.hutool.core.map.MapUtil; +import com.alibaba.fastjson.JSON; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * @author yanglin + */ +@Slf4j +@Component +@RequiredArgsConstructor +class GroupManager { + + private final NimClient nimClient; + private final GroupDao groupDao; + private final GroupAccountDao groupAccountDao; + private final GroupSupport groupSupport; + private final AccountService accountService; + private final GroupBroadcaster groupBroadcaster; + + @Transactional + public GroupCreateResponse createGroup(GroupCreateRequest request) { + PersonImAccounts accounts = accountService.findPersonAccounts(request.getOwnerAndMembers()); + Group group = groupSupport.buildNewGroup(request, accounts); + try { + groupDao.save(group); + } catch (DuplicateKeyException e) { + log.warn("重复创建群, request={}", request, e); + throw new ServiceException(403, String.format("群已经存在: %s", request.getName())); + } + NimGroupCreateRequest nimRequest = groupSupport.buildNimCreateGroupRequest(request, group, accounts); + NimGroupCreateResponse nimResponse = nimClient.createGroup(nimRequest); + log.info("创建群, request={}, response={}", nimRequest, nimResponse); + BizAssertions.assertTrue(nimResponse.isSuccess(), "创建群失败: {}", nimResponse.getDesc()); + groupDao.updateTid(group.getId(), nimResponse.getTid()); + GroupMembersDiff memberDiff = createMembersDiff(nimResponse.getTid()); + syncGroupAccounts(group); + groupBroadcaster.fireMembersAdded(group, memberDiff); + GroupCreateResponse response = new GroupCreateResponse(); + response.setTid(nimResponse.getTid()); + Set notFound = accounts.getAccountNotFoundPersons(request.getMembers()); + if (!notFound.isEmpty()) + groupSupport.log("创建群[TID:{}], IM账号不存在列表: {}", group.getTid(), JSON.toJSONString(notFound)); + response.setAccountsNotFound(notFound); + return response; + } + + @Transactional + public void dismissGroup(GroupDismissRequest request) { + Group group = findGroupForUpdateOrThrow(request.getTid()); + if (group.isDismissed()) return; + NimGroupDismissRequest nimRequest = groupSupport + .buildNimDismissGroupRequest(group.getOwnerAccount(), group); + NimGroupDismissResponse nimResponse = nimClient.dismissGroup(nimRequest); + log.info("解散群, request={}, response={}", nimRequest, nimResponse); + if (!nimResponse.isGroupNotFoundError()) + BizAssertions.assertTrue(nimResponse.isSuccess(), "解散群失败: {}", nimResponse.getDesc()); + groupDao.setDismissed(group.getTid()); + } + + @Transactional + public GroupAddMembersResponse addMembers(GroupAddMembersRequest request) { + Group group = findGroupForUpdateOrThrow(request.getTid()); + BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); + NimGroupInfo groupInfo = fetchGroupInfo(group).orElse(null); + BizAssertions.assertNotNull(groupInfo, "[NIM] 群不存在: {}", group.getTid()); + PersonImAccounts accounts = accountService.findPersonAccounts(request.getMembers()); + NimGroupAddMembersRequest nimRequest = groupSupport + .buildAddMembersRequest(request, group, groupInfo.getOwner().getAccid(), accounts); + GroupMembersDiff memberDiff = createMembersDiff(group.getTid()); + NimGroupAddMembersResponse nimResponse = nimClient.addMembers(nimRequest); + log.info("添加群成员, request={}, response={}", nimRequest, nimResponse); + BizAssertions.assertTrue(nimResponse.isSuccess(), "添加群成员失败: {}", nimResponse.getDesc()); + if (MapUtil.isNotEmpty(nimResponse.getFaccid())) + groupSupport.log("添加群成员[TID:{}], 错误信息: {}", + group.getTid(), JSON.toJSONString(nimResponse.getFaccid())); + syncGroupAccounts(group); + groupBroadcaster.fireMembersAdded(group, memberDiff); + GroupAddMembersResponse response = new GroupAddMembersResponse(); + Set notFound = accounts.getAccountNotFoundPersons(request.getMembers()); + if (!notFound.isEmpty()) + groupSupport.log("创建群[TID:{}], IM账号不存在列表: {}", group.getTid(), JSON.toJSONString(notFound)); + response.setAccountsNotFound(notFound); + return response; + } + + private void syncGroupAccounts(Group group) { + NimGroupInfo groupInfo = fetchGroupInfo(group).orElse(null); + if (groupInfo == null) return; + groupAccountDao.deleteAccounts(group.getTid()); + List accounts = groupSupport + .parseGroupAccounts(group, groupInfo.getOwnerAndMembers()); + if (CollectionUtils.isNotEmpty(accounts)) + groupAccountDao.saveBatch(accounts); + groupDao.updateMembersCount(group.getTid(), accounts.size()); + } + + @NotNull + private Group findGroupForUpdateOrThrow(Long tid) { + Group group = groupDao.findByTid(tid, true).orElse(null); + BizAssertions.assertNotNull(group, "群不存在: {}", tid); + return group; + } + + private Optional fetchGroupInfo(Group group) { + NimGroupGetInfoRequest nimRequest = new NimGroupGetInfoRequest(); + nimRequest.setTid(group.getTid()); + long start = System.currentTimeMillis(); + NimGroupGetInfoResponse nimResponse = nimClient.getGroupInfo(nimRequest); + log.info("获取群信息, request={}, response={}, timeUsed={}", + nimRequest, nimResponse, System.currentTimeMillis() - start); + if (nimResponse.isGroupNotFoundError()) + return Optional.empty(); + BizAssertions.assertTrue(nimResponse.isSuccess(), + "获取群信息失败: {}", nimResponse.getDesc()); + return Optional.of(nimResponse.getTinfo()); + } + + private GroupMembersDiff createMembersDiff(Long tid) { + return new GroupMembersDiff(() -> groupAccountDao.getByTid(tid)); + } +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java new file mode 100644 index 0000000..87b3864 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -0,0 +1,119 @@ +package cn.axzo.im.group; + +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; +import cn.axzo.im.center.api.vo.req.GroupCreateRequest; +import cn.axzo.im.center.common.enums.YesOrNo; +import cn.axzo.im.channel.netease.dto.NimGroupAddMembersRequest; +import cn.axzo.im.channel.netease.dto.NimGroupCreateRequest; +import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; +import cn.axzo.im.channel.netease.dto.NimGroupMemberInfo; +import cn.axzo.im.entity.Group; +import cn.axzo.im.entity.GroupAccount; +import cn.axzo.im.service.ChatGroupService; +import cn.axzo.im.service.domain.PersonImAccounts; +import cn.axzo.im.utils.BizAssertions; +import cn.axzo.im.utils.ImAccountParser; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.helpers.MessageFormatter; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * @author yanglin + */ +@Slf4j +@Component +@RequiredArgsConstructor +class GroupSupport { + + private final ChatGroupService chatGroupService; + + Group buildNewGroup(GroupCreateRequest request, PersonImAccounts accounts) { + String owner = accounts.findAccount(request.getOwner()).orElse(null); + BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); + Group group = new Group(); + group.setName(request.getName()); + group.setBizCode(request.getBizCode()); + group.setType(request.getGroupType()); + group.setAvatar(request.getAvatar()); + group.setMemberCount((long) request.getOwnerAndMembers().size()); + Long memberLimit = request.getMemberLimit(); + group.setMemberLimit(memberLimit == null ? 0L : memberLimit); + group.setOwnerAccount(owner); + group.setOwnerPersonId(request.getOwner().personIdAsLong()); + group.setCreatePersonId(request.getOwner().personIdAsLong()); + group.setIsDismissed(YesOrNo.NO); + return group; + } + + NimGroupCreateRequest buildNimCreateGroupRequest( + GroupCreateRequest request, Group group, PersonImAccounts accounts) { + BizAssertions.assertFalse(group.isMemberLimitReached( + accounts.getAccountSize()), "无法创建群, 群成员数量超过上限"); + String owner = accounts.findAccount(request.getOwner()).orElse(null); + BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); + BizAssertions.assertTrue(accounts.getAccountSize() > 1, "无法创建群. 存在的群成员IM账号数量需要大于等于2"); + + NimGroupCreateRequest nimRequest = new NimGroupCreateRequest(); + nimRequest.setName(request.getName()); + nimRequest.setOwner(owner); + nimRequest.addMembers(accounts.filterAccounts(account -> !account.equals(owner))); + nimRequest.setIntroduceMessage(request.getIntroduceMessage()); + nimRequest.setIcon(request.getAvatar()); + nimRequest.addAttachment(Group.ATTACHMENT_GROUP_TYPE, request.getGroupType()); + return nimRequest; + } + + NimGroupDismissRequest buildNimDismissGroupRequest(String owner, Group group) { + NimGroupDismissRequest nimRequest = new NimGroupDismissRequest(); + nimRequest.setTid(group.getTid()); + nimRequest.setOwner(owner); + return nimRequest; + } + + NimGroupAddMembersRequest buildAddMembersRequest( + GroupAddMembersRequest request, Group group, String owner, PersonImAccounts accounts) { + NimGroupAddMembersRequest nimRequest = new NimGroupAddMembersRequest(); + nimRequest.setTid(group.getTid()); + nimRequest.setOwner(owner); + nimRequest.setMsg(request.getIntroduceMessage()); + nimRequest.addMembers(accounts.getAccounts()); + return nimRequest; + } + + void log(String message, Object... args) { + try { + chatGroupService.sendDingRobot(MessageFormatter.arrayFormat(message, args).getMessage()); + } catch (Exception e) { + log.warn("发送钉钉机器人消息失败", e); + } + } + + List parseGroupAccounts(Group group, Set members) { + ArrayList accounts = new ArrayList<>(); + for (NimGroupMemberInfo member : members) { + PersonAccountAttribute person = ImAccountParser.parsePerson(member.getAccid()).orElse(null); + GroupAccount account = new GroupAccount(); + accounts.add(account); + account.setTid(group.getTid()); + account.setImAccount(member.getAccid()); + if (person == null) { + account.setPersonId(0L); + account.setPersonOuId(0L); + account.setAppType(null); + account.setIsRobot(YesOrNo.YES); + } else { + account.setPersonId(Long.valueOf(person.getPersonId())); + account.setPersonOuId(person.ouIdOrDefault()); + account.setAppType(person.getAppType()); + account.setIsRobot(YesOrNo.NO); + } + } + return accounts; + } +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/domain/GroupMembersDiff.java b/im-center-server/src/main/java/cn/axzo/im/group/domain/GroupMembersDiff.java new file mode 100644 index 0000000..7480069 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/domain/GroupMembersDiff.java @@ -0,0 +1,57 @@ +package cn.axzo.im.group.domain; + +import cn.axzo.im.entity.GroupAccount; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +/** + * @author yanglin + */ +@SuppressWarnings("DuplicatedCode") +public class GroupMembersDiff { + + private final Supplier> accountsProvider; + private final Map before; + private Map after; + + public GroupMembersDiff(Supplier> accountsProvider) { + this.accountsProvider = accountsProvider; + this.before = reload(); + } + + public void diff() { + if (after == null) + after = reload(); + } + + public Collection getAdded() { + HashMap accounts = new HashMap<>(); + for (GroupAccount account : after.values()) { + String imAccount = account.getImAccount(); + if (!before.containsKey(imAccount) && !accounts.containsKey(imAccount)) + accounts.put(imAccount, account); + } + return accounts.values(); + } + + public Collection getRemoved() { + HashMap accounts = new HashMap<>(); + for (GroupAccount account : before.values()) { + String imAccount = account.getImAccount(); + if (!after.containsKey(imAccount) && !accounts.containsKey(imAccount)) + accounts.put(imAccount, account); + } + return accounts.values(); + } + + private Map reload() { + return accountsProvider.get().stream() + .collect(Collectors.toMap(GroupAccount::getImAccount, account -> account)); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/PersonProfileAvatarUpdateEventHandler.java b/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/PersonProfileAvatarUpdateEventHandler.java index b48304c..19a47df 100644 --- a/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/PersonProfileAvatarUpdateEventHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/PersonProfileAvatarUpdateEventHandler.java @@ -7,7 +7,7 @@ import cn.axzo.basics.profiles.dto.mq.ProfileMQBaseEntity; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; -import cn.axzo.im.channel.netease.dto.GetAccountInfoResponse; +import cn.axzo.im.channel.netease.dto.NimGetAccountInfoResponse; import cn.axzo.im.entity.AccountRegister; import cn.axzo.im.entity.bo.AccountQueryParam; import cn.axzo.im.event.inner.EventTypeEnum; @@ -83,7 +83,7 @@ public class PersonProfileAvatarUpdateEventHandler implements EventHandler, Init //3 同步网易云信账号 PersonProfileDto personProfileDto = personProfileDtoCommonResponse.getData(); for (AccountRegister accountRegister : accountRegisters) { - GetAccountInfoResponse.AccountInfo accountInfo = accountService.fetchImAccountInfoByImAccount(accountRegister.getImAccount()); + NimGetAccountInfoResponse.AccountInfo accountInfo = accountService.fetchImAccountInfoByImAccount(accountRegister.getImAccount()); accountService.syncImAccount(accountRegister.getAccountId(), accountRegister.getImAccount(), accountInfo.getOrCreateExtObject(),personProfileDto.getAvatarUrl(), personProfileDto.getRealName()); } } diff --git a/im-center-server/src/main/java/cn/axzo/im/job/RevokeAllMessagesJob.java b/im-center-server/src/main/java/cn/axzo/im/job/RevokeAllMessagesJob.java index 1557802..695a989 100644 --- a/im-center-server/src/main/java/cn/axzo/im/job/RevokeAllMessagesJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/job/RevokeAllMessagesJob.java @@ -3,7 +3,7 @@ package cn.axzo.im.job; import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum; import cn.axzo.basics.common.page.PageRequest; import cn.axzo.im.channel.netease.client.NimClient; -import cn.axzo.im.channel.netease.dto.RevokeMessageRequest; +import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; import cn.axzo.im.dao.mapper.MessageHistoryMapper; import cn.axzo.im.entity.MessageHistory; import cn.axzo.im.utils.Queries; @@ -99,11 +99,11 @@ public class RevokeAllMessagesJob extends IJobHandler { private void revokeImpl(List messages) { for (MessageHistory message : messages) { - RevokeMessageRequest request = new RevokeMessageRequest(); + NimRevokeMessageRequest request = new NimRevokeMessageRequest(); request.setMessageId(message.getMessageId()); request.setFrom(message.getFromAccount()); request.setTo(message.getToAccount()); - NimClient.CodeResponse resp = nimClient.revoke(request); + NimClient.NimCodeResponse resp = nimClient.revoke(request); log.info("revokeImpl, req={}, resp={}", JSON.toJSONString(request), JSON.toJSONString(resp)); } } diff --git a/im-center-server/src/main/java/cn/axzo/im/job/UpdateImAccountPersonInfoJob.java b/im-center-server/src/main/java/cn/axzo/im/job/UpdateImAccountPersonInfoJob.java index d83ceff..1a641bb 100644 --- a/im-center-server/src/main/java/cn/axzo/im/job/UpdateImAccountPersonInfoJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/job/UpdateImAccountPersonInfoJob.java @@ -6,9 +6,9 @@ import cn.axzo.basics.profiles.dto.basic.BasicDto; import cn.axzo.basics.profiles.dto.basic.PersonProfileDto; import cn.axzo.im.center.common.enums.AccountTypeEnum; import cn.axzo.im.channel.netease.client.NimClient; -import cn.axzo.im.channel.netease.dto.GetAccountInfoResponse; -import cn.axzo.im.channel.netease.dto.UpdateAccountInfoRequest; -import cn.axzo.im.channel.netease.dto.UpdateAccountInfoResponse; +import cn.axzo.im.channel.netease.dto.NimGetAccountInfoResponse; +import cn.axzo.im.channel.netease.dto.NimUpdateAccountInfoRequest; +import cn.axzo.im.channel.netease.dto.NimUpdateAccountInfoResponse; import cn.axzo.im.dao.repository.AccountRegisterDao; import cn.axzo.im.entity.AccountRegister; import cn.axzo.im.service.AccountService; @@ -107,7 +107,7 @@ public class UpdateImAccountPersonInfoJob { } log.info("updateImAccountByAccountRegis, count: {}", accounts.size()); //1 获取IM账号 - GetAccountInfoResponse imAccountList = accountService.getImAccount(accounts); + NimGetAccountInfoResponse imAccountList = accountService.getImAccount(accounts); if (!imAccountList.isSuccess()) { log.warn("get account info failed, {}", imAccountList); @@ -116,7 +116,7 @@ public class UpdateImAccountPersonInfoJob { //2 构建PersonProfile Map id2PersonProfile = this.buildPersonProfileMap(accounts); for (AccountRegister account : accounts) { - GetAccountInfoResponse.AccountInfo imAccount = imAccountList.findImAccountInfo(account.getImAccount()).orElse(null); + NimGetAccountInfoResponse.AccountInfo imAccount = imAccountList.findImAccountInfo(account.getImAccount()).orElse(null); if (imAccount == null) continue; //3 获取personProfile PersonProfileDto person = this.fetchPersonById(account.getAccountId(), id2PersonProfile); @@ -125,7 +125,7 @@ public class UpdateImAccountPersonInfoJob { continue; } //4 更新IM账号 - UpdateAccountInfoResponse updateAccountInfoResponse + NimUpdateAccountInfoResponse updateAccountInfoResponse = accountService.syncImAccount(account.getAccountId(), imAccount.getAccid() ,imAccount.getOrCreateExtObject(), person.getAvatarUrl(), person.getRealName()); //日志打印 @@ -147,7 +147,7 @@ public class UpdateImAccountPersonInfoJob { * 日志打印 * @param updateAccountInfoResponse */ - private void successLog(UpdateAccountInfoResponse updateAccountInfoResponse) { + private void successLog(NimUpdateAccountInfoResponse updateAccountInfoResponse) { if (updateAccountInfoResponse.isSuccess()) { log.info("update account info success, {}", updateAccountInfoResponse); } else { @@ -168,12 +168,12 @@ public class UpdateImAccountPersonInfoJob { .collect(Collectors.toMap(BasicDto::getId, i -> i)); } - private UpdateAccountInfoResponse updateImAccount(AccountRegister account, GetAccountInfoResponse.AccountInfo accountInfo,Map id2PersonProfile) { + private NimUpdateAccountInfoResponse updateImAccount(AccountRegister account, NimGetAccountInfoResponse.AccountInfo accountInfo, Map id2PersonProfile) { RateLimiter rateLimiter = RateLimiter.create(60); JSONObject ext = accountInfo.getOrCreateExtObject(); ext.put("personId", account.getAccountId()); - UpdateAccountInfoRequest updateAccountInfoRequest = new UpdateAccountInfoRequest(); + NimUpdateAccountInfoRequest updateAccountInfoRequest = new NimUpdateAccountInfoRequest(); updateAccountInfoRequest.setImAccountId(accountInfo.getAccid()); updateAccountInfoRequest.addExt(ext); diff --git a/im-center-server/src/main/java/cn/axzo/im/send/SendExecutor.java b/im-center-server/src/main/java/cn/axzo/im/send/SendExecutor.java index dbf7a78..920d07e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/SendExecutor.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/SendExecutor.java @@ -1,6 +1,6 @@ package cn.axzo.im.send; -import cn.axzo.im.channel.netease.dto.BatchSendCustomMessageResponse; +import cn.axzo.im.channel.netease.dto.NimBatchSendCustomMessageResponse; import cn.axzo.im.channel.netease.dto.MessageBatchDispatchResponse; import cn.axzo.im.entity.HistoryRecordExt; import cn.axzo.im.entity.MessageHistory; @@ -129,7 +129,7 @@ public class SendExecutor implements Supplier { } public void setBatchSendSuccess(List histories, - BatchSendCustomMessageResponse response, + NimBatchSendCustomMessageResponse response, HistoryRecordExt updateExt) { sendCount.addAndGet(histories.size()); sendManager.setBatchSendSuccess(histories, response, updateExt); diff --git a/im-center-server/src/main/java/cn/axzo/im/send/SendManager.java b/im-center-server/src/main/java/cn/axzo/im/send/SendManager.java index 14846f6..840a67c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/SendManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/SendManager.java @@ -1,6 +1,6 @@ package cn.axzo.im.send; -import cn.axzo.im.channel.netease.dto.BatchSendCustomMessageResponse; +import cn.axzo.im.channel.netease.dto.NimBatchSendCustomMessageResponse; import cn.axzo.im.channel.netease.dto.MessageBatchDispatchResponse; import cn.axzo.im.dao.mapper.MessageHistoryMapper; import cn.axzo.im.entity.HistoryRecordExt; @@ -226,7 +226,7 @@ public class SendManager { } void setBatchSendSuccess(List histories, - BatchSendCustomMessageResponse response, + NimBatchSendCustomMessageResponse response, HistoryRecordExt updateExt) { transactionTemplate.executeWithoutResult(unused -> { messageHistoryService.setBatchSendSuccess(histories, response, updateExt); diff --git a/im-center-server/src/main/java/cn/axzo/im/send/handler/CustomSendBatchHandler.java b/im-center-server/src/main/java/cn/axzo/im/send/handler/CustomSendBatchHandler.java index 2025d54..2e805c2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/handler/CustomSendBatchHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/handler/CustomSendBatchHandler.java @@ -1,8 +1,8 @@ package cn.axzo.im.send.handler; import cn.axzo.im.channel.netease.client.NimClient; -import cn.axzo.im.channel.netease.dto.BatchSendCustomMessageRequest; -import cn.axzo.im.channel.netease.dto.BatchSendCustomMessageResponse; +import cn.axzo.im.channel.netease.dto.NimBatchSendCustomMessageRequest; +import cn.axzo.im.channel.netease.dto.NimBatchSendCustomMessageResponse; import cn.axzo.im.entity.HistoryRecordExt; import cn.axzo.im.entity.MessageHistory; import cn.axzo.im.send.MessageHistoryNimLogger; @@ -36,7 +36,7 @@ public class CustomSendBatchHandler extends SendBatchHandler { executor.log("batchSendCustomMessage - request record size: {}, batchNo={}", histories.size(), histories.get(0).determineBatchNo().orElse(null)); MessageHistory sample = histories.get(0); - BatchSendCustomMessageRequest request = new BatchSendCustomMessageRequest(); + NimBatchSendCustomMessageRequest request = new NimBatchSendCustomMessageRequest(); request.setFromAccount(sample.getFromAccount()); request.setToAccountJsonString(JSON.toJSONString(Lists.transform( histories, MessageHistory::getToAccount))); @@ -45,7 +45,7 @@ public class CustomSendBatchHandler extends SendBatchHandler { request.setSound(sample.getOrCreateRecordExt().getSound()); pushPropPopulator.populate(request, sample); messageHistoryNimLogger.logAsync(histories, request); - BatchSendCustomMessageResponse response = nimClient.batchSendCustomMessage(request); + NimBatchSendCustomMessageResponse response = nimClient.batchSendCustomMessage(request); HistoryRecordExt ext = new HistoryRecordExt(); ext.setSendApi("batchSendCustomMessage"); ext.setSendExecId(executor.sendExec().getExecId()); diff --git a/im-center-server/src/main/java/cn/axzo/im/send/handler/CustomSendOneHandler.java b/im-center-server/src/main/java/cn/axzo/im/send/handler/CustomSendOneHandler.java index 8435ec6..159ebf7 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/handler/CustomSendOneHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/handler/CustomSendOneHandler.java @@ -1,8 +1,8 @@ package cn.axzo.im.send.handler; import cn.axzo.im.channel.netease.client.NimClient; -import cn.axzo.im.channel.netease.dto.SendCustomMessageRequest; -import cn.axzo.im.channel.netease.dto.SendCustomMessageResponse; +import cn.axzo.im.channel.netease.dto.NimSendCustomMessageRequest; +import cn.axzo.im.channel.netease.dto.NimSendCustomMessageResponse; import cn.axzo.im.entity.MessageHistory; import cn.axzo.im.send.MessageHistoryNimLogger; import cn.axzo.im.send.SendExecutor; @@ -27,7 +27,7 @@ public class CustomSendOneHandler extends SendOneHandler { executor.log("sendCustomMessage - historyId={}, taskId={}, bizId={}, batchNo={}", history.getId(), history.getImMessageTaskId(), history.getBizId(), history.determineBatchNo().orElse(null)); - SendCustomMessageRequest request = new SendCustomMessageRequest(); + NimSendCustomMessageRequest request = new NimSendCustomMessageRequest(); request.setFromAccount(history.getFromAccount()); request.setToAccount(history.getToAccount()); request.setAttachJsonString(history.getMessageBody()); @@ -36,7 +36,7 @@ public class CustomSendOneHandler extends SendOneHandler { request.setPayloadJsonString(history.getMessageBody()); request.setSound(history.getOrCreateRecordExt().getSound()); messageHistoryNimLogger.logAsync(history, request); - SendCustomMessageResponse response = nimClient.sendCustomMessage(request); + NimSendCustomMessageResponse response = nimClient.sendCustomMessage(request); if (response.isRateLimited()) executor.scheduleRetrySend(history, null); else if (response.isSuccess()) diff --git a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java index ea565cc..734da4b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java @@ -4,6 +4,7 @@ import cn.axzo.basics.common.BeanMapper; import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum; import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.basics.profiles.dto.basic.PersonProfileDto; +import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.api.vo.req.AccountAbsentQuery; import cn.axzo.im.center.api.vo.req.AccountQuery; import cn.axzo.im.center.api.vo.req.RobotAccountReq; @@ -15,15 +16,15 @@ import cn.axzo.im.center.common.enums.RobotStatusEnum; import cn.axzo.im.channel.IMChannelProvider; import cn.axzo.im.channel.netease.INotifyService; import cn.axzo.im.channel.netease.client.NimClient; -import cn.axzo.im.channel.netease.dto.GetAccountInfoRequest; -import cn.axzo.im.channel.netease.dto.GetAccountInfoResponse; import cn.axzo.im.channel.netease.dto.NimAccountInfo; -import cn.axzo.im.channel.netease.dto.RefreshTokenRequest; -import cn.axzo.im.channel.netease.dto.RefreshTokenResponse; +import cn.axzo.im.channel.netease.dto.NimGetAccountInfoRequest; +import cn.axzo.im.channel.netease.dto.NimGetAccountInfoResponse; +import cn.axzo.im.channel.netease.dto.NimRefreshTokenRequest; +import cn.axzo.im.channel.netease.dto.NimRefreshTokenResponse; +import cn.axzo.im.channel.netease.dto.NimUpdateAccountInfoRequest; +import cn.axzo.im.channel.netease.dto.NimUpdateAccountInfoResponse; import cn.axzo.im.channel.netease.dto.RegisterRequest; import cn.axzo.im.channel.netease.dto.RegisterResponse; -import cn.axzo.im.channel.netease.dto.UpdateAccountInfoRequest; -import cn.axzo.im.channel.netease.dto.UpdateAccountInfoResponse; import cn.axzo.im.dao.mapper.AccountRegisterMapper; import cn.axzo.im.dao.repository.AccountRegisterDao; import cn.axzo.im.dao.repository.RobotInfoDao; @@ -31,6 +32,7 @@ import cn.axzo.im.entity.AccountRegister; import cn.axzo.im.entity.RobotInfo; import cn.axzo.im.entity.bo.AccountQueryParam; import cn.axzo.im.gateway.ProfilesApiGateway; +import cn.axzo.im.service.domain.PersonImAccounts; import cn.axzo.im.utils.MiscUtils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; @@ -248,8 +250,8 @@ public class AccountService { } private UserAccountResp createAccountRegister(String userId, String userIdWrapper, String appType, - String accountType, String headImageUrl, String nickName, - Long ouId) { + String accountType, String headImageUrl, String nickName, + Long ouId) { //1.检查账户是否已经创建 String appKey = imChannelProvider.getProviderAppKey(); UserAccountResp userAccountResp = new UserAccountResp(); @@ -293,10 +295,10 @@ public class AccountService { //重复注册的用户 会返回imaccount 不会返回token String token = accountResp.getToken(); if (token == null && accountResp.getDesc() != null && accountResp.getDesc().contains("already")) { - RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest(); + NimRefreshTokenRequest refreshTokenRequest = new NimRefreshTokenRequest(); refreshTokenRequest.setAccid(userIdWrapper); log.info("refreshing token for account={}", userIdWrapper); - RefreshTokenResponse refreshTokenResponse = nimClient.refreshToken(refreshTokenRequest); + NimRefreshTokenResponse refreshTokenResponse = nimClient.refreshToken(refreshTokenRequest); if (refreshTokenResponse.isSuccess() && refreshTokenResponse.getInfo() != null) { token = refreshTokenResponse.getInfo().getToken(); } @@ -341,6 +343,7 @@ public class AccountService { /** * 建议用更通用的AccountRegisterService.page解耦 + * * @param accountQuery * @return */ @@ -398,7 +401,7 @@ public class AccountService { throw new ServiceException("请求参数AppType=[" + accountAbsentQuery.getAppType() + "]不支持!"); } List userAccountAll = Lists.newArrayList(); - AppTypeEnum[] target = new AppTypeEnum[] {appType}; + AppTypeEnum[] target = new AppTypeEnum[]{appType}; for (AppTypeEnum appTypeEnum : target) { AccountRegisterService.ListAccountRegisterParam listAccountRegisterParam = AccountRegisterService.ListAccountRegisterParam.builder() .appType(appTypeEnum.getCode()) @@ -432,10 +435,10 @@ public class AccountService { PersonProfileDto personProfileDto = profilesApiGateway.getPersonProfileById(Long.valueOf(accountAbsentQuery.getPersonId())); - userAccountReq.setNickName(StringUtils.isNotBlank(personProfileDto.getRealName())? personProfileDto.getRealName() : DEFAULT_NICK_NAME + accountAbsentQuery.getPersonId()); + userAccountReq.setNickName(StringUtils.isNotBlank(personProfileDto.getRealName()) ? personProfileDto.getRealName() : DEFAULT_NICK_NAME + accountAbsentQuery.getPersonId()); userAccountReq.setHeadImageUrl(personProfileDto.getAvatarUrl()); // 管理版需要根据ou注册IM账号,做数据隔离 - if (appTypeEnum == AppTypeEnum.CMP && accountAbsentQuery.getOuId() != null && accountAbsentQuery.getOuId() != 0) { + if (appTypeEnum == AppTypeEnum.CMP && accountAbsentQuery.getOuId() != null && accountAbsentQuery.getOuId() != 0) { userAccountReq.setOrganizationalUnitId(accountAbsentQuery.getOuId()); } UserAccountResp accountResp = null; @@ -511,11 +514,11 @@ public class AccountService { /** * 同步网易云信账号 */ - public UpdateAccountInfoResponse syncImAccount(String accountId, String accid, JSONObject ext, String avatarUrl, String realName) { + public NimUpdateAccountInfoResponse syncImAccount(String accountId, String accid, JSONObject ext, String avatarUrl, String realName) { RateLimiter rateLimiter = RateLimiter.create(60); ext.put("personId", accountId); - UpdateAccountInfoRequest updateAccountInfoRequest = new UpdateAccountInfoRequest(); + NimUpdateAccountInfoRequest updateAccountInfoRequest = new NimUpdateAccountInfoRequest(); updateAccountInfoRequest.setImAccountId(accid); updateAccountInfoRequest.addExt(ext); @@ -530,41 +533,41 @@ public class AccountService { rateLimiter.acquire(); log.info("syncImAccount-updateAccountInfoRequest, params:{}", JSON.toJSONString(updateAccountInfoRequest)); - UpdateAccountInfoResponse updateAccountInfoResponse = nimClient.updateAccountInfo(updateAccountInfoRequest); + NimUpdateAccountInfoResponse updateAccountInfoResponse = nimClient.updateAccountInfo(updateAccountInfoRequest); log.info("syncImAccount-updateAccountInfoRequest, result:{}", JSON.toJSONString(updateAccountInfoResponse)); return updateAccountInfoResponse; } - public GetAccountInfoResponse getImAccount(List accounts) { + public NimGetAccountInfoResponse getImAccount(List accounts) { if (CollectionUtils.isEmpty(accounts)) { return null; } - GetAccountInfoRequest getAccountInfoRequest = new GetAccountInfoRequest(); + NimGetAccountInfoRequest getAccountInfoRequest = new NimGetAccountInfoRequest(); List imAccount = accounts.stream().map(item -> item.getImAccount()).distinct().collect(toList()); getAccountInfoRequest.setAccids(JSON.toJSONString(imAccount)); // getAccountInfoRequest.setImAccountIds(accounts.stream().map(item -> item.getImAccount()).distinct().collect(toList())); return nimClient.getAccountInfo(getAccountInfoRequest); } - public List fetchImAccountsByImAccounts(List accounts) { + public List fetchImAccountsByImAccounts(List accounts) { if (CollectionUtils.isEmpty(accounts)) { return null; } - GetAccountInfoRequest getAccountInfoRequest = new GetAccountInfoRequest(); + NimGetAccountInfoRequest getAccountInfoRequest = new NimGetAccountInfoRequest(); // getAccountInfoRequest.setImAccountIds(accounts); getAccountInfoRequest.setAccids(JSON.toJSONString(accounts)); - GetAccountInfoResponse response = nimClient.getAccountInfo(getAccountInfoRequest); + NimGetAccountInfoResponse response = nimClient.getAccountInfo(getAccountInfoRequest); if (Objects.isNull(response) || CollectionUtils.isEmpty(response.getUinfos())) { return null; } return response.getUinfos(); } - public GetAccountInfoResponse.AccountInfo fetchImAccountInfoByImAccount(String imAccount) { + public NimGetAccountInfoResponse.AccountInfo fetchImAccountInfoByImAccount(String imAccount) { if (StringUtils.isBlank(imAccount)) { return null; } - List accountInfos = this.fetchImAccountsByImAccounts(Lists.newArrayList(imAccount)); + List accountInfos = this.fetchImAccountsByImAccounts(Lists.newArrayList(imAccount)); if (CollectionUtils.isEmpty(accountInfos)) { return null; } @@ -577,4 +580,20 @@ public class AccountService { AccountTypeEnum.CUSTOM, AppTypeEnum.SYSTEM, appKey); } + public PersonImAccounts findPersonAccounts(Collection persons) { + if (CollectionUtils.isEmpty(persons)) + return new PersonImAccounts(Collections.emptyList()); + List accounts = accountRegisterDao.lambdaQuery() + .nested(wrapper -> { + for (PersonAccountAttribute person : persons) { + wrapper.or() + .eq(AccountRegister::getAccountId, person.getPersonId()) + .eq(AccountRegister::getAppType, person.getAppType().getCode()) + .eq(person.getAppType() == AppTypeEnum.CMP, AccountRegister::getOuId, person.getOuId()); + } + }) + .list(); + return new PersonImAccounts(accounts); + } + } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/domain/PersonImAccounts.java b/im-center-server/src/main/java/cn/axzo/im/service/domain/PersonImAccounts.java new file mode 100644 index 0000000..1be4cf8 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/service/domain/PersonImAccounts.java @@ -0,0 +1,65 @@ +package cn.axzo.im.service.domain; + +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.entity.AccountRegister; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.apache.commons.collections.CollectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +import static java.util.stream.Collectors.toSet; + +/** + * @author yanglin + */ +@Setter +@RequiredArgsConstructor +public class PersonImAccounts { + + private final List imAccounts; + + public Set + getAccountNotFoundPersons(Set persons) { + if (CollectionUtils.isEmpty(persons)) + return Collections.emptySet(); + return persons.stream() + .filter(person -> !findAccount(person).isPresent()) + .collect(toSet()); + } + + public Set filterAccounts(Predicate filter) { + return getAccounts().stream() + .filter(filter) + .collect(toSet()); + } + + public int getAccountSize() { + return imAccounts.size(); + } + + public Set getAccounts() { + return imAccounts.stream() + .map(AccountRegister::getImAccount) + .collect(toSet()); + } + + public Optional findAccount(PersonAccountAttribute person) { + return imAccounts.stream() + .filter(account -> isAccountMatchPerson(person, account)) + .findFirst() + .map(AccountRegister::getImAccount); + } + + private static boolean isAccountMatchPerson(PersonAccountAttribute person, AccountRegister account) { + return person.getPersonId().equals(account.getAccountId()) + && person.getAppType().getCode().equals(account.getAppType()) + && Objects.equals(person.getOuId(), account.getOuId()); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java index 334a65f..2b51607 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java @@ -27,6 +27,7 @@ import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.ChatGroupStatusEnum; import cn.axzo.im.center.common.enums.ChatGroupUserDataSourceEnum; import cn.axzo.im.center.common.enums.ChatGroupUserTypeEnum; +import cn.axzo.im.center.common.enums.GroupType; import cn.axzo.im.center.common.enums.OperateLogTypeEnum; import cn.axzo.im.channel.IMChannelProvider; import cn.axzo.im.channel.netease.NimChannelService; @@ -46,6 +47,7 @@ import cn.axzo.im.config.JobCodeProperties; import cn.axzo.im.config.MqProducer; import cn.axzo.im.dao.mapper.ChatGroupMapper; import cn.axzo.im.entity.ChatGroup; +import cn.axzo.im.entity.Group; import cn.axzo.im.event.payload.ChatGroupCreatePayload; import cn.axzo.im.gateway.OrganizationalNodeUserApiGateway; import cn.axzo.im.gateway.ProfilesApiGateway; @@ -286,6 +288,16 @@ public class ChatGroupServiceImpl extends ServiceImpl attachMap = new HashMap<>(); attachMap.put("workspaceId", req.getWorkspaceId().toString()); attachMap.put("workspaceName", workspaceName); + GroupType groupType = null; + if (req.getCrowType() == ChatGroupCreateReq.CrowTypeEnum.OU) + groupType = GroupType.WORKSPACE_OU; + else if (req.getCrowType() == ChatGroupCreateReq.CrowTypeEnum.TEAM) + groupType = GroupType.WORKSPACE_TEAM; + else if (req.getCrowType() == ChatGroupCreateReq.CrowTypeEnum.WORKSPACE) + groupType = GroupType.WORKSPACE; + if (groupType != null) { + attachMap.put(Group.ATTACHMENT_GROUP_TYPE, groupType.getCode()); + } return JSONUtil.toJsonStr(attachMap);//TODO } diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageHistoryServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageHistoryServiceImpl.java index a1bb8af..78d4a66 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageHistoryServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageHistoryServiceImpl.java @@ -5,7 +5,7 @@ import cn.axzo.basics.profiles.dto.basic.PersonProfileDto; import cn.axzo.framework.rocketmq.Event; import cn.axzo.im.center.api.vo.req.UpdateTemplateSendPriorityRequest; import cn.axzo.im.channel.IMChannelProvider; -import cn.axzo.im.channel.netease.dto.BatchSendCustomMessageResponse; +import cn.axzo.im.channel.netease.dto.NimBatchSendCustomMessageResponse; import cn.axzo.im.channel.netease.dto.MessageBatchDispatchRequest; import cn.axzo.im.channel.netease.dto.MessageBatchDispatchResponse; import cn.axzo.im.config.MqProducer; @@ -20,9 +20,6 @@ import cn.axzo.im.service.AccountService; import cn.axzo.im.service.MessageHistoryService; import cn.axzo.orggateway.api.unit.resp.OrgUnitResp; import cn.axzo.im.utils.PropsUtils; -import cn.axzo.maokai.api.client.OrganizationalUnitApi; -import cn.axzo.maokai.api.vo.request.OrganizationalUnitQuery; -import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO; import cn.axzo.pokonyan.client.RateLimiter; import cn.axzo.pokonyan.client.RateLimiterClient; import cn.axzo.pokonyan.dao.converter.PageConverter; @@ -222,7 +219,7 @@ public class MessageHistoryServiceImpl extends ServiceImpl histories, - BatchSendCustomMessageResponse response, + NimBatchSendCustomMessageResponse response, HistoryRecordExt updateExt) { ArrayList updates = new ArrayList<>(histories.size()); for (MessageHistory history : histories) { diff --git a/im-center-server/src/main/java/cn/axzo/im/updatable/RevokeService.java b/im-center-server/src/main/java/cn/axzo/im/updatable/RevokeService.java index 4006101..e6ef141 100644 --- a/im-center-server/src/main/java/cn/axzo/im/updatable/RevokeService.java +++ b/im-center-server/src/main/java/cn/axzo/im/updatable/RevokeService.java @@ -3,6 +3,7 @@ package cn.axzo.im.updatable; import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.im.center.api.vo.req.RevokeMessageRequest; import cn.axzo.im.channel.netease.client.NimClient; +import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; import cn.axzo.im.dao.repository.MessageHistoryColdDao; import cn.axzo.im.dao.repository.MessageHistoryDao; import cn.axzo.im.entity.MessageHistory; @@ -96,12 +97,12 @@ public class RevokeService { } private void revoke(NimMessageHistory history) { - cn.axzo.im.channel.netease.dto.RevokeMessageRequest nimRequest = - new cn.axzo.im.channel.netease.dto.RevokeMessageRequest(); + NimRevokeMessageRequest nimRequest = + new NimRevokeMessageRequest(); nimRequest.setMessageId(history.getMessageId()); nimRequest.setFrom(history.getFromAccount()); nimRequest.setTo(history.getToAccount()); - NimClient.CodeResponse resp = nimClient.revoke(nimRequest); + NimClient.NimCodeResponse resp = nimClient.revoke(nimRequest); log.info("revoke messageId={}, code={}, desc={}", history.getMessageId(), resp.getCode(), resp.getDesc()); } diff --git a/im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java b/im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java new file mode 100644 index 0000000..04afb3e --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java @@ -0,0 +1,32 @@ +package cn.axzo.im.utils; + +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.common.enums.AppTypeEnum; + +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author yanglin + */ +public class ImAccountParser { + + private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z]+(\\d+)_cm(p?)_?(\\d+)?$"); + + public static Optional parsePerson(String imAccount) { + Matcher matcher = PATTERN.matcher(imAccount); + if (!matcher.find()) + return Optional.empty(); + String personId = matcher.group(1); + AppTypeEnum appType = matcher.group(2).isEmpty() ? AppTypeEnum.CM : AppTypeEnum.CMP; + String ouId = matcher.group(3) != null ? matcher.group(3) : null; + + PersonAccountAttribute person = new PersonAccountAttribute(); + person.setPersonId(personId); + person.setOuId(ouId != null ? Long.parseLong(ouId.substring(1)) : null); + person.setAppType(appType); + return Optional.of(person); + } + +} diff --git a/im-center-server/src/test/java/cn/axzo/im/channel/netease/client/NimClientTest.java b/im-center-server/src/test/java/cn/axzo/im/channel/netease/client/NimClientTest.java index 7aaa86f..ffc15ae 100644 --- a/im-center-server/src/test/java/cn/axzo/im/channel/netease/client/NimClientTest.java +++ b/im-center-server/src/test/java/cn/axzo/im/channel/netease/client/NimClientTest.java @@ -1,7 +1,7 @@ package cn.axzo.im.channel.netease.client; import cn.axzo.im.Application; -import cn.axzo.im.channel.netease.dto.RevokeMessageRequest; +import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; import lombok.RequiredArgsConstructor; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -18,11 +18,11 @@ class NimClientTest { @Test void revoke() { - RevokeMessageRequest request = new RevokeMessageRequest(); + NimRevokeMessageRequest request = new NimRevokeMessageRequest(); request.setMessageId("13017220665628"); request.setFrom("eac6c28d888c4cca87683e5c75a34ec4"); request.setTo("master177117_cmp_20350"); - NimClient.CodeResponse revoke = nimClient.revoke(request); + NimClient.NimCodeResponse revoke = nimClient.revoke(request); System.out.println(); } diff --git a/im-center-server/src/test/java/cn/axzo/im/group/GroupManagerTest.java b/im-center-server/src/test/java/cn/axzo/im/group/GroupManagerTest.java new file mode 100644 index 0000000..122fbef --- /dev/null +++ b/im-center-server/src/test/java/cn/axzo/im/group/GroupManagerTest.java @@ -0,0 +1,55 @@ +package cn.axzo.im.group; + +import cn.axzo.im.Application; +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; +import cn.axzo.im.center.api.vo.req.GroupCreateRequest; +import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; +import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; +import cn.axzo.im.center.common.enums.GroupType; +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * @author yanglin + */ +@SpringBootTest(classes = Application.class) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +class GroupManagerTest { + + private final GroupManager groupManager; + + @Test + void createGroup() { + GroupCreateRequest request = new GroupCreateRequest(); + request.setGroupType(GroupType.VISA); + request.setBizCode("yl-group-2"); + request.setName("杨林测试群2"); + request.setOwner(PersonAccountAttribute.cmp(9000399522L, 10616L)); + request.addMember(PersonAccountAttribute.cm(9000399522L)); + request.setAvatar("https://axzo-app.oss-cn-chengdu.aliyuncs.com/dev/common/92c412eb7e62542998cc10059fa7619e6.jpg"); + GroupCreateResponse group = groupManager.createGroup(request); + System.out.println(group); + } + + @Test + void dismissGroup() { + GroupDismissRequest request = new GroupDismissRequest(); + request.setTid(32504762462L); + groupManager.dismissGroup(request); + } + + @Test + void addMembers() { + GroupAddMembersRequest request = new GroupAddMembersRequest(); + request.setTid(32505385179L); + request.addMember(PersonAccountAttribute.cmp(13335L, 8507L)); + request.addMember(PersonAccountAttribute.cmp(13335000000L, 8507L)); + GroupAddMembersResponse response = groupManager.addMembers(request); + System.out.println(response); + } + +} \ No newline at end of file From 2a0b772a12bb6547acea8539cabb2be4a826f98c Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 21 Jan 2025 14:08:46 +0800 Subject: [PATCH 002/201] =?UTF-8?q?REQ-3345:=20=E7=BE=A4=E6=88=90=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/center/api/feign/GroupApi.java | 24 ++++ .../center/api/vo/PersonAccountAttribute.java | 6 +- .../im/center/api/vo/group/GroupInfo.java | 64 +++++++++ .../center/api/vo/group/GroupMemberInfo.java | 25 ++++ .../api/vo/mq/GroupMembersChangeMessage.java | 43 +----- .../api/vo/req/GroupAddMembersRequest.java | 8 -- .../center/api/vo/req/GroupCreateRequest.java | 7 - .../api/vo/req/GroupGetMembersRequest.java | 18 +++ .../api/vo/req/GroupRemoveMembersRequest.java | 27 ++++ .../api/vo/req/SendTemplateMessageParam.java | 2 +- .../api/vo/resp/GroupGetMembersResponse.java | 19 +++ .../im/channel/netease/client/NimClient.java | 5 + .../netease/dto/GroupMemberRequest.java | 27 ++++ .../dto/NimGroupAddMembersRequest.java | 20 +-- .../netease/dto/NimGroupCreateRequest.java | 23 +--- .../dto/NimGroupRemoveMembersRequest.java | 22 ++++ .../dto/NimGroupRemoveMembersResponse.java | 21 +++ .../axzo/im/controller/PrivateController.java | 29 ++++- ...ountMapper.java => GroupMapperMapper.java} | 4 +- .../im/dao/repository/GroupAccountDao.java | 28 ---- .../im/dao/repository/GroupMemberDao.java | 64 +++++++++ .../{GroupAccount.java => GroupMember.java} | 4 +- .../cn/axzo/im/group/GroupBroadcaster.java | 26 ++-- .../cn/axzo/im/group/GroupController.java | 24 ++++ .../java/cn/axzo/im/group/GroupLogger.java | 8 ++ .../java/cn/axzo/im/group/GroupManager.java | 123 ++++++++++++------ .../java/cn/axzo/im/group/GroupSupport.java | 47 ++++--- .../im/group/domain/GroupMembersDiff.java | 57 -------- .../cn/axzo/im/service/AccountService.java | 8 +- ...{PersonImAccounts.java => ImAccounts.java} | 19 ++- .../cn/axzo/im/utils/ImAccountParser.java | 2 +- .../cn/axzo/im/group/GroupManagerTest.java | 9 +- 32 files changed, 544 insertions(+), 269 deletions(-) create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupInfo.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupMemberInfo.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetMembersRequest.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupRemoveMembersRequest.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetMembersResponse.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GroupMemberRequest.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupRemoveMembersRequest.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupRemoveMembersResponse.java rename im-center-server/src/main/java/cn/axzo/im/dao/mapper/{GroupAccountMapper.java => GroupMapperMapper.java} (51%) delete mode 100644 im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupAccountDao.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java rename im-center-server/src/main/java/cn/axzo/im/entity/{GroupAccount.java => GroupMember.java} (86%) create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/GroupLogger.java delete mode 100644 im-center-server/src/main/java/cn/axzo/im/group/domain/GroupMembersDiff.java rename im-center-server/src/main/java/cn/axzo/im/service/domain/{PersonImAccounts.java => ImAccounts.java} (73%) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java index 10a5d17..3e67e8b 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java @@ -4,8 +4,11 @@ import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.req.GroupGetMembersRequest; +import cn.axzo.im.center.api.vo.req.GroupRemoveMembersRequest; import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; +import cn.axzo.im.center.api.vo.resp.GroupGetMembersResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; @@ -19,13 +22,34 @@ public interface GroupApi { String INTRODUCE_MESSAGE = "邀请您加入群聊"; + /** + * 创建群 + */ @PostMapping("/api/im/group/createGroup") ApiResult createGroup(@RequestBody @Validated GroupCreateRequest request); + /** + * 解散群 + */ @PostMapping("/api/im/group/dismissGroup") ApiResult dismissGroup(@RequestBody @Validated GroupDismissRequest request); + /** + * 添加群成员 + */ @PostMapping("/api/im/group/addMembers") ApiResult addMembers(@RequestBody @Validated GroupAddMembersRequest request); + /** + * 移除群成员 + */ + @PostMapping("/api/im/group/removeMembers") + ApiResult removeMembers(@RequestBody @Validated GroupRemoveMembersRequest request); + + /** + * 获取群成员列表 + */ + @PostMapping("/api/im/group/getMembers") + ApiResult getMembers(@RequestBody @Validated GroupGetMembersRequest request); + } \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java index 93a89f9..b84ed90 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java @@ -76,12 +76,14 @@ public class PersonAccountAttribute { public boolean equals(Object o) { if (!(o instanceof PersonAccountAttribute)) return false; PersonAccountAttribute that = (PersonAccountAttribute) o; - return Objects.equals(personId, that.personId) && Objects.equals(ouId, that.ouId) && appType == that.appType; + return Objects.equals(personId, that.personId) + && Objects.equals(ouIdOrDefault(), that.ouIdOrDefault()) + && appType == that.appType; } @Override public int hashCode() { - return Objects.hash(personId, ouId, appType); + return Objects.hash(personId, ouIdOrDefault(), appType); } @Override diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupInfo.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupInfo.java new file mode 100644 index 0000000..1e99f96 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupInfo.java @@ -0,0 +1,64 @@ +package cn.axzo.im.center.api.vo.group; + +import cn.axzo.im.center.common.enums.GroupType; +import cn.axzo.im.center.common.enums.YesOrNo; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupInfo { + /** + * 群id + */ + private Long tid; + /** + * 群名称 + */ + private String name; + /** + * 群业务id + */ + private String bizCode; + /** + * 群类型. VISA: 变洽签, WORKSPACE: 项目群, WORKSPACE_OU: 项目单位群, WORKSPACE_TEAM: 项目班组群 + */ + private GroupType type; + /** + * 群头像 + */ + private String avatar; + /** + * 群成员数量 + */ + private Long memberCount; + /** + * 群成员上限 + */ + private Long memberLimit; + /** + * 群主账号 + */ + private String ownerAccount; + /** + * 群主personId + */ + private Long ownerPersonId; + /** + * 群创建人ouId + */ + private Long createPersonId; + /** + * 是否解散 + */ + private YesOrNo isDismissed; + /** + * 创建时间 + */ + private Date createAt; +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupMemberInfo.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupMemberInfo.java new file mode 100644 index 0000000..ba669d5 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupMemberInfo.java @@ -0,0 +1,25 @@ +package cn.axzo.im.center.api.vo.group; + +import cn.axzo.im.center.common.enums.AppTypeEnum; +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupMemberInfo { + /** + * 群成员personId + */ + private Long personId; + /** + * 群成员ouId + */ + private Long personOuId; + /** + * 群成员端类型 + */ + private AppTypeEnum appType; +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupMembersChangeMessage.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupMembersChangeMessage.java index 0a98b5f..ba5b4ec 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupMembersChangeMessage.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupMembersChangeMessage.java @@ -1,13 +1,10 @@ package cn.axzo.im.center.api.vo.mq; -import cn.axzo.im.center.common.enums.AppTypeEnum; -import cn.axzo.im.center.common.enums.GroupType; -import cn.axzo.im.center.common.enums.YesOrNo; +import cn.axzo.im.center.api.vo.group.GroupInfo; +import cn.axzo.im.center.api.vo.group.GroupMemberInfo; import lombok.Getter; import lombok.Setter; -import java.util.Date; - /** * @author yanglin */ @@ -17,41 +14,11 @@ public class GroupMembersChangeMessage extends MqMessage { /** * 群信息 */ - private GroupInfo groupInfo; + private GroupInfo group; /** - * 账号信息 + * 群成员信息 */ - private AccountInfo account; + private GroupMemberInfo member; - @Setter @Getter - public static class GroupInfo { - private Long id; - private Long tid; - private String name; - private String bizCode; - private GroupType type; - private String avatar; - private Long memberCount; - private Long memberLimit; - private String ownerAccount; - private Long ownerPersonId; - private Long createPersonId; - private YesOrNo isDismissed; - private Date createAt; - private Date updateAt; - } - - @Setter @Getter - public static class AccountInfo { - private Long id; - private Long tid; - private String imAccount; - private Long personId; - private Long personOuId; - private AppTypeEnum appType; - private YesOrNo isRobot; - private Date createAt; - private Date updateAt; - } } \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java index 41a7f2c..6f4a330 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java @@ -1,12 +1,10 @@ package cn.axzo.im.center.api.vo.req; -import cn.axzo.im.center.api.feign.GroupApi; import cn.axzo.im.center.api.vo.PersonAccountAttribute; import com.alibaba.fastjson.JSON; import lombok.Getter; import lombok.Setter; -import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.util.HashSet; @@ -22,12 +20,6 @@ public class GroupAddMembersRequest { @NotNull(message = "群ID不能为空") private Long tid; - /** - * 邀请发送的文字,最大长度 150 位字符 - */ - @NotBlank(message = "邀请发送的文字不能为空") - private String introduceMessage = GroupApi.INTRODUCE_MESSAGE; - /** * 群成员, 不包含群主. members数量不能超过199 */ diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java index 3ee64ad..8afff1b 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java @@ -1,6 +1,5 @@ package cn.axzo.im.center.api.vo.req; -import cn.axzo.im.center.api.feign.GroupApi; import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.common.enums.GroupType; import com.alibaba.fastjson.JSON; @@ -55,12 +54,6 @@ public class GroupCreateRequest { */ private Long memberLimit; - /** - * 邀请发送的文字,最大长度 150 位字符 - */ - @NotBlank(message = "邀请发送的文字不能为空") - private String introduceMessage = GroupApi.INTRODUCE_MESSAGE; - /** * 群头像,最大长度 1024 位字符 */ diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetMembersRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetMembersRequest.java new file mode 100644 index 0000000..ed84b2f --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetMembersRequest.java @@ -0,0 +1,18 @@ +package cn.axzo.im.center.api.vo.req; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotNull; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupGetMembersRequest { + + @NotNull(message = "群ID不能为空") + private Long tid; + +} diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupRemoveMembersRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupRemoveMembersRequest.java new file mode 100644 index 0000000..62dc102 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupRemoveMembersRequest.java @@ -0,0 +1,27 @@ +package cn.axzo.im.center.api.vo.req; + +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Set; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupRemoveMembersRequest { + + @NotNull(message = "群ID不能为空") + private Long tid; + + /** + * 一次性最多传200个 + */ + @NotEmpty(message = "群成员不能为空") + private Set members; + +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java index 7cb48c0..29dca84 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java @@ -93,7 +93,7 @@ public class SendTemplateMessageParam { public Long determineSenderOuId() { if (sender != null) - return sender.getOuId(); + return sender.ouIdOrDefault(); return 0L; } diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetMembersResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetMembersResponse.java new file mode 100644 index 0000000..07c18fe --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetMembersResponse.java @@ -0,0 +1,19 @@ +package cn.axzo.im.center.api.vo.resp; + +import cn.axzo.im.center.api.vo.group.GroupMemberInfo; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupGetMembersResponse { + /** + * 群成员信息列表 + */ + private List member; +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java index 6bc6a17..1b4c514 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java @@ -12,6 +12,8 @@ import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; import cn.axzo.im.channel.netease.dto.NimGroupDismissResponse; import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; import cn.axzo.im.channel.netease.dto.NimGroupGetInfoResponse; +import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersRequest; +import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersResponse; import cn.axzo.im.channel.netease.dto.NimQueryEventRequest; import cn.axzo.im.channel.netease.dto.NimQueryEventResponse; import cn.axzo.im.channel.netease.dto.NimQueryMessageRequest; @@ -76,6 +78,9 @@ public interface NimClient { @PostMapping(value = "/team/add.action") NimGroupAddMembersResponse addMembers(NimGroupAddMembersRequest request); + @PostMapping(value = "/team/kick.action") + NimGroupRemoveMembersResponse removeMembers(NimGroupRemoveMembersRequest request); + @Data class NimCodeResponse { private Integer code; diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GroupMemberRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GroupMemberRequest.java new file mode 100644 index 0000000..90a9230 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/GroupMemberRequest.java @@ -0,0 +1,27 @@ +package cn.axzo.im.channel.netease.dto; + +import com.alibaba.fastjson.JSON; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collection; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupMemberRequest { + + private String members; + + public void addMembers(Collection members) { + if (StringUtils.isBlank(this.members)) + this.members = "[]"; + this.members = JSON.parseArray(this.members) + .fluentAddAll(members) + .toJSONString(); + } + +} diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersRequest.java index 6924b90..33a8539 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupAddMembersRequest.java @@ -2,31 +2,21 @@ package cn.axzo.im.channel.netease.dto; import cn.axzo.im.channel.netease.client.FormRequest; import com.alibaba.fastjson.JSON; -import lombok.Data; -import org.apache.commons.lang3.StringUtils; - -import java.util.Collection; +import lombok.Getter; +import lombok.Setter; /** * @author yanglin */ -@Data +@Setter +@Getter @FormRequest -public class NimGroupAddMembersRequest { +public class NimGroupAddMembersRequest extends GroupMemberRequest { private Long tid; private String owner; - private String members; private String msg; - public void addMembers(Collection members) { - if (StringUtils.isBlank(this.members)) - this.members = "[]"; - this.members = JSON.parseArray(this.members) - .fluentAddAll(members) - .toJSONString(); - } - @Override public String toString() { return JSON.toJSONString(this); diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java index 0097886..87eeb46 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java @@ -3,17 +3,16 @@ package cn.axzo.im.channel.netease.dto; import cn.axzo.im.channel.netease.client.FormRequest; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.annotation.JSONField; -import lombok.Data; +import lombok.Getter; +import lombok.Setter; import org.apache.commons.lang3.StringUtils; -import java.util.Collection; - /** * @author yanglin */ -@Data +@Setter @Getter @FormRequest -public class NimGroupCreateRequest { +public class NimGroupCreateRequest extends GroupMemberRequest { /** * 群名称,最大长度 64 位字符 @@ -26,12 +25,6 @@ public class NimGroupCreateRequest { */ private String owner; - /** - * 邀请的群成员列表,\["aaa","bbb"\](JSONArray 对应的 accid,如果解析出错会报 414) - * members 与 owner 总和上限为 200。members 中无需再加 owner 自己的账号 - */ - private String members; - /** * 群描述,最大长度 512 位字符 */ @@ -93,14 +86,6 @@ public class NimGroupCreateRequest { */ private String attach; - public void addMembers(Collection members) { - if (StringUtils.isBlank(this.members)) - this.members = "[]"; - this.members = JSON.parseArray(this.members) - .fluentAddAll(members) - .toJSONString(); - } - public void addAttachment(String key, Object value) { if (StringUtils.isBlank(this.attach)) this.attach = "{}"; diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupRemoveMembersRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupRemoveMembersRequest.java new file mode 100644 index 0000000..1c3828f --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupRemoveMembersRequest.java @@ -0,0 +1,22 @@ +package cn.axzo.im.channel.netease.dto; + +import cn.axzo.im.channel.netease.client.FormRequest; +import com.alibaba.fastjson.JSON; +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +@FormRequest +public class NimGroupRemoveMembersRequest extends GroupMemberRequest { + private Long tid; + private String owner; + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupRemoveMembersResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupRemoveMembersResponse.java new file mode 100644 index 0000000..2f02fac --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupRemoveMembersResponse.java @@ -0,0 +1,21 @@ +package cn.axzo.im.channel.netease.dto; + +import cn.axzo.im.channel.netease.client.NimClient; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class NimGroupRemoveMembersResponse extends NimClient.NimCodeResponse { + private JSONObject faccid; + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java index dab47ef..e0b7d74 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java @@ -1,12 +1,16 @@ package cn.axzo.im.controller; +import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; +import cn.axzo.im.center.api.vo.req.GroupCreateRequest; +import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.req.GroupRemoveMembersRequest; import cn.axzo.im.center.api.vo.req.SendMessageParam; import cn.axzo.im.channel.netease.client.NimClient; -import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; import cn.axzo.im.channel.netease.dto.NimQueryEventRequest; import cn.axzo.im.channel.netease.dto.NimQueryMessageRequest; import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; +import cn.axzo.im.group.GroupManager; import cn.axzo.im.job.CreateMessageHistoryJob; import cn.axzo.im.job.ExpungeImTaskJob; import cn.axzo.im.job.RevokeAllMessagesJob; @@ -34,6 +38,7 @@ public class PrivateController { private final CreateMessageHistoryJob createMessageHistoryJob; private final MessageController messageController; private final ExpungeImTaskJob expungeImTaskJob; + private final GroupManager groupManager; @PostMapping("/private/revoke") public Object revoke(@Valid @RequestBody NimRevokeMessageRequest request) { @@ -76,9 +81,27 @@ public class PrivateController { return CommonResponse.success(count); } + @PostMapping("/private/group/createGroup") + public Object createGroup(@Valid @RequestBody GroupCreateRequest request) { + return CommonResponse.success(groupManager.createGroup(request)); + } + @PostMapping("/private/group/dismissGroup") - public Object dismissGroup(@Valid @RequestBody NimGroupDismissRequest request) { - return CommonResponse.success(nimClient.dismissGroup(request)); + public Object dismissGroup(@Valid @RequestBody GroupDismissRequest request) { + groupManager.dismissGroup(request); + return CommonResponse.success(); + } + + @PostMapping("/private/group/addMembers") + public Object addMembers(@Valid @RequestBody GroupAddMembersRequest request) { + groupManager.addMembers(request); + return CommonResponse.success(); + } + + @PostMapping("/private/group/removeMembers") + public Object removeMembers(@Valid @RequestBody GroupRemoveMembersRequest request) { + groupManager.removeMembers(request); + return CommonResponse.success(); } @PostMapping("/private/group/getGroupInfo") diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupAccountMapper.java b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java similarity index 51% rename from im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupAccountMapper.java rename to im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java index ab253f1..61477c6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupAccountMapper.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java @@ -1,10 +1,10 @@ package cn.axzo.im.dao.mapper; -import cn.axzo.im.entity.GroupAccount; +import cn.axzo.im.entity.GroupMember; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** * @author yanglin */ -public interface GroupAccountMapper extends BaseMapper { +public interface GroupMapperMapper extends BaseMapper { } diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupAccountDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupAccountDao.java deleted file mode 100644 index b15ab1d..0000000 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupAccountDao.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.axzo.im.dao.repository; - -import cn.axzo.im.dao.mapper.GroupAccountMapper; -import cn.axzo.im.entity.GroupAccount; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import org.springframework.stereotype.Repository; - -import java.util.List; - -/** - * @author yanglin - */ -@Repository("groupAccountDao") -public class GroupAccountDao extends ServiceImpl { - - public List getByTid(Long tid) { - return lambdaQuery() - .eq(GroupAccount::getTid, tid) - .list(); - } - - public void deleteAccounts(Long tid) { - lambdaUpdate() - .eq(GroupAccount::getTid, tid) - .remove(); - } - -} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java new file mode 100644 index 0000000..4042ceb --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java @@ -0,0 +1,64 @@ +package cn.axzo.im.dao.repository; + +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.dao.mapper.GroupMapperMapper; +import cn.axzo.im.entity.GroupMember; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static java.util.stream.Collectors.toSet; + +/** + * @author yanglin + */ +@Repository("groupMemberDao") +public class GroupMemberDao extends ServiceImpl { + + public void deleteAccounts(Long tid) { + lambdaUpdate() + .eq(GroupMember::getTid, tid) + .remove(); + } + + public Set getGroupPersons(Long tid) { + return getByTid(tid).stream() + .map(account -> { + PersonAccountAttribute person = new PersonAccountAttribute(); + person.setPersonId(account.getPersonId() + ""); + person.setOuId(account.getPersonOuId()); + person.setAppType(account.getAppType()); + return person; + }) + .collect(toSet()); + } + + public List getByTid(Long tid) { + return lambdaQuery() + .eq(GroupMember::getTid, tid) + .list(); + } + + public List getByPersons( + Long tid, Collection persons) { + if (CollectionUtils.isEmpty(persons)) + return Collections.emptyList(); + return lambdaQuery() + .eq(GroupMember::getTid, tid) + .nested(wrapper -> { + for (PersonAccountAttribute person : persons) { + wrapper.or() + .eq(GroupMember::getPersonId, Long.parseLong(person.getPersonId())) + .eq(GroupMember::getPersonOuId, person.ouIdOrDefault()) + .eq(GroupMember::getAppType, person.getAppType()); + } + }) + .list(); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupAccount.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java similarity index 86% rename from im-center-server/src/main/java/cn/axzo/im/entity/GroupAccount.java rename to im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java index c21eae7..98e2387 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/GroupAccount.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java @@ -13,8 +13,8 @@ import java.util.Date; */ @Setter @Getter -@TableName(value = "im_group_account", autoResultMap = true) -public class GroupAccount { +@TableName(value = "im_group_member", autoResultMap = true) +public class GroupMember { private Long id; private Long tid; private String imAccount; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java index b147ea3..665da59 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java @@ -3,12 +3,13 @@ package cn.axzo.im.group; import cn.axzo.basics.common.BeanMapper; import cn.axzo.framework.rocketmq.Event; import cn.axzo.im.center.api.vo.mq.GroupMembersChangeMessage; +import cn.axzo.im.center.api.vo.req.GroupInfo; +import cn.axzo.im.center.api.vo.mq.GroupMembersChangeMessage.MemberInfo; import cn.axzo.im.config.MqProducer; import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.entity.Group; -import cn.axzo.im.entity.GroupAccount; +import cn.axzo.im.entity.GroupMember; import cn.axzo.im.event.inner.EventTypeEnum; -import cn.axzo.im.group.domain.GroupMembersDiff; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -24,27 +25,26 @@ class GroupBroadcaster { private final MqProducer mqProducer; private final GroupDao groupDao; - void fireMembersAdded(Group group, GroupMembersDiff diff) { - diff.diff(); - fireMembersChanged(group, diff.getAdded(), EventTypeEnum.GROUP_ADD_MEMBERS); + void fireMembersAdded(Group group, Collection accounts) { + fireMembersChanged(group, accounts, EventTypeEnum.GROUP_ADD_MEMBERS); } - void fireMembersRemoved(Group group, GroupMembersDiff diff) { - diff.diff(); - fireMembersChanged(group, diff.getRemoved(), EventTypeEnum.GROUP_REMOVE_MEMBERS); + void fireMembersRemoved(Group group, Collection accounts) { + fireMembersChanged(group, accounts, EventTypeEnum.GROUP_REMOVE_MEMBERS); } - private void fireMembersChanged(Group group, Collection accounts, EventTypeEnum eventType) { + private void fireMembersChanged(Group group, Collection accounts, EventTypeEnum eventType) { if (accounts.isEmpty()) return; Group effectiveGroup = groupDao.getById(group.getId()); - for (GroupAccount account : accounts) { + for (GroupMember account : accounts) { GroupMembersChangeMessage message = new GroupMembersChangeMessage(); - message.setGroupInfo(BeanMapper.copyBean(effectiveGroup, GroupMembersChangeMessage.GroupInfo.class)); - message.setAccount(BeanMapper.copyBean(account, GroupMembersChangeMessage.AccountInfo.class)); + message.setGroup(BeanMapper.copyBean(effectiveGroup, GroupInfo.class)); + message.setMember(BeanMapper.copyBean(account, MemberInfo.class)); Event event = Event.builder() - .targetId(account.getImAccount()) + .targetId(String.format("%d:%d", group.getTid(), account.getPersonId())) .targetType(eventType.getModel()) .eventCode(eventType.getEventCode()) + .shardingKey(group.getId() + "") .data(message) .build(); mqProducer.send(event); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java index 888c082..f03f9bb 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java @@ -1,16 +1,25 @@ package cn.axzo.im.group; +import cn.axzo.basics.common.BeanMapper; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.im.center.api.feign.GroupApi; +import cn.axzo.im.center.api.vo.group.GroupMemberInfo; import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.req.GroupGetMembersRequest; +import cn.axzo.im.center.api.vo.req.GroupRemoveMembersRequest; import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; +import cn.axzo.im.center.api.vo.resp.GroupGetMembersResponse; +import cn.axzo.im.dao.repository.GroupMemberDao; +import cn.axzo.im.entity.GroupMember; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + /** * @author yanglin */ @@ -20,6 +29,7 @@ import org.springframework.web.bind.annotation.RestController; public class GroupController implements GroupApi { private final GroupManager groupManager; + private final GroupMemberDao groupMemberDao; @Override public ApiResult createGroup(GroupCreateRequest request) { @@ -37,4 +47,18 @@ public class GroupController implements GroupApi { return ApiResult.ok(groupManager.addMembers(request)); } + @Override + public ApiResult addMembers(GroupRemoveMembersRequest request) { + groupManager.removeMembers(request); + return ApiResult.ok(); + } + + @Override + public ApiResult getMembers(GroupGetMembersRequest request) { + List members = groupMemberDao.getByTid(request.getTid()); + GroupGetMembersResponse response = new GroupGetMembersResponse(); + response.setMember(BeanMapper.copyList(members, GroupMemberInfo.class)); + return ApiResult.ok(response); + } + } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupLogger.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupLogger.java new file mode 100644 index 0000000..bc0a9d1 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupLogger.java @@ -0,0 +1,8 @@ +package cn.axzo.im.group; + +/** + * @author yanglin + */ +public interface GroupLogger { + void log(String message, Object... args); +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 5d04b2b..66dc9dd 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -5,6 +5,7 @@ import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.req.GroupRemoveMembersRequest; import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; import cn.axzo.im.channel.netease.client.NimClient; @@ -17,15 +18,15 @@ import cn.axzo.im.channel.netease.dto.NimGroupDismissResponse; import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; import cn.axzo.im.channel.netease.dto.NimGroupGetInfoResponse; import cn.axzo.im.channel.netease.dto.NimGroupInfo; -import cn.axzo.im.dao.repository.GroupAccountDao; +import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersRequest; +import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersResponse; import cn.axzo.im.dao.repository.GroupDao; +import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.Group; -import cn.axzo.im.entity.GroupAccount; -import cn.axzo.im.group.domain.GroupMembersDiff; +import cn.axzo.im.entity.GroupMember; import cn.axzo.im.service.AccountService; -import cn.axzo.im.service.domain.PersonImAccounts; +import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.BizAssertions; -import cn.hutool.core.map.MapUtil; import com.alibaba.fastjson.JSON; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -39,45 +40,49 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import static java.util.stream.Collectors.toList; + /** * @author yanglin */ @Slf4j @Component @RequiredArgsConstructor -class GroupManager { +public class GroupManager { private final NimClient nimClient; private final GroupDao groupDao; - private final GroupAccountDao groupAccountDao; + private final GroupMemberDao groupMemberDao; private final GroupSupport groupSupport; private final AccountService accountService; private final GroupBroadcaster groupBroadcaster; @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { - PersonImAccounts accounts = accountService.findPersonAccounts(request.getOwnerAndMembers()); - Group group = groupSupport.buildNewGroup(request, accounts); + BizAssertions.assertTrue(request.getOwnerAndMembers().size() > 1, "群成员数量(含群主)不能少于2"); + ImAccounts imAccounts = accountService.getAccountsByPersons(request.getOwnerAndMembers()); + Group group = groupSupport.buildNewGroup(request, imAccounts); + BizAssertions.assertFalse(group.isMemberLimitReached( + request.getOwnerAndMembers().size()), "无法创建群, 群成员数量超过上限" + group.getMemberLimit()); try { groupDao.save(group); } catch (DuplicateKeyException e) { log.warn("重复创建群, request={}", request, e); throw new ServiceException(403, String.format("群已经存在: %s", request.getName())); } - NimGroupCreateRequest nimRequest = groupSupport.buildNimCreateGroupRequest(request, group, accounts); + NimGroupCreateRequest nimRequest = groupSupport + .buildNimCreateGroupRequest(request, imAccounts); NimGroupCreateResponse nimResponse = nimClient.createGroup(nimRequest); log.info("创建群, request={}, response={}", nimRequest, nimResponse); BizAssertions.assertTrue(nimResponse.isSuccess(), "创建群失败: {}", nimResponse.getDesc()); groupDao.updateTid(group.getId(), nimResponse.getTid()); - GroupMembersDiff memberDiff = createMembersDiff(nimResponse.getTid()); - syncGroupAccounts(group); - groupBroadcaster.fireMembersAdded(group, memberDiff); + group = groupDao.getById(group.getId()); + syncGroupMembers(group); + groupBroadcaster.fireMembersAdded(group, groupMemberDao.getByTid(nimResponse.getTid())); GroupCreateResponse response = new GroupCreateResponse(); response.setTid(nimResponse.getTid()); - Set notFound = accounts.getAccountNotFoundPersons(request.getMembers()); - if (!notFound.isEmpty()) - groupSupport.log("创建群[TID:{}], IM账号不存在列表: {}", group.getTid(), JSON.toJSONString(notFound)); - response.setAccountsNotFound(notFound); + response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( + groupSupport, "创建群", group, request.getMembers())); return response; } @@ -98,37 +103,61 @@ class GroupManager { public GroupAddMembersResponse addMembers(GroupAddMembersRequest request) { Group group = findGroupForUpdateOrThrow(request.getTid()); BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); - NimGroupInfo groupInfo = fetchGroupInfo(group).orElse(null); - BizAssertions.assertNotNull(groupInfo, "[NIM] 群不存在: {}", group.getTid()); - PersonImAccounts accounts = accountService.findPersonAccounts(request.getMembers()); + // sync members 1 + syncGroupMembers(group); + // prepare add members + Set preMembers = groupMemberDao.getGroupPersons(group.getTid()); + List toAddMembers = request.getMembers().stream() + .filter(member -> !preMembers.contains(member)) + .collect(toList()); + if (group.isMemberLimitReached(preMembers.size() + toAddMembers.size())) + throw new ServiceException("群聊人数上限" + group.getMemberLimit() +"人, 请删除部分已选人员"); + ImAccounts imAccounts = accountService.getAccountsByPersons(toAddMembers); + if (imAccounts.isAccountEmpty()) { + groupSupport.log("添加群成员[TID:{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + group.getTid(), JSON.toJSONString(request.getMembers())); + return new GroupAddMembersResponse(); + } NimGroupAddMembersRequest nimRequest = groupSupport - .buildAddMembersRequest(request, group, groupInfo.getOwner().getAccid(), accounts); - GroupMembersDiff memberDiff = createMembersDiff(group.getTid()); + .buildAddMembersRequest(group, group.getOwnerAccount(), imAccounts); + // add members NimGroupAddMembersResponse nimResponse = nimClient.addMembers(nimRequest); log.info("添加群成员, request={}, response={}", nimRequest, nimResponse); BizAssertions.assertTrue(nimResponse.isSuccess(), "添加群成员失败: {}", nimResponse.getDesc()); - if (MapUtil.isNotEmpty(nimResponse.getFaccid())) - groupSupport.log("添加群成员[TID:{}], 错误信息: {}", - group.getTid(), JSON.toJSONString(nimResponse.getFaccid())); - syncGroupAccounts(group); - groupBroadcaster.fireMembersAdded(group, memberDiff); + // sync members 2 + syncGroupMembers(group); + groupBroadcaster.fireMembersAdded(group, groupMemberDao + .getByPersons(group.getTid(), toAddMembers)); GroupAddMembersResponse response = new GroupAddMembersResponse(); - Set notFound = accounts.getAccountNotFoundPersons(request.getMembers()); - if (!notFound.isEmpty()) - groupSupport.log("创建群[TID:{}], IM账号不存在列表: {}", group.getTid(), JSON.toJSONString(notFound)); - response.setAccountsNotFound(notFound); + response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( + groupSupport, "添加群成员", group, request.getMembers())); return response; } - private void syncGroupAccounts(Group group) { - NimGroupInfo groupInfo = fetchGroupInfo(group).orElse(null); - if (groupInfo == null) return; - groupAccountDao.deleteAccounts(group.getTid()); - List accounts = groupSupport - .parseGroupAccounts(group, groupInfo.getOwnerAndMembers()); - if (CollectionUtils.isNotEmpty(accounts)) - groupAccountDao.saveBatch(accounts); - groupDao.updateMembersCount(group.getTid(), accounts.size()); + @Transactional + public void removeMembers(GroupRemoveMembersRequest request) { + Group group = findGroupForUpdateOrThrow(request.getTid()); + BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); + ImAccounts imAccounts = accountService.getAccountsByPersons(request.getMembers()); + if (imAccounts.isAccountEmpty()) { + groupSupport.log("添加群成员[TID:{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + group.getTid(), JSON.toJSONString(request.getMembers())); + return; + } + syncGroupMembers(group); + List toRemoveMembers = groupMemberDao.getByPersons( + group.getTid(), request.getMembers()); + if (CollectionUtils.isEmpty(toRemoveMembers)) + return; + NimGroupRemoveMembersRequest nimRequest = groupSupport + .buildRemoveMembersRequest(group, group.getOwnerAccount(), imAccounts); + NimGroupRemoveMembersResponse nimResponse = nimClient.removeMembers(nimRequest); + log.info("移除群成员, request={}, response={}", nimRequest, nimResponse); + if (nimResponse.isSuccess()) { + syncGroupMembers(group); + // 不比较直接发消息 + groupBroadcaster.fireMembersAdded(group, toRemoveMembers); + } } @NotNull @@ -138,6 +167,17 @@ class GroupManager { return group; } + private void syncGroupMembers(Group group) { + NimGroupInfo groupInfo = fetchGroupInfo(group).orElse(null); + if (groupInfo == null) return; + groupMemberDao.deleteAccounts(group.getTid()); + List accounts = groupSupport + .parseGroupMembers(group, groupInfo.getOwnerAndMembers()); + if (CollectionUtils.isNotEmpty(accounts)) + groupMemberDao.saveBatch(accounts); + groupDao.updateMembersCount(group.getTid(), accounts.size()); + } + private Optional fetchGroupInfo(Group group) { NimGroupGetInfoRequest nimRequest = new NimGroupGetInfoRequest(); nimRequest.setTid(group.getTid()); @@ -152,7 +192,4 @@ class GroupManager { return Optional.of(nimResponse.getTinfo()); } - private GroupMembersDiff createMembersDiff(Long tid) { - return new GroupMembersDiff(() -> groupAccountDao.getByTid(tid)); - } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index 87b3864..3dbb7a1 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -1,17 +1,18 @@ package cn.axzo.im.group; +import cn.axzo.im.center.api.feign.GroupApi; import cn.axzo.im.center.api.vo.PersonAccountAttribute; -import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.channel.netease.dto.NimGroupAddMembersRequest; import cn.axzo.im.channel.netease.dto.NimGroupCreateRequest; import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; import cn.axzo.im.channel.netease.dto.NimGroupMemberInfo; +import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersRequest; import cn.axzo.im.entity.Group; -import cn.axzo.im.entity.GroupAccount; +import cn.axzo.im.entity.GroupMember; import cn.axzo.im.service.ChatGroupService; -import cn.axzo.im.service.domain.PersonImAccounts; +import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.BizAssertions; import cn.axzo.im.utils.ImAccountParser; import lombok.RequiredArgsConstructor; @@ -29,11 +30,11 @@ import java.util.Set; @Slf4j @Component @RequiredArgsConstructor -class GroupSupport { +public class GroupSupport implements GroupLogger { private final ChatGroupService chatGroupService; - Group buildNewGroup(GroupCreateRequest request, PersonImAccounts accounts) { + Group buildNewGroup(GroupCreateRequest request, ImAccounts accounts) { String owner = accounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); Group group = new Group(); @@ -52,18 +53,16 @@ class GroupSupport { } NimGroupCreateRequest buildNimCreateGroupRequest( - GroupCreateRequest request, Group group, PersonImAccounts accounts) { - BizAssertions.assertFalse(group.isMemberLimitReached( - accounts.getAccountSize()), "无法创建群, 群成员数量超过上限"); - String owner = accounts.findAccount(request.getOwner()).orElse(null); + GroupCreateRequest request, ImAccounts imAccounts) { + String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); - BizAssertions.assertTrue(accounts.getAccountSize() > 1, "无法创建群. 存在的群成员IM账号数量需要大于等于2"); + BizAssertions.assertTrue(imAccounts.getAccountSize() > 1, "无法创建群. 存在的群成员IM账号数量需要大于等于2"); NimGroupCreateRequest nimRequest = new NimGroupCreateRequest(); nimRequest.setName(request.getName()); nimRequest.setOwner(owner); - nimRequest.addMembers(accounts.filterAccounts(account -> !account.equals(owner))); - nimRequest.setIntroduceMessage(request.getIntroduceMessage()); + nimRequest.addMembers(imAccounts.filterAccounts(account -> !account.equals(owner))); + nimRequest.setIntroduceMessage(GroupApi.INTRODUCE_MESSAGE); nimRequest.setIcon(request.getAvatar()); nimRequest.addAttachment(Group.ATTACHMENT_GROUP_TYPE, request.getGroupType()); return nimRequest; @@ -77,16 +76,27 @@ class GroupSupport { } NimGroupAddMembersRequest buildAddMembersRequest( - GroupAddMembersRequest request, Group group, String owner, PersonImAccounts accounts) { + Group group, String owner, ImAccounts accounts) { + BizAssertions.assertNotEmpty(accounts.getAccounts(), "有效群成员IM账号列表为空"); NimGroupAddMembersRequest nimRequest = new NimGroupAddMembersRequest(); nimRequest.setTid(group.getTid()); nimRequest.setOwner(owner); - nimRequest.setMsg(request.getIntroduceMessage()); + nimRequest.setMsg(GroupApi.INTRODUCE_MESSAGE); nimRequest.addMembers(accounts.getAccounts()); return nimRequest; } - void log(String message, Object... args) { + NimGroupRemoveMembersRequest buildRemoveMembersRequest( + Group group, String owner, ImAccounts accounts) { + BizAssertions.assertNotEmpty(accounts.getAccounts(), "有效群成员IM账号列表为空"); + NimGroupRemoveMembersRequest nimRequest = new NimGroupRemoveMembersRequest(); + nimRequest.setTid(group.getTid()); + nimRequest.setOwner(owner); + nimRequest.addMembers(accounts.getAccounts()); + return nimRequest; + } + + public void log(String message, Object... args) { try { chatGroupService.sendDingRobot(MessageFormatter.arrayFormat(message, args).getMessage()); } catch (Exception e) { @@ -94,11 +104,11 @@ class GroupSupport { } } - List parseGroupAccounts(Group group, Set members) { - ArrayList accounts = new ArrayList<>(); + List parseGroupMembers(Group group, Set members) { + ArrayList accounts = new ArrayList<>(); for (NimGroupMemberInfo member : members) { PersonAccountAttribute person = ImAccountParser.parsePerson(member.getAccid()).orElse(null); - GroupAccount account = new GroupAccount(); + GroupMember account = new GroupMember(); accounts.add(account); account.setTid(group.getTid()); account.setImAccount(member.getAccid()); @@ -116,4 +126,5 @@ class GroupSupport { } return accounts; } + } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/domain/GroupMembersDiff.java b/im-center-server/src/main/java/cn/axzo/im/group/domain/GroupMembersDiff.java deleted file mode 100644 index 7480069..0000000 --- a/im-center-server/src/main/java/cn/axzo/im/group/domain/GroupMembersDiff.java +++ /dev/null @@ -1,57 +0,0 @@ -package cn.axzo.im.group.domain; - -import cn.axzo.im.entity.GroupAccount; - -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -/** - * @author yanglin - */ -@SuppressWarnings("DuplicatedCode") -public class GroupMembersDiff { - - private final Supplier> accountsProvider; - private final Map before; - private Map after; - - public GroupMembersDiff(Supplier> accountsProvider) { - this.accountsProvider = accountsProvider; - this.before = reload(); - } - - public void diff() { - if (after == null) - after = reload(); - } - - public Collection getAdded() { - HashMap accounts = new HashMap<>(); - for (GroupAccount account : after.values()) { - String imAccount = account.getImAccount(); - if (!before.containsKey(imAccount) && !accounts.containsKey(imAccount)) - accounts.put(imAccount, account); - } - return accounts.values(); - } - - public Collection getRemoved() { - HashMap accounts = new HashMap<>(); - for (GroupAccount account : before.values()) { - String imAccount = account.getImAccount(); - if (!after.containsKey(imAccount) && !accounts.containsKey(imAccount)) - accounts.put(imAccount, account); - } - return accounts.values(); - } - - private Map reload() { - return accountsProvider.get().stream() - .collect(Collectors.toMap(GroupAccount::getImAccount, account -> account)); - } - -} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java index 734da4b..63e6a89 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java @@ -32,7 +32,7 @@ import cn.axzo.im.entity.AccountRegister; import cn.axzo.im.entity.RobotInfo; import cn.axzo.im.entity.bo.AccountQueryParam; import cn.axzo.im.gateway.ProfilesApiGateway; -import cn.axzo.im.service.domain.PersonImAccounts; +import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.MiscUtils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; @@ -580,9 +580,9 @@ public class AccountService { AccountTypeEnum.CUSTOM, AppTypeEnum.SYSTEM, appKey); } - public PersonImAccounts findPersonAccounts(Collection persons) { + public ImAccounts getAccountsByPersons(Collection persons) { if (CollectionUtils.isEmpty(persons)) - return new PersonImAccounts(Collections.emptyList()); + return new ImAccounts(Collections.emptyList()); List accounts = accountRegisterDao.lambdaQuery() .nested(wrapper -> { for (PersonAccountAttribute person : persons) { @@ -593,7 +593,7 @@ public class AccountService { } }) .list(); - return new PersonImAccounts(accounts); + return new ImAccounts(accounts); } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/domain/PersonImAccounts.java b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java similarity index 73% rename from im-center-server/src/main/java/cn/axzo/im/service/domain/PersonImAccounts.java rename to im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java index 1be4cf8..4100883 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/domain/PersonImAccounts.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java @@ -1,7 +1,10 @@ package cn.axzo.im.service.domain; +import cn.axzo.framework.jackson.utility.JSON; import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.entity.AccountRegister; +import cn.axzo.im.entity.Group; +import cn.axzo.im.group.GroupLogger; import lombok.RequiredArgsConstructor; import lombok.Setter; import org.apache.commons.collections.CollectionUtils; @@ -20,17 +23,25 @@ import static java.util.stream.Collectors.toSet; */ @Setter @RequiredArgsConstructor -public class PersonImAccounts { +public class ImAccounts { private final List imAccounts; - public Set - getAccountNotFoundPersons(Set persons) { + public boolean isAccountEmpty() { + return imAccounts.isEmpty(); + } + + public Set getAccountNotFoundPersons( + GroupLogger logger, String operation, + Group group, Set persons) { if (CollectionUtils.isEmpty(persons)) return Collections.emptySet(); - return persons.stream() + Set notFound = persons.stream() .filter(person -> !findAccount(person).isPresent()) .collect(toSet()); + if (!notFound.isEmpty()) + logger.log("{}[TID:{}], IM账号不存在列表: {}", operation, group.getTid(), JSON.toJSONString(notFound)); + return notFound; } public Set filterAccounts(Predicate filter) { diff --git a/im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java b/im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java index 04afb3e..4251ed3 100644 --- a/im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java +++ b/im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java @@ -24,7 +24,7 @@ public class ImAccountParser { PersonAccountAttribute person = new PersonAccountAttribute(); person.setPersonId(personId); - person.setOuId(ouId != null ? Long.parseLong(ouId.substring(1)) : null); + person.setOuId(ouId != null ? Long.parseLong(ouId) : null); person.setAppType(appType); return Optional.of(person); } diff --git a/im-center-server/src/test/java/cn/axzo/im/group/GroupManagerTest.java b/im-center-server/src/test/java/cn/axzo/im/group/GroupManagerTest.java index 122fbef..fee3326 100644 --- a/im-center-server/src/test/java/cn/axzo/im/group/GroupManagerTest.java +++ b/im-center-server/src/test/java/cn/axzo/im/group/GroupManagerTest.java @@ -24,10 +24,11 @@ class GroupManagerTest { @Test void createGroup() { + int idx = 6; GroupCreateRequest request = new GroupCreateRequest(); request.setGroupType(GroupType.VISA); - request.setBizCode("yl-group-2"); - request.setName("杨林测试群2"); + request.setBizCode("yl-group-" + idx); + request.setName("杨林测试群" + idx); request.setOwner(PersonAccountAttribute.cmp(9000399522L, 10616L)); request.addMember(PersonAccountAttribute.cm(9000399522L)); request.setAvatar("https://axzo-app.oss-cn-chengdu.aliyuncs.com/dev/common/92c412eb7e62542998cc10059fa7619e6.jpg"); @@ -38,14 +39,14 @@ class GroupManagerTest { @Test void dismissGroup() { GroupDismissRequest request = new GroupDismissRequest(); - request.setTid(32504762462L); + request.setTid(32543625538L); groupManager.dismissGroup(request); } @Test void addMembers() { GroupAddMembersRequest request = new GroupAddMembersRequest(); - request.setTid(32505385179L); + request.setTid(32544969049L); request.addMember(PersonAccountAttribute.cmp(13335L, 8507L)); request.addMember(PersonAccountAttribute.cmp(13335000000L, 8507L)); GroupAddMembersResponse response = groupManager.addMembers(request); From ea0d9e638effcab990314dec1543a333b2eac658 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 22 Jan 2025 11:28:00 +0800 Subject: [PATCH 003/201] =?UTF-8?q?REQ-3345:=20=E5=90=91=E7=BE=A4=E9=87=8C?= =?UTF-8?q?=E5=8F=91=E5=8D=A1=E7=89=87=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/center/api/feign/GroupApi.java | 8 +++ .../center/api/vo/PersonAccountAttribute.java | 11 +-- .../api/vo/req/GroupGetOwnerRequest.java | 18 +++++ .../api/vo/req/SendTemplateMessageParam.java | 16 ++++- .../api/vo/resp/GroupGetOwnerResponse.java | 19 ++++++ .../im/center/common/enums/AppTypeEnum.java | 7 +- .../center/common/enums/GroupMemberType.java | 18 +++++ .../axzo/im/center/common/enums/YesOrNo.java | 3 + .../im/channel/netease/NimChannelService.java | 2 - .../axzo/im/controller/MessageController.java | 14 +++- .../java/cn/axzo/im/entity/GroupMember.java | 2 + .../cn/axzo/im/entity/UpdatableMessage.java | 1 + .../cn/axzo/im/group/GroupBroadcaster.java | 6 +- .../cn/axzo/im/group/GroupController.java | 15 +++- .../java/cn/axzo/im/group/GroupManager.java | 42 ++---------- .../cn/axzo/im/group/GroupMemberManager.java | 68 +++++++++++++++++++ .../java/cn/axzo/im/group/GroupSupport.java | 9 ++- .../cn/axzo/im/group/MergedGroupSupport.java | 60 ++++++++++++++++ .../send/handler/CommonSendBatchHandler.java | 1 + .../im/send/handler/CommonSendOneHandler.java | 7 +- .../cn/axzo/im/send/job/SendMessageJob.java | 4 +- .../service/impl/MessageTaskServiceImpl.java | 55 +++++++++++---- .../cn/axzo/im/updatable/InitHistories.java | 7 ++ .../im/updatable/UpdatableMessageManager.java | 37 ++++++++-- 24 files changed, 345 insertions(+), 85 deletions(-) create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetOwnerRequest.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetOwnerResponse.java create mode 100644 im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupMemberType.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/GroupMemberManager.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/MergedGroupSupport.java diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java index 3e67e8b..836fba8 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java @@ -5,10 +5,12 @@ import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; import cn.axzo.im.center.api.vo.req.GroupDismissRequest; import cn.axzo.im.center.api.vo.req.GroupGetMembersRequest; +import cn.axzo.im.center.api.vo.req.GroupGetOwnerRequest; import cn.axzo.im.center.api.vo.req.GroupRemoveMembersRequest; import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; import cn.axzo.im.center.api.vo.resp.GroupGetMembersResponse; +import cn.axzo.im.center.api.vo.resp.GroupGetOwnerResponse; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; @@ -52,4 +54,10 @@ public interface GroupApi { @PostMapping("/api/im/group/getMembers") ApiResult getMembers(@RequestBody @Validated GroupGetMembersRequest request); + /** + * 获取群主信息 + */ + @PostMapping("/api/im/group/getOwner") + ApiResult getOwner(@RequestBody @Validated GroupGetOwnerRequest request); + } \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java index b84ed90..38be41d 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java @@ -27,22 +27,17 @@ public class PersonAccountAttribute { private String personId; /** - * appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号, - * 所以需要根据organizationalUnitId获取账号 + * 单位id, 管理端人员必填 */ private Long ouId; /** - * 项目id + * 项目id, 选填 */ private Long workspaceId; /** - * 发送消息到App端 - * 工人端、企业端、服务器 - * CM、CMP、SYSTEM - * - * @See cn.axzo.im.center.common.enums.AppTypeEnum + * 发送消息到App端. CM: 工人端, CMP: 企业端 */ @NotNull(message = "appType不能为空") private AppTypeEnum appType; diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetOwnerRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetOwnerRequest.java new file mode 100644 index 0000000..65dad3c --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetOwnerRequest.java @@ -0,0 +1,18 @@ +package cn.axzo.im.center.api.vo.req; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotNull; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupGetOwnerRequest { + + @NotNull(message = "群ID不能为空") + private Long tid; + +} diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java index 29dca84..a4e9807 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java @@ -11,8 +11,8 @@ import lombok.NoArgsConstructor; import javax.validation.Valid; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -32,9 +32,13 @@ public class SendTemplateMessageParam { /** * 消息接收用户信息 */ - @NotEmpty(message = "消息接收用户信息不能为空") @Valid - private List receivePersons; + private Set receivePersons; + + /** + * 消息接收IM账号或群id + */ + private Set imReceiveAccounts; /** * 消息标题 @@ -102,9 +106,15 @@ public class SendTemplateMessageParam { } public Set uniqueReceivePersons() { + if (receivePersons == null) + return Collections.emptySet(); return new HashSet<>(receivePersons); } + public Set imReceiveAccountsOrEmpty() { + return imReceiveAccounts == null ? Collections.emptySet() : imReceiveAccounts; + } + @Override public String toString() { return JSON.toJSONString(this); diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetOwnerResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetOwnerResponse.java new file mode 100644 index 0000000..e7b1816 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetOwnerResponse.java @@ -0,0 +1,19 @@ +package cn.axzo.im.center.api.vo.resp; + +import cn.axzo.im.center.api.vo.group.GroupMemberInfo; +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupGetOwnerResponse { + + /** + * 群主信息 + */ + private GroupMemberInfo owner; + +} \ No newline at end of file diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java index 92fa644..0174ace 100644 --- a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java @@ -27,7 +27,12 @@ public enum AppTypeEnum implements CodeDefinition { /** * 服务器 机器人 */ - SYSTEM("system", "服务器"); + SYSTEM("system", "服务器"), + + /** + * 没有端信息 + */ + NONE("none", "没有端信息"); @EnumValue private final String code; diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupMemberType.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupMemberType.java new file mode 100644 index 0000000..f3cd724 --- /dev/null +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupMemberType.java @@ -0,0 +1,18 @@ +package cn.axzo.im.center.common.enums; + +import cn.axzo.basics.common.constant.enums.CodeDefinition; + +/** + * @author yanglin + */ +public enum GroupMemberType implements CodeDefinition { + + MEMBER, + OWNER + ; + + @Override + public String getCode() { + return name(); + } +} diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java index 7b836b5..485e818 100644 --- a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java @@ -20,4 +20,7 @@ public enum YesOrNo implements CodeDefinition { private final String code; private final String desc; + public static YesOrNo of(boolean value) { + return value ? YES : NO; + } } diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java index 43c9177..b04a51a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java @@ -213,8 +213,6 @@ public class NimChannelService implements IMChannelProvider { if (messageInfo == null) { throw new ServiceException("发送单聊消息请求,请求参数不能为空!"); } - //目前支持的默认值 0、单聊消息 100、自定义消息 - messageInfo.setOpe(MSG_OPE); HashMap paramMap = Maps.newHashMap(); paramMap.put("from", messageInfo.getFrom()); paramMap.put("body", messageInfo.getBody()); diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index 0d09d2c..c834304 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -57,6 +57,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; @@ -195,8 +196,16 @@ public class MessageController implements MessageApi { .senderPersonId(request.determineSenderPersonId()) .build(); Date now = new Date(); - List receivePersons = JSONArray.parseArray( + List requestReceivePersons = JSONArray.parseArray( JSONObject.toJSONString(request.uniqueReceivePersons()), MessageTask.ReceivePerson.class); + List receivePersons = new ArrayList<>(requestReceivePersons); + if (CollectionUtils.isNotEmpty(request.getImReceiveAccounts())) { + for (String account : request.getImReceiveAccounts()) { + receivePersons.add(MessageTask.ReceivePerson.builder() + .imAccount(account) + .build()); + } + } MessageTask messageTask = messageTaskService.create(MessageTask.builder() .bizId(request.getBizId()) .sendImAccount(sendImAccount) @@ -214,7 +223,8 @@ public class MessageController implements MessageApi { .build()); List updatableMessageSendResults = Collections.emptyList(); if (request.isUpdatable()) { - updatableMessageSendResults = updatableMessageManager.createUpdatableMessage(messageTask, request, receivePersons); + updatableMessageSendResults = updatableMessageManager.createUpdatableMessage( + messageTask, request, requestReceivePersons, request.imReceiveAccountsOrEmpty()); } MessageTaskResp messageTaskResp = toMessageTaskResp(messageTask); messageTaskResp.setUpdatableMessageSendResults(updatableMessageSendResults); diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java index 98e2387..0a11855 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java @@ -1,6 +1,7 @@ package cn.axzo.im.entity; import cn.axzo.im.center.common.enums.AppTypeEnum; +import cn.axzo.im.center.common.enums.GroupMemberType; import cn.axzo.im.center.common.enums.YesOrNo; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Getter; @@ -21,6 +22,7 @@ public class GroupMember { private Long personId; private Long personOuId; private AppTypeEnum appType; + private GroupMemberType memberType; private YesOrNo isRobot; private Long isDelete; private Date createAt; diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/UpdatableMessage.java b/im-center-server/src/main/java/cn/axzo/im/entity/UpdatableMessage.java index e8a9e08..8fdc23a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/UpdatableMessage.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/UpdatableMessage.java @@ -113,6 +113,7 @@ public class UpdatableMessage implements MessageUpdateInfo { @Setter public static class RecordExt { private Long receiverWorkspaceId; + private boolean isSendByImAccountDirectly; } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java index 665da59..01164c4 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java @@ -2,9 +2,9 @@ package cn.axzo.im.group; import cn.axzo.basics.common.BeanMapper; import cn.axzo.framework.rocketmq.Event; +import cn.axzo.im.center.api.vo.group.GroupInfo; +import cn.axzo.im.center.api.vo.group.GroupMemberInfo; import cn.axzo.im.center.api.vo.mq.GroupMembersChangeMessage; -import cn.axzo.im.center.api.vo.req.GroupInfo; -import cn.axzo.im.center.api.vo.mq.GroupMembersChangeMessage.MemberInfo; import cn.axzo.im.config.MqProducer; import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.entity.Group; @@ -39,7 +39,7 @@ class GroupBroadcaster { for (GroupMember account : accounts) { GroupMembersChangeMessage message = new GroupMembersChangeMessage(); message.setGroup(BeanMapper.copyBean(effectiveGroup, GroupInfo.class)); - message.setMember(BeanMapper.copyBean(account, MemberInfo.class)); + message.setMember(BeanMapper.copyBean(account, GroupMemberInfo.class)); Event event = Event.builder() .targetId(String.format("%d:%d", group.getTid(), account.getPersonId())) .targetType(eventType.getModel()) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java index f03f9bb..35bffb0 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java @@ -8,10 +8,12 @@ import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; import cn.axzo.im.center.api.vo.req.GroupDismissRequest; import cn.axzo.im.center.api.vo.req.GroupGetMembersRequest; +import cn.axzo.im.center.api.vo.req.GroupGetOwnerRequest; import cn.axzo.im.center.api.vo.req.GroupRemoveMembersRequest; import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; import cn.axzo.im.center.api.vo.resp.GroupGetMembersResponse; +import cn.axzo.im.center.api.vo.resp.GroupGetOwnerResponse; import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.GroupMember; import lombok.RequiredArgsConstructor; @@ -29,6 +31,7 @@ import java.util.List; public class GroupController implements GroupApi { private final GroupManager groupManager; + private final GroupMemberManager groupMemberManager; private final GroupMemberDao groupMemberDao; @Override @@ -48,17 +51,25 @@ public class GroupController implements GroupApi { } @Override - public ApiResult addMembers(GroupRemoveMembersRequest request) { + public ApiResult removeMembers(GroupRemoveMembersRequest request) { groupManager.removeMembers(request); return ApiResult.ok(); } @Override public ApiResult getMembers(GroupGetMembersRequest request) { - List members = groupMemberDao.getByTid(request.getTid()); + List members = groupMemberManager.getMembers(request.getTid()); GroupGetMembersResponse response = new GroupGetMembersResponse(); response.setMember(BeanMapper.copyList(members, GroupMemberInfo.class)); return ApiResult.ok(response); } + @Override + public ApiResult getOwner(GroupGetOwnerRequest request) { + GroupMember owner = groupMemberManager.getOwner(request.getTid()); + GroupGetOwnerResponse response = new GroupGetOwnerResponse(); + response.setOwner(BeanMapper.copyBean(owner, GroupMemberInfo.class)); + return ApiResult.ok(response); + } + } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 66dc9dd..4cc9ee5 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -15,9 +15,6 @@ import cn.axzo.im.channel.netease.dto.NimGroupCreateRequest; import cn.axzo.im.channel.netease.dto.NimGroupCreateResponse; import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; import cn.axzo.im.channel.netease.dto.NimGroupDismissResponse; -import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; -import cn.axzo.im.channel.netease.dto.NimGroupGetInfoResponse; -import cn.axzo.im.channel.netease.dto.NimGroupInfo; import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersRequest; import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersResponse; import cn.axzo.im.dao.repository.GroupDao; @@ -37,7 +34,6 @@ import org.springframework.transaction.annotation.Transactional; import javax.validation.constraints.NotNull; import java.util.List; -import java.util.Optional; import java.util.Set; import static java.util.stream.Collectors.toList; @@ -56,6 +52,7 @@ public class GroupManager { private final GroupSupport groupSupport; private final AccountService accountService; private final GroupBroadcaster groupBroadcaster; + private final GroupMemberManager groupMemberManager; @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { @@ -77,7 +74,7 @@ public class GroupManager { BizAssertions.assertTrue(nimResponse.isSuccess(), "创建群失败: {}", nimResponse.getDesc()); groupDao.updateTid(group.getId(), nimResponse.getTid()); group = groupDao.getById(group.getId()); - syncGroupMembers(group); + groupMemberManager.syncGroupMembers(group); groupBroadcaster.fireMembersAdded(group, groupMemberDao.getByTid(nimResponse.getTid())); GroupCreateResponse response = new GroupCreateResponse(); response.setTid(nimResponse.getTid()); @@ -104,7 +101,7 @@ public class GroupManager { Group group = findGroupForUpdateOrThrow(request.getTid()); BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); // sync members 1 - syncGroupMembers(group); + groupMemberManager.syncGroupMembers(group); // prepare add members Set preMembers = groupMemberDao.getGroupPersons(group.getTid()); List toAddMembers = request.getMembers().stream() @@ -125,7 +122,7 @@ public class GroupManager { log.info("添加群成员, request={}, response={}", nimRequest, nimResponse); BizAssertions.assertTrue(nimResponse.isSuccess(), "添加群成员失败: {}", nimResponse.getDesc()); // sync members 2 - syncGroupMembers(group); + groupMemberManager.syncGroupMembers(group); groupBroadcaster.fireMembersAdded(group, groupMemberDao .getByPersons(group.getTid(), toAddMembers)); GroupAddMembersResponse response = new GroupAddMembersResponse(); @@ -144,7 +141,7 @@ public class GroupManager { group.getTid(), JSON.toJSONString(request.getMembers())); return; } - syncGroupMembers(group); + groupMemberManager.syncGroupMembers(group); List toRemoveMembers = groupMemberDao.getByPersons( group.getTid(), request.getMembers()); if (CollectionUtils.isEmpty(toRemoveMembers)) @@ -154,9 +151,9 @@ public class GroupManager { NimGroupRemoveMembersResponse nimResponse = nimClient.removeMembers(nimRequest); log.info("移除群成员, request={}, response={}", nimRequest, nimResponse); if (nimResponse.isSuccess()) { - syncGroupMembers(group); + groupMemberManager.syncGroupMembers(group); // 不比较直接发消息 - groupBroadcaster.fireMembersAdded(group, toRemoveMembers); + groupBroadcaster.fireMembersRemoved(group, toRemoveMembers); } } @@ -167,29 +164,4 @@ public class GroupManager { return group; } - private void syncGroupMembers(Group group) { - NimGroupInfo groupInfo = fetchGroupInfo(group).orElse(null); - if (groupInfo == null) return; - groupMemberDao.deleteAccounts(group.getTid()); - List accounts = groupSupport - .parseGroupMembers(group, groupInfo.getOwnerAndMembers()); - if (CollectionUtils.isNotEmpty(accounts)) - groupMemberDao.saveBatch(accounts); - groupDao.updateMembersCount(group.getTid(), accounts.size()); - } - - private Optional fetchGroupInfo(Group group) { - NimGroupGetInfoRequest nimRequest = new NimGroupGetInfoRequest(); - nimRequest.setTid(group.getTid()); - long start = System.currentTimeMillis(); - NimGroupGetInfoResponse nimResponse = nimClient.getGroupInfo(nimRequest); - log.info("获取群信息, request={}, response={}, timeUsed={}", - nimRequest, nimResponse, System.currentTimeMillis() - start); - if (nimResponse.isGroupNotFoundError()) - return Optional.empty(); - BizAssertions.assertTrue(nimResponse.isSuccess(), - "获取群信息失败: {}", nimResponse.getDesc()); - return Optional.of(nimResponse.getTinfo()); - } - } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberManager.java new file mode 100644 index 0000000..2e1834e --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberManager.java @@ -0,0 +1,68 @@ +package cn.axzo.im.group; + +import cn.axzo.im.center.common.enums.GroupMemberType; +import cn.axzo.im.channel.netease.client.NimClient; +import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; +import cn.axzo.im.channel.netease.dto.NimGroupGetInfoResponse; +import cn.axzo.im.channel.netease.dto.NimGroupInfo; +import cn.axzo.im.dao.repository.GroupDao; +import cn.axzo.im.dao.repository.GroupMemberDao; +import cn.axzo.im.entity.Group; +import cn.axzo.im.entity.GroupMember; +import cn.axzo.im.utils.BizAssertions; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; + +/** + * @author yanglin + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class GroupMemberManager { + + private final GroupMemberDao groupMemberDao; + private final GroupSupport groupSupport; + private final GroupDao groupDao; + private final NimClient nimClient; + + List getMembers(Long tid) { + return groupMemberDao.getByTid(tid); + } + + GroupMember getOwner(Long tid) { + return groupMemberDao.lambdaQuery() + .eq(GroupMember::getTid, tid) + .eq(GroupMember::getMemberType, GroupMemberType.OWNER) + .one(); + } + + void syncGroupMembers(Group group) { + NimGroupInfo groupInfo = fetchGroupInfo(group).orElse(null); + if (groupInfo == null) return; + groupMemberDao.deleteAccounts(group.getTid()); + List accounts = groupSupport.parseGroupMembers(group, groupInfo); + if (CollectionUtils.isNotEmpty(accounts)) + groupMemberDao.saveBatch(accounts); + groupDao.updateMembersCount(group.getTid(), accounts.size()); + } + + private Optional fetchGroupInfo(Group group) { + NimGroupGetInfoRequest nimRequest = new NimGroupGetInfoRequest(); + nimRequest.setTid(group.getTid()); + long start = System.currentTimeMillis(); + NimGroupGetInfoResponse nimResponse = nimClient.getGroupInfo(nimRequest); + log.info("获取群信息, request={}, response={}, timeUsed={}", + nimRequest, nimResponse, System.currentTimeMillis() - start); + if (nimResponse.isGroupNotFoundError()) + return Optional.empty(); + BizAssertions.assertTrue(nimResponse.isSuccess(), + "获取群信息失败: {}", nimResponse.getDesc()); + return Optional.of(nimResponse.getTinfo()); + } +} diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index 3dbb7a1..c864e58 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -3,10 +3,12 @@ package cn.axzo.im.group; import cn.axzo.im.center.api.feign.GroupApi; import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; +import cn.axzo.im.center.common.enums.GroupMemberType; import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.channel.netease.dto.NimGroupAddMembersRequest; import cn.axzo.im.channel.netease.dto.NimGroupCreateRequest; import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; +import cn.axzo.im.channel.netease.dto.NimGroupInfo; import cn.axzo.im.channel.netease.dto.NimGroupMemberInfo; import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersRequest; import cn.axzo.im.entity.Group; @@ -22,7 +24,6 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; -import java.util.Set; /** * @author yanglin @@ -104,14 +105,16 @@ public class GroupSupport implements GroupLogger { } } - List parseGroupMembers(Group group, Set members) { + List parseGroupMembers(Group group, NimGroupInfo groupInfo) { ArrayList accounts = new ArrayList<>(); - for (NimGroupMemberInfo member : members) { + for (NimGroupMemberInfo member : groupInfo.getOwnerAndMembers()) { PersonAccountAttribute person = ImAccountParser.parsePerson(member.getAccid()).orElse(null); GroupMember account = new GroupMember(); accounts.add(account); account.setTid(group.getTid()); account.setImAccount(member.getAccid()); + account.setMemberType(groupInfo.getOwner().equals(member) + ? GroupMemberType.OWNER : GroupMemberType.MEMBER); if (person == null) { account.setPersonId(0L); account.setPersonOuId(0L); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/MergedGroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/MergedGroupSupport.java new file mode 100644 index 0000000..674a635 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/MergedGroupSupport.java @@ -0,0 +1,60 @@ +package cn.axzo.im.group; + +import cn.axzo.im.dao.mapper.ChatGroupMapper; +import cn.axzo.im.dao.repository.GroupDao; +import cn.axzo.im.entity.ChatGroup; +import cn.axzo.im.entity.Group; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static cn.axzo.im.utils.Queries.query; +import static java.util.stream.Collectors.toList; + +/** + * @author yanglin + */ +@Component +@RequiredArgsConstructor +public class MergedGroupSupport { + + private final GroupDao groupDao; + private final ChatGroupMapper chatGroupMapper; + + public List getGroupAccounts(Set groupIds) { + if (CollectionUtils.isEmpty(groupIds)) + return Collections.emptyList(); + if (parseLongs(groupIds).isEmpty()) + return Collections.emptyList(); + return groupDao.lambdaQuery() + .in(Group::getTid, parseLongs(groupIds)) + .list().stream() + .map(Group::getTid) + .map(String::valueOf) + .collect(toList()); + } + + public List getGroupCatAccounts(Set groupIds) { + if (CollectionUtils.isEmpty(groupIds)) + return Collections.emptyList(); + return chatGroupMapper.selectList( + query(ChatGroup.class) + .in(ChatGroup::getTid, groupIds)).stream() + .map(ChatGroup::getTid) + .collect(toList()); + } + + private List parseLongs(Collection groupIds) { + return groupIds.stream() + .filter(NumberUtils::isDigits) + .map(Long::parseLong) + .collect(toList()); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java index 6cb65f0..075b33a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java @@ -18,6 +18,7 @@ import java.util.List; * @author yanglin */ @Component +@Deprecated // 发送给群时无法使用批量接口, 也不想改动SendQueue了, 后续有时间再优化 @RequiredArgsConstructor public class CommonSendBatchHandler extends SendBatchHandler { diff --git a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java index 94bc647..40cb09e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java @@ -1,6 +1,8 @@ package cn.axzo.im.send.handler; +import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.ChannelMsgTypeEnum; +import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.channel.IMChannelProvider; import cn.axzo.im.channel.netease.dto.MessageDispatchRequest; import cn.axzo.im.channel.netease.dto.MessageDispatchResponse; @@ -9,6 +11,7 @@ import cn.axzo.im.send.MessageHistoryNimLogger; import cn.axzo.im.send.SendExecutor; import cn.axzo.im.utils.ImProperties; import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.math.NumberUtils; import org.springframework.stereotype.Component; /** @@ -29,7 +32,9 @@ public class CommonSendOneHandler extends SendOneHandler { history.getBizId(), history.determineBatchNo().orElse(null)); MessageDispatchRequest sendRequest = new MessageDispatchRequest(); sendRequest.setFrom(history.getFromAccount()); - sendRequest.setOpe(0); + boolean isSendToGroup = AppTypeEnum.NONE.is(history.getAppType()) + && NumberUtils.isDigits(history.getToAccount()); + sendRequest.setOpe(isSendToGroup ? 1 : 0); sendRequest.setTo(history.getToAccount()); sendRequest.setType(ChannelMsgTypeEnum.CUSTOM.getCode()); sendRequest.setBody(history.getMessageBody()); diff --git a/im-center-server/src/main/java/cn/axzo/im/send/job/SendMessageJob.java b/im-center-server/src/main/java/cn/axzo/im/send/job/SendMessageJob.java index 435d1ab..d36523b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/job/SendMessageJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/job/SendMessageJob.java @@ -3,7 +3,6 @@ package cn.axzo.im.send.job; import cn.axzo.im.center.api.vo.ApiChannel; import cn.axzo.im.send.ScanAndSendService; import cn.axzo.im.send.SendExec; -import cn.axzo.im.send.handler.CommonSendBatchHandler; import cn.axzo.im.send.handler.CommonSendOneHandler; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.annotation.XxlJob; @@ -35,8 +34,7 @@ public class SendMessageJob extends SendMessageExecInstance { @Override SendExec newExecution() { - return new SendExec(ApiChannel.COMMON_MESSAGE, - CommonSendBatchHandler.class, CommonSendOneHandler.class); + return new SendExec(ApiChannel.COMMON_MESSAGE, CommonSendOneHandler.class); } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java index e1807f3..4fce6e9 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java @@ -13,6 +13,7 @@ import cn.axzo.im.entity.AccountRegister; import cn.axzo.im.entity.MessageHistory; import cn.axzo.im.entity.MessageTask; import cn.axzo.im.enums.MessageHistoryStatus; +import cn.axzo.im.group.MergedGroupSupport; import cn.axzo.im.push.NimPushService; import cn.axzo.im.push.PushPeer; import cn.axzo.im.service.AccountRegisterService; @@ -47,6 +48,7 @@ import org.springframework.util.CollectionUtils; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -55,6 +57,7 @@ import java.util.Set; import java.util.stream.Collectors; import static cn.axzo.im.config.BizResultCode.MESSAGE_TASK_NOT_FOUND; +import static java.util.stream.Collectors.toSet; @Slf4j @Service @@ -75,6 +78,8 @@ public class MessageTaskServiceImpl extends ServiceImpl page = accountRegisterService.page(AccountRegisterService.PageAccountRegisterParam.builder() .accountType(AccountTypeEnum.USER.getCode()) - .appTypes(bizData.getAppTypes().stream().map(AppTypeEnum::getCode).collect(Collectors.toSet())) + .appTypes(bizData.getAppTypes().stream().map(AppTypeEnum::getCode).collect(toSet())) .page(pageNumber++) .pageSize(DEFAULT_PAGE_SIZE) .build()); @@ -182,7 +187,7 @@ public class MessageTaskServiceImpl extends ServiceImpl ouIdMap = resolveOuId(receivePersons.stream() .map(MessageTask.ReceivePerson::getOuId) .filter(Objects::nonNull) - .collect(Collectors.toSet())); + .collect(toSet())); List absentReceivePersons = receivePersons.stream() .filter(e -> { @@ -200,9 +205,10 @@ public class MessageTaskServiceImpl extends ServiceImpl accountRegisters = listAccountRegisters(absentReceivePersons); Map imAccounts = listImAccount(absentReceivePersons); + Set groupAccounts = listGroupAccounts(receivePersons); List messageHistories = absentReceivePersons.stream() - .map(receivePerson -> resolveMessageHistory(batchNo, messageTask, receivePerson, imAccounts, accountRegisters, ouIdMap, tryCreateAccount)) + .map(receivePerson -> resolveMessageHistory(batchNo, messageTask, receivePerson, imAccounts, groupAccounts, accountRegisters, ouIdMap, tryCreateAccount)) .collect(Collectors.toList()); messageHistoryService.createBatch(messageHistories); List historyIds = messageHistories.stream() @@ -215,6 +221,7 @@ public class MessageTaskServiceImpl extends ServiceImpl imAccounts, + Set groupAccounts, Map accountRegisters, Map ouIdMap, boolean tryCreateAccount) { @@ -231,17 +238,24 @@ public class MessageTaskServiceImpl extends ServiceImpl imAccounts = receivePersons.stream() .map(MessageTask.ReceivePerson::getImAccount) .filter(Objects::nonNull) - .collect(Collectors.toSet()); + .collect(toSet()); if (CollectionUtils.isEmpty(imAccounts)) { return Collections.emptySet(); @@ -329,7 +343,7 @@ public class MessageTaskServiceImpl extends ServiceImpl listExistPerson(List receivePersons, @@ -337,7 +351,7 @@ public class MessageTaskServiceImpl extends ServiceImpl personIds = receivePersons.stream() .map(MessageTask.ReceivePerson::getPersonId) .filter(Objects::nonNull) - .collect(Collectors.toSet()); + .collect(toSet()); if (CollectionUtils.isEmpty(personIds)) { return Collections.emptySet(); } @@ -348,7 +362,7 @@ public class MessageTaskServiceImpl extends ServiceImpl e.getReceivePersonId() + "_" + e.getAppType() + "_" + e.getReceiveOuId()) - .collect(Collectors.toSet()); + .collect(toSet()); } private Map listAccountRegisters(List receivePersons) { @@ -356,7 +370,7 @@ public class MessageTaskServiceImpl extends ServiceImpl StringUtils.isNotBlank(receivePerson.getPersonId()) && StringUtils.isBlank(receivePerson.getImAccount())) .map(MessageTask.ReceivePerson::getPersonId) - .collect(Collectors.toSet()); + .collect(toSet()); if (CollectionUtils.isEmpty(personIds)) { return Collections.emptyMap(); } @@ -379,7 +393,7 @@ public class MessageTaskServiceImpl extends ServiceImpl imAccounts = receivePersons.stream() .filter(receivePerson -> StringUtils.isNotBlank(receivePerson.getImAccount())) .map(MessageTask.ReceivePerson::getImAccount) - .collect(Collectors.toSet()); + .collect(toSet()); if (CollectionUtils.isEmpty(imAccounts)) { return Collections.emptyMap(); } @@ -395,6 +409,17 @@ public class MessageTaskServiceImpl extends ServiceImpl listGroupAccounts(List receivePersons) { + Set imAccounts = receivePersons.stream() + .map(MessageTask.ReceivePerson::getImAccount) + .filter(StringUtils::isNotBlank) + .collect(toSet()); + HashSet result = new HashSet<>(); + result.addAll(mergedGroupSupport.getGroupAccounts(imAccounts)); + result.addAll(mergedGroupSupport.getGroupCatAccounts(imAccounts)); + return result; + } + private String resolveBody(MessageTask.ReceivePerson receivePerson, MessageTask messageTask, MessageHistory history) { MessageTask.BizData bizData = messageTask.getBizData(); diff --git a/im-center-server/src/main/java/cn/axzo/im/updatable/InitHistories.java b/im-center-server/src/main/java/cn/axzo/im/updatable/InitHistories.java index acc12ab..1a1213d 100644 --- a/im-center-server/src/main/java/cn/axzo/im/updatable/InitHistories.java +++ b/im-center-server/src/main/java/cn/axzo/im/updatable/InitHistories.java @@ -44,6 +44,13 @@ class InitHistories { } public Optional findHistory(UpdatableMessage message) { + if (message.getOrCreateRecordExt().isSendByImAccountDirectly()) { + for (MessageHistory history : account2histories.values()) { + if (AppTypeEnum.NONE.is(history.getAppType()) + && history.getToAccount().equals(message.getToAccount())) + return Optional.of(history); + } + } HistoryTaskAccount account = new HistoryTaskAccount( message.getTaskId(), message.parsePersonAccount()); return Optional.ofNullable(account2histories.get(account)); diff --git a/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageManager.java b/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageManager.java index 3090b60..35ad06f 100644 --- a/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageManager.java @@ -7,6 +7,7 @@ import cn.axzo.im.center.api.vo.req.UpdateMessageRequest; import cn.axzo.im.center.api.vo.resp.MessageUpdateResponse; import cn.axzo.im.center.api.vo.resp.MessageUpdateResponse.NonUpdateMessageReason; import cn.axzo.im.center.api.vo.resp.UpdatableMessageSendResult; +import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.channel.netease.dto.MessageBody; import cn.axzo.im.dao.repository.MessageHistoryDao; @@ -38,12 +39,13 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionTemplate; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; +import java.util.function.Supplier; import static cn.axzo.im.center.api.vo.req.MessageUpdateInfo.collectBizMessageIds; import static java.util.function.Function.identity; @@ -71,21 +73,18 @@ public class UpdatableMessageManager { // !! schedule in task public List createUpdatableMessage( - MessageTask task, SendTemplateMessageParam request, List receivePersons) { - if (CollectionUtils.isEmpty(receivePersons)) return Collections.emptyList(); + MessageTask task, SendTemplateMessageParam request, + List receivePersons, Set imReceiveAccounts) { String batchNo = UUIDUtil.uuidString(); ArrayList sendResults = new ArrayList<>(); CardManipulateCollector collector = cardManipulateCollectorFactory.create(); - for (ReceivePerson person : receivePersons) { + Supplier messageFactory = () -> { UpdatableMessage message = new UpdatableMessage(); collector.addMessage(message); message.setBatchNo(batchNo); message.setTemplateId(request.getMsgTemplateId()); message.setBizId(request.getBizId()); message.setTaskId(task.getId()); - message.setReceiverPersonId(person.getPersonId()); - message.setReceiverOuId(person.getOuId()); - message.setAppType(person.getAppType()); message.setMsgType(request.getTemplatedMsgType()); message.setState(UpdatableMessageState.TASK_CREATED); message.setBizMessageId(UUIDUtil.uuidString()); @@ -93,6 +92,13 @@ public class UpdatableMessageManager { message.setSenderPersonId(request.determineSenderPersonId() + ""); message.setSenderOuId(request.determineSenderOuId()); message.setIsSenderRobot(request.isSendByRobot() ? YesOrNo.YES : YesOrNo.NO); + return message; + }; + for (ReceivePerson person : receivePersons) { + UpdatableMessage message = messageFactory.get(); + message.setReceiverPersonId(person.getPersonId()); + message.setReceiverOuId(person.getOuId()); + message.setAppType(person.getAppType()); message.getOrCreateRecordExt().setReceiverWorkspaceId(person.getWorkspaceId()); UpdatableMessageLog messageLog = message.toMessageLog(request); @@ -104,6 +110,23 @@ public class UpdatableMessageManager { sendResult.setBizMessageId(message.bizMessageId()); sendResult.setAccount(message.parsePersonAccount()); } + for (String imAccount : imReceiveAccounts) { + UpdatableMessage message = messageFactory.get(); + message.setToAccount(imAccount); + message.setReceiverPersonId("-1"); + message.setReceiverOuId(-1L); + message.setAppType(AppTypeEnum.NONE); + message.getOrCreateRecordExt().setSendByImAccountDirectly(true); + + UpdatableMessageLog messageLog = message.toMessageLog(request); + collector.addLog(messageLog); + messageLog.setContext("scheduleInTask"); + + UpdatableMessageSendResult sendResult = new UpdatableMessageSendResult(); + sendResults.add(sendResult); + sendResult.setBizMessageId(message.bizMessageId()); + sendResult.setAccount(null); + } collector.finish(); return sendResults; } From b42deed48680be87ae0eaa54ad36e9f6c9078afd Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 22 Jan 2025 13:47:22 +0800 Subject: [PATCH 004/201] =?UTF-8?q?REQ-3345:=20=E5=90=91=E7=BE=A4=E9=87=8C?= =?UTF-8?q?=E5=8F=91=E5=8D=A1=E7=89=87=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/center/api/vo/group/GroupMemberInfo.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupMemberInfo.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupMemberInfo.java index ba669d5..65c28ab 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupMemberInfo.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupMemberInfo.java @@ -1,6 +1,7 @@ package cn.axzo.im.center.api.vo.group; import cn.axzo.im.center.common.enums.AppTypeEnum; +import cn.axzo.im.center.common.enums.GroupMemberType; import lombok.Getter; import lombok.Setter; @@ -22,4 +23,8 @@ public class GroupMemberInfo { * 群成员端类型 */ private AppTypeEnum appType; + /** + * 群成员类型. MEMBER: 普通成员, OWNER: 群主 + */ + private GroupMemberType memberType; } \ No newline at end of file From cafc969b02c84377392597a07440dd1ef532e890 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 13:32:33 +0800 Subject: [PATCH 005/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/center/api/feign/GroupMessageApi.java | 27 ++++ .../axzo/im/center/api/feign/MessageApi.java | 5 + .../im/center/api/feign/SendPriority.java | 1 + .../center/api/vo/req/GroupCreateRequest.java | 6 + .../vo/req/GroupMessagePageQueryRequest.java | 22 +++ .../api/vo/req/SendChatMessageRequest.java | 78 +++++++++++ .../center/api/vo/req/SendMessageRequest.java | 71 ++++++++++ .../api/vo/req/SendTemplateMessageParam.java | 68 +-------- .../resp/GroupMessagePageQueryResponse.java | 72 ++++++++++ .../common/enums/NimFromClientType.java | 20 +-- .../center/common/enums/NimMessageType.java | 27 ++-- .../im/channel/netease/client/NimClient.java | 9 +- .../dto/NimGroupGetMessagesRequest.java | 34 +++++ .../dto/NimGroupGetMessagesResponse.java | 35 +++++ .../axzo/im/controller/MessageController.java | 42 +++++- .../axzo/im/controller/PrivateController.java | 8 ++ .../cn/axzo/im/dao/repository/GroupDao.java | 2 + .../im/dao/repository/GroupMessageDao.java | 20 +++ .../main/java/cn/axzo/im/entity/Group.java | 9 ++ .../java/cn/axzo/im/entity/GroupMessage.java | 9 +- .../cn/axzo/im/entity/HistoryRecordExt.java | 2 + .../java/cn/axzo/im/entity/MessageTask.java | 8 ++ .../cn/axzo/im/group/GroupController.java | 9 +- .../java/cn/axzo/im/group/GroupManager.java | 28 ++-- .../java/cn/axzo/im/group/GroupSupport.java | 36 +---- .../group/member/GroupMemberQueryService.java | 33 +++++ .../GroupMemberSyncer.java} | 53 ++++--- .../im/group/message/GroupMessageSyncJob.java | 57 ++++++++ .../message/GroupMessageSyncService.java | 122 +++++++++++++++++ .../im/group/message/GroupMessageSyncer.java | 129 ++++++++++++++++++ .../group/message/MessageSyncController.java | 80 +++++++++++ .../axzo/im/group/message/UniqueMessage.java | 51 +++++++ .../im/group/message/timeline/TimeNode.java | 26 ++++ .../im/group/message/timeline/Timeline.java | 83 +++++++++++ .../im/send/handler/CommonSendOneHandler.java | 7 +- .../service/impl/MessageTaskServiceImpl.java | 6 + .../src/main/resources/application.yml | 2 +- .../im/group/GroupMessageSyncJobTest.java | 23 ++++ .../message/GroupMessageSyncServiceTest.java | 23 ++++ 39 files changed, 1181 insertions(+), 162 deletions(-) create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupMessageApi.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupMessagePageQueryRequest.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendMessageRequest.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesRequest.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesResponse.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java rename im-center-server/src/main/java/cn/axzo/im/group/{GroupMemberManager.java => member/GroupMemberSyncer.java} (55%) create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/message/UniqueMessage.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java create mode 100644 im-center-server/src/test/java/cn/axzo/im/group/GroupMessageSyncJobTest.java create mode 100644 im-center-server/src/test/java/cn/axzo/im/group/message/GroupMessageSyncServiceTest.java diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupMessageApi.java b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupMessageApi.java new file mode 100644 index 0000000..61e43a2 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupMessageApi.java @@ -0,0 +1,27 @@ +package cn.axzo.im.center.api.feign; + +import cn.axzo.framework.domain.web.result.ApiPageResult; +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.im.center.api.vo.req.GroupCreateRequest; +import cn.axzo.im.center.api.vo.req.GroupMessagePageQueryRequest; +import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; +import cn.axzo.im.center.api.vo.resp.GroupMessagePageQueryResponse; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +/** + * @author yanglin + */ +@FeignClient(name = "im-center", url = "${axzo.service.im-center:http://im-center:8080}") +public interface GroupMessageApi { + + /** + * 查询群聊历史消息 + */ + @PostMapping("/api/im/group/message/pageQuery") + ApiPageResult pageQuery( + @RequestBody @Validated GroupMessagePageQueryRequest request); + +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/MessageApi.java b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/MessageApi.java index 0fa9362..dff2fe1 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/MessageApi.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/MessageApi.java @@ -6,6 +6,7 @@ import cn.axzo.im.center.api.vo.req.CustomMessageInfo; import cn.axzo.im.center.api.vo.req.FetchUpdatableMessageRequest; import cn.axzo.im.center.api.vo.req.GetMessageDetailRequest; import cn.axzo.im.center.api.vo.req.MessageInfo; +import cn.axzo.im.center.api.vo.req.SendChatMessageRequest; import cn.axzo.im.center.api.vo.req.SendMessageParam; import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam; import cn.axzo.im.center.api.vo.req.UpdatableMessageAckRequest; @@ -64,6 +65,10 @@ public interface MessageApi { ApiResult sendTemplateMessageAsync( @RequestBody @Validated SendTemplateMessageParam sendMessageParam); + @PostMapping("/api/im/template-message/async/send/chatMessage") + ApiResult sendChatMessage( + @RequestBody @Validated SendChatMessageRequest request); + /** * 更新消息 */ diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/SendPriority.java b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/SendPriority.java index 40ac9da..d37221b 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/SendPriority.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/SendPriority.java @@ -12,6 +12,7 @@ import lombok.RequiredArgsConstructor; public class SendPriority { public static final SendPriority TEMPLATE_MESSAGE = create(1000); + public static final SendPriority CHAT_MESSAGE = create(1500); public static final SendPriority SYSTEM_CUSTOM_MESSAGE = create(5000); public static final SendPriority UPDATE_MESSAGE = create(5500); public static final SendPriority UPDATE_MESSAGE_RETRY = create(5510); // lower priority than UPDATE_MESSAGE diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java index 8afff1b..716b9f7 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java @@ -11,6 +11,7 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.util.HashSet; +import java.util.Map; import java.util.Set; /** @@ -59,6 +60,11 @@ public class GroupCreateRequest { */ private String avatar; + /** + * 群聊业务扩展信息, 透传到群属性中 + */ + private Map bizAttachment; + @JSONField(serialize = false, deserialize = false) public Set getOwnerAndMembers() { Set ownerAndMembers = new HashSet<>(members); diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupMessagePageQueryRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupMessagePageQueryRequest.java new file mode 100644 index 0000000..cf075fe --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupMessagePageQueryRequest.java @@ -0,0 +1,22 @@ +package cn.axzo.im.center.api.vo.req; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotNull; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupMessagePageQueryRequest { + + @NotNull(message = "群ID不能为空") + private Long tid; + + private Integer page; + + private Integer pageSize; + +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java new file mode 100644 index 0000000..4ab93f7 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java @@ -0,0 +1,78 @@ +package cn.axzo.im.center.api.vo.req; + +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.common.enums.NimMessageType; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author yanglin + */ +@Setter +@Getter +public class SendChatMessageRequest extends SendMessageRequest { + + /** + * 消息类型 + */ + @NotNull(message = "消息类型不能为空") + private NimMessageType messageType; + + /** + * 消息内容 + */ + @NotEmpty(message = "消息体不能为空") + private Map messageBody; + + /** + * 发送文本消息 + * + * @param text 消息内容 + */ + public void setAsTextMessage(String text) { + messageType = NimMessageType.TEXT; + addToMessageBody("msg", text); + } + + /** + * 发送图片消息 + * + * @param name 图片名称 + * @param md5 图片文件 md5,按照字节流加密 + * @param url url + * @param ext 图片后缀 + * @param width 宽,单位为像素 + * @param height 高,单位为像素 + * @param size 图片文件大小,单位为字节(Byte) + */ + public void setAsImageMessage(String name, + String md5, + String url, + String ext, + int width, + int height, + int size) { + messageType = NimMessageType.IMAGE; + addToMessageBody("name", name); + addToMessageBody("md5", md5); + addToMessageBody("url", url); + addToMessageBody("ext", ext); + addToMessageBody("w", width); + addToMessageBody("h", height); + addToMessageBody("size", size); + } + + private void addToMessageBody(String key, Object value) { + if (messageBody == null) + messageBody = new java.util.HashMap<>(); + messageBody.put(key, value); + } +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendMessageRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendMessageRequest.java new file mode 100644 index 0000000..ffd5b39 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendMessageRequest.java @@ -0,0 +1,71 @@ +package cn.axzo.im.center.api.vo.req; + +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * @author yanglin + */ +@Setter +@Getter +public class SendMessageRequest { + + /** + * 业务id + */ + @NotBlank(message = "业务id不能为空") + private String bizId; + + /** + * 发送人 + */ + @NotNull(message = "发送人不能为空") + private PersonAccountAttribute sender; + + /** + * 消息接收用户信息 + */ + @Valid + private Set receivePersons; + + /** + * 消息接收IM账号或群id + */ + private Set imReceiveAccounts; + + + public Long determineSenderPersonId() { + if (sender != null) + return Long.parseLong(sender.getPersonId()); + return 0L; + } + + public boolean isSendByRobot() { + return sender.getAppType() == null; + } + + public Set receivePersonsOrEmpty() { + if (receivePersons == null) + return Collections.emptySet(); + return new HashSet<>(receivePersons); + } + + public Set imReceiveAccountsOrEmpty() { + return imReceiveAccounts == null ? Collections.emptySet() : imReceiveAccounts; + } + + public Long determineSenderOuId() { + if (sender != null) + return sender.ouIdOrDefault(); + return 0L; + } + +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java index a4e9807..2f931eb 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java @@ -1,44 +1,17 @@ package cn.axzo.im.center.api.vo.req; -import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.common.enums.TemplatedMsgType; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; +import lombok.Getter; +import lombok.Setter; -import javax.validation.Valid; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class SendTemplateMessageParam { - - /** - * 发送人 - */ - @NotNull(message = "发送人不能为空") - private PersonAccountAttribute sender; - - /** - * 消息接收用户信息 - */ - @Valid - private Set receivePersons; - - /** - * 消息接收IM账号或群id - */ - private Set imReceiveAccounts; +@Setter +@Getter +public class SendTemplateMessageParam extends SendMessageRequest { /** * 消息标题 @@ -67,11 +40,6 @@ public class SendTemplateMessageParam { */ private JSONObject ext; - /** - * 业务的唯一ID,用于查询发送消息的记录和结果,不验证唯一 - */ - private String bizId; - private Integer sendPriority; private TemplatedMsgType templatedMsgType = TemplatedMsgType.TEMPLATE; @@ -81,40 +49,14 @@ public class SendTemplateMessageParam { */ private boolean isUpdatable; - public boolean isSendByRobot() { - return sender.getAppType() == null; - } - private PushContent pushContent; private List excludePushPayloads; - public Long determineSenderPersonId() { - if (sender != null) - return Long.parseLong(sender.getPersonId()); - return 0L; - } - - public Long determineSenderOuId() { - if (sender != null) - return sender.ouIdOrDefault(); - return 0L; - } - public boolean isUpdatable() { return isUpdatable; } - public Set uniqueReceivePersons() { - if (receivePersons == null) - return Collections.emptySet(); - return new HashSet<>(receivePersons); - } - - public Set imReceiveAccountsOrEmpty() { - return imReceiveAccounts == null ? Collections.emptySet() : imReceiveAccounts; - } - @Override public String toString() { return JSON.toJSONString(this); diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java new file mode 100644 index 0000000..16ea155 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java @@ -0,0 +1,72 @@ +package cn.axzo.im.center.api.vo.resp; + +import cn.axzo.im.center.common.enums.AppTypeEnum; +import cn.axzo.im.center.common.enums.NimFromClientType; +import cn.axzo.im.center.common.enums.NimMessageType; +import cn.axzo.im.center.common.enums.YesOrNo; +import com.alibaba.fastjson.JSONObject; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * @author yanglin + */ +@Setter @Getter +public class GroupMessagePageQueryResponse { + /** + * 服务器消息id + */ + private Long id; + /** + * 群id + */ + private Long tid; + /** + * 发送者IM账号 + */ + private String fromAccount; + /** + * 发送者自然人ID + */ + private Long fromPersonId; + /** + * 发送者OU ID + */ + private Long fromPersonOuId; + /** + * 发送者应用类型 + */ + private AppTypeEnum fromPersonAppType; + /** + * 是否来自机器人 + */ + private YesOrNo isFromRobot; + /** + * 云信消息ID + */ + private Long messageId; + /** + * 消息类型. TEXT: 文本, IMAGE: 图片, SPEECH: 语音, VIDEO: 视频, POSITION: 地理位置, FILE: 文件, CUSTOM: 自定义消息 + */ + private NimMessageType messageType; + /** + * 发送者的客户端类型. ANDROID, IOS, PC, WEB, REST, MAC + */ + private NimFromClientType fromClientType; + /** + * 发送时间 + */ + private Date sendTime; + /** + * 消息体. 具体格式根据messageType来定, 字段参考云信文档的body部分: https://doc.yunxin.163.com/messaging/server-apis/DE0MTk0OTY?platform=server#%E5%8E%86%E5%8F%B2%E6%B6%88%E6%81%AF%E6%9F%A5%E8%AF%A2%E8%BF%94%E5%9B%9E%E7%9A%84%E6%B6%88%E6%81%AF%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E + */ + private JSONObject body; + + /** + * 单位名称 + */ + private String unitName; + +} diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimFromClientType.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimFromClientType.java index 7644dc0..fa1007a 100644 --- a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimFromClientType.java +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimFromClientType.java @@ -7,17 +7,19 @@ import lombok.RequiredArgsConstructor; * @author yanglin */ @RequiredArgsConstructor -public enum NimFromClientType implements CodeDefinition { - ANDROID, - IOS, - PC, - WEB, - REST, - MAC +public enum NimFromClientType implements CodeDefinition { + ANDROID(1), + IOS(2), + PC(4), + WEB(16), + REST(32), + MAC(64) ; + private final Integer nimCode; + @Override - public String getCode() { - return name(); + public Integer getCode() { + return nimCode; } } diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimMessageType.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimMessageType.java index a61de1e..d2d6cab 100644 --- a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimMessageType.java +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/NimMessageType.java @@ -1,28 +1,29 @@ package cn.axzo.im.center.common.enums; import cn.axzo.basics.common.constant.enums.CodeDefinition; +import lombok.Getter; import lombok.RequiredArgsConstructor; /** * @author yanglin */ +@Getter @RequiredArgsConstructor -public enum NimMessageType implements CodeDefinition { - TEXT("文本"), - IMAGE("图片"), - SPEECH("语音"), - VIDEO("视频"), - POSITION("地理位置"), - FILE("文件"), - CUSTOM("第三方自定义消息"), - GROUP_NOTIFICATION("群通知"), - CHAT_GROUP_NOTIFICATION("聊天室通知"), +public enum NimMessageType implements CodeDefinition { + TEXT("文本", 0), + IMAGE("图片", 1), + SPEECH("语音", 2), + VIDEO("视频", 3), + POSITION("地理位置", 4), + FILE("文件", 6), + CUSTOM("自定义", 100), ; - private final String description; + private final String name; + private final int nimCode; @Override - public String getCode() { - return name(); + public Integer getCode() { + return nimCode; } } diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java index 1b4c514..f98e73b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/client/NimClient.java @@ -12,6 +12,8 @@ import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; import cn.axzo.im.channel.netease.dto.NimGroupDismissResponse; import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; import cn.axzo.im.channel.netease.dto.NimGroupGetInfoResponse; +import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesRequest; +import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesResponse; import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersRequest; import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersResponse; import cn.axzo.im.channel.netease.dto.NimQueryEventRequest; @@ -76,10 +78,13 @@ public interface NimClient { NimGroupCreateResponse createGroup(NimGroupCreateRequest request); @PostMapping(value = "/team/add.action") - NimGroupAddMembersResponse addMembers(NimGroupAddMembersRequest request); + NimGroupAddMembersResponse addGroupMembers(NimGroupAddMembersRequest request); @PostMapping(value = "/team/kick.action") - NimGroupRemoveMembersResponse removeMembers(NimGroupRemoveMembersRequest request); + NimGroupRemoveMembersResponse removeGroupMembers(NimGroupRemoveMembersRequest request); + + @PostMapping(value = "/history/queryTeamMsg.action") + NimGroupGetMessagesResponse getGroupMessages(NimGroupGetMessagesRequest request); @Data class NimCodeResponse { diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesRequest.java new file mode 100644 index 0000000..0f62c09 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesRequest.java @@ -0,0 +1,34 @@ +package cn.axzo.im.channel.netease.dto; + +import cn.axzo.im.channel.netease.client.FormRequest; +import com.alibaba.fastjson.JSON; +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +@FormRequest +public class NimGroupGetMessagesRequest { + private Long tid; + private String accid; + private Long begintime; + private Long endtime; + private Long limit; + // 1 按时间正序排列,2 按时间降序排列。其它返回参数 414 错误。默认是按降序排列,即时间戳最晚的消息排在最前面。 + private Integer reverse; + // 查询指定的多个消息类型,类型之间用","分割,不设置该参数则查询全部类型消息格式示例:0,1,2,3 + //类型支持:0:文本,1:图片,2:语音,3:视频,4:地理位置,5:通知,6:文件,10:提示,11:Robot,100:自定义 + private String type; + private Boolean checkTeamValid; + private Boolean includeNoSenseMsg; + // 结束查询的最后一条消息的 msgid(不包含在查询结果中),用于定位锚点 + private Long excludeMsgid; + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesResponse.java new file mode 100644 index 0000000..0cc6806 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesResponse.java @@ -0,0 +1,35 @@ +package cn.axzo.im.channel.netease.dto; + +import cn.axzo.im.channel.netease.client.NimClient; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * @author yanglin + */ +@Setter +@Getter +public class NimGroupGetMessagesResponse extends NimClient.NimCodeResponse { + private List msgs; + + @Setter + @Getter + public static class NimGroupMessage { + private String from; + private Long msgid; + private Long sendtime; + private Integer type; + private Integer fromclienttype; + private String msgidclient; + private JSONObject body; + } + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index c834304..c611b1d 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -13,6 +13,7 @@ import cn.axzo.im.center.api.vo.req.CustomMessageInfo; import cn.axzo.im.center.api.vo.req.FetchUpdatableMessageRequest; import cn.axzo.im.center.api.vo.req.GetMessageDetailRequest; import cn.axzo.im.center.api.vo.req.MessageInfo; +import cn.axzo.im.center.api.vo.req.SendChatMessageRequest; import cn.axzo.im.center.api.vo.req.SendMessageParam; import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam; import cn.axzo.im.center.api.vo.req.UpdatableMessageAckRequest; @@ -39,7 +40,9 @@ import cn.axzo.im.service.RobotMsgTemplateService; import cn.axzo.im.updatable.UpdatableMessageManager; import cn.axzo.im.updatable.UpdatableMessageQueryService; import cn.axzo.im.updatable.UpdateSupport; +import cn.axzo.im.utils.BizAssertions; import cn.axzo.pokonyan.exception.Aassert; +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Sets; @@ -197,7 +200,7 @@ public class MessageController implements MessageApi { .build(); Date now = new Date(); List requestReceivePersons = JSONArray.parseArray( - JSONObject.toJSONString(request.uniqueReceivePersons()), MessageTask.ReceivePerson.class); + JSONObject.toJSONString(request.receivePersonsOrEmpty()), MessageTask.ReceivePerson.class); List receivePersons = new ArrayList<>(requestReceivePersons); if (CollectionUtils.isNotEmpty(request.getImReceiveAccounts())) { for (String account : request.getImReceiveAccounts()) { @@ -231,6 +234,43 @@ public class MessageController implements MessageApi { return ApiResult.ok(messageTaskResp); } + @Override + public ApiResult sendChatMessage(SendChatMessageRequest request) { + PersonAccountAttribute sender = request.getSender(); + BizAssertions.assertNotNull(sender.getAppType(), "发送人appType不能为空"); + String sendImAccount = accountService.registerAccountIfAbsent( + sender.getPersonId(), sender.getOuId(), sender.getAppType()); + MessageTask.BizData bizData = MessageTask.BizData.builder() + .messageBody(JSON.toJSONString(request.getMessageBody())) + .isSenderRobot(false) + .senderPersonId(request.determineSenderPersonId()) + .nimMessageType(request.getMessageType()) + .build(); + Date now = new Date(); + List requestReceivePersons = JSONArray.parseArray( + JSONObject.toJSONString(request.receivePersonsOrEmpty()), MessageTask.ReceivePerson.class); + List receivePersons = new ArrayList<>(requestReceivePersons); + if (CollectionUtils.isNotEmpty(request.getImReceiveAccounts())) { + for (String account : request.getImReceiveAccounts()) { + receivePersons.add(MessageTask.ReceivePerson.builder() + .imAccount(account) + .build()); + } + } + MessageTask messageTask = messageTaskService.create(MessageTask.builder() + .bizId(request.getBizId()) + .sendImAccount(sendImAccount) + .receivePersons(receivePersons) + .status(MessageTaskStatus.PENDING) + .bizData(bizData) + .planStartTime(now) + .createAt(now) + .sendPriority(SendPriority.CHAT_MESSAGE.getPriority()) + .apiChannel(ApiChannel.COMMON_MESSAGE) + .build()); + return ApiResult.ok(messageTask.getId()); + } + @Override public ApiResult updateMessage(UpdateMessageRequest request) { log.info("updateMessage, request={}", request); diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java index e0b7d74..af035aa 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java @@ -11,6 +11,7 @@ import cn.axzo.im.channel.netease.dto.NimQueryEventRequest; import cn.axzo.im.channel.netease.dto.NimQueryMessageRequest; import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; import cn.axzo.im.group.GroupManager; +import cn.axzo.im.group.message.GroupMessageSyncService; import cn.axzo.im.job.CreateMessageHistoryJob; import cn.axzo.im.job.ExpungeImTaskJob; import cn.axzo.im.job.RevokeAllMessagesJob; @@ -39,6 +40,7 @@ public class PrivateController { private final MessageController messageController; private final ExpungeImTaskJob expungeImTaskJob; private final GroupManager groupManager; + private final GroupMessageSyncService groupMessageSyncService; @PostMapping("/private/revoke") public Object revoke(@Valid @RequestBody NimRevokeMessageRequest request) { @@ -109,4 +111,10 @@ public class PrivateController { return CommonResponse.success(nimClient.getGroupInfo(request)); } + @PostMapping("/private/group/syncGroupMessages") + public Object syncGroupMessages() throws Exception { + groupMessageSyncService.syncAndWait(); + return "done"; + } + } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java index 8af7f1e..5415712 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java @@ -7,6 +7,7 @@ import cn.axzo.im.entity.Group; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Repository; +import java.util.Date; import java.util.Optional; /** @@ -49,6 +50,7 @@ public class GroupDao extends ServiceImpl { lambdaUpdate() .eq(Group::getTid, tid) .set(Group::getIsDismissed, YesOrNo.YES) + .set(Group::getDismissedAt, new Date()) .update(); } diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java index 88f6c8f..5a5b413 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java @@ -3,11 +3,31 @@ package cn.axzo.im.dao.repository; import cn.axzo.im.dao.mapper.GroupMessageMapper; import cn.axzo.im.entity.GroupMessage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Repository; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + /** * @author yanglin */ @Repository("groupMessageDao") public class GroupMessageDao extends ServiceImpl { + + public List reload(Collection messages) { + if (CollectionUtils.isEmpty(messages)) + return Collections.emptyList(); + return lambdaQuery() + .nested(wrapper -> { + for (GroupMessage message : messages) { + wrapper.or().nested(nested -> nested + .eq(GroupMessage::getTid, message.getTid()) + .eq(GroupMessage::getMessageId, message.getMessageId())); + } + }) + .list(); + } + } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/Group.java b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java index 130faca..7a0a4e9 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/Group.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java @@ -2,6 +2,7 @@ package cn.axzo.im.entity; import cn.axzo.im.center.common.enums.GroupType; import cn.axzo.im.center.common.enums.YesOrNo; +import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; @@ -19,6 +20,8 @@ import java.util.Date; public class Group { public static final String ATTACHMENT_GROUP_TYPE = "groupType"; + public static final String ATTACHMENT_BIZ_CODE = "bizCode"; + public static final String ATTACHMENT_BIZ_ATTACHMENT = "bizAttachment"; private Long id; private Long tid; @@ -31,6 +34,7 @@ public class Group { private String ownerAccount; private Long ownerPersonId; private Long createPersonId; + private Date dismissedAt; private Long isDelete; private YesOrNo isDismissed; private Date createAt; @@ -47,6 +51,11 @@ public class Group { return getIsDismissed() == YesOrNo.YES; } + @Override + public String toString() { + return JSON.toJSONString(this); + } + @Setter @Getter public static class RecordExt { diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java index ca0f9eb..e4997a1 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java @@ -8,7 +8,6 @@ import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; -import com.dingtalk.api.request.OapiAtsResumeAddRequest; import lombok.Getter; import lombok.Setter; @@ -28,8 +27,10 @@ public class GroupMessage { private Long fromPersonOuId; private AppTypeEnum fromPersonAppType; private YesOrNo isFromRobot; + private Long messageId; private NimMessageType messageType; private NimFromClientType fromClientType; + private String messageIdClient; private Date sendTime; @TableField(typeHandler = FastjsonTypeHandler.class) private JSONObject body; @@ -39,6 +40,12 @@ public class GroupMessage { private Date createAt; private Date updateAt; + public RecordExt getOrCreateRecordExt() { + if (recordExt == null) + recordExt = new RecordExt(); + return recordExt; + } + @Setter @Getter public static class RecordExt { diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/HistoryRecordExt.java b/im-center-server/src/main/java/cn/axzo/im/entity/HistoryRecordExt.java index 6a816c0..621c8f8 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/HistoryRecordExt.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/HistoryRecordExt.java @@ -35,4 +35,6 @@ public class HistoryRecordExt { private Long updateRetryCount; private Map initMessageExt; private Long workspaceId; + + private Integer nimMessageType; } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java index 7415b57..3e8e70f 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java @@ -6,6 +6,7 @@ import cn.axzo.im.center.api.vo.req.PushContent; import cn.axzo.im.center.api.vo.req.SendMessageParam; import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.BizTypeEnum; +import cn.axzo.im.center.common.enums.NimMessageType; import cn.axzo.im.center.common.enums.TemplatedMsgType; import cn.axzo.im.config.BaseListTypeHandler; import cn.axzo.im.enums.MessageTaskStatus; @@ -130,6 +131,11 @@ public class MessageTask { */ private String msgTemplateContent; + /** + * 直接发送的消息内容 + */ + private String messageBody; + /** * 网易云信-自定义消息使用 */ @@ -162,6 +168,8 @@ public class MessageTask { private Boolean isSenderRobot; + private NimMessageType nimMessageType; + public boolean determineIsSenderRobot() { return isSenderRobot != null && isSenderRobot; } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java index 35bffb0..46a5e93 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java @@ -14,8 +14,8 @@ import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; import cn.axzo.im.center.api.vo.resp.GroupGetMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupGetOwnerResponse; -import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.GroupMember; +import cn.axzo.im.group.member.GroupMemberQueryService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RestController; @@ -31,8 +31,7 @@ import java.util.List; public class GroupController implements GroupApi { private final GroupManager groupManager; - private final GroupMemberManager groupMemberManager; - private final GroupMemberDao groupMemberDao; + private final GroupMemberQueryService groupMemberQueryService; @Override public ApiResult createGroup(GroupCreateRequest request) { @@ -58,7 +57,7 @@ public class GroupController implements GroupApi { @Override public ApiResult getMembers(GroupGetMembersRequest request) { - List members = groupMemberManager.getMembers(request.getTid()); + List members = groupMemberQueryService.getMembers(request.getTid()); GroupGetMembersResponse response = new GroupGetMembersResponse(); response.setMember(BeanMapper.copyList(members, GroupMemberInfo.class)); return ApiResult.ok(response); @@ -66,7 +65,7 @@ public class GroupController implements GroupApi { @Override public ApiResult getOwner(GroupGetOwnerRequest request) { - GroupMember owner = groupMemberManager.getOwner(request.getTid()); + GroupMember owner = groupMemberQueryService.getOwner(request.getTid()); GroupGetOwnerResponse response = new GroupGetOwnerResponse(); response.setOwner(BeanMapper.copyBean(owner, GroupMemberInfo.class)); return ApiResult.ok(response); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 4cc9ee5..25b91b5 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -21,6 +21,7 @@ import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMember; +import cn.axzo.im.group.member.GroupMemberSyncer; import cn.axzo.im.service.AccountService; import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.BizAssertions; @@ -52,7 +53,7 @@ public class GroupManager { private final GroupSupport groupSupport; private final AccountService accountService; private final GroupBroadcaster groupBroadcaster; - private final GroupMemberManager groupMemberManager; + private final GroupMemberSyncer groupMemberSyncer; @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { @@ -74,7 +75,7 @@ public class GroupManager { BizAssertions.assertTrue(nimResponse.isSuccess(), "创建群失败: {}", nimResponse.getDesc()); groupDao.updateTid(group.getId(), nimResponse.getTid()); group = groupDao.getById(group.getId()); - groupMemberManager.syncGroupMembers(group); + groupMemberSyncer.syncMembers(group); groupBroadcaster.fireMembersAdded(group, groupMemberDao.getByTid(nimResponse.getTid())); GroupCreateResponse response = new GroupCreateResponse(); response.setTid(nimResponse.getTid()); @@ -101,14 +102,14 @@ public class GroupManager { Group group = findGroupForUpdateOrThrow(request.getTid()); BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); // sync members 1 - groupMemberManager.syncGroupMembers(group); + groupMemberSyncer.syncMembers(group); // prepare add members Set preMembers = groupMemberDao.getGroupPersons(group.getTid()); List toAddMembers = request.getMembers().stream() .filter(member -> !preMembers.contains(member)) .collect(toList()); if (group.isMemberLimitReached(preMembers.size() + toAddMembers.size())) - throw new ServiceException("群聊人数上限" + group.getMemberLimit() +"人, 请删除部分已选人员"); + throw new ServiceException("群聊人数上限" + group.getMemberLimit() + "人, 请删除部分已选人员"); ImAccounts imAccounts = accountService.getAccountsByPersons(toAddMembers); if (imAccounts.isAccountEmpty()) { groupSupport.log("添加群成员[TID:{}], 有效群成员IM账号列表为空. 请求成员信息: {}", @@ -118,11 +119,11 @@ public class GroupManager { NimGroupAddMembersRequest nimRequest = groupSupport .buildAddMembersRequest(group, group.getOwnerAccount(), imAccounts); // add members - NimGroupAddMembersResponse nimResponse = nimClient.addMembers(nimRequest); + NimGroupAddMembersResponse nimResponse = nimClient.addGroupMembers(nimRequest); log.info("添加群成员, request={}, response={}", nimRequest, nimResponse); BizAssertions.assertTrue(nimResponse.isSuccess(), "添加群成员失败: {}", nimResponse.getDesc()); // sync members 2 - groupMemberManager.syncGroupMembers(group); + groupMemberSyncer.syncMembers(group); groupBroadcaster.fireMembersAdded(group, groupMemberDao .getByPersons(group.getTid(), toAddMembers)); GroupAddMembersResponse response = new GroupAddMembersResponse(); @@ -137,24 +138,23 @@ public class GroupManager { BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); ImAccounts imAccounts = accountService.getAccountsByPersons(request.getMembers()); if (imAccounts.isAccountEmpty()) { - groupSupport.log("添加群成员[TID:{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + groupSupport.log("移除群成员[TID:{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), JSON.toJSONString(request.getMembers())); return; } - groupMemberManager.syncGroupMembers(group); + groupMemberSyncer.syncMembers(group); List toRemoveMembers = groupMemberDao.getByPersons( group.getTid(), request.getMembers()); if (CollectionUtils.isEmpty(toRemoveMembers)) return; NimGroupRemoveMembersRequest nimRequest = groupSupport .buildRemoveMembersRequest(group, group.getOwnerAccount(), imAccounts); - NimGroupRemoveMembersResponse nimResponse = nimClient.removeMembers(nimRequest); + // 不判断NIM响应状态, 因为前端可能已经调用app sdk移除过成员了(支持重复移除) + NimGroupRemoveMembersResponse nimResponse = nimClient.removeGroupMembers(nimRequest); log.info("移除群成员, request={}, response={}", nimRequest, nimResponse); - if (nimResponse.isSuccess()) { - groupMemberManager.syncGroupMembers(group); - // 不比较直接发消息 - groupBroadcaster.fireMembersRemoved(group, toRemoveMembers); - } + groupMemberSyncer.syncMembers(group); + // 不比较直接发消息 + groupBroadcaster.fireMembersRemoved(group, toRemoveMembers); } @NotNull diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index c864e58..cfe6349 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -1,30 +1,21 @@ package cn.axzo.im.group; import cn.axzo.im.center.api.feign.GroupApi; -import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; -import cn.axzo.im.center.common.enums.GroupMemberType; import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.channel.netease.dto.NimGroupAddMembersRequest; import cn.axzo.im.channel.netease.dto.NimGroupCreateRequest; import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; -import cn.axzo.im.channel.netease.dto.NimGroupInfo; -import cn.axzo.im.channel.netease.dto.NimGroupMemberInfo; import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersRequest; import cn.axzo.im.entity.Group; -import cn.axzo.im.entity.GroupMember; import cn.axzo.im.service.ChatGroupService; import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.BizAssertions; -import cn.axzo.im.utils.ImAccountParser; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.slf4j.helpers.MessageFormatter; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.List; - /** * @author yanglin */ @@ -66,6 +57,8 @@ public class GroupSupport implements GroupLogger { nimRequest.setIntroduceMessage(GroupApi.INTRODUCE_MESSAGE); nimRequest.setIcon(request.getAvatar()); nimRequest.addAttachment(Group.ATTACHMENT_GROUP_TYPE, request.getGroupType()); + nimRequest.addAttachment(Group.ATTACHMENT_BIZ_CODE, request.getBizCode()); + nimRequest.addAttachment(Group.ATTACHMENT_BIZ_ATTACHMENT, request.getBizAttachment()); return nimRequest; } @@ -105,29 +98,4 @@ public class GroupSupport implements GroupLogger { } } - List parseGroupMembers(Group group, NimGroupInfo groupInfo) { - ArrayList accounts = new ArrayList<>(); - for (NimGroupMemberInfo member : groupInfo.getOwnerAndMembers()) { - PersonAccountAttribute person = ImAccountParser.parsePerson(member.getAccid()).orElse(null); - GroupMember account = new GroupMember(); - accounts.add(account); - account.setTid(group.getTid()); - account.setImAccount(member.getAccid()); - account.setMemberType(groupInfo.getOwner().equals(member) - ? GroupMemberType.OWNER : GroupMemberType.MEMBER); - if (person == null) { - account.setPersonId(0L); - account.setPersonOuId(0L); - account.setAppType(null); - account.setIsRobot(YesOrNo.YES); - } else { - account.setPersonId(Long.valueOf(person.getPersonId())); - account.setPersonOuId(person.ouIdOrDefault()); - account.setAppType(person.getAppType()); - account.setIsRobot(YesOrNo.NO); - } - } - return accounts; - } - } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java new file mode 100644 index 0000000..180070f --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java @@ -0,0 +1,33 @@ +package cn.axzo.im.group.member; + +import cn.axzo.im.center.common.enums.GroupMemberType; +import cn.axzo.im.dao.repository.GroupMemberDao; +import cn.axzo.im.entity.GroupMember; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author yanglin + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class GroupMemberQueryService { + + private final GroupMemberDao groupMemberDao; + + public List getMembers(Long tid) { + return groupMemberDao.getByTid(tid); + } + + public GroupMember getOwner(Long tid) { + return groupMemberDao.lambdaQuery() + .eq(GroupMember::getTid, tid) + .eq(GroupMember::getMemberType, GroupMemberType.OWNER) + .one(); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberManager.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java similarity index 55% rename from im-center-server/src/main/java/cn/axzo/im/group/GroupMemberManager.java rename to im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index 2e1834e..89258c8 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -1,20 +1,25 @@ -package cn.axzo.im.group; +package cn.axzo.im.group.member; +import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.common.enums.GroupMemberType; +import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.channel.netease.client.NimClient; import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; import cn.axzo.im.channel.netease.dto.NimGroupGetInfoResponse; import cn.axzo.im.channel.netease.dto.NimGroupInfo; +import cn.axzo.im.channel.netease.dto.NimGroupMemberInfo; import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMember; import cn.axzo.im.utils.BizAssertions; +import cn.axzo.im.utils.ImAccountParser; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; +import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -24,29 +29,17 @@ import java.util.Optional; @Slf4j @Component @RequiredArgsConstructor -public class GroupMemberManager { +public class GroupMemberSyncer { private final GroupMemberDao groupMemberDao; - private final GroupSupport groupSupport; private final GroupDao groupDao; private final NimClient nimClient; - List getMembers(Long tid) { - return groupMemberDao.getByTid(tid); - } - - GroupMember getOwner(Long tid) { - return groupMemberDao.lambdaQuery() - .eq(GroupMember::getTid, tid) - .eq(GroupMember::getMemberType, GroupMemberType.OWNER) - .one(); - } - - void syncGroupMembers(Group group) { + public void syncMembers(Group group) { NimGroupInfo groupInfo = fetchGroupInfo(group).orElse(null); if (groupInfo == null) return; groupMemberDao.deleteAccounts(group.getTid()); - List accounts = groupSupport.parseGroupMembers(group, groupInfo); + List accounts = parseGroupMembers(group, groupInfo); if (CollectionUtils.isNotEmpty(accounts)) groupMemberDao.saveBatch(accounts); groupDao.updateMembersCount(group.getTid(), accounts.size()); @@ -65,4 +58,30 @@ public class GroupMemberManager { "获取群信息失败: {}", nimResponse.getDesc()); return Optional.of(nimResponse.getTinfo()); } -} + + private List parseGroupMembers(Group group, NimGroupInfo groupInfo) { + ArrayList accounts = new ArrayList<>(); + for (NimGroupMemberInfo member : groupInfo.getOwnerAndMembers()) { + PersonAccountAttribute person = ImAccountParser.parsePerson(member.getAccid()).orElse(null); + GroupMember account = new GroupMember(); + accounts.add(account); + account.setTid(group.getTid()); + account.setImAccount(member.getAccid()); + account.setMemberType(groupInfo.getOwner().equals(member) + ? GroupMemberType.OWNER : GroupMemberType.MEMBER); + if (person == null) { + account.setPersonId(0L); + account.setPersonOuId(0L); + account.setAppType(null); + account.setIsRobot(YesOrNo.YES); + } else { + account.setPersonId(Long.valueOf(person.getPersonId())); + account.setPersonOuId(person.ouIdOrDefault()); + account.setAppType(person.getAppType()); + account.setIsRobot(YesOrNo.NO); + } + } + return accounts; + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java new file mode 100644 index 0000000..98b73a4 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -0,0 +1,57 @@ +package cn.axzo.im.group.message; + +import cn.axzo.basics.common.exception.ServiceException; +import com.alibaba.fastjson.JSON; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.concurrent.CountDownLatch; + +/** + * @author yanglin + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class GroupMessageSyncJob { + + private final GroupMessageSyncService groupMessageSyncService; + + private volatile boolean isRunning = false; + + @XxlJob("groupMessageSyncJob") + public ReturnT execute(String jsonStr) throws Exception { + if (isRunning) + throw new ServiceException("任务正在执行中,请稍后再试..."); + synchronized (this) { + if (isRunning) + throw new ServiceException("任务正在执行中,请稍后再试..."); + isRunning = true; + } + Param param = StringUtils.isBlank(jsonStr) + ? new Param() : JSON.parseObject(jsonStr, Param.class); + CountDownLatch latch = new CountDownLatch(1); + groupMessageSyncService.sync(param.tps, () -> { + synchronized (GroupMessageSyncJob.this) { + isRunning = false; + } + latch.countDown(); + log.info("group message sync job finished"); + }); + latch.await(); + return ReturnT.SUCCESS; + } + + @Setter + @Getter + public static class Param { + private int tps = 30; + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java new file mode 100644 index 0000000..6fb2c2c --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -0,0 +1,122 @@ +package cn.axzo.im.group.message; + +import cn.axzo.im.center.common.enums.YesOrNo; +import cn.axzo.im.channel.netease.client.NimClient; +import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesRequest; +import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesResponse; +import cn.axzo.im.dao.repository.GroupDao; +import cn.axzo.im.dao.repository.GroupMessageDao; +import cn.axzo.im.entity.Group; +import cn.axzo.im.entity.GroupMessage; +import cn.axzo.im.utils.RecordCursor; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.joda.time.DateTime; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author yanglin + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class GroupMessageSyncService { + + private final GroupDao groupDao; + private final GroupMessageDao groupMessageDao; + private final NimClient nimClient; + + public void syncAndWait() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + sync(5, latch::countDown); + latch.await(); + } + + void sync(int tps, Runnable onComplete) { + AtomicBoolean completed = new AtomicBoolean(false); + Runnable runOnce = () -> { + if (completed.compareAndSet(false, true)) + onComplete.run(); + }; + try { + syncImpl(tps, runOnce); + } catch (Exception e) { + log.warn("sync group message failed", e); + runOnce.run(); + } + } + + private void syncImpl(int tps, Runnable onComplete) throws Exception { + ExecutorService executor = Executors.newFixedThreadPool(tps + 1); + MessageSyncController controller = new MessageSyncController(tps, onComplete); + Date twoDayAgo = new DateTime(new Date()).minusDays(2).toDate(); + RecordCursor cursor = new RecordCursor<>(Group::getId, () -> + groupDao.lambdaQuery() + .nested(w1 -> w1 + .eq(Group::getIsDismissed, YesOrNo.NO) + .or().nested(w2 -> w2 + .eq(Group::getIsDismissed, YesOrNo.YES) + .gt(Group::getDismissedAt, twoDayAgo))) + ); + for (List groups : cursor) { + for (Group group : groups) { + controller.acquireSubmitGroup(); + executor.execute(new GroupMessageSyncer(this, controller, group) { + @Override + public void run() { + try { + super.run(); + } catch (Exception e) { + log.warn("sync group message failed: {}", group.getId(), e); + } finally { + controller.setGroupCompleted(group); + } + } + }); + controller.setGroupSubmitted(group); + } + } + controller.setSubmitFinished(); + } + + void saveMessagesBatch(Collection messages) { + if (CollectionUtils.isEmpty(messages)) + return; + groupMessageDao.saveBatch(messages); + } + + void saveMessage(GroupMessage message) { + groupMessageDao.save(message); + } + + List reloadMessages(Collection messages) { + return groupMessageDao.reload(messages); + } + + Optional getMaxSendTime(Long tid) { + GroupMessage groupMessage = groupMessageDao.getBaseMapper() + .selectOne(new QueryWrapper() + .select("MAX(send_time) AS send_time") + .lambda() + .eq(GroupMessage::getTid, tid)); + return groupMessage == null + ? Optional.empty() + : Optional.of(groupMessage.getSendTime()); + } + + NimGroupGetMessagesResponse getGroupMessages(NimGroupGetMessagesRequest request) { + return nimClient.getGroupMessages(request); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java new file mode 100644 index 0000000..ecdcd19 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -0,0 +1,129 @@ +package cn.axzo.im.group.message; + +import cn.axzo.basics.common.constant.enums.CodeDefinition; +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.common.enums.AppTypeEnum; +import cn.axzo.im.center.common.enums.NimFromClientType; +import cn.axzo.im.center.common.enums.NimMessageType; +import cn.axzo.im.center.common.enums.YesOrNo; +import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesRequest; +import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesResponse; +import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesResponse.NimGroupMessage; +import cn.axzo.im.entity.Group; +import cn.axzo.im.entity.GroupMessage; +import cn.axzo.im.group.message.timeline.TimeNode; +import cn.axzo.im.group.message.timeline.Timeline; +import cn.axzo.im.utils.BizAssertions; +import cn.axzo.im.utils.ImAccountParser; +import com.google.common.collect.Sets; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.joda.time.DateTime; +import org.springframework.dao.DuplicateKeyException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +import static java.util.stream.Collectors.toList; + +/** + * @author yanglin + */ +@Slf4j +@RequiredArgsConstructor +class GroupMessageSyncer implements Runnable { + + private final GroupMessageSyncService service; + private final MessageSyncController controller; + private final Group group; + + @Override + public void run() { + Long beginMs = service.getMaxSendTime(group.getTid()).orElse(oneAgo()).getTime(); + Long endMs = System.currentTimeMillis(); + Timeline timeline = new Timeline(beginMs, endMs); + long limit = 100L; + TimeNode node = timeline.peek(); + while (node != null) { + NimGroupGetMessagesResponse response = fetchMessages(node, limit, null); + BizAssertions.assertTrue(response.isSuccess(), "fetch group messages failed"); + List msgList = response.getMsgs(); + if (CollectionUtils.isEmpty(msgList)) { + timeline.consume(); + node = timeline.peek(); + continue; + } + if (response.getSize() > limit && msgList.size() == limit && node.isSplittable()) { + timeline.split(); + node = timeline.peek(); + continue; + } + saveMessages(asGroupMessages(msgList)); + timeline.consume(); + node = timeline.peek(); + } + } + + private NimGroupGetMessagesResponse fetchMessages(TimeNode node, Long limit, Long lastMessageId) { + NimGroupGetMessagesRequest request = new NimGroupGetMessagesRequest(); + request.setTid(group.getTid()); + request.setAccid(group.getOwnerAccount()); + request.setBegintime(node.getBeginMs()); + request.setEndtime(node.getEndMs()); + request.setLimit(limit); + request.setReverse(1); + request.setCheckTeamValid(false); + request.setIncludeNoSenseMsg(false); + request.setExcludeMsgid(lastMessageId); + request.setType("0,1,2,3,4,6,100"); + controller.acquireFetchMessages(); + NimGroupGetMessagesResponse response = service.getGroupMessages(request); + log.info("fetch group messages, request={}, response={}", request, response); + return response; + } + + private Collection asGroupMessages(List msgList) { + ArrayList messages = new ArrayList<>(); + for (NimGroupMessage nimMessage : msgList) { + PersonAccountAttribute person = ImAccountParser.parsePerson(nimMessage.getFrom()).orElse(null); + GroupMessage message = new GroupMessage(); + messages.add(message); + message.setTid(group.getTid()); + message.setFromAccount(nimMessage.getFrom()); + message.setFromPersonId(person == null ? 0L : Long.parseLong(person.getPersonId())); + message.setFromPersonOuId(person == null ? 0L : person.getOuId()); + message.setFromPersonAppType(person == null ? AppTypeEnum.NONE : person.getAppType()); + message.setIsFromRobot(YesOrNo.of(person == null)); + message.setMessageId(nimMessage.getMsgid()); + message.setMessageType(CodeDefinition.findByCode( + NimMessageType.class, nimMessage.getType()).orElse(null)); + message.setFromClientType(CodeDefinition.findByCode( + NimFromClientType.class, nimMessage.getFromclienttype()).orElse(null)); + message.setSendTime(new Date(nimMessage.getSendtime())); + message.setBody(nimMessage.getBody()); + message.setMessageIdClient(nimMessage.getMsgidclient()); + } + return messages; + } + + private void saveMessages(Collection messages) { + if (CollectionUtils.isEmpty(messages)) + return; + try { + service.saveMessagesBatch(messages); + } catch (DuplicateKeyException ignored) { + List savedMessages = service.reloadMessages(messages); + List notSaved = Sets.difference( + UniqueMessage.from(messages), UniqueMessage.from(savedMessages)) + .stream().map(UniqueMessage::getGroupMessage).collect(toList()); + saveMessages(notSaved); + } + } + + private Date oneAgo() { + return DateTime.now().minusDays(1).toDate(); + } +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java new file mode 100644 index 0000000..c362e17 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java @@ -0,0 +1,80 @@ +package cn.axzo.im.group.message; + + +import cn.axzo.basics.common.exception.ServiceException; +import cn.axzo.im.entity.Group; +import com.google.common.util.concurrent.RateLimiter; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Semaphore; + +/** + * @author yanglin + */ +@Slf4j +class MessageSyncController { + + private static final Object SUBMITTED = new Object(); + + private final RateLimiter rateLimiter; + private final Semaphore submitGroupSemaphore; + private final Runnable onComplete; + + private final Map groups = new ConcurrentHashMap<>(); + private int submittedGroup = 0; + private int completedGroup = 0; + private boolean submitFinished = false; + + MessageSyncController(int tps, Runnable onComplete) { + this.rateLimiter = RateLimiter.create(tps); + this.submitGroupSemaphore = new Semaphore(tps); + this.onComplete = onComplete; + } + + void acquireSubmitGroup() throws Exception { + submitGroupSemaphore.acquire(); + } + + void setGroupSubmitted(Group group) { + Object submitted = groups.putIfAbsent(group.getId(), SUBMITTED); + if (submitted != null) + throw new ServiceException("group already submitted: " + group.getId()); + synchronized (this) { + if (submitFinished) + throw new ServiceException("submit finished"); + submittedGroup++; + } + log.info("submitted group: {}", group.getId()); + } + + void setGroupCompleted(Group group) { + Object submitted = groups.remove(group.getId()); + if (submitted == null) return; + submitGroupSemaphore.release(); + synchronized (this) { + completedGroup++; + maybeComplete(); + } + log.info("completed group: {}", group.getId()); + } + + void setSubmitFinished() { + synchronized (this) { + submitFinished = true; + } + log.info("submit finished"); + maybeComplete(); + } + + private void maybeComplete() { + if (submitFinished && completedGroup == submittedGroup) + onComplete.run(); + } + + void acquireFetchMessages() { + rateLimiter.acquire(); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/UniqueMessage.java b/im-center-server/src/main/java/cn/axzo/im/group/message/UniqueMessage.java new file mode 100644 index 0000000..7cc9d08 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/UniqueMessage.java @@ -0,0 +1,51 @@ +package cn.axzo.im.group.message; + +import cn.axzo.im.entity.GroupMessage; +import lombok.RequiredArgsConstructor; + +import java.util.Collection; +import java.util.Objects; +import java.util.Set; + +import static java.util.stream.Collectors.toSet; + +/** + * @author yanglin + */ +@RequiredArgsConstructor +class UniqueMessage { + + private final GroupMessage message; + + public static Set from(Collection messages) { + return messages.stream() + .map(UniqueMessage::new) + .collect(toSet()); + } + + public Long getTid() { + return message.getTid(); + } + + public Long getMessageId() { + return message.getMessageId(); + } + + public GroupMessage getGroupMessage() { + return message; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof UniqueMessage)) return false; + UniqueMessage that = (UniqueMessage) o; + return Objects.equals(getTid(), that.getTid()) + && Objects.equals(getMessageId(), that.getMessageId()); + } + + @Override + public int hashCode() { + return Objects.hash(getTid(), getMessageId()); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java new file mode 100644 index 0000000..7d4ac1c --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java @@ -0,0 +1,26 @@ +package cn.axzo.im.group.message.timeline; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * @author yanglin + */ +@Getter +@RequiredArgsConstructor(access = AccessLevel.PACKAGE) +public class TimeNode { + + private final Long beginMs; + private final Long endMs; + + public boolean isSplittable() { + return endMs - beginMs > 0; + } + + @Override + public String toString() { + return String.format("%s~%s", beginMs, endMs); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java new file mode 100644 index 0000000..b371db2 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -0,0 +1,83 @@ +package cn.axzo.im.group.message.timeline; + +import cn.axzo.im.utils.BizAssertions; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import static java.util.stream.Collectors.joining; + +/** + * @author yanglin + */ +public class Timeline { + + private final LinkedList nodes; + private int splitCount = 1; + + public Timeline(Long beginMs, Long endMs) { + BizAssertions.assertTrue(beginMs <= endMs, "beginMs must be less than or equal to endMs"); + nodes = new LinkedList<>(); + prepend(split(beginMs, endMs, splitCount)); + } + + private void prepend(List nodes) { + this.nodes.addAll(0, nodes); + } + + public void split() { + TimeNode node = nodes.peek(); + BizAssertions.assertNotNull(node, "timeline is empty"); + //noinspection DataFlowIssue + BizAssertions.assertTrue(node.isSplittable(), "node is not splittable"); + nodes.removeFirst(); + splitCount *= 2; + prepend(split(node.getBeginMs(), node.getEndMs(), splitCount)); + } + + public void consume() { + TimeNode node = nodes.peek(); + BizAssertions.assertNotNull(node, "timeline is empty"); + nodes.removeFirst(); + splitCount = 1; + } + + @Nullable + public TimeNode peek() { + return nodes.peek(); + } + + private List split(Long beginMs, Long endMs, int splitCount) { + BizAssertions.assertTrue(beginMs <= endMs, "beginMs must be less than or equal to endMs"); + List nodes = new ArrayList<>(); + long totalDuration = endMs - beginMs; + if (totalDuration == 0) { + nodes.add(new TimeNode(beginMs, endMs)); + return nodes; + } + long duration = totalDuration / splitCount; + if (duration == 0) + duration = 1; + for (int i = 0; i < splitCount; i++) { + long start = beginMs + i * duration; + long end = duration == 1 + ? (start) + : ((i == splitCount - 1) ? endMs : start + duration - 1); + nodes.add(new TimeNode(start, end)); + if (duration == 1 && end == endMs) + break; + if (duration != 1 && end >= endMs - 1) + break; + } + return nodes; + } + + @Override + public String toString() { + String nodes = this.nodes.stream() + .map(TimeNode::toString).collect(joining(",")); + return String.format("[%s]", nodes); + } +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java index 40cb09e..df7f8c1 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java @@ -2,7 +2,6 @@ package cn.axzo.im.send.handler; import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.ChannelMsgTypeEnum; -import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.channel.IMChannelProvider; import cn.axzo.im.channel.netease.dto.MessageDispatchRequest; import cn.axzo.im.channel.netease.dto.MessageDispatchResponse; @@ -36,7 +35,11 @@ public class CommonSendOneHandler extends SendOneHandler { && NumberUtils.isDigits(history.getToAccount()); sendRequest.setOpe(isSendToGroup ? 1 : 0); sendRequest.setTo(history.getToAccount()); - sendRequest.setType(ChannelMsgTypeEnum.CUSTOM.getCode()); + Integer nimMessageType = history.getOrCreateRecordExt().getNimMessageType(); + if (nimMessageType != null) + sendRequest.setType(nimMessageType); + else + sendRequest.setType(ChannelMsgTypeEnum.CUSTOM.getCode()); sendRequest.setBody(history.getMessageBody()); sendRequest.setPayload(history.getOrCreateRecordExt().getPayload()); sendRequest.populateOption(); diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java index 4fce6e9..cc3f64e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java @@ -297,6 +297,10 @@ public class MessageTaskServiceImpl extends ServiceImpl excludePushPayloads = @@ -423,6 +427,8 @@ public class MessageTaskServiceImpl extends ServiceImpl Date: Thu, 23 Jan 2025 13:51:26 +0800 Subject: [PATCH 006/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resp/GroupMessagePageQueryResponse.java | 4 +++ .../axzo/im/group/GroupMessageController.java | 28 +++++++++++++++++++ .../message/GroupMessageSyncService.java | 12 ++------ .../group/message/MessageSyncController.java | 11 ++++---- .../src/main/resources/application.yml | 2 +- 5 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java index 16ea155..2a6419c 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java @@ -69,4 +69,8 @@ public class GroupMessagePageQueryResponse { */ private String unitName; + /** + * 客户端id + */ + private String messageIdClient; } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java new file mode 100644 index 0000000..93941f9 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java @@ -0,0 +1,28 @@ +package cn.axzo.im.group; + +import cn.axzo.framework.domain.web.result.ApiPageResult; +import cn.axzo.im.center.api.feign.GroupMessageApi; +import cn.axzo.im.center.api.vo.req.GroupMessagePageQueryRequest; +import cn.axzo.im.center.api.vo.resp.GroupMessagePageQueryResponse; +import cn.axzo.im.dao.repository.GroupMessageDao; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author yanglin + */ +@Slf4j +@RestController +@RequiredArgsConstructor +public class GroupMessageController implements GroupMessageApi { + + private final GroupMessageDao groupMessageDao; + + @Override + public ApiPageResult + pageQuery(GroupMessagePageQueryRequest request) { + return null; + } + +} diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index 6fb2c2c..9effc7e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -71,7 +71,7 @@ public class GroupMessageSyncService { ); for (List groups : cursor) { for (Group group : groups) { - controller.acquireSubmitGroup(); + controller.acquireSubmitGroup(group); executor.execute(new GroupMessageSyncer(this, controller, group) { @Override public void run() { @@ -84,20 +84,14 @@ public class GroupMessageSyncService { } } }); - controller.setGroupSubmitted(group); } } controller.setSubmitFinished(); } void saveMessagesBatch(Collection messages) { - if (CollectionUtils.isEmpty(messages)) - return; - groupMessageDao.saveBatch(messages); - } - - void saveMessage(GroupMessage message) { - groupMessageDao.save(message); + if (CollectionUtils.isNotEmpty(messages)) + groupMessageDao.saveBatch(messages); } List reloadMessages(Collection messages) { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java index c362e17..d6ddafe 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java @@ -33,14 +33,13 @@ class MessageSyncController { this.onComplete = onComplete; } - void acquireSubmitGroup() throws Exception { + void acquireSubmitGroup(Group group) throws Exception { submitGroupSemaphore.acquire(); - } - - void setGroupSubmitted(Group group) { Object submitted = groups.putIfAbsent(group.getId(), SUBMITTED); - if (submitted != null) + if (submitted != null) { + submitGroupSemaphore.release(); throw new ServiceException("group already submitted: " + group.getId()); + } synchronized (this) { if (submitFinished) throw new ServiceException("submit finished"); @@ -63,9 +62,9 @@ class MessageSyncController { void setSubmitFinished() { synchronized (this) { submitFinished = true; + maybeComplete(); } log.info("submit finished"); - maybeComplete(); } private void maybeComplete() { diff --git a/im-center-server/src/main/resources/application.yml b/im-center-server/src/main/resources/application.yml index 3176c5c..3415f51 100644 --- a/im-center-server/src/main/resources/application.yml +++ b/im-center-server/src/main/resources/application.yml @@ -20,7 +20,7 @@ mybatis-plus: configuration: auto-mapping-behavior: full map-underscore-to-camel-case: true - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: auto From 0cafc5d53ff9996e6e017c9d2313b2bfcdf96f58 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 13:57:55 +0800 Subject: [PATCH 007/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/group/message/GroupMessageSyncJob.java | 15 ++------------- .../im/group/message/GroupMessageSyncService.java | 11 ++++++----- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 98b73a4..6abe7c1 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -1,14 +1,10 @@ package cn.axzo.im.group.message; import cn.axzo.basics.common.exception.ServiceException; -import com.alibaba.fastjson.JSON; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.annotation.XxlJob; -import lombok.Getter; import lombok.RequiredArgsConstructor; -import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import java.util.concurrent.CountDownLatch; @@ -25,6 +21,7 @@ public class GroupMessageSyncJob { private volatile boolean isRunning = false; + @SuppressWarnings("unused") @XxlJob("groupMessageSyncJob") public ReturnT execute(String jsonStr) throws Exception { if (isRunning) @@ -34,10 +31,8 @@ public class GroupMessageSyncJob { throw new ServiceException("任务正在执行中,请稍后再试..."); isRunning = true; } - Param param = StringUtils.isBlank(jsonStr) - ? new Param() : JSON.parseObject(jsonStr, Param.class); CountDownLatch latch = new CountDownLatch(1); - groupMessageSyncService.sync(param.tps, () -> { + groupMessageSyncService.sync(() -> { synchronized (GroupMessageSyncJob.this) { isRunning = false; } @@ -48,10 +43,4 @@ public class GroupMessageSyncJob { return ReturnT.SUCCESS; } - @Setter - @Getter - public static class Param { - private int tps = 30; - } - } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index 9effc7e..854310a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -33,32 +33,33 @@ import java.util.concurrent.atomic.AtomicBoolean; @RequiredArgsConstructor public class GroupMessageSyncService { + private final int tps = 30; + private final ExecutorService executor = Executors.newFixedThreadPool(tps + 1); private final GroupDao groupDao; private final GroupMessageDao groupMessageDao; private final NimClient nimClient; public void syncAndWait() throws Exception { CountDownLatch latch = new CountDownLatch(1); - sync(5, latch::countDown); + sync(latch::countDown); latch.await(); } - void sync(int tps, Runnable onComplete) { + void sync(Runnable onComplete) { AtomicBoolean completed = new AtomicBoolean(false); Runnable runOnce = () -> { if (completed.compareAndSet(false, true)) onComplete.run(); }; try { - syncImpl(tps, runOnce); + syncImpl(runOnce); } catch (Exception e) { log.warn("sync group message failed", e); runOnce.run(); } } - private void syncImpl(int tps, Runnable onComplete) throws Exception { - ExecutorService executor = Executors.newFixedThreadPool(tps + 1); + private void syncImpl(Runnable onComplete) throws Exception { MessageSyncController controller = new MessageSyncController(tps, onComplete); Date twoDayAgo = new DateTime(new Date()).minusDays(2).toDate(); RecordCursor cursor = new RecordCursor<>(Group::getId, () -> From 598611f004131c50f49a95b9391198af3202c101 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 14:19:11 +0800 Subject: [PATCH 008/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/message/GroupMessageSyncer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index ecdcd19..a633b28 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -56,7 +56,8 @@ class GroupMessageSyncer implements Runnable { node = timeline.peek(); continue; } - if (response.getSize() > limit && msgList.size() == limit && node.isSplittable()) { + // response.size 不可靠 + if (msgList.size() == limit && node.isSplittable()) { timeline.split(); node = timeline.peek(); continue; From 8fcb284cce5018036b42a2fd2c4579f1ff835d30 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 14:19:21 +0800 Subject: [PATCH 009/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/message/GroupMessageSyncer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index a633b28..276f785 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -45,6 +45,7 @@ class GroupMessageSyncer implements Runnable { Long beginMs = service.getMaxSendTime(group.getTid()).orElse(oneAgo()).getTime(); Long endMs = System.currentTimeMillis(); Timeline timeline = new Timeline(beginMs, endMs); + // don't change long limit = 100L; TimeNode node = timeline.peek(); while (node != null) { From c94e781f51182ef4ef9797a6017603bf48dd8218 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 14:26:08 +0800 Subject: [PATCH 010/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncer.java | 9 +++------ .../java/cn/axzo/im/group/message/timeline/Timeline.java | 6 ++++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 276f785..12866f9 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -53,19 +53,16 @@ class GroupMessageSyncer implements Runnable { BizAssertions.assertTrue(response.isSuccess(), "fetch group messages failed"); List msgList = response.getMsgs(); if (CollectionUtils.isEmpty(msgList)) { - timeline.consume(); - node = timeline.peek(); + node = timeline.consume(); continue; } // response.size 不可靠 if (msgList.size() == limit && node.isSplittable()) { - timeline.split(); - node = timeline.peek(); + node = timeline.split(); continue; } saveMessages(asGroupMessages(msgList)); - timeline.consume(); - node = timeline.peek(); + node = timeline.consume(); } } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java index b371db2..433473e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -27,7 +27,7 @@ public class Timeline { this.nodes.addAll(0, nodes); } - public void split() { + public TimeNode split() { TimeNode node = nodes.peek(); BizAssertions.assertNotNull(node, "timeline is empty"); //noinspection DataFlowIssue @@ -35,13 +35,15 @@ public class Timeline { nodes.removeFirst(); splitCount *= 2; prepend(split(node.getBeginMs(), node.getEndMs(), splitCount)); + return peek(); } - public void consume() { + public TimeNode consume() { TimeNode node = nodes.peek(); BizAssertions.assertNotNull(node, "timeline is empty"); nodes.removeFirst(); splitCount = 1; + return peek(); } @Nullable From 050dd7c81b076b03feac6878f6e57ee095159991 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 14:31:53 +0800 Subject: [PATCH 011/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/controller/PrivateController.java | 2 +- .../im/group/message/GroupMessageSyncJob.java | 22 +--------- .../message/GroupMessageSyncService.java | 41 +++++++++++-------- .../message/GroupMessageSyncServiceTest.java | 23 ----------- 4 files changed, 26 insertions(+), 62 deletions(-) delete mode 100644 im-center-server/src/test/java/cn/axzo/im/group/message/GroupMessageSyncServiceTest.java diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java index af035aa..9d093a2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java @@ -113,7 +113,7 @@ public class PrivateController { @PostMapping("/private/group/syncGroupMessages") public Object syncGroupMessages() throws Exception { - groupMessageSyncService.syncAndWait(); + groupMessageSyncService.sync(); return "done"; } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 6abe7c1..d4ae12e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -1,14 +1,11 @@ package cn.axzo.im.group.message; -import cn.axzo.basics.common.exception.ServiceException; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.annotation.XxlJob; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.util.concurrent.CountDownLatch; - /** * @author yanglin */ @@ -19,27 +16,10 @@ public class GroupMessageSyncJob { private final GroupMessageSyncService groupMessageSyncService; - private volatile boolean isRunning = false; - @SuppressWarnings("unused") @XxlJob("groupMessageSyncJob") public ReturnT execute(String jsonStr) throws Exception { - if (isRunning) - throw new ServiceException("任务正在执行中,请稍后再试..."); - synchronized (this) { - if (isRunning) - throw new ServiceException("任务正在执行中,请稍后再试..."); - isRunning = true; - } - CountDownLatch latch = new CountDownLatch(1); - groupMessageSyncService.sync(() -> { - synchronized (GroupMessageSyncJob.this) { - isRunning = false; - } - latch.countDown(); - log.info("group message sync job finished"); - }); - latch.await(); + groupMessageSyncService.sync(); return ReturnT.SUCCESS; } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index 854310a..e394633 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -1,5 +1,6 @@ package cn.axzo.im.group.message; +import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.channel.netease.client.NimClient; import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesRequest; @@ -39,28 +40,33 @@ public class GroupMessageSyncService { private final GroupMessageDao groupMessageDao; private final NimClient nimClient; - public void syncAndWait() throws Exception { - CountDownLatch latch = new CountDownLatch(1); - sync(latch::countDown); - latch.await(); - } + private volatile boolean isRunning = false; - void sync(Runnable onComplete) { - AtomicBoolean completed = new AtomicBoolean(false); - Runnable runOnce = () -> { - if (completed.compareAndSet(false, true)) - onComplete.run(); - }; + public void sync() throws Exception { + if (isRunning) + throw new ServiceException("任务正在执行中,请稍后再试..."); + synchronized (this) { + if (isRunning) + throw new ServiceException("任务正在执行中,请稍后再试..."); + isRunning = true; + } try { - syncImpl(runOnce); - } catch (Exception e) { - log.warn("sync group message failed", e); - runOnce.run(); + syncImpl(); + } finally { + synchronized (this) { + isRunning = false; + } } } - private void syncImpl(Runnable onComplete) throws Exception { - MessageSyncController controller = new MessageSyncController(tps, onComplete); + private void syncImpl() throws Exception { + AtomicBoolean completed = new AtomicBoolean(false); + CountDownLatch latch = new CountDownLatch(1); + Runnable runOnce = () -> { + if (completed.compareAndSet(false, true)) + latch.countDown(); + }; + MessageSyncController controller = new MessageSyncController(tps, runOnce); Date twoDayAgo = new DateTime(new Date()).minusDays(2).toDate(); RecordCursor cursor = new RecordCursor<>(Group::getId, () -> groupDao.lambdaQuery() @@ -88,6 +94,7 @@ public class GroupMessageSyncService { } } controller.setSubmitFinished(); + latch.await(); } void saveMessagesBatch(Collection messages) { diff --git a/im-center-server/src/test/java/cn/axzo/im/group/message/GroupMessageSyncServiceTest.java b/im-center-server/src/test/java/cn/axzo/im/group/message/GroupMessageSyncServiceTest.java deleted file mode 100644 index 2f7ebe9..0000000 --- a/im-center-server/src/test/java/cn/axzo/im/group/message/GroupMessageSyncServiceTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.axzo.im.group.message; - -import cn.axzo.im.Application; -import lombok.RequiredArgsConstructor; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author yanglin - */ -@SpringBootTest(classes = Application.class) -@RequiredArgsConstructor(onConstructor_ = @Autowired) -class GroupMessageSyncServiceTest { - - private final GroupMessageSyncService groupMessageSyncService; - - @Test - void sync() throws Exception { - groupMessageSyncService.syncAndWait(); - } - -} \ No newline at end of file From 6e9a7ba0887778751e52cedb911fe6fe11baa6c1 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 14:40:05 +0800 Subject: [PATCH 012/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java | 2 +- .../main/java/cn/axzo/im/group/message/GroupMessageSyncer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java index 485e818..159989f 100644 --- a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java @@ -20,7 +20,7 @@ public enum YesOrNo implements CodeDefinition { private final String code; private final String desc; - public static YesOrNo of(boolean value) { + public static YesOrNo valueOf(boolean value) { return value ? YES : NO; } } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 12866f9..71d7cd8 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -95,7 +95,7 @@ class GroupMessageSyncer implements Runnable { message.setFromPersonId(person == null ? 0L : Long.parseLong(person.getPersonId())); message.setFromPersonOuId(person == null ? 0L : person.getOuId()); message.setFromPersonAppType(person == null ? AppTypeEnum.NONE : person.getAppType()); - message.setIsFromRobot(YesOrNo.of(person == null)); + message.setIsFromRobot(YesOrNo.valueOf(person == null)); message.setMessageId(nimMessage.getMsgid()); message.setMessageType(CodeDefinition.findByCode( NimMessageType.class, nimMessage.getType()).orElse(null)); From 1804e2e377ba8ec31afc0ca895aec88fac78f706 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 14:40:28 +0800 Subject: [PATCH 013/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 71d7cd8..5a7fcf1 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -114,9 +114,9 @@ class GroupMessageSyncer implements Runnable { try { service.saveMessagesBatch(messages); } catch (DuplicateKeyException ignored) { - List savedMessages = service.reloadMessages(messages); + List saved = service.reloadMessages(messages); List notSaved = Sets.difference( - UniqueMessage.from(messages), UniqueMessage.from(savedMessages)) + UniqueMessage.from(messages), UniqueMessage.from(saved)) .stream().map(UniqueMessage::getGroupMessage).collect(toList()); saveMessages(notSaved); } From b383110d0c03e8c9c01c853ece9c480e17190bff Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 14:42:44 +0800 Subject: [PATCH 014/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncService.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index e394633..9421d98 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -53,9 +53,7 @@ public class GroupMessageSyncService { try { syncImpl(); } finally { - synchronized (this) { - isRunning = false; - } + isRunning = false; } } From 066689954c6c536cee2a30d7882436ee0fdaf1dd Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 14:43:40 +0800 Subject: [PATCH 015/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index 9421d98..8bcc968 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -72,8 +72,7 @@ public class GroupMessageSyncService { .eq(Group::getIsDismissed, YesOrNo.NO) .or().nested(w2 -> w2 .eq(Group::getIsDismissed, YesOrNo.YES) - .gt(Group::getDismissedAt, twoDayAgo))) - ); + .gt(Group::getDismissedAt, twoDayAgo)))); for (List groups : cursor) { for (Group group : groups) { controller.acquireSubmitGroup(group); From 0572e4338465858e6fff5d48f3d57cb96b8e4b0f Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 14:44:28 +0800 Subject: [PATCH 016/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncer.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 5a7fcf1..d0168ef 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -49,7 +49,7 @@ class GroupMessageSyncer implements Runnable { long limit = 100L; TimeNode node = timeline.peek(); while (node != null) { - NimGroupGetMessagesResponse response = fetchMessages(node, limit, null); + NimGroupGetMessagesResponse response = fetchMessages(node, limit); BizAssertions.assertTrue(response.isSuccess(), "fetch group messages failed"); List msgList = response.getMsgs(); if (CollectionUtils.isEmpty(msgList)) { @@ -66,7 +66,7 @@ class GroupMessageSyncer implements Runnable { } } - private NimGroupGetMessagesResponse fetchMessages(TimeNode node, Long limit, Long lastMessageId) { + private NimGroupGetMessagesResponse fetchMessages(TimeNode node, Long limit) { NimGroupGetMessagesRequest request = new NimGroupGetMessagesRequest(); request.setTid(group.getTid()); request.setAccid(group.getOwnerAccount()); @@ -76,7 +76,6 @@ class GroupMessageSyncer implements Runnable { request.setReverse(1); request.setCheckTeamValid(false); request.setIncludeNoSenseMsg(false); - request.setExcludeMsgid(lastMessageId); request.setType("0,1,2,3,4,6,100"); controller.acquireFetchMessages(); NimGroupGetMessagesResponse response = service.getGroupMessages(request); From 5d52e9639d30ae58d02fbe299701f9c0911c2ff2 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 14:45:47 +0800 Subject: [PATCH 017/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/timeline/Timeline.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java index 433473e..532a19d 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -20,7 +20,7 @@ public class Timeline { public Timeline(Long beginMs, Long endMs) { BizAssertions.assertTrue(beginMs <= endMs, "beginMs must be less than or equal to endMs"); nodes = new LinkedList<>(); - prepend(split(beginMs, endMs, splitCount)); + prepend(split(beginMs, endMs)); } private void prepend(List nodes) { @@ -34,7 +34,7 @@ public class Timeline { BizAssertions.assertTrue(node.isSplittable(), "node is not splittable"); nodes.removeFirst(); splitCount *= 2; - prepend(split(node.getBeginMs(), node.getEndMs(), splitCount)); + prepend(split(node.getBeginMs(), node.getEndMs())); return peek(); } @@ -51,7 +51,7 @@ public class Timeline { return nodes.peek(); } - private List split(Long beginMs, Long endMs, int splitCount) { + private List split(Long beginMs, Long endMs) { BizAssertions.assertTrue(beginMs <= endMs, "beginMs must be less than or equal to endMs"); List nodes = new ArrayList<>(); long totalDuration = endMs - beginMs; From d4920cb062890817c20916a40db8fc7d30150f72 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 14:53:45 +0800 Subject: [PATCH 018/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncer.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index d0168ef..bfd933c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -42,7 +42,9 @@ class GroupMessageSyncer implements Runnable { @Override public void run() { - Long beginMs = service.getMaxSendTime(group.getTid()).orElse(oneAgo()).getTime(); + Long beginMs = service.getMaxSendTime(group.getTid()) + .orElse(oneAndHalfDayAgo()) + .getTime(); Long endMs = System.currentTimeMillis(); Timeline timeline = new Timeline(beginMs, endMs); // don't change @@ -121,7 +123,7 @@ class GroupMessageSyncer implements Runnable { } } - private Date oneAgo() { - return DateTime.now().minusDays(1).toDate(); + private Date oneAndHalfDayAgo() { + return DateTime.now().minusDays(1).minusHours(12).toDate(); } } \ No newline at end of file From f5e65246bc3980b85bd4e060999a8e1d1b364844 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 15:41:37 +0800 Subject: [PATCH 019/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/message/timeline/Timeline.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java index 532a19d..deb674e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -28,7 +28,7 @@ public class Timeline { } public TimeNode split() { - TimeNode node = nodes.peek(); + TimeNode node = peek(); BizAssertions.assertNotNull(node, "timeline is empty"); //noinspection DataFlowIssue BizAssertions.assertTrue(node.isSplittable(), "node is not splittable"); @@ -39,7 +39,7 @@ public class Timeline { } public TimeNode consume() { - TimeNode node = nodes.peek(); + TimeNode node = peek(); BizAssertions.assertNotNull(node, "timeline is empty"); nodes.removeFirst(); splitCount = 1; From 0ffc88a215615f4c0399a7b0d4e7154a23ec9d36 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 15:42:55 +0800 Subject: [PATCH 020/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/message/timeline/Timeline.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java index deb674e..241ecb6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -31,7 +31,7 @@ public class Timeline { TimeNode node = peek(); BizAssertions.assertNotNull(node, "timeline is empty"); //noinspection DataFlowIssue - BizAssertions.assertTrue(node.isSplittable(), "node is not splittable"); + BizAssertions.assertTrue(node.isSplittable(), "node is not splittable: ", node); nodes.removeFirst(); splitCount *= 2; prepend(split(node.getBeginMs(), node.getEndMs())); From e9ddb00e80d805c24df669b2957510b8fdf34de2 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:01:13 +0800 Subject: [PATCH 021/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index 8bcc968..67459d2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -111,7 +111,7 @@ public class GroupMessageSyncService { .eq(GroupMessage::getTid, tid)); return groupMessage == null ? Optional.empty() - : Optional.of(groupMessage.getSendTime()); + : Optional.ofNullable(groupMessage.getSendTime()); } NimGroupGetMessagesResponse getGroupMessages(NimGroupGetMessagesRequest request) { From a6945cf35a65fcf728156df3bf1c5f1cc90cb2b2 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:05:50 +0800 Subject: [PATCH 022/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 25b91b5..1dfd781 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -86,7 +86,7 @@ public class GroupManager { @Transactional public void dismissGroup(GroupDismissRequest request) { - Group group = findGroupForUpdateOrThrow(request.getTid()); + Group group = getGroupForUpdateOrThrow(request.getTid()); if (group.isDismissed()) return; NimGroupDismissRequest nimRequest = groupSupport .buildNimDismissGroupRequest(group.getOwnerAccount(), group); @@ -99,7 +99,7 @@ public class GroupManager { @Transactional public GroupAddMembersResponse addMembers(GroupAddMembersRequest request) { - Group group = findGroupForUpdateOrThrow(request.getTid()); + Group group = getGroupForUpdateOrThrow(request.getTid()); BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); // sync members 1 groupMemberSyncer.syncMembers(group); @@ -134,7 +134,7 @@ public class GroupManager { @Transactional public void removeMembers(GroupRemoveMembersRequest request) { - Group group = findGroupForUpdateOrThrow(request.getTid()); + Group group = getGroupForUpdateOrThrow(request.getTid()); BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); ImAccounts imAccounts = accountService.getAccountsByPersons(request.getMembers()); if (imAccounts.isAccountEmpty()) { @@ -158,7 +158,7 @@ public class GroupManager { } @NotNull - private Group findGroupForUpdateOrThrow(Long tid) { + private Group getGroupForUpdateOrThrow(Long tid) { Group group = groupDao.findByTid(tid, true).orElse(null); BizAssertions.assertNotNull(group, "群不存在: {}", tid); return group; From acf4be4e6a130db460900e5699089bb10e8a1aaa Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:08:29 +0800 Subject: [PATCH 023/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 1dfd781..11de92a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -142,7 +142,7 @@ public class GroupManager { group.getTid(), JSON.toJSONString(request.getMembers())); return; } - groupMemberSyncer.syncMembers(group); + // 获取人员之前不能做同步, 因为app可能已经通过sdk移除过成员了 List toRemoveMembers = groupMemberDao.getByPersons( group.getTid(), request.getMembers()); if (CollectionUtils.isEmpty(toRemoveMembers)) From b1ae00c2b247b86275fa99ea280266bd7449cb4b Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:20:11 +0800 Subject: [PATCH 024/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 6 ++++++ .../src/main/java/cn/axzo/im/group/GroupSupport.java | 4 ++-- .../src/main/java/cn/axzo/im/service/AccountService.java | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 11de92a..823fa30 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -59,7 +59,13 @@ public class GroupManager { public GroupCreateResponse createGroup(GroupCreateRequest request) { BizAssertions.assertTrue(request.getOwnerAndMembers().size() > 1, "群成员数量(含群主)不能少于2"); ImAccounts imAccounts = accountService.getAccountsByPersons(request.getOwnerAndMembers()); + String owner = imAccounts.findAccount(request.getOwner()).orElse(null); + if (owner == null) { + accountService.registerAccountIfAbsent(request.getOwner()); + imAccounts = accountService.getAccountsByPersons(request.getOwnerAndMembers()); + } Group group = groupSupport.buildNewGroup(request, imAccounts); + BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); BizAssertions.assertFalse(group.isMemberLimitReached( request.getOwnerAndMembers().size()), "无法创建群, 群成员数量超过上限" + group.getMemberLimit()); try { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index cfe6349..ecf4cb3 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -26,8 +26,8 @@ public class GroupSupport implements GroupLogger { private final ChatGroupService chatGroupService; - Group buildNewGroup(GroupCreateRequest request, ImAccounts accounts) { - String owner = accounts.findAccount(request.getOwner()).orElse(null); + Group buildNewGroup(GroupCreateRequest request, ImAccounts imAccounts) { + String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); Group group = new Group(); group.setName(request.getName()); diff --git a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java index 63e6a89..26585e5 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java @@ -380,6 +380,10 @@ public class AccountService { return Lists.newArrayList(); } + public String registerAccountIfAbsent(PersonAccountAttribute person) { + return registerAccountIfAbsent(person.getPersonId(), person.getOuId(), person.getAppType()); + } + public String registerAccountIfAbsent(String personId, Long ouId, AppTypeEnum appType) { AccountAbsentQuery accountQuery = new AccountAbsentQuery(); accountQuery.setPersonId(personId); From ed33fecd1ec91aff4f4b82bdbf7c41aa2fa97964 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:31:27 +0800 Subject: [PATCH 025/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/GroupManager.java | 23 ++++++----- .../cn/axzo/im/send/ScanAndSendService.java | 1 + .../java/cn/axzo/im/send/SendExecutor.java | 3 +- .../java/cn/axzo/im/send/SendManager.java | 1 + .../cn/axzo/im/service/AccountService.java | 17 ++++++++ .../service/impl/MessageTaskServiceImpl.java | 25 +++++------- .../cn/axzo/im/utils/async/AsyncRunTasks.java | 31 +++++++++++++++ .../axzo/im/utils/async/AsyncSupplyTasks.java | 34 ++++++++++++++++ .../im/{send => utils/async}/AsyncTasks.java | 16 ++++---- .../cn/axzo/im/utils/async/FutureWrapper.java | 39 +++++++++++++++++++ 10 files changed, 156 insertions(+), 34 deletions(-) create mode 100644 im-center-server/src/main/java/cn/axzo/im/utils/async/AsyncRunTasks.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/utils/async/AsyncSupplyTasks.java rename im-center-server/src/main/java/cn/axzo/im/{send => utils/async}/AsyncTasks.java (74%) create mode 100644 im-center-server/src/main/java/cn/axzo/im/utils/async/FutureWrapper.java diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 823fa30..ff0ef04 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -37,7 +37,7 @@ import javax.validation.constraints.NotNull; import java.util.List; import java.util.Set; -import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; /** * @author yanglin @@ -58,12 +58,8 @@ public class GroupManager { @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { BizAssertions.assertTrue(request.getOwnerAndMembers().size() > 1, "群成员数量(含群主)不能少于2"); - ImAccounts imAccounts = accountService.getAccountsByPersons(request.getOwnerAndMembers()); + ImAccounts imAccounts = getImAccounts(request.getOwnerAndMembers()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); - if (owner == null) { - accountService.registerAccountIfAbsent(request.getOwner()); - imAccounts = accountService.getAccountsByPersons(request.getOwnerAndMembers()); - } Group group = groupSupport.buildNewGroup(request, imAccounts); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); BizAssertions.assertFalse(group.isMemberLimitReached( @@ -111,12 +107,12 @@ public class GroupManager { groupMemberSyncer.syncMembers(group); // prepare add members Set preMembers = groupMemberDao.getGroupPersons(group.getTid()); - List toAddMembers = request.getMembers().stream() + Set toAddMembers = request.getMembers().stream() .filter(member -> !preMembers.contains(member)) - .collect(toList()); + .collect(toSet()); if (group.isMemberLimitReached(preMembers.size() + toAddMembers.size())) throw new ServiceException("群聊人数上限" + group.getMemberLimit() + "人, 请删除部分已选人员"); - ImAccounts imAccounts = accountService.getAccountsByPersons(toAddMembers); + ImAccounts imAccounts = getImAccounts(toAddMembers); if (imAccounts.isAccountEmpty()) { groupSupport.log("添加群成员[TID:{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), JSON.toJSONString(request.getMembers())); @@ -138,6 +134,15 @@ public class GroupManager { return response; } + private ImAccounts getImAccounts(Set persons) { + ImAccounts imAccounts = accountService.getAccountsByPersons(persons); + if (imAccounts.getAccountSize() != persons.size()) { + accountService.registerAccountIfAbsent(persons); + imAccounts = accountService.getAccountsByPersons(persons); + } + return imAccounts; + } + @Transactional public void removeMembers(GroupRemoveMembersRequest request) { Group group = getGroupForUpdateOrThrow(request.getTid()); diff --git a/im-center-server/src/main/java/cn/axzo/im/send/ScanAndSendService.java b/im-center-server/src/main/java/cn/axzo/im/send/ScanAndSendService.java index d8f8bf9..e82ff9b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/ScanAndSendService.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/ScanAndSendService.java @@ -6,6 +6,7 @@ import cn.axzo.im.entity.SendJobInfo.InterruptedValue; import cn.axzo.im.send.handler.SendHandler; import cn.axzo.im.utils.MiscUtils; import cn.axzo.im.utils.YesNo; +import cn.axzo.im.utils.async.AsyncTasks; import com.xxl.job.core.log.XxlJobFileAppender; import com.xxl.job.core.util.IpUtil; import lombok.RequiredArgsConstructor; diff --git a/im-center-server/src/main/java/cn/axzo/im/send/SendExecutor.java b/im-center-server/src/main/java/cn/axzo/im/send/SendExecutor.java index 920d07e..29ce6e4 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/SendExecutor.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/SendExecutor.java @@ -1,11 +1,12 @@ package cn.axzo.im.send; -import cn.axzo.im.channel.netease.dto.NimBatchSendCustomMessageResponse; import cn.axzo.im.channel.netease.dto.MessageBatchDispatchResponse; +import cn.axzo.im.channel.netease.dto.NimBatchSendCustomMessageResponse; import cn.axzo.im.entity.HistoryRecordExt; import cn.axzo.im.entity.MessageHistory; import cn.axzo.im.send.handler.SendHandler; import cn.axzo.im.utils.MiscUtils; +import cn.axzo.im.utils.async.AsyncTasks; import com.google.common.util.concurrent.RateLimiter; import lombok.Getter; import org.apache.commons.collections4.CollectionUtils; diff --git a/im-center-server/src/main/java/cn/axzo/im/send/SendManager.java b/im-center-server/src/main/java/cn/axzo/im/send/SendManager.java index 840a67c..d7e0a4a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/SendManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/SendManager.java @@ -11,6 +11,7 @@ import cn.axzo.im.updatable.UpdatableMessageManager; import cn.axzo.im.utils.DateFormatUtil; import cn.axzo.im.utils.ImProperties; import cn.axzo.im.utils.ImProperties.SendMessageConfig; +import cn.axzo.im.utils.async.AsyncTasks; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import lombok.Getter; import org.slf4j.Logger; diff --git a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java index 26585e5..105c4dd 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java @@ -34,6 +34,8 @@ import cn.axzo.im.entity.bo.AccountQueryParam; import cn.axzo.im.gateway.ProfilesApiGateway; import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.MiscUtils; +import cn.axzo.im.utils.async.AsyncRunTasks; +import cn.hutool.core.thread.NamedThreadFactory; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -62,6 +64,8 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -128,6 +132,11 @@ public class AccountService { @Value("${im-center.env.live:}") public String liveEnvPrefix; + // 简单处理: 每个机器10的流量 + private final RateLimiter createAccountRateLimiter = RateLimiter.create(10); + private final ExecutorService executor = Executors.newFixedThreadPool(15, + new NamedThreadFactory(getClass().getSimpleName(), false)); + public Set getUserAccountIds() { String appKey = imChannelProvider.getProviderAppKey(); QueryWrapper query = new QueryWrapper<>(); @@ -330,6 +339,7 @@ public class AccountService { register.setName(name); UserAccountResp userAccountResp = new UserAccountResp(); //3.调用公共的网易云信IM接口创建账户 网易云信只是一种IM实现 + createAccountRateLimiter.acquire(); RegisterResponse registerResponse = imChannelProvider.registerAccount(register); if (registerResponse.getInfo() != null) { NimAccountInfo userAccount = BeanMapper.map(registerResponse.getInfo(), NimAccountInfo.class); @@ -380,6 +390,13 @@ public class AccountService { return Lists.newArrayList(); } + public void registerAccountIfAbsent(Collection persons) { + AsyncRunTasks tasks = new AsyncRunTasks(executor); + for (PersonAccountAttribute person : persons) + tasks.runAsync(() -> registerAccountIfAbsent(person)); + tasks.awaitTermination(); + } + public String registerAccountIfAbsent(PersonAccountAttribute person) { return registerAccountIfAbsent(person.getPersonId(), person.getOuId(), person.getAppType()); } diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java index cc3f64e..5737343 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java @@ -37,7 +37,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.util.concurrent.RateLimiter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -81,8 +80,6 @@ public class MessageTaskServiceImpl extends ServiceImpl { + + private final ExecutorService executor; + + /** + * use common pool + */ + public AsyncRunTasks() { + this(null); + } + + public AsyncRunTasks(ExecutorService executor) { + this.executor = executor; + } + + public void runAsync(Runnable runnable) { + CompletableFuture future = executor == null + ? CompletableFuture.runAsync(runnable) + : CompletableFuture.runAsync(runnable, executor); + add(future); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/utils/async/AsyncSupplyTasks.java b/im-center-server/src/main/java/cn/axzo/im/utils/async/AsyncSupplyTasks.java new file mode 100644 index 0000000..f140482 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/utils/async/AsyncSupplyTasks.java @@ -0,0 +1,34 @@ +package cn.axzo.im.utils.async; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.function.Supplier; + +/** + * @author yanglin + */ +public class AsyncSupplyTasks extends AsyncTasks { + + private final ExecutorService executor; + + /** + * use common pool + */ + public AsyncSupplyTasks() { + this(null); + } + + public AsyncSupplyTasks(ExecutorService executor) { + this.executor = executor; + } + + public FutureWrapper supplyAsync(Supplier supplier) { + CompletableFuture future = executor == null + ? CompletableFuture.supplyAsync(supplier) + : CompletableFuture.supplyAsync(supplier, executor); + //noinspection unchecked + add((CompletableFuture) future); + return new FutureWrapper<>(future); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/send/AsyncTasks.java b/im-center-server/src/main/java/cn/axzo/im/utils/async/AsyncTasks.java similarity index 74% rename from im-center-server/src/main/java/cn/axzo/im/send/AsyncTasks.java rename to im-center-server/src/main/java/cn/axzo/im/utils/async/AsyncTasks.java index ea78387..3315fca 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/AsyncTasks.java +++ b/im-center-server/src/main/java/cn/axzo/im/utils/async/AsyncTasks.java @@ -1,4 +1,4 @@ -package cn.axzo.im.send; +package cn.axzo.im.utils.async; import java.util.ArrayList; import java.util.Collections; @@ -11,34 +11,34 @@ import java.util.concurrent.TimeoutException; /** * @author yanglin */ -class AsyncTasks { +public class AsyncTasks { private final List> futures = Collections.synchronizedList(new ArrayList<>()); private final boolean removeFutureWhenComplete; - AsyncTasks() { + public AsyncTasks() { this(true); } - AsyncTasks(boolean removeFutureWhenComplete) { + public AsyncTasks(boolean removeFutureWhenComplete) { this.removeFutureWhenComplete = removeFutureWhenComplete; } - void add(CompletableFuture future) { + public void add(CompletableFuture future) { futures.add(future); if (removeFutureWhenComplete) future.whenComplete((unused, throwable) -> futures.remove(future)); } - CompletableFuture getFuture(int index) { + public CompletableFuture getFuture(int index) { return futures.get(index); } - void awaitTermination() { + public void awaitTermination() { collectAll().join(); } - void awaitTermination(long timeout, TimeUnit unit) + public void awaitTermination(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { collectAll().get(timeout, unit); } diff --git a/im-center-server/src/main/java/cn/axzo/im/utils/async/FutureWrapper.java b/im-center-server/src/main/java/cn/axzo/im/utils/async/FutureWrapper.java new file mode 100644 index 0000000..3469d70 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/utils/async/FutureWrapper.java @@ -0,0 +1,39 @@ +package cn.axzo.im.utils.async; + +import cn.axzo.basics.common.exception.ServiceException; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * @author yanglin + */ +@Slf4j +@RequiredArgsConstructor(access = AccessLevel.PACKAGE) +public class FutureWrapper { + + private final CompletableFuture future; + + public T get() { + try { + return future.get(); + } catch (InterruptedException | ExecutionException e) { + log.error("执行异常", e); + throw new ServiceException("执行异常"); + } + } + + public T get(long timeout, TimeUnit unit) { + try { + return future.get(timeout, unit); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + log.error("执行异常", e); + throw new ServiceException("执行异常"); + } + } +} \ No newline at end of file From 81b6db09b295f77a0f362b2288897f3cb3ea9b82 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:32:07 +0800 Subject: [PATCH 026/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index ff0ef04..c39226b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -60,8 +60,8 @@ public class GroupManager { BizAssertions.assertTrue(request.getOwnerAndMembers().size() > 1, "群成员数量(含群主)不能少于2"); ImAccounts imAccounts = getImAccounts(request.getOwnerAndMembers()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); - Group group = groupSupport.buildNewGroup(request, imAccounts); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); + Group group = groupSupport.buildNewGroup(request, imAccounts); BizAssertions.assertFalse(group.isMemberLimitReached( request.getOwnerAndMembers().size()), "无法创建群, 群成员数量超过上限" + group.getMemberLimit()); try { From 47bc2b289a935bccd128292c93c1afe7bc0c5a64 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:36:57 +0800 Subject: [PATCH 027/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/controller/MessageController.java | 2 ++ .../java/cn/axzo/im/service/AccountService.java | 16 +++++++++------- .../im/service/impl/MessageTaskServiceImpl.java | 2 ++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index c611b1d..f5b5d19 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -185,6 +185,7 @@ public class MessageController implements MessageApi { if (sender.getAppType() != null) { sendImAccount = accountService.registerAccountIfAbsent( sender.getPersonId(), sender.getOuId(), sender.getAppType()); + BizAssertions.assertNotNull(sendImAccount, "创建账号失败"); } else { sendImAccount = check(request); } @@ -240,6 +241,7 @@ public class MessageController implements MessageApi { BizAssertions.assertNotNull(sender.getAppType(), "发送人appType不能为空"); String sendImAccount = accountService.registerAccountIfAbsent( sender.getPersonId(), sender.getOuId(), sender.getAppType()); + BizAssertions.assertNotNull(sendImAccount, "创建账号失败"); MessageTask.BizData bizData = MessageTask.BizData.builder() .messageBody(JSON.toJSONString(request.getMessageBody())) .isSenderRobot(false) diff --git a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java index 105c4dd..21e5b1a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java @@ -393,21 +393,17 @@ public class AccountService { public void registerAccountIfAbsent(Collection persons) { AsyncRunTasks tasks = new AsyncRunTasks(executor); for (PersonAccountAttribute person : persons) - tasks.runAsync(() -> registerAccountIfAbsent(person)); + tasks.runAsync(() -> registerAccountIfAbsent(person.getPersonId(), person.getOuId(), person.getAppType())); tasks.awaitTermination(); } - public String registerAccountIfAbsent(PersonAccountAttribute person) { - return registerAccountIfAbsent(person.getPersonId(), person.getOuId(), person.getAppType()); - } - public String registerAccountIfAbsent(String personId, Long ouId, AppTypeEnum appType) { AccountAbsentQuery accountQuery = new AccountAbsentQuery(); accountQuery.setPersonId(personId); accountQuery.setOuId(ouId); accountQuery.setAppType(appType.getCode()); List accounts = registerAccountIfAbsent(accountQuery); - return accounts.get(0).getImAccount(); + return CollectionUtils.isEmpty(accounts) ? null : accounts.get(0).getImAccount(); } /** @@ -454,7 +450,13 @@ public class AccountService { userAccountReq.setAppType(appTypeEnum.getCode()); userAccountReq.setUserId(accountAbsentQuery.getPersonId()); - PersonProfileDto personProfileDto = profilesApiGateway.getPersonProfileById(Long.valueOf(accountAbsentQuery.getPersonId())); + PersonProfileDto personProfileDto = null; + try { + personProfileDto = profilesApiGateway.getPersonProfileById(Long.valueOf(accountAbsentQuery.getPersonId())); + } catch (Exception e) { + log.warn("getPersonProfileById error, personId={}", accountAbsentQuery.getPersonId()); + return Collections.emptyList(); + } userAccountReq.setNickName(StringUtils.isNotBlank(personProfileDto.getRealName()) ? personProfileDto.getRealName() : DEFAULT_NICK_NAME + accountAbsentQuery.getPersonId()); userAccountReq.setHeadImageUrl(personProfileDto.getAvatarUrl()); diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java index 5737343..2b40d9c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java @@ -22,6 +22,7 @@ import cn.axzo.im.service.AccountService; import cn.axzo.im.service.MessageHistoryService; import cn.axzo.im.service.MessageTaskService; import cn.axzo.im.updatable.UpdatableMessageManager; +import cn.axzo.im.utils.BizAssertions; import cn.axzo.im.utils.UUIDUtil; import cn.axzo.orggateway.api.orgteamourelation.OrgTeamOuRelationApi; import cn.axzo.orggateway.api.orgteamourelation.req.OrgTeamOuRelationReq; @@ -273,6 +274,7 @@ public class MessageTaskServiceImpl extends ServiceImpl Date: Thu, 23 Jan 2025 16:38:10 +0800 Subject: [PATCH 028/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index c39226b..5530678 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -58,7 +58,7 @@ public class GroupManager { @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { BizAssertions.assertTrue(request.getOwnerAndMembers().size() > 1, "群成员数量(含群主)不能少于2"); - ImAccounts imAccounts = getImAccounts(request.getOwnerAndMembers()); + ImAccounts imAccounts = getOrCreateImAccounts(request.getOwnerAndMembers()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); Group group = groupSupport.buildNewGroup(request, imAccounts); @@ -112,7 +112,7 @@ public class GroupManager { .collect(toSet()); if (group.isMemberLimitReached(preMembers.size() + toAddMembers.size())) throw new ServiceException("群聊人数上限" + group.getMemberLimit() + "人, 请删除部分已选人员"); - ImAccounts imAccounts = getImAccounts(toAddMembers); + ImAccounts imAccounts = getOrCreateImAccounts(toAddMembers); if (imAccounts.isAccountEmpty()) { groupSupport.log("添加群成员[TID:{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), JSON.toJSONString(request.getMembers())); @@ -134,7 +134,7 @@ public class GroupManager { return response; } - private ImAccounts getImAccounts(Set persons) { + private ImAccounts getOrCreateImAccounts(Set persons) { ImAccounts imAccounts = accountService.getAccountsByPersons(persons); if (imAccounts.getAccountSize() != persons.size()) { accountService.registerAccountIfAbsent(persons); From 162689ce653c19d1c12a7a1bf9d6d0bea049d04e Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:43:41 +0800 Subject: [PATCH 029/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/vo/resp/GroupAddMembersResponse.java | 3 ++- .../main/java/cn/axzo/im/group/GroupManager.java | 15 ++++----------- .../java/cn/axzo/im/service/AccountService.java | 8 ++++++++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupAddMembersResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupAddMembersResponse.java index 634f693..69c5182 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupAddMembersResponse.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupAddMembersResponse.java @@ -6,6 +6,7 @@ import com.alibaba.fastjson.JSONObject; import lombok.Getter; import lombok.Setter; +import java.util.HashSet; import java.util.Set; /** @@ -18,7 +19,7 @@ public class GroupAddMembersResponse { /** * 未找到IM账号的列表 */ - private Set accountsNotFound; + private Set accountsNotFound = new HashSet<>(); private JSONObject faccid; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 5530678..f02f98a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -58,7 +58,7 @@ public class GroupManager { @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { BizAssertions.assertTrue(request.getOwnerAndMembers().size() > 1, "群成员数量(含群主)不能少于2"); - ImAccounts imAccounts = getOrCreateImAccounts(request.getOwnerAndMembers()); + ImAccounts imAccounts = accountService.getOrCreateImAccounts(request.getOwnerAndMembers()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); Group group = groupSupport.buildNewGroup(request, imAccounts); @@ -110,9 +110,11 @@ public class GroupManager { Set toAddMembers = request.getMembers().stream() .filter(member -> !preMembers.contains(member)) .collect(toSet()); + if (toAddMembers.isEmpty()) + return new GroupAddMembersResponse(); if (group.isMemberLimitReached(preMembers.size() + toAddMembers.size())) throw new ServiceException("群聊人数上限" + group.getMemberLimit() + "人, 请删除部分已选人员"); - ImAccounts imAccounts = getOrCreateImAccounts(toAddMembers); + ImAccounts imAccounts = accountService.getOrCreateImAccounts(toAddMembers); if (imAccounts.isAccountEmpty()) { groupSupport.log("添加群成员[TID:{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), JSON.toJSONString(request.getMembers())); @@ -134,15 +136,6 @@ public class GroupManager { return response; } - private ImAccounts getOrCreateImAccounts(Set persons) { - ImAccounts imAccounts = accountService.getAccountsByPersons(persons); - if (imAccounts.getAccountSize() != persons.size()) { - accountService.registerAccountIfAbsent(persons); - imAccounts = accountService.getAccountsByPersons(persons); - } - return imAccounts; - } - @Transactional public void removeMembers(GroupRemoveMembersRequest request) { Group group = getGroupForUpdateOrThrow(request.getTid()); diff --git a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java index 21e5b1a..42c8817 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java @@ -390,6 +390,14 @@ public class AccountService { return Lists.newArrayList(); } + public ImAccounts getOrCreateImAccounts(Set persons) { + ImAccounts imAccounts = getAccountsByPersons(persons); + if (imAccounts.getAccountSize() == persons.size()) + return imAccounts; + registerAccountIfAbsent(persons); + return getAccountsByPersons(persons); + } + public void registerAccountIfAbsent(Collection persons) { AsyncRunTasks tasks = new AsyncRunTasks(executor); for (PersonAccountAttribute person : persons) From de8bd2aba44d7ea8554eac17ac8a01ae63b1dbba Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:44:24 +0800 Subject: [PATCH 030/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/service/AccountService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java index 42c8817..d2c9ff2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java @@ -134,7 +134,7 @@ public class AccountService { // 简单处理: 每个机器10的流量 private final RateLimiter createAccountRateLimiter = RateLimiter.create(10); - private final ExecutorService executor = Executors.newFixedThreadPool(15, + private final ExecutorService executor = Executors.newFixedThreadPool(11, new NamedThreadFactory(getClass().getSimpleName(), false)); public Set getUserAccountIds() { From d22decd2590bf04fb07067f7ff35eb9913bb47e2 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:51:02 +0800 Subject: [PATCH 031/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index f02f98a..628c6b2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -116,8 +116,8 @@ public class GroupManager { throw new ServiceException("群聊人数上限" + group.getMemberLimit() + "人, 请删除部分已选人员"); ImAccounts imAccounts = accountService.getOrCreateImAccounts(toAddMembers); if (imAccounts.isAccountEmpty()) { - groupSupport.log("添加群成员[TID:{}], 有效群成员IM账号列表为空. 请求成员信息: {}", - group.getTid(), JSON.toJSONString(request.getMembers())); + groupSupport.log("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); return new GroupAddMembersResponse(); } NimGroupAddMembersRequest nimRequest = groupSupport @@ -142,8 +142,8 @@ public class GroupManager { BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); ImAccounts imAccounts = accountService.getAccountsByPersons(request.getMembers()); if (imAccounts.isAccountEmpty()) { - groupSupport.log("移除群成员[TID:{}], 有效群成员IM账号列表为空. 请求成员信息: {}", - group.getTid(), JSON.toJSONString(request.getMembers())); + groupSupport.log("移除群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); return; } // 获取人员之前不能做同步, 因为app可能已经通过sdk移除过成员了 From 783bae4805b51c6ce09170757e922190dda17bdc Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:52:00 +0800 Subject: [PATCH 032/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/service/domain/ImAccounts.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java index 4100883..ad24833 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java @@ -40,7 +40,9 @@ public class ImAccounts { .filter(person -> !findAccount(person).isPresent()) .collect(toSet()); if (!notFound.isEmpty()) - logger.log("{}[TID:{}], IM账号不存在列表: {}", operation, group.getTid(), JSON.toJSONString(notFound)); + logger.log("{}[{},{}], IM账号不存在列表: {}", operation, + group.getTid(), group.getName(), + JSON.toJSONString(notFound)); return notFound; } From 9fcc43f5b4af7d7fc772d00a7eadd9ddac43b0ed Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:57:39 +0800 Subject: [PATCH 033/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java index 716b9f7..cf1e1e6 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java @@ -61,7 +61,7 @@ public class GroupCreateRequest { private String avatar; /** - * 群聊业务扩展信息, 透传到群属性中 + * 群聊业务扩展信息, 透传到群属性中. 不能传太多属性或较长字段,云信有长度限制 */ private Map bizAttachment; From 16e7260b386788e339021d70468615195957650b Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 16:57:52 +0800 Subject: [PATCH 034/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java index cf1e1e6..499b8aa 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java @@ -4,6 +4,7 @@ import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.common.enums.GroupType; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; import lombok.Setter; @@ -65,7 +66,7 @@ public class GroupCreateRequest { */ private Map bizAttachment; - @JSONField(serialize = false, deserialize = false) + @JsonIgnore @JSONField(serialize = false, deserialize = false) public Set getOwnerAndMembers() { Set ownerAndMembers = new HashSet<>(members); ownerAndMembers.add(owner); From 4d92ce92a3992dcdc4d3f36dd76bd8bfae3d37f0 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 17:06:15 +0800 Subject: [PATCH 035/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index bfd933c..25e1b9c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -43,7 +43,7 @@ class GroupMessageSyncer implements Runnable { @Override public void run() { Long beginMs = service.getMaxSendTime(group.getTid()) - .orElse(oneAndHalfDayAgo()) + .orElse(twoDaysAgo()) .getTime(); Long endMs = System.currentTimeMillis(); Timeline timeline = new Timeline(beginMs, endMs); @@ -123,7 +123,7 @@ class GroupMessageSyncer implements Runnable { } } - private Date oneAndHalfDayAgo() { - return DateTime.now().minusDays(1).minusHours(12).toDate(); + private Date twoDaysAgo() { + return DateTime.now().minusDays(2).toDate(); } } \ No newline at end of file From dc9fff1876282a4e828c3e10aa301e58b853f47c Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 17:07:57 +0800 Subject: [PATCH 036/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncer.java | 2 +- .../cn/axzo/im/group/message/timeline/Timeline.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 25e1b9c..c91b674 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -49,7 +49,7 @@ class GroupMessageSyncer implements Runnable { Timeline timeline = new Timeline(beginMs, endMs); // don't change long limit = 100L; - TimeNode node = timeline.peek(); + TimeNode node = timeline.head(); while (node != null) { NimGroupGetMessagesResponse response = fetchMessages(node, limit); BizAssertions.assertTrue(response.isSuccess(), "fetch group messages failed"); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java index 241ecb6..21047d8 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -28,26 +28,26 @@ public class Timeline { } public TimeNode split() { - TimeNode node = peek(); + TimeNode node = head(); BizAssertions.assertNotNull(node, "timeline is empty"); //noinspection DataFlowIssue BizAssertions.assertTrue(node.isSplittable(), "node is not splittable: ", node); nodes.removeFirst(); splitCount *= 2; prepend(split(node.getBeginMs(), node.getEndMs())); - return peek(); + return head(); } public TimeNode consume() { - TimeNode node = peek(); + TimeNode node = head(); BizAssertions.assertNotNull(node, "timeline is empty"); nodes.removeFirst(); splitCount = 1; - return peek(); + return head(); } @Nullable - public TimeNode peek() { + public TimeNode head() { return nodes.peek(); } From 752be28a1c1e0daf990f8be2c3f4ad0d89c9730c Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 17:08:26 +0800 Subject: [PATCH 037/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncer.java | 4 ++-- .../main/java/cn/axzo/im/group/message/timeline/Timeline.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index c91b674..1a71511 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -55,7 +55,7 @@ class GroupMessageSyncer implements Runnable { BizAssertions.assertTrue(response.isSuccess(), "fetch group messages failed"); List msgList = response.getMsgs(); if (CollectionUtils.isEmpty(msgList)) { - node = timeline.consume(); + node = timeline.advance(); continue; } // response.size 不可靠 @@ -64,7 +64,7 @@ class GroupMessageSyncer implements Runnable { continue; } saveMessages(asGroupMessages(msgList)); - node = timeline.consume(); + node = timeline.advance(); } } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java index 21047d8..7c37981 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -38,7 +38,7 @@ public class Timeline { return head(); } - public TimeNode consume() { + public TimeNode advance() { TimeNode node = head(); BizAssertions.assertNotNull(node, "timeline is empty"); nodes.removeFirst(); From cd86ae220a5a6a01e62a3dc337e7f216a438e267 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 17:36:02 +0800 Subject: [PATCH 038/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncer.java | 2 +- .../cn/axzo/im/group/message/timeline/Timeline.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 1a71511..3b4a038 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -49,7 +49,7 @@ class GroupMessageSyncer implements Runnable { Timeline timeline = new Timeline(beginMs, endMs); // don't change long limit = 100L; - TimeNode node = timeline.head(); + TimeNode node = timeline.current(); while (node != null) { NimGroupGetMessagesResponse response = fetchMessages(node, limit); BizAssertions.assertTrue(response.isSuccess(), "fetch group messages failed"); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java index 7c37981..1f2f99d 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -28,26 +28,26 @@ public class Timeline { } public TimeNode split() { - TimeNode node = head(); + TimeNode node = current(); BizAssertions.assertNotNull(node, "timeline is empty"); //noinspection DataFlowIssue BizAssertions.assertTrue(node.isSplittable(), "node is not splittable: ", node); nodes.removeFirst(); splitCount *= 2; prepend(split(node.getBeginMs(), node.getEndMs())); - return head(); + return current(); } public TimeNode advance() { - TimeNode node = head(); + TimeNode node = current(); BizAssertions.assertNotNull(node, "timeline is empty"); nodes.removeFirst(); splitCount = 1; - return head(); + return current(); } @Nullable - public TimeNode head() { + public TimeNode current() { return nodes.peek(); } From 3d5f90fb80c78a06d557d0ccfd81ea15222384f6 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 17:37:47 +0800 Subject: [PATCH 039/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java index 159989f..4cf4d4c 100644 --- a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/YesOrNo.java @@ -23,4 +23,8 @@ public enum YesOrNo implements CodeDefinition { public static YesOrNo valueOf(boolean value) { return value ? YES : NO; } + + public boolean booleanValue() { + return this == YES; + } } From ab69f5f59c640f66d959600c25fb2dd5b56603dc Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 17:41:57 +0800 Subject: [PATCH 040/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/group/message/GroupMessageSyncer.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 3b4a038..834685a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -49,22 +49,22 @@ class GroupMessageSyncer implements Runnable { Timeline timeline = new Timeline(beginMs, endMs); // don't change long limit = 100L; - TimeNode node = timeline.current(); - while (node != null) { - NimGroupGetMessagesResponse response = fetchMessages(node, limit); + TimeNode current = timeline.current(); + while (current != null) { + NimGroupGetMessagesResponse response = fetchMessages(current, limit); BizAssertions.assertTrue(response.isSuccess(), "fetch group messages failed"); List msgList = response.getMsgs(); if (CollectionUtils.isEmpty(msgList)) { - node = timeline.advance(); + current = timeline.advance(); continue; } // response.size 不可靠 - if (msgList.size() == limit && node.isSplittable()) { - node = timeline.split(); + if (msgList.size() == limit && current.isSplittable()) { + current = timeline.split(); continue; } saveMessages(asGroupMessages(msgList)); - node = timeline.advance(); + current = timeline.advance(); } } From e6fa8bd5a72e695f46ffc1b617acd74c61fd49fc Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 17:56:25 +0800 Subject: [PATCH 041/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/message/GroupMessageSyncer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 834685a..9098e3b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -44,7 +44,7 @@ class GroupMessageSyncer implements Runnable { public void run() { Long beginMs = service.getMaxSendTime(group.getTid()) .orElse(twoDaysAgo()) - .getTime(); + .getTime() + 1; Long endMs = System.currentTimeMillis(); Timeline timeline = new Timeline(beginMs, endMs); // don't change From cfcb878f289f7270fa0dd568951a5c60afde03a5 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 17:57:30 +0800 Subject: [PATCH 042/201] =?UTF-8?q?Revert=20"REQ-3345:=20=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E6=B6=88=E6=81=AF"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit e6fa8bd5a72e695f46ffc1b617acd74c61fd49fc. --- .../main/java/cn/axzo/im/group/message/GroupMessageSyncer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 9098e3b..834685a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -44,7 +44,7 @@ class GroupMessageSyncer implements Runnable { public void run() { Long beginMs = service.getMaxSendTime(group.getTid()) .orElse(twoDaysAgo()) - .getTime() + 1; + .getTime(); Long endMs = System.currentTimeMillis(); Timeline timeline = new Timeline(beginMs, endMs); // don't change From 2b594a6b548ea79c5bb8eb1f41cd3a11358ba6ca Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 18:05:16 +0800 Subject: [PATCH 043/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/member/GroupMemberSyncer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index 89258c8..f87af88 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -1,6 +1,7 @@ package cn.axzo.im.group.member; import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.GroupMemberType; import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.channel.netease.client.NimClient; @@ -72,7 +73,7 @@ public class GroupMemberSyncer { if (person == null) { account.setPersonId(0L); account.setPersonOuId(0L); - account.setAppType(null); + account.setAppType(AppTypeEnum.NONE); account.setIsRobot(YesOrNo.YES); } else { account.setPersonId(Long.valueOf(person.getPersonId())); From a995b7e361370666ed7c0f393c40ff433305c98c Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 18:10:56 +0800 Subject: [PATCH 044/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncService.java | 4 ++-- .../java/cn/axzo/im/group/message/MessageSyncController.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index 67459d2..8733b9e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -75,7 +75,7 @@ public class GroupMessageSyncService { .gt(Group::getDismissedAt, twoDayAgo)))); for (List groups : cursor) { for (Group group : groups) { - controller.acquireSubmitGroup(group); + controller.submitGroup(group); executor.execute(new GroupMessageSyncer(this, controller, group) { @Override public void run() { @@ -84,7 +84,7 @@ public class GroupMessageSyncService { } catch (Exception e) { log.warn("sync group message failed: {}", group.getId(), e); } finally { - controller.setGroupCompleted(group); + controller.completeGroup(group); } } }); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java index d6ddafe..22d0b40 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java @@ -33,7 +33,7 @@ class MessageSyncController { this.onComplete = onComplete; } - void acquireSubmitGroup(Group group) throws Exception { + void submitGroup(Group group) throws Exception { submitGroupSemaphore.acquire(); Object submitted = groups.putIfAbsent(group.getId(), SUBMITTED); if (submitted != null) { @@ -48,7 +48,7 @@ class MessageSyncController { log.info("submitted group: {}", group.getId()); } - void setGroupCompleted(Group group) { + void completeGroup(Group group) { Object submitted = groups.remove(group.getId()); if (submitted == null) return; submitGroupSemaphore.release(); From e324e652082769e94188f9898b7735e3c30c27a0 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 18:11:07 +0800 Subject: [PATCH 045/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncService.java | 2 +- .../java/cn/axzo/im/group/message/MessageSyncController.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index 8733b9e..c8c49ea 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -90,7 +90,7 @@ public class GroupMessageSyncService { }); } } - controller.setSubmitFinished(); + controller.submitFinished(); latch.await(); } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java index 22d0b40..11a29cd 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java @@ -59,7 +59,7 @@ class MessageSyncController { log.info("completed group: {}", group.getId()); } - void setSubmitFinished() { + void submitFinished() { synchronized (this) { submitFinished = true; maybeComplete(); From 68069b1975434e78ab467076812ff4c318cbd19d Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 23 Jan 2025 18:26:38 +0800 Subject: [PATCH 046/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/message/GroupMessageSyncer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 834685a..dee16ea 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -45,8 +45,7 @@ class GroupMessageSyncer implements Runnable { Long beginMs = service.getMaxSendTime(group.getTid()) .orElse(twoDaysAgo()) .getTime(); - Long endMs = System.currentTimeMillis(); - Timeline timeline = new Timeline(beginMs, endMs); + Timeline timeline = new Timeline(beginMs, System.currentTimeMillis()); // don't change long limit = 100L; TimeNode current = timeline.current(); From 91e3747f4c18027ad9e6eea3cdb0aafa0cae67e0 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 09:30:42 +0800 Subject: [PATCH 047/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/group/message/GroupMessageSyncer.java | 14 +++++++------- .../axzo/im/group/message/timeline/Timeline.java | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index dee16ea..846694c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -48,22 +48,22 @@ class GroupMessageSyncer implements Runnable { Timeline timeline = new Timeline(beginMs, System.currentTimeMillis()); // don't change long limit = 100L; - TimeNode current = timeline.current(); - while (current != null) { - NimGroupGetMessagesResponse response = fetchMessages(current, limit); + TimeNode head = timeline.head(); + while (head != null) { + NimGroupGetMessagesResponse response = fetchMessages(head, limit); BizAssertions.assertTrue(response.isSuccess(), "fetch group messages failed"); List msgList = response.getMsgs(); if (CollectionUtils.isEmpty(msgList)) { - current = timeline.advance(); + head = timeline.consume(); continue; } // response.size 不可靠 - if (msgList.size() == limit && current.isSplittable()) { - current = timeline.split(); + if (msgList.size() == limit && head.isSplittable()) { + head = timeline.split(); continue; } saveMessages(asGroupMessages(msgList)); - current = timeline.advance(); + head = timeline.consume(); } } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java index 1f2f99d..21047d8 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -28,26 +28,26 @@ public class Timeline { } public TimeNode split() { - TimeNode node = current(); + TimeNode node = head(); BizAssertions.assertNotNull(node, "timeline is empty"); //noinspection DataFlowIssue BizAssertions.assertTrue(node.isSplittable(), "node is not splittable: ", node); nodes.removeFirst(); splitCount *= 2; prepend(split(node.getBeginMs(), node.getEndMs())); - return current(); + return head(); } - public TimeNode advance() { - TimeNode node = current(); + public TimeNode consume() { + TimeNode node = head(); BizAssertions.assertNotNull(node, "timeline is empty"); nodes.removeFirst(); splitCount = 1; - return current(); + return head(); } @Nullable - public TimeNode current() { + public TimeNode head() { return nodes.peek(); } From 6765ac28063ea313503602a623ee5b8480d26180 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 09:37:25 +0800 Subject: [PATCH 048/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/group/message/MessageSyncController.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java index 11a29cd..24807ca 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java @@ -19,7 +19,7 @@ class MessageSyncController { private static final Object SUBMITTED = new Object(); private final RateLimiter rateLimiter; - private final Semaphore submitGroupSemaphore; + private final Semaphore submitGroupLimit; private final Runnable onComplete; private final Map groups = new ConcurrentHashMap<>(); @@ -29,15 +29,15 @@ class MessageSyncController { MessageSyncController(int tps, Runnable onComplete) { this.rateLimiter = RateLimiter.create(tps); - this.submitGroupSemaphore = new Semaphore(tps); + this.submitGroupLimit = new Semaphore(tps); this.onComplete = onComplete; } void submitGroup(Group group) throws Exception { - submitGroupSemaphore.acquire(); + submitGroupLimit.acquire(); Object submitted = groups.putIfAbsent(group.getId(), SUBMITTED); if (submitted != null) { - submitGroupSemaphore.release(); + submitGroupLimit.release(); throw new ServiceException("group already submitted: " + group.getId()); } synchronized (this) { @@ -51,7 +51,7 @@ class MessageSyncController { void completeGroup(Group group) { Object submitted = groups.remove(group.getId()); if (submitted == null) return; - submitGroupSemaphore.release(); + submitGroupLimit.release(); synchronized (this) { completedGroup++; maybeComplete(); From eb2eb79153513181d14413232c0407715482b124 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 09:37:56 +0800 Subject: [PATCH 049/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/group/message/MessageSyncController.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java index 24807ca..6f6a505 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java @@ -19,7 +19,7 @@ class MessageSyncController { private static final Object SUBMITTED = new Object(); private final RateLimiter rateLimiter; - private final Semaphore submitGroupLimit; + private final Semaphore groupLimit; private final Runnable onComplete; private final Map groups = new ConcurrentHashMap<>(); @@ -29,15 +29,15 @@ class MessageSyncController { MessageSyncController(int tps, Runnable onComplete) { this.rateLimiter = RateLimiter.create(tps); - this.submitGroupLimit = new Semaphore(tps); + this.groupLimit = new Semaphore(tps); this.onComplete = onComplete; } void submitGroup(Group group) throws Exception { - submitGroupLimit.acquire(); + groupLimit.acquire(); Object submitted = groups.putIfAbsent(group.getId(), SUBMITTED); if (submitted != null) { - submitGroupLimit.release(); + groupLimit.release(); throw new ServiceException("group already submitted: " + group.getId()); } synchronized (this) { @@ -51,7 +51,7 @@ class MessageSyncController { void completeGroup(Group group) { Object submitted = groups.remove(group.getId()); if (submitted == null) return; - submitGroupLimit.release(); + groupLimit.release(); synchronized (this) { completedGroup++; maybeComplete(); From d35a2e9d849e8586534d12cd5d7a9b189c0ffa82 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 09:37:56 +0800 Subject: [PATCH 050/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/group/message/GroupMessageSyncService.java | 8 +------- .../axzo/im/group/message/MessageSyncController.java | 10 +++++----- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index c8c49ea..bc09cc2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -24,7 +24,6 @@ import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; /** * @author yanglin @@ -58,13 +57,8 @@ public class GroupMessageSyncService { } private void syncImpl() throws Exception { - AtomicBoolean completed = new AtomicBoolean(false); CountDownLatch latch = new CountDownLatch(1); - Runnable runOnce = () -> { - if (completed.compareAndSet(false, true)) - latch.countDown(); - }; - MessageSyncController controller = new MessageSyncController(tps, runOnce); + MessageSyncController controller = new MessageSyncController(tps, latch::countDown); Date twoDayAgo = new DateTime(new Date()).minusDays(2).toDate(); RecordCursor cursor = new RecordCursor<>(Group::getId, () -> groupDao.lambdaQuery() diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java index 24807ca..6f6a505 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java @@ -19,7 +19,7 @@ class MessageSyncController { private static final Object SUBMITTED = new Object(); private final RateLimiter rateLimiter; - private final Semaphore submitGroupLimit; + private final Semaphore groupLimit; private final Runnable onComplete; private final Map groups = new ConcurrentHashMap<>(); @@ -29,15 +29,15 @@ class MessageSyncController { MessageSyncController(int tps, Runnable onComplete) { this.rateLimiter = RateLimiter.create(tps); - this.submitGroupLimit = new Semaphore(tps); + this.groupLimit = new Semaphore(tps); this.onComplete = onComplete; } void submitGroup(Group group) throws Exception { - submitGroupLimit.acquire(); + groupLimit.acquire(); Object submitted = groups.putIfAbsent(group.getId(), SUBMITTED); if (submitted != null) { - submitGroupLimit.release(); + groupLimit.release(); throw new ServiceException("group already submitted: " + group.getId()); } synchronized (this) { @@ -51,7 +51,7 @@ class MessageSyncController { void completeGroup(Group group) { Object submitted = groups.remove(group.getId()); if (submitted == null) return; - submitGroupLimit.release(); + groupLimit.release(); synchronized (this) { completedGroup++; maybeComplete(); From 7f1caa9274ebeea43c2cb20eeee40d15707d9674 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 11:07:11 +0800 Subject: [PATCH 051/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncer.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 846694c..0736c09 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -108,15 +108,15 @@ class GroupMessageSyncer implements Runnable { return messages; } - private void saveMessages(Collection messages) { - if (CollectionUtils.isEmpty(messages)) + private void saveMessages(Collection toSave) { + if (CollectionUtils.isEmpty(toSave)) return; try { - service.saveMessagesBatch(messages); + service.saveMessagesBatch(toSave); } catch (DuplicateKeyException ignored) { - List saved = service.reloadMessages(messages); + List saved = service.reloadMessages(toSave); List notSaved = Sets.difference( - UniqueMessage.from(messages), UniqueMessage.from(saved)) + UniqueMessage.from(toSave), UniqueMessage.from(saved)) .stream().map(UniqueMessage::getGroupMessage).collect(toList()); saveMessages(notSaved); } From 51e87a8db7b7c85af67ecaa6d9f469d327e379ae Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 11:26:26 +0800 Subject: [PATCH 052/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/entity/MessageHistory.java | 8 ++++++++ .../src/main/java/cn/axzo/im/send/SendQueue.java | 5 +++++ .../cn/axzo/im/send/handler/CommonSendBatchHandler.java | 1 - .../cn/axzo/im/send/handler/CommonSendOneHandler.java | 6 +----- .../src/main/java/cn/axzo/im/send/job/SendMessageJob.java | 4 +++- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/MessageHistory.java b/im-center-server/src/main/java/cn/axzo/im/entity/MessageHistory.java index c7b9fb3..fb88575 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/MessageHistory.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/MessageHistory.java @@ -14,6 +14,7 @@ import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import lombok.experimental.SuperBuilder; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; import java.io.Serializable; import java.util.Date; @@ -160,6 +161,8 @@ public class MessageHistory implements Serializable, NimMessageHistory { public Optional determineBatchNo() { if (isUpdatableMessage()) return Optional.empty(); + if (isSendToGroup()) + return Optional.empty(); String batchNo = this.batchNo; // 兼容在途数据 if (StringUtils.isBlank(batchNo) && imMessageTaskId != null) @@ -168,4 +171,9 @@ public class MessageHistory implements Serializable, NimMessageHistory { batchNo = null; return Optional.ofNullable(batchNo); } + + public boolean isSendToGroup() { + return AppTypeEnum.NONE.is(getAppType()) + && NumberUtils.isDigits(getToAccount()); + } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java b/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java index 7e055b7..819c561 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java @@ -58,6 +58,7 @@ public class SendQueue { private int sendCount = 0; private boolean lastLoadEmpty = false; private long lastPrintCompleted = 0; + private boolean seenSendToGroupMessage = false; SendQueue(ApplicationContext applicationContext, ApiChannel apiChannel) { this.apiChannel = apiChannel; @@ -70,6 +71,8 @@ public class SendQueue { @NotNull public synchronized List pollBatch(int batchSize) { BizAssertions.assertTrue(batchSize > 0, "batchSize必须大于0"); + if (seenSendToGroupMessage) + return Collections.emptyList(); if (determineNoMoreRecords()) return Collections.emptyList(); // 绝对的优先级优先 @@ -210,6 +213,8 @@ public class SendQueue { } if (this.records.isEmpty()) lastLoadEmpty = true; + this.seenSendToGroupMessage = this.seenSendToGroupMessage + || records.stream().anyMatch(MessageHistory::isSendToGroup); } public void scheduleRetrySend(List histories, HistoryRecordExt updateExt) { diff --git a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java index 075b33a..6cb65f0 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java @@ -18,7 +18,6 @@ import java.util.List; * @author yanglin */ @Component -@Deprecated // 发送给群时无法使用批量接口, 也不想改动SendQueue了, 后续有时间再优化 @RequiredArgsConstructor public class CommonSendBatchHandler extends SendBatchHandler { diff --git a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java index df7f8c1..285632c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java @@ -1,6 +1,5 @@ package cn.axzo.im.send.handler; -import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.ChannelMsgTypeEnum; import cn.axzo.im.channel.IMChannelProvider; import cn.axzo.im.channel.netease.dto.MessageDispatchRequest; @@ -10,7 +9,6 @@ import cn.axzo.im.send.MessageHistoryNimLogger; import cn.axzo.im.send.SendExecutor; import cn.axzo.im.utils.ImProperties; import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.math.NumberUtils; import org.springframework.stereotype.Component; /** @@ -31,9 +29,7 @@ public class CommonSendOneHandler extends SendOneHandler { history.getBizId(), history.determineBatchNo().orElse(null)); MessageDispatchRequest sendRequest = new MessageDispatchRequest(); sendRequest.setFrom(history.getFromAccount()); - boolean isSendToGroup = AppTypeEnum.NONE.is(history.getAppType()) - && NumberUtils.isDigits(history.getToAccount()); - sendRequest.setOpe(isSendToGroup ? 1 : 0); + sendRequest.setOpe(history.isSendToGroup() ? 1 : 0); sendRequest.setTo(history.getToAccount()); Integer nimMessageType = history.getOrCreateRecordExt().getNimMessageType(); if (nimMessageType != null) diff --git a/im-center-server/src/main/java/cn/axzo/im/send/job/SendMessageJob.java b/im-center-server/src/main/java/cn/axzo/im/send/job/SendMessageJob.java index d36523b..435d1ab 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/job/SendMessageJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/job/SendMessageJob.java @@ -3,6 +3,7 @@ package cn.axzo.im.send.job; import cn.axzo.im.center.api.vo.ApiChannel; import cn.axzo.im.send.ScanAndSendService; import cn.axzo.im.send.SendExec; +import cn.axzo.im.send.handler.CommonSendBatchHandler; import cn.axzo.im.send.handler.CommonSendOneHandler; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.annotation.XxlJob; @@ -34,7 +35,8 @@ public class SendMessageJob extends SendMessageExecInstance { @Override SendExec newExecution() { - return new SendExec(ApiChannel.COMMON_MESSAGE, CommonSendOneHandler.class); + return new SendExec(ApiChannel.COMMON_MESSAGE, + CommonSendBatchHandler.class, CommonSendOneHandler.class); } } \ No newline at end of file From 2ec42119246bceb52d8f16bd798903ecc6333502 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 11:27:24 +0800 Subject: [PATCH 053/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java | 1 + 1 file changed, 1 insertion(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java b/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java index 819c561..8d40c3c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java @@ -71,6 +71,7 @@ public class SendQueue { @NotNull public synchronized List pollBatch(int batchSize) { BizAssertions.assertTrue(batchSize > 0, "batchSize必须大于0"); + // 如果有群发消息, 就不再按批量发送 if (seenSendToGroupMessage) return Collections.emptyList(); if (determineNoMoreRecords()) From 1b85984dda3abab0436cccada3f4e583cbea5e73 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 11:30:42 +0800 Subject: [PATCH 054/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java b/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java index 8d40c3c..6789ab0 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/SendQueue.java @@ -214,8 +214,7 @@ public class SendQueue { } if (this.records.isEmpty()) lastLoadEmpty = true; - this.seenSendToGroupMessage = this.seenSendToGroupMessage - || records.stream().anyMatch(MessageHistory::isSendToGroup); + this.seenSendToGroupMessage = records.stream().anyMatch(MessageHistory::isSendToGroup); } public void scheduleRetrySend(List histories, HistoryRecordExt updateExt) { From 0bcf17a7c9656094621c5a4e5e63998e6389f37e Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 11:46:41 +0800 Subject: [PATCH 055/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/timeline/TimeNode.java | 6 +++--- .../java/cn/axzo/im/group/message/timeline/Timeline.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java index 7d4ac1c..cd604a8 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java @@ -11,11 +11,11 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor(access = AccessLevel.PACKAGE) public class TimeNode { - private final Long beginMs; - private final Long endMs; + private final long beginMs; + private final long endMs; public boolean isSplittable() { - return endMs - beginMs > 0; + return endMs != beginMs; } @Override diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java index 21047d8..311e2a3 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -51,7 +51,7 @@ public class Timeline { return nodes.peek(); } - private List split(Long beginMs, Long endMs) { + private List split(long beginMs, long endMs) { BizAssertions.assertTrue(beginMs <= endMs, "beginMs must be less than or equal to endMs"); List nodes = new ArrayList<>(); long totalDuration = endMs - beginMs; From a1e3acdfc35ad28fc8f680fe49e308a7a0e85e6a Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 11:47:03 +0800 Subject: [PATCH 056/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/message/GroupMessageSyncer.java | 2 +- .../main/java/cn/axzo/im/group/message/timeline/Timeline.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java index 0736c09..f82a762 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java @@ -42,7 +42,7 @@ class GroupMessageSyncer implements Runnable { @Override public void run() { - Long beginMs = service.getMaxSendTime(group.getTid()) + long beginMs = service.getMaxSendTime(group.getTid()) .orElse(twoDaysAgo()) .getTime(); Timeline timeline = new Timeline(beginMs, System.currentTimeMillis()); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java index 311e2a3..eb88669 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -17,7 +17,7 @@ public class Timeline { private final LinkedList nodes; private int splitCount = 1; - public Timeline(Long beginMs, Long endMs) { + public Timeline(long beginMs, long endMs) { BizAssertions.assertTrue(beginMs <= endMs, "beginMs must be less than or equal to endMs"); nodes = new LinkedList<>(); prepend(split(beginMs, endMs)); From 152f0ee811f78507eb345024573588a65416d5ee Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 15:38:16 +0800 Subject: [PATCH 057/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index 888f316..64a5b49 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -70,7 +70,7 @@ public class GroupMessageSyncService { for (List groups : cursor) { for (Group group : groups) { controller.submitGroup(group); - executor.execute(new GroupMessageSyncer(this, controller, group) { + executor.execute(new GroupMessageSyncHandler(this, controller, group) { @Override public void run() { try { From 0a0d3d8cd1c0cf2e640d17e25271965fdd394e13 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 15:38:32 +0800 Subject: [PATCH 058/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{GroupMessageSyncer.java => GroupMessageSyncHandler.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename im-center-server/src/main/java/cn/axzo/im/group/message/{GroupMessageSyncer.java => GroupMessageSyncHandler.java} (99%) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java similarity index 99% rename from im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java rename to im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index f82a762..847dd43 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -34,7 +34,7 @@ import static java.util.stream.Collectors.toList; */ @Slf4j @RequiredArgsConstructor -class GroupMessageSyncer implements Runnable { +class GroupMessageSyncHandler implements Runnable { private final GroupMessageSyncService service; private final MessageSyncController controller; From 449cc2291a800659b6816a3f57e8239b4fe093b1 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 24 Jan 2025 15:58:32 +0800 Subject: [PATCH 059/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index 64a5b49..8a8ec8c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -50,7 +50,9 @@ public class GroupMessageSyncService { isRunning = true; } try { + log.info("start sync group messages..."); syncImpl(); + log.info("sync group messages finished"); } finally { isRunning = false; } From 78011e50a2375c0e3fd3ed8a2ce7a5668eea7e3b Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 10:13:28 +0800 Subject: [PATCH 060/201] =?UTF-8?q?REQ-3345:=20=E5=B0=86=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E6=94=BE=E5=88=B0=E7=BE=A4=E7=9A=84custom?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../center/api/vo/req/GroupCreateRequest.java | 2 +- .../vo/req/GroupMessagePageQueryRequest.java | 7 ++----- .../netease/dto/NimGroupCreateRequest.java | 8 ++++++++ .../axzo/im/controller/PrivateController.java | 6 ------ .../src/main/java/cn/axzo/im/entity/Group.java | 6 +++--- .../axzo/im/group/GroupMessageController.java | 18 +++++++++++++++--- .../java/cn/axzo/im/group/GroupSupport.java | 6 +++--- .../im/service/impl/ChatGroupServiceImpl.java | 2 +- 8 files changed, 33 insertions(+), 22 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java index 499b8aa..163335b 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java @@ -64,7 +64,7 @@ public class GroupCreateRequest { /** * 群聊业务扩展信息, 透传到群属性中. 不能传太多属性或较长字段,云信有长度限制 */ - private Map bizAttachment; + private Map bizGroupInfo; @JsonIgnore @JSONField(serialize = false, deserialize = false) public Set getOwnerAndMembers() { diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupMessagePageQueryRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupMessagePageQueryRequest.java index cf075fe..7d03824 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupMessagePageQueryRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupMessagePageQueryRequest.java @@ -1,5 +1,6 @@ package cn.axzo.im.center.api.vo.req; +import cn.axzo.basics.common.page.PageRequest; import lombok.Getter; import lombok.Setter; @@ -10,13 +11,9 @@ import javax.validation.constraints.NotNull; */ @Setter @Getter -public class GroupMessagePageQueryRequest { +public class GroupMessagePageQueryRequest extends PageRequest { @NotNull(message = "群ID不能为空") private Long tid; - private Integer page; - - private Integer pageSize; - } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java index 87eeb46..7f2d84b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupCreateRequest.java @@ -94,6 +94,14 @@ public class NimGroupCreateRequest extends GroupMemberRequest { .toJSONString(); } + public void addCustom(String key, Object value) { + if (StringUtils.isBlank(this.custom)) + this.custom = "{}"; + this.custom = JSON.parseObject(this.custom) + .fluentPut(key, value) + .toJSONString(); + } + @Override public String toString() { return JSON.toJSONString(this); diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java index 9d093a2..4d60740 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java @@ -111,10 +111,4 @@ public class PrivateController { return CommonResponse.success(nimClient.getGroupInfo(request)); } - @PostMapping("/private/group/syncGroupMessages") - public Object syncGroupMessages() throws Exception { - groupMessageSyncService.sync(); - return "done"; - } - } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/Group.java b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java index 7a0a4e9..f964d6e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/Group.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java @@ -19,9 +19,9 @@ import java.util.Date; @TableName(value = "im_group", autoResultMap = true) public class Group { - public static final String ATTACHMENT_GROUP_TYPE = "groupType"; - public static final String ATTACHMENT_BIZ_CODE = "bizCode"; - public static final String ATTACHMENT_BIZ_ATTACHMENT = "bizAttachment"; + public static final String CUSTOM_GROUP_TYPE = "groupType"; + public static final String CUSTOM_BIZ_CODE = "bizCode"; + public static final String CUSTOM_BIZ_GROUP_INFO = "bizGroupInfo"; private Long id; private Long tid; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java index 93941f9..867c90b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java @@ -1,10 +1,14 @@ package cn.axzo.im.group; +import cn.axzo.basics.common.BeanMapper; +import cn.axzo.framework.domain.page.PageResp; import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.im.center.api.feign.GroupMessageApi; import cn.axzo.im.center.api.vo.req.GroupMessagePageQueryRequest; import cn.axzo.im.center.api.vo.resp.GroupMessagePageQueryResponse; import cn.axzo.im.dao.repository.GroupMessageDao; +import cn.axzo.im.entity.GroupMessage; +import com.baomidou.mybatisplus.core.metadata.IPage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RestController; @@ -20,9 +24,17 @@ public class GroupMessageController implements GroupMessageApi { private final GroupMessageDao groupMessageDao; @Override - public ApiPageResult - pageQuery(GroupMessagePageQueryRequest request) { - return null; + public ApiPageResult pageQuery(GroupMessagePageQueryRequest request) { + @SuppressWarnings("unchecked") + IPage page = groupMessageDao.lambdaQuery() + .orderByDesc(GroupMessage::getTid, GroupMessage::getSendTime) + .page(request.toPage()); + PageResp pageResp = PageResp.list( + page.getCurrent(), + page.getSize(), + page.getTotal(), + BeanMapper.copyList(page.getRecords(), GroupMessagePageQueryResponse.class)); + return ApiPageResult.ok(pageResp); } } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index ecf4cb3..5332d9e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -56,9 +56,9 @@ public class GroupSupport implements GroupLogger { nimRequest.addMembers(imAccounts.filterAccounts(account -> !account.equals(owner))); nimRequest.setIntroduceMessage(GroupApi.INTRODUCE_MESSAGE); nimRequest.setIcon(request.getAvatar()); - nimRequest.addAttachment(Group.ATTACHMENT_GROUP_TYPE, request.getGroupType()); - nimRequest.addAttachment(Group.ATTACHMENT_BIZ_CODE, request.getBizCode()); - nimRequest.addAttachment(Group.ATTACHMENT_BIZ_ATTACHMENT, request.getBizAttachment()); + nimRequest.addCustom(Group.CUSTOM_GROUP_TYPE, request.getGroupType()); + nimRequest.addCustom(Group.CUSTOM_BIZ_CODE, request.getBizCode()); + nimRequest.addCustom(Group.CUSTOM_BIZ_GROUP_INFO, request.getBizGroupInfo()); return nimRequest; } diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java index 2b51607..94292de 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java @@ -296,7 +296,7 @@ public class ChatGroupServiceImpl extends ServiceImpl Date: Wed, 5 Feb 2025 10:48:11 +0800 Subject: [PATCH 061/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java index 8a8ec8c..d0a72a0 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java @@ -23,7 +23,7 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.ForkJoinPool; /** * @author yanglin @@ -34,7 +34,7 @@ import java.util.concurrent.Executors; public class GroupMessageSyncService { private final int tps = 30; - private final ExecutorService executor = Executors.newFixedThreadPool(tps + 1); + private final ExecutorService executor = new ForkJoinPool(tps); private final GroupDao groupDao; private final GroupMessageDao groupMessageDao; private final NimClient nimClient; From a5123c100ac8685992f65b5f39bb6d454f0c1502 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 11:03:27 +0800 Subject: [PATCH 062/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncHandler.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 847dd43..65abc3f 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -43,7 +43,7 @@ class GroupMessageSyncHandler implements Runnable { @Override public void run() { long beginMs = service.getMaxSendTime(group.getTid()) - .orElse(twoDaysAgo()) + .orElseGet(() -> DateTime.now().minusDays(2).toDate()) .getTime(); Timeline timeline = new Timeline(beginMs, System.currentTimeMillis()); // don't change @@ -122,7 +122,4 @@ class GroupMessageSyncHandler implements Runnable { } } - private Date twoDaysAgo() { - return DateTime.now().minusDays(2).toDate(); - } } \ No newline at end of file From e98753f2589ce179907c766c20bf00ae9de232a7 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 14:55:18 +0800 Subject: [PATCH 063/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/controller/PrivateController.java | 4 +- .../message/GroupMessageSyncHandler.java | 2 +- .../im/group/message/GroupMessageSyncJob.java | 104 +++++++++++++++- .../message/GroupMessageSyncService.java | 117 ------------------ .../im/group/GroupMessageSyncJobTest.java | 23 ---- 5 files changed, 103 insertions(+), 147 deletions(-) delete mode 100644 im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java delete mode 100644 im-center-server/src/test/java/cn/axzo/im/group/GroupMessageSyncJobTest.java diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java index 4d60740..7fa6641 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java @@ -11,7 +11,7 @@ import cn.axzo.im.channel.netease.dto.NimQueryEventRequest; import cn.axzo.im.channel.netease.dto.NimQueryMessageRequest; import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; import cn.axzo.im.group.GroupManager; -import cn.axzo.im.group.message.GroupMessageSyncService; +import cn.axzo.im.group.message.GroupMessageSyncJob; import cn.axzo.im.job.CreateMessageHistoryJob; import cn.axzo.im.job.ExpungeImTaskJob; import cn.axzo.im.job.RevokeAllMessagesJob; @@ -40,7 +40,7 @@ public class PrivateController { private final MessageController messageController; private final ExpungeImTaskJob expungeImTaskJob; private final GroupManager groupManager; - private final GroupMessageSyncService groupMessageSyncService; + private final GroupMessageSyncJob groupMessageSyncService; @PostMapping("/private/revoke") public Object revoke(@Valid @RequestBody NimRevokeMessageRequest request) { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 65abc3f..c5074b4 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -36,7 +36,7 @@ import static java.util.stream.Collectors.toList; @RequiredArgsConstructor class GroupMessageSyncHandler implements Runnable { - private final GroupMessageSyncService service; + private final GroupMessageSyncJob service; private final MessageSyncController controller; private final Group group; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index d4ae12e..2294725 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -1,26 +1,122 @@ package cn.axzo.im.group.message; +import cn.axzo.basics.common.exception.ServiceException; +import cn.axzo.im.center.common.enums.YesOrNo; +import cn.axzo.im.channel.netease.client.NimClient; +import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesRequest; +import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesResponse; +import cn.axzo.im.dao.repository.GroupDao; +import cn.axzo.im.dao.repository.GroupMessageDao; +import cn.axzo.im.entity.Group; +import cn.axzo.im.entity.GroupMessage; +import cn.axzo.im.utils.RecordCursor; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.annotation.XxlJob; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; +import org.apache.commons.collections4.CollectionUtils; +import org.joda.time.DateTime; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ForkJoinPool; /** * @author yanglin */ @Slf4j -@Component +@Service @RequiredArgsConstructor public class GroupMessageSyncJob { - private final GroupMessageSyncService groupMessageSyncService; + private final int tps = 30; + private final ExecutorService executor = new ForkJoinPool(tps); + private final GroupDao groupDao; + private final GroupMessageDao groupMessageDao; + private final NimClient nimClient; + + private volatile boolean isRunning = false; @SuppressWarnings("unused") @XxlJob("groupMessageSyncJob") public ReturnT execute(String jsonStr) throws Exception { - groupMessageSyncService.sync(); + if (isRunning) + throw new ServiceException("任务正在执行中,请稍后再试..."); + synchronized (this) { + if (isRunning) + throw new ServiceException("任务正在执行中,请稍后再试..."); + isRunning = true; + } + try { + log.info("start sync group messages..."); + syncImpl(); + log.info("sync group messages finished"); + } finally { + isRunning = false; + } return ReturnT.SUCCESS; } + private void syncImpl() throws Exception { + CountDownLatch completed = new CountDownLatch(1); + MessageSyncController controller = new MessageSyncController(tps, completed::countDown); + Date twoDayAgo = new DateTime(new Date()).minusDays(2).toDate(); + RecordCursor cursor = new RecordCursor<>(Group::getId, () -> + groupDao.lambdaQuery() + .nested(w1 -> w1 + .eq(Group::getIsDismissed, YesOrNo.NO) + .or().nested(w2 -> w2 + .eq(Group::getIsDismissed, YesOrNo.YES) + .gt(Group::getDismissedAt, twoDayAgo)))); + for (List groups : cursor) { + for (Group group : groups) { + controller.submitGroup(group); + executor.execute(new GroupMessageSyncHandler(this, controller, group) { + @Override + public void run() { + try { + super.run(); + } catch (Exception e) { + log.warn("sync group message failed: {}", group.getId(), e); + } finally { + controller.completeGroup(group); + } + } + }); + } + } + controller.submitFinished(); + completed.await(); + } + + void saveMessagesBatch(Collection messages) { + if (CollectionUtils.isNotEmpty(messages)) + groupMessageDao.saveBatch(messages); + } + + List reloadMessages(Collection messages) { + return groupMessageDao.reload(messages); + } + + Optional getMaxSendTime(Long tid) { + GroupMessage groupMessage = groupMessageDao.getBaseMapper() + .selectOne(new QueryWrapper() + .select("MAX(send_time) AS send_time") + .lambda() + .eq(GroupMessage::getTid, tid)); + return groupMessage == null + ? Optional.empty() + : Optional.ofNullable(groupMessage.getSendTime()); + } + + NimGroupGetMessagesResponse getGroupMessages(NimGroupGetMessagesRequest request) { + return nimClient.getGroupMessages(request); + } + } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java deleted file mode 100644 index d0a72a0..0000000 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncService.java +++ /dev/null @@ -1,117 +0,0 @@ -package cn.axzo.im.group.message; - -import cn.axzo.basics.common.exception.ServiceException; -import cn.axzo.im.center.common.enums.YesOrNo; -import cn.axzo.im.channel.netease.client.NimClient; -import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesRequest; -import cn.axzo.im.channel.netease.dto.NimGroupGetMessagesResponse; -import cn.axzo.im.dao.repository.GroupDao; -import cn.axzo.im.dao.repository.GroupMessageDao; -import cn.axzo.im.entity.Group; -import cn.axzo.im.entity.GroupMessage; -import cn.axzo.im.utils.RecordCursor; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.CollectionUtils; -import org.joda.time.DateTime; -import org.springframework.stereotype.Service; - -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ForkJoinPool; - -/** - * @author yanglin - */ -@Slf4j -@Service -@RequiredArgsConstructor -public class GroupMessageSyncService { - - private final int tps = 30; - private final ExecutorService executor = new ForkJoinPool(tps); - private final GroupDao groupDao; - private final GroupMessageDao groupMessageDao; - private final NimClient nimClient; - - private volatile boolean isRunning = false; - - public void sync() throws Exception { - if (isRunning) - throw new ServiceException("任务正在执行中,请稍后再试..."); - synchronized (this) { - if (isRunning) - throw new ServiceException("任务正在执行中,请稍后再试..."); - isRunning = true; - } - try { - log.info("start sync group messages..."); - syncImpl(); - log.info("sync group messages finished"); - } finally { - isRunning = false; - } - } - - private void syncImpl() throws Exception { - CountDownLatch completed = new CountDownLatch(1); - MessageSyncController controller = new MessageSyncController(tps, completed::countDown); - Date twoDayAgo = new DateTime(new Date()).minusDays(2).toDate(); - RecordCursor cursor = new RecordCursor<>(Group::getId, () -> - groupDao.lambdaQuery() - .nested(w1 -> w1 - .eq(Group::getIsDismissed, YesOrNo.NO) - .or().nested(w2 -> w2 - .eq(Group::getIsDismissed, YesOrNo.YES) - .gt(Group::getDismissedAt, twoDayAgo)))); - for (List groups : cursor) { - for (Group group : groups) { - controller.submitGroup(group); - executor.execute(new GroupMessageSyncHandler(this, controller, group) { - @Override - public void run() { - try { - super.run(); - } catch (Exception e) { - log.warn("sync group message failed: {}", group.getId(), e); - } finally { - controller.completeGroup(group); - } - } - }); - } - } - controller.submitFinished(); - completed.await(); - } - - void saveMessagesBatch(Collection messages) { - if (CollectionUtils.isNotEmpty(messages)) - groupMessageDao.saveBatch(messages); - } - - List reloadMessages(Collection messages) { - return groupMessageDao.reload(messages); - } - - Optional getMaxSendTime(Long tid) { - GroupMessage groupMessage = groupMessageDao.getBaseMapper() - .selectOne(new QueryWrapper() - .select("MAX(send_time) AS send_time") - .lambda() - .eq(GroupMessage::getTid, tid)); - return groupMessage == null - ? Optional.empty() - : Optional.ofNullable(groupMessage.getSendTime()); - } - - NimGroupGetMessagesResponse getGroupMessages(NimGroupGetMessagesRequest request) { - return nimClient.getGroupMessages(request); - } - -} \ No newline at end of file diff --git a/im-center-server/src/test/java/cn/axzo/im/group/GroupMessageSyncJobTest.java b/im-center-server/src/test/java/cn/axzo/im/group/GroupMessageSyncJobTest.java deleted file mode 100644 index 20d18ca..0000000 --- a/im-center-server/src/test/java/cn/axzo/im/group/GroupMessageSyncJobTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.axzo.im.group; - -import cn.axzo.im.Application; -import cn.axzo.im.group.message.GroupMessageSyncJob; -import lombok.RequiredArgsConstructor; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -/** - * @author yanglin - */ -@SpringBootTest(classes = Application.class) -@RequiredArgsConstructor(onConstructor_ = @Autowired) -class GroupMessageSyncJobTest { - - private final GroupMessageSyncJob groupMessageSyncJob; - - @Test - void exec() { - } - -} \ No newline at end of file From dbd34a3bff121f603235f9c436fc8899708cb753 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 14:57:39 +0800 Subject: [PATCH 064/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncHandler.java | 2 +- .../main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index c5074b4..d682f63 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -112,7 +112,7 @@ class GroupMessageSyncHandler implements Runnable { if (CollectionUtils.isEmpty(toSave)) return; try { - service.saveMessagesBatch(toSave); + service.batchSaveMessages(toSave); } catch (DuplicateKeyException ignored) { List saved = service.reloadMessages(toSave); List notSaved = Sets.difference( diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 2294725..e12e90f 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -95,7 +95,7 @@ public class GroupMessageSyncJob { completed.await(); } - void saveMessagesBatch(Collection messages) { + void batchSaveMessages(Collection messages) { if (CollectionUtils.isNotEmpty(messages)) groupMessageDao.saveBatch(messages); } From 23e8ef15d1051d34e248971ca013302c37ba9d04 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 15:01:47 +0800 Subject: [PATCH 065/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/MessageSyncController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java index 6f6a505..0815786 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java @@ -18,7 +18,7 @@ class MessageSyncController { private static final Object SUBMITTED = new Object(); - private final RateLimiter rateLimiter; + private final RateLimiter nimFetchLimiter; private final Semaphore groupLimit; private final Runnable onComplete; @@ -28,7 +28,7 @@ class MessageSyncController { private boolean submitFinished = false; MessageSyncController(int tps, Runnable onComplete) { - this.rateLimiter = RateLimiter.create(tps); + this.nimFetchLimiter = RateLimiter.create(tps); this.groupLimit = new Semaphore(tps); this.onComplete = onComplete; } @@ -73,7 +73,7 @@ class MessageSyncController { } void acquireFetchMessages() { - rateLimiter.acquire(); + nimFetchLimiter.acquire(); } } \ No newline at end of file From ee1816d524ac544ecafd8b3cbb17e6e8e28a999f Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 15:02:24 +0800 Subject: [PATCH 066/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/MessageSyncController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java index 0815786..4857d18 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/MessageSyncController.java @@ -18,7 +18,7 @@ class MessageSyncController { private static final Object SUBMITTED = new Object(); - private final RateLimiter nimFetchLimiter; + private final RateLimiter nimFetchRateLimiter; private final Semaphore groupLimit; private final Runnable onComplete; @@ -28,7 +28,7 @@ class MessageSyncController { private boolean submitFinished = false; MessageSyncController(int tps, Runnable onComplete) { - this.nimFetchLimiter = RateLimiter.create(tps); + this.nimFetchRateLimiter = RateLimiter.create(tps); this.groupLimit = new Semaphore(tps); this.onComplete = onComplete; } @@ -73,7 +73,7 @@ class MessageSyncController { } void acquireFetchMessages() { - nimFetchLimiter.acquire(); + nimFetchRateLimiter.acquire(); } } \ No newline at end of file From fa435084cf15a567ff7630b8121caa1e1f5a35eb Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 15:09:57 +0800 Subject: [PATCH 067/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/center/api/feign/GroupApi.java | 2 -- .../src/main/java/cn/axzo/im/group/GroupSupport.java | 7 ++++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java index 836fba8..e5950b9 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java @@ -22,8 +22,6 @@ import org.springframework.web.bind.annotation.RequestBody; @FeignClient(name = "im-center", url = "${axzo.service.im-center:http://im-center:8080}") public interface GroupApi { - String INTRODUCE_MESSAGE = "邀请您加入群聊"; - /** * 创建群 */ diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index 5332d9e..d1cb8cf 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -1,6 +1,5 @@ package cn.axzo.im.group; -import cn.axzo.im.center.api.feign.GroupApi; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.channel.netease.dto.NimGroupAddMembersRequest; @@ -24,6 +23,8 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class GroupSupport implements GroupLogger { + private static final String INTRODUCE_MESSAGE = "邀请您加入群聊"; + private final ChatGroupService chatGroupService; Group buildNewGroup(GroupCreateRequest request, ImAccounts imAccounts) { @@ -54,7 +55,7 @@ public class GroupSupport implements GroupLogger { nimRequest.setName(request.getName()); nimRequest.setOwner(owner); nimRequest.addMembers(imAccounts.filterAccounts(account -> !account.equals(owner))); - nimRequest.setIntroduceMessage(GroupApi.INTRODUCE_MESSAGE); + nimRequest.setIntroduceMessage(INTRODUCE_MESSAGE); nimRequest.setIcon(request.getAvatar()); nimRequest.addCustom(Group.CUSTOM_GROUP_TYPE, request.getGroupType()); nimRequest.addCustom(Group.CUSTOM_BIZ_CODE, request.getBizCode()); @@ -75,7 +76,7 @@ public class GroupSupport implements GroupLogger { NimGroupAddMembersRequest nimRequest = new NimGroupAddMembersRequest(); nimRequest.setTid(group.getTid()); nimRequest.setOwner(owner); - nimRequest.setMsg(GroupApi.INTRODUCE_MESSAGE); + nimRequest.setMsg(INTRODUCE_MESSAGE); nimRequest.addMembers(accounts.getAccounts()); return nimRequest; } From 4a64ec8fcade31d347b26c779d3e5f61f217e6fa Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 15:14:52 +0800 Subject: [PATCH 068/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncHandler.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index d682f63..4d2fed7 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -23,10 +23,12 @@ import org.joda.time.DateTime; import org.springframework.dao.DuplicateKeyException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.List; +import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; /** @@ -77,7 +79,10 @@ class GroupMessageSyncHandler implements Runnable { request.setReverse(1); request.setCheckTeamValid(false); request.setIncludeNoSenseMsg(false); - request.setType("0,1,2,3,4,6,100"); + request.setType(Arrays.stream(NimMessageType.values()) + .map(NimMessageType::getNimCode) + .map(String::valueOf) + .collect(joining(","))); controller.acquireFetchMessages(); NimGroupGetMessagesResponse response = service.getGroupMessages(request); log.info("fetch group messages, request={}, response={}", request, response); From 98ad6ac4db29a96aa2933f6ee6eaa99e47fb3d82 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 15:20:34 +0800 Subject: [PATCH 069/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index e12e90f..7664992 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -35,7 +35,7 @@ import java.util.concurrent.ForkJoinPool; @RequiredArgsConstructor public class GroupMessageSyncJob { - private final int tps = 30; + private final int tps = 10; private final ExecutorService executor = new ForkJoinPool(tps); private final GroupDao groupDao; private final GroupMessageDao groupMessageDao; From ae654442e76d13035be2e92cf647f2721c99e910 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 15:25:27 +0800 Subject: [PATCH 070/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/group/message/GroupMessageSyncHandler.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 4d2fed7..1bb31ae 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -16,17 +16,20 @@ import cn.axzo.im.group.message.timeline.Timeline; import cn.axzo.im.utils.BizAssertions; import cn.axzo.im.utils.ImAccountParser; import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Uninterruptibles; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.joda.time.DateTime; import org.springframework.dao.DuplicateKeyException; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Random; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; @@ -42,6 +45,8 @@ class GroupMessageSyncHandler implements Runnable { private final MessageSyncController controller; private final Group group; + private boolean removeDuplicateSleep = false; + @Override public void run() { long beginMs = service.getMaxSendTime(group.getTid()) @@ -123,8 +128,18 @@ class GroupMessageSyncHandler implements Runnable { List notSaved = Sets.difference( UniqueMessage.from(toSave), UniqueMessage.from(saved)) .stream().map(UniqueMessage::getGroupMessage).collect(toList()); + if (!removeDuplicateSleep) { + removeDuplicateSleep = true; + randomSleep(); + } saveMessages(notSaved); } } + private static void randomSleep() { + int ms = Math.abs(new Random().nextInt(5)) * 1000; + if (ms > 0) + Uninterruptibles.sleepUninterruptibly(Duration.ofMillis(ms)); + } + } \ No newline at end of file From 83d694c5e031556fe403e1169ed7e80a9e0b634e Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 15:25:38 +0800 Subject: [PATCH 071/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 1bb31ae..6708eba 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -129,8 +129,8 @@ class GroupMessageSyncHandler implements Runnable { UniqueMessage.from(toSave), UniqueMessage.from(saved)) .stream().map(UniqueMessage::getGroupMessage).collect(toList()); if (!removeDuplicateSleep) { - removeDuplicateSleep = true; randomSleep(); + removeDuplicateSleep = true; } saveMessages(notSaved); } From 0cd729a16c49693a0383f83f60ca9a6831fb2a23 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 15:26:20 +0800 Subject: [PATCH 072/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 6708eba..87402ed 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -45,7 +45,7 @@ class GroupMessageSyncHandler implements Runnable { private final MessageSyncController controller; private final Group group; - private boolean removeDuplicateSleep = false; + private boolean removeDuplicateSleeped = false; @Override public void run() { @@ -128,9 +128,9 @@ class GroupMessageSyncHandler implements Runnable { List notSaved = Sets.difference( UniqueMessage.from(toSave), UniqueMessage.from(saved)) .stream().map(UniqueMessage::getGroupMessage).collect(toList()); - if (!removeDuplicateSleep) { + if (!notSaved.isEmpty() && !removeDuplicateSleeped) { randomSleep(); - removeDuplicateSleep = true; + removeDuplicateSleeped = true; } saveMessages(notSaved); } From 353fbf79450e896b29f57e7c839cb6e0d310fa55 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 15:27:01 +0800 Subject: [PATCH 073/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 87402ed..3faee0f 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -45,7 +45,7 @@ class GroupMessageSyncHandler implements Runnable { private final MessageSyncController controller; private final Group group; - private boolean removeDuplicateSleeped = false; + private boolean removeDuplicateSlept = false; @Override public void run() { @@ -128,9 +128,9 @@ class GroupMessageSyncHandler implements Runnable { List notSaved = Sets.difference( UniqueMessage.from(toSave), UniqueMessage.from(saved)) .stream().map(UniqueMessage::getGroupMessage).collect(toList()); - if (!notSaved.isEmpty() && !removeDuplicateSleeped) { + if (!notSaved.isEmpty() && !removeDuplicateSlept) { randomSleep(); - removeDuplicateSleeped = true; + removeDuplicateSlept = true; } saveMessages(notSaved); } From c34e582f0e8ecc600468afa8af782f9020fe5474 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 15:36:17 +0800 Subject: [PATCH 074/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/dao/repository/GroupMessageDao.java | 2 +- .../message/GroupMessageSyncHandler.java | 27 +++++++++---------- .../im/group/message/GroupMessageSyncJob.java | 14 ++++++++-- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java index 5a5b413..653b175 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMessageDao.java @@ -16,7 +16,7 @@ import java.util.List; @Repository("groupMessageDao") public class GroupMessageDao extends ServiceImpl { - public List reload(Collection messages) { + public List reloadByNimId(Collection messages) { if (CollectionUtils.isEmpty(messages)) return Collections.emptyList(); return lambdaQuery() diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 3faee0f..2c52c07 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -16,20 +16,18 @@ import cn.axzo.im.group.message.timeline.Timeline; import cn.axzo.im.utils.BizAssertions; import cn.axzo.im.utils.ImAccountParser; import com.google.common.collect.Sets; -import com.google.common.util.concurrent.Uninterruptibles; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.joda.time.DateTime; import org.springframework.dao.DuplicateKeyException; -import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.List; -import java.util.Random; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; @@ -45,8 +43,6 @@ class GroupMessageSyncHandler implements Runnable { private final MessageSyncController controller; private final Group group; - private boolean removeDuplicateSlept = false; - @Override public void run() { long beginMs = service.getMaxSendTime(group.getTid()) @@ -121,25 +117,28 @@ class GroupMessageSyncHandler implements Runnable { private void saveMessages(Collection toSave) { if (CollectionUtils.isEmpty(toSave)) return; + if (toSave.size() == 1) { + trySaveOne(toSave.iterator().next()); + return; + } try { service.batchSaveMessages(toSave); } catch (DuplicateKeyException ignored) { - List saved = service.reloadMessages(toSave); + List saved = service.reloadMessagesByNimId(toSave); List notSaved = Sets.difference( UniqueMessage.from(toSave), UniqueMessage.from(saved)) .stream().map(UniqueMessage::getGroupMessage).collect(toList()); - if (!notSaved.isEmpty() && !removeDuplicateSlept) { - randomSleep(); - removeDuplicateSlept = true; - } saveMessages(notSaved); } } - private static void randomSleep() { - int ms = Math.abs(new Random().nextInt(5)) * 1000; - if (ms > 0) - Uninterruptibles.sleepUninterruptibly(Duration.ofMillis(ms)); + private void trySaveOne(GroupMessage message) { + GroupMessage savedMessage = service.reloadMessageByNimId(message).orElse(null); + if (savedMessage != null) return; + try { + service.batchSaveMessages(Collections.singletonList(message)); + } catch (DuplicateKeyException ignored) { + } } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 7664992..2ec43c0 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -20,6 +20,7 @@ import org.joda.time.DateTime; import org.springframework.stereotype.Service; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Optional; @@ -100,8 +101,17 @@ public class GroupMessageSyncJob { groupMessageDao.saveBatch(messages); } - List reloadMessages(Collection messages) { - return groupMessageDao.reload(messages); + Optional reloadMessageByNimId(GroupMessage message) { + if (message == null) + return Optional.empty(); + List messages = reloadMessagesByNimId(Collections.singletonList(message)); + return CollectionUtils.isEmpty(messages) + ? Optional.empty() + : Optional.of(messages.get(0)); + } + + List reloadMessagesByNimId(Collection messages) { + return groupMessageDao.reloadByNimId(messages); } Optional getMaxSendTime(Long tid) { From 0b2ec584373c114fe8cd86f4929e932de24d24ee Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 15:36:58 +0800 Subject: [PATCH 075/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 2c52c07..fba35c1 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -118,7 +118,7 @@ class GroupMessageSyncHandler implements Runnable { if (CollectionUtils.isEmpty(toSave)) return; if (toSave.size() == 1) { - trySaveOne(toSave.iterator().next()); + trySaveOneMessage(toSave.iterator().next()); return; } try { @@ -132,7 +132,7 @@ class GroupMessageSyncHandler implements Runnable { } } - private void trySaveOne(GroupMessage message) { + private void trySaveOneMessage(GroupMessage message) { GroupMessage savedMessage = service.reloadMessageByNimId(message).orElse(null); if (savedMessage != null) return; try { From ed8a003dff1b2de360633d593d66f48f6eaace0c Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 17:00:25 +0800 Subject: [PATCH 076/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupBroadcaster.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java index 01164c4..e6dc02a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java @@ -41,7 +41,7 @@ class GroupBroadcaster { message.setGroup(BeanMapper.copyBean(effectiveGroup, GroupInfo.class)); message.setMember(BeanMapper.copyBean(account, GroupMemberInfo.class)); Event event = Event.builder() - .targetId(String.format("%d:%d", group.getTid(), account.getPersonId())) + .targetId(group.getTid() + "") .targetType(eventType.getModel()) .eventCode(eventType.getEventCode()) .shardingKey(group.getId() + "") From 79953267be7545d3b42ed3305678c11a35699355 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 17:33:22 +0800 Subject: [PATCH 077/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/dao/repository/GroupDao.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java index 5415712..5945663 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java @@ -1,6 +1,5 @@ package cn.axzo.im.dao.repository; -import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.dao.mapper.GroupMapper; import cn.axzo.im.entity.Group; @@ -23,14 +22,6 @@ public class GroupDao extends ServiceImpl { .update(); } - public void updateOwner(Long tid, String imAccount, PersonAccountAttribute person) { - lambdaUpdate() - .eq(Group::getTid, tid) - .set(Group::getOwnerAccount, imAccount) - .set(Group::getOwnerPersonId, person.getPersonId()) - .update(); - } - public void updateTid(Long id, Long tid) { lambdaUpdate() .eq(Group::getId, id) From e6f803ec3906d6783a578094b2eda755233c1ef4 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 17:34:51 +0800 Subject: [PATCH 078/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index fba35c1..89c97ee 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -118,6 +118,7 @@ class GroupMessageSyncHandler implements Runnable { if (CollectionUtils.isEmpty(toSave)) return; if (toSave.size() == 1) { + // 不知道网易接口那边咋回事, 极端情况下时间不在区间内也会返回一条数据 trySaveOneMessage(toSave.iterator().next()); return; } From afc2d04c0ff2884603c2f88b720eb6baea291e04 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 17:35:50 +0800 Subject: [PATCH 079/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 89c97ee..781421f 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -119,6 +119,7 @@ class GroupMessageSyncHandler implements Runnable { return; if (toSave.size() == 1) { // 不知道网易接口那边咋回事, 极端情况下时间不在区间内也会返回一条数据 + // 如果只有一条数据, 这里优先走去重逻辑, 不走唯一键冲突逻辑 trySaveOneMessage(toSave.iterator().next()); return; } From 8bdc8cc2f34396a1a0b6db743611b6de2d07aa08 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 18:20:14 +0800 Subject: [PATCH 080/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/service/AccountService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java index d2c9ff2..88b3f2c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java @@ -390,6 +390,9 @@ public class AccountService { return Lists.newArrayList(); } + /** + * 无法保证所有账号创建成功,可能的原因是因为人员的信息不全,或者是人员信息不正确 + */ public ImAccounts getOrCreateImAccounts(Set persons) { ImAccounts imAccounts = getAccountsByPersons(persons); if (imAccounts.getAccountSize() == persons.size()) From 4f5fef5f17b855f04f63680d46e7fae56c9affcb Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 19:23:24 +0800 Subject: [PATCH 081/201] =?UTF-8?q?REQ-3345:=20=E8=A1=A5=E5=85=A8=E5=8D=95?= =?UTF-8?q?=E4=BD=8D=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/gateway/OrgGateway.java | 50 +++++++++++++++++++ .../axzo/im/group/GroupMessageController.java | 20 +++++++- 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java diff --git a/im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java b/im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java new file mode 100644 index 0000000..d3ef79e --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java @@ -0,0 +1,50 @@ +package cn.axzo.im.gateway; + +import cn.axzo.im.utils.BizAssertions; +import cn.axzo.maokai.api.client.OrganizationalUnitApi; +import cn.axzo.maokai.api.vo.request.OrganizationalUnitQuery; +import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +/** + * @author yanglin + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class OrgGateway { + + private final OrganizationalUnitApi organizationalUnitApi; + + public List getUnits(List ouIdList) { + if (ouIdList.isEmpty()) + return Collections.emptyList(); + OrganizationalUnitQuery req = new OrganizationalUnitQuery(); + req.setPageSize((long) ouIdList.size()); + req.setUnitIds(ouIdList); + return BizAssertions.assertResponse(organizationalUnitApi.list(req)); + } + + @RequiredArgsConstructor(access = AccessLevel.PRIVATE) + public static class Orgs { + + private final List units; + + public static Orgs wrap(List units) { + return new Orgs(units); + } + + public Optional findUnit(Long ouId) { + return units.stream().filter(unit -> unit.getId().equals(ouId)).findFirst(); + } + + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java index 867c90b..9406ab1 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java @@ -8,11 +8,17 @@ import cn.axzo.im.center.api.vo.req.GroupMessagePageQueryRequest; import cn.axzo.im.center.api.vo.resp.GroupMessagePageQueryResponse; import cn.axzo.im.dao.repository.GroupMessageDao; import cn.axzo.im.entity.GroupMessage; +import cn.axzo.im.gateway.OrgGateway; import com.baomidou.mybatisplus.core.metadata.IPage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RestController; +import java.util.List; +import java.util.Objects; + +import static java.util.stream.Collectors.toList; + /** * @author yanglin */ @@ -22,6 +28,7 @@ import org.springframework.web.bind.annotation.RestController; public class GroupMessageController implements GroupMessageApi { private final GroupMessageDao groupMessageDao; + private final OrgGateway orgGateway; @Override public ApiPageResult pageQuery(GroupMessagePageQueryRequest request) { @@ -29,11 +36,22 @@ public class GroupMessageController implements GroupMessageApi { IPage page = groupMessageDao.lambdaQuery() .orderByDesc(GroupMessage::getTid, GroupMessage::getSendTime) .page(request.toPage()); + List messages = BeanMapper.copyList( + page.getRecords(), GroupMessagePageQueryResponse.class); + OrgGateway.Orgs units = OrgGateway.Orgs.wrap(orgGateway.getUnits(messages.stream() + .map(GroupMessagePageQueryResponse::getFromPersonOuId) + .filter(Objects::nonNull) + .filter(ouId -> ouId > 0) + .distinct() + .collect(toList()))); + for (GroupMessagePageQueryResponse message : messages) + units.findUnit(message.getFromPersonOuId()) + .ifPresent(unit -> message.setUnitName(unit.getName())); PageResp pageResp = PageResp.list( page.getCurrent(), page.getSize(), page.getTotal(), - BeanMapper.copyList(page.getRecords(), GroupMessagePageQueryResponse.class)); + messages); return ApiPageResult.ok(pageResp); } From 4a13a9bdc15f7425b8755e2f7b81ebc34a7aead9 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 19:25:11 +0800 Subject: [PATCH 082/201] =?UTF-8?q?REQ-3345:=20=E8=A1=A5=E5=85=A8=E5=8D=95?= =?UTF-8?q?=E4=BD=8D=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/gateway/OrgGateway.java | 15 ----------- .../axzo/im/gateway/domain/OrgCollection.java | 26 +++++++++++++++++++ .../axzo/im/group/GroupMessageController.java | 3 ++- 3 files changed, 28 insertions(+), 16 deletions(-) create mode 100644 im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgCollection.java diff --git a/im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java b/im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java index d3ef79e..231187e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java +++ b/im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java @@ -32,19 +32,4 @@ public class OrgGateway { return BizAssertions.assertResponse(organizationalUnitApi.list(req)); } - @RequiredArgsConstructor(access = AccessLevel.PRIVATE) - public static class Orgs { - - private final List units; - - public static Orgs wrap(List units) { - return new Orgs(units); - } - - public Optional findUnit(Long ouId) { - return units.stream().filter(unit -> unit.getId().equals(ouId)).findFirst(); - } - - } - } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgCollection.java b/im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgCollection.java new file mode 100644 index 0000000..6ce2d5e --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgCollection.java @@ -0,0 +1,26 @@ +package cn.axzo.im.gateway.domain; + +import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; + +import java.util.List; +import java.util.Optional; + +/** + * @author yanglin + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class OrgCollection { + + private final List units; + + public static OrgCollection wrap(List units) { + return new OrgCollection(units); + } + + public Optional findUnit(Long ouId) { + return units.stream().filter(unit -> unit.getId().equals(ouId)).findFirst(); + } + +} diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java index 9406ab1..544d0a3 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java @@ -8,6 +8,7 @@ import cn.axzo.im.center.api.vo.req.GroupMessagePageQueryRequest; import cn.axzo.im.center.api.vo.resp.GroupMessagePageQueryResponse; import cn.axzo.im.dao.repository.GroupMessageDao; import cn.axzo.im.entity.GroupMessage; +import cn.axzo.im.gateway.domain.OrgCollection; import cn.axzo.im.gateway.OrgGateway; import com.baomidou.mybatisplus.core.metadata.IPage; import lombok.RequiredArgsConstructor; @@ -38,7 +39,7 @@ public class GroupMessageController implements GroupMessageApi { .page(request.toPage()); List messages = BeanMapper.copyList( page.getRecords(), GroupMessagePageQueryResponse.class); - OrgGateway.Orgs units = OrgGateway.Orgs.wrap(orgGateway.getUnits(messages.stream() + OrgCollection units = OrgCollection.wrap(orgGateway.getUnits(messages.stream() .map(GroupMessagePageQueryResponse::getFromPersonOuId) .filter(Objects::nonNull) .filter(ouId -> ouId > 0) From 74fd7b1047ac373ba1eefbb446c7104cfec1d86f Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 19:26:19 +0800 Subject: [PATCH 083/201] =?UTF-8?q?REQ-3345:=20=E8=A1=A5=E5=85=A8=E5=8D=95?= =?UTF-8?q?=E4=BD=8D=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/gateway/domain/OrgCollection.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgCollection.java b/im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgCollection.java index 6ce2d5e..45841b4 100644 --- a/im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgCollection.java +++ b/im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgCollection.java @@ -4,7 +4,7 @@ import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; -import java.util.List; +import java.util.Collection; import java.util.Optional; /** @@ -13,9 +13,9 @@ import java.util.Optional; @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class OrgCollection { - private final List units; + private final Collection units; - public static OrgCollection wrap(List units) { + public static OrgCollection wrap(Collection units) { return new OrgCollection(units); } From 555ed4dd49f1aafb8a663c0b0b4a23f46ea95eb9 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 19:27:40 +0800 Subject: [PATCH 084/201] =?UTF-8?q?REQ-3345:=20=E8=A1=A5=E5=85=A8=E5=8D=95?= =?UTF-8?q?=E4=BD=8D=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/gateway/OrgGateway.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java b/im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java index 231187e..725bd56 100644 --- a/im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java +++ b/im-center-server/src/main/java/cn/axzo/im/gateway/OrgGateway.java @@ -4,14 +4,14 @@ import cn.axzo.im.utils.BizAssertions; import cn.axzo.maokai.api.client.OrganizationalUnitApi; import cn.axzo.maokai.api.vo.request.OrganizationalUnitQuery; import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO; -import lombok.AccessLevel; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.Collections; import java.util.List; -import java.util.Optional; /** * @author yanglin @@ -28,7 +28,7 @@ public class OrgGateway { return Collections.emptyList(); OrganizationalUnitQuery req = new OrganizationalUnitQuery(); req.setPageSize((long) ouIdList.size()); - req.setUnitIds(ouIdList); + req.setUnitIds(Lists.newArrayList(Sets.newHashSet(ouIdList))); return BizAssertions.assertResponse(organizationalUnitApi.list(req)); } From 269a04e04d2c2ea28e742bbf7c59b9344effe671 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 19:33:48 +0800 Subject: [PATCH 085/201] =?UTF-8?q?REQ-3345:=20=E8=A1=A5=E5=85=A8=E5=8D=95?= =?UTF-8?q?=E4=BD=8D=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 781421f..e546c89 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -61,7 +61,7 @@ class GroupMessageSyncHandler implements Runnable { continue; } // response.size 不可靠 - if (msgList.size() == limit && head.isSplittable()) { + if (msgList.size() >= limit && head.isSplittable()) { head = timeline.split(); continue; } From cfb366949595da5aaf047ff617562ef77b9b4c69 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 19:35:29 +0800 Subject: [PATCH 086/201] =?UTF-8?q?REQ-3345:=20=E8=A1=A5=E5=85=A8=E5=8D=95?= =?UTF-8?q?=E4=BD=8D=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/job/JobHttpHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/job/JobHttpHandler.java b/im-center-server/src/main/java/cn/axzo/im/job/JobHttpHandler.java index 608e986..60e9111 100644 --- a/im-center-server/src/main/java/cn/axzo/im/job/JobHttpHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/job/JobHttpHandler.java @@ -21,8 +21,7 @@ public class JobHttpHandler { IJobHandler jobHandler = XxlJobExecutor.loadJobHandler(jobName); if (jobHandler == null) return new ReturnT<>(ReturnT.FAIL_CODE, String.format("找不到job: %s", jobName)); - jobHandler.execute(paramObj == null? null : paramObj.toJSONString()); - return ReturnT.SUCCESS; + return jobHandler.execute(paramObj == null ? null : paramObj.toJSONString()); } } \ No newline at end of file From 95adbc88903849926d4ad5588f300f202b0b30a5 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 19:57:42 +0800 Subject: [PATCH 087/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E7=BE=A4?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/entity/GroupMessage.java | 2 +- .../message/GroupMessageSyncHandler.java | 24 +++---------------- .../im/group/message/GroupMessageSyncJob.java | 2 +- .../im/group/message/timeline/TimeNode.java | 5 +++- 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java index e4997a1..f176069 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java @@ -31,7 +31,7 @@ public class GroupMessage { private NimMessageType messageType; private NimFromClientType fromClientType; private String messageIdClient; - private Date sendTime; + private Long sendTime; @TableField(typeHandler = FastjsonTypeHandler.class) private JSONObject body; @TableField(typeHandler = FastjsonTypeHandler.class) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index e546c89..0255900 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -25,8 +25,6 @@ import org.springframework.dao.DuplicateKeyException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.Date; import java.util.List; import static java.util.stream.Collectors.joining; @@ -46,9 +44,8 @@ class GroupMessageSyncHandler implements Runnable { @Override public void run() { long beginMs = service.getMaxSendTime(group.getTid()) - .orElseGet(() -> DateTime.now().minusDays(2).toDate()) - .getTime(); - Timeline timeline = new Timeline(beginMs, System.currentTimeMillis()); + .orElseGet(() -> DateTime.now().minusDays(1).toDate().getTime()); + Timeline timeline = new Timeline(beginMs + 1, System.currentTimeMillis()); // don't change long limit = 100L; TimeNode head = timeline.head(); @@ -107,7 +104,7 @@ class GroupMessageSyncHandler implements Runnable { NimMessageType.class, nimMessage.getType()).orElse(null)); message.setFromClientType(CodeDefinition.findByCode( NimFromClientType.class, nimMessage.getFromclienttype()).orElse(null)); - message.setSendTime(new Date(nimMessage.getSendtime())); + message.setSendTime(nimMessage.getSendtime()); message.setBody(nimMessage.getBody()); message.setMessageIdClient(nimMessage.getMsgidclient()); } @@ -117,12 +114,6 @@ class GroupMessageSyncHandler implements Runnable { private void saveMessages(Collection toSave) { if (CollectionUtils.isEmpty(toSave)) return; - if (toSave.size() == 1) { - // 不知道网易接口那边咋回事, 极端情况下时间不在区间内也会返回一条数据 - // 如果只有一条数据, 这里优先走去重逻辑, 不走唯一键冲突逻辑 - trySaveOneMessage(toSave.iterator().next()); - return; - } try { service.batchSaveMessages(toSave); } catch (DuplicateKeyException ignored) { @@ -134,13 +125,4 @@ class GroupMessageSyncHandler implements Runnable { } } - private void trySaveOneMessage(GroupMessage message) { - GroupMessage savedMessage = service.reloadMessageByNimId(message).orElse(null); - if (savedMessage != null) return; - try { - service.batchSaveMessages(Collections.singletonList(message)); - } catch (DuplicateKeyException ignored) { - } - } - } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 2ec43c0..b0809db 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -114,7 +114,7 @@ public class GroupMessageSyncJob { return groupMessageDao.reloadByNimId(messages); } - Optional getMaxSendTime(Long tid) { + Optional getMaxSendTime(Long tid) { GroupMessage groupMessage = groupMessageDao.getBaseMapper() .selectOne(new QueryWrapper() .select("MAX(send_time) AS send_time") diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java index cd604a8..9fd4b51 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/TimeNode.java @@ -4,6 +4,8 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; +import java.text.SimpleDateFormat; + /** * @author yanglin */ @@ -20,7 +22,8 @@ public class TimeNode { @Override public String toString() { - return String.format("%s~%s", beginMs, endMs); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return String.format("%s~%s %s-%s", beginMs, endMs, sdf.format(beginMs), sdf.format(endMs)); } } \ No newline at end of file From 99b92e3c3b58f9490172ae0798c38de68e4332f5 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 19:58:21 +0800 Subject: [PATCH 088/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E7=BE=A4?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncHandler.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 0255900..c8abf3e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -19,7 +19,6 @@ import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; -import org.joda.time.DateTime; import org.springframework.dao.DuplicateKeyException; import java.util.ArrayList; @@ -43,8 +42,7 @@ class GroupMessageSyncHandler implements Runnable { @Override public void run() { - long beginMs = service.getMaxSendTime(group.getTid()) - .orElseGet(() -> DateTime.now().minusDays(1).toDate().getTime()); + long beginMs = service.getMaxSendTime(group.getTid()).orElse(0L); Timeline timeline = new Timeline(beginMs + 1, System.currentTimeMillis()); // don't change long limit = 100L; From 44b14284da94ea7c0f0726625400c19c364e77c8 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 19:58:43 +0800 Subject: [PATCH 089/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E7=BE=A4?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncHandler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index c8abf3e..0255900 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -19,6 +19,7 @@ import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; +import org.joda.time.DateTime; import org.springframework.dao.DuplicateKeyException; import java.util.ArrayList; @@ -42,7 +43,8 @@ class GroupMessageSyncHandler implements Runnable { @Override public void run() { - long beginMs = service.getMaxSendTime(group.getTid()).orElse(0L); + long beginMs = service.getMaxSendTime(group.getTid()) + .orElseGet(() -> DateTime.now().minusDays(1).toDate().getTime()); Timeline timeline = new Timeline(beginMs + 1, System.currentTimeMillis()); // don't change long limit = 100L; From d6b46971f63a0bb5df808ac17ae506795d073130 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 20:00:43 +0800 Subject: [PATCH 090/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E7=BE=A4?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncHandler.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 0255900..c8abf3e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -19,7 +19,6 @@ import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; -import org.joda.time.DateTime; import org.springframework.dao.DuplicateKeyException; import java.util.ArrayList; @@ -43,8 +42,7 @@ class GroupMessageSyncHandler implements Runnable { @Override public void run() { - long beginMs = service.getMaxSendTime(group.getTid()) - .orElseGet(() -> DateTime.now().minusDays(1).toDate().getTime()); + long beginMs = service.getMaxSendTime(group.getTid()).orElse(0L); Timeline timeline = new Timeline(beginMs + 1, System.currentTimeMillis()); // don't change long limit = 100L; From 714834786b698054a146c341e785ac456ff51dbd Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 20:28:08 +0800 Subject: [PATCH 091/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E7=BE=A4?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/center/api/vo/resp/GroupGetMembersResponse.java | 2 +- .../src/main/java/cn/axzo/im/group/GroupController.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetMembersResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetMembersResponse.java index 07c18fe..bc51aea 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetMembersResponse.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetMembersResponse.java @@ -15,5 +15,5 @@ public class GroupGetMembersResponse { /** * 群成员信息列表 */ - private List member; + private List members; } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java index 46a5e93..edc68f1 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java @@ -59,7 +59,7 @@ public class GroupController implements GroupApi { public ApiResult getMembers(GroupGetMembersRequest request) { List members = groupMemberQueryService.getMembers(request.getTid()); GroupGetMembersResponse response = new GroupGetMembersResponse(); - response.setMember(BeanMapper.copyList(members, GroupMemberInfo.class)); + response.setMembers(BeanMapper.copyList(members, GroupMemberInfo.class)); return ApiResult.ok(response); } From 047d0e98416a78d25bd928f803b5a5ba24732a22 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 5 Feb 2025 20:31:38 +0800 Subject: [PATCH 092/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E7=BE=A4?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index c8abf3e..b889468 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -42,8 +42,8 @@ class GroupMessageSyncHandler implements Runnable { @Override public void run() { - long beginMs = service.getMaxSendTime(group.getTid()).orElse(0L); - Timeline timeline = new Timeline(beginMs + 1, System.currentTimeMillis()); + long maxMs = service.getMaxSendTime(group.getTid()).orElse(0L); + Timeline timeline = new Timeline(maxMs + 1, System.currentTimeMillis()); // don't change long limit = 100L; TimeNode head = timeline.head(); From 1aba2eddc3a38c6f71c2a923ff3d74110e53f1d4 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 09:14:11 +0800 Subject: [PATCH 093/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E7=BE=A4?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncJob.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index b0809db..3e702c2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -20,7 +20,6 @@ import org.joda.time.DateTime; import org.springframework.stereotype.Service; import java.util.Collection; -import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Optional; @@ -101,15 +100,6 @@ public class GroupMessageSyncJob { groupMessageDao.saveBatch(messages); } - Optional reloadMessageByNimId(GroupMessage message) { - if (message == null) - return Optional.empty(); - List messages = reloadMessagesByNimId(Collections.singletonList(message)); - return CollectionUtils.isEmpty(messages) - ? Optional.empty() - : Optional.of(messages.get(0)); - } - List reloadMessagesByNimId(Collection messages) { return groupMessageDao.reloadByNimId(messages); } From 81f64fefa908ff3c531de41669b7d59f3a7e202d Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 09:23:24 +0800 Subject: [PATCH 094/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E4=BA=91?= =?UTF-8?q?=E4=BF=A1msgid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/center/api/vo/resp/GroupMessagePageQueryResponse.java | 2 +- .../im/channel/netease/dto/NimGroupGetMessagesResponse.java | 2 +- .../src/main/java/cn/axzo/im/entity/GroupMessage.java | 2 +- .../src/main/java/cn/axzo/im/group/message/UniqueMessage.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java index 2a6419c..307d253 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java @@ -46,7 +46,7 @@ public class GroupMessagePageQueryResponse { /** * 云信消息ID */ - private Long messageId; + private String messageId; /** * 消息类型. TEXT: 文本, IMAGE: 图片, SPEECH: 语音, VIDEO: 视频, POSITION: 地理位置, FILE: 文件, CUSTOM: 自定义消息 */ diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesResponse.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesResponse.java index 0cc6806..9c36c73 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesResponse.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupGetMessagesResponse.java @@ -20,7 +20,7 @@ public class NimGroupGetMessagesResponse extends NimClient.NimCodeResponse { @Getter public static class NimGroupMessage { private String from; - private Long msgid; + private String msgid; private Long sendtime; private Integer type; private Integer fromclienttype; diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java index f176069..ae5db66 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMessage.java @@ -27,7 +27,7 @@ public class GroupMessage { private Long fromPersonOuId; private AppTypeEnum fromPersonAppType; private YesOrNo isFromRobot; - private Long messageId; + private String messageId; private NimMessageType messageType; private NimFromClientType fromClientType; private String messageIdClient; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/UniqueMessage.java b/im-center-server/src/main/java/cn/axzo/im/group/message/UniqueMessage.java index 7cc9d08..df8cb53 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/UniqueMessage.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/UniqueMessage.java @@ -27,7 +27,7 @@ class UniqueMessage { return message.getTid(); } - public Long getMessageId() { + public String getMessageId() { return message.getMessageId(); } From cb47ad50266ff7cf334338376dd64b69950995a0 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 09:35:13 +0800 Subject: [PATCH 095/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E4=BA=91?= =?UTF-8?q?=E4=BF=A1msgid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index b889468..af47082 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -88,7 +88,8 @@ class GroupMessageSyncHandler implements Runnable { private Collection asGroupMessages(List msgList) { ArrayList messages = new ArrayList<>(); for (NimGroupMessage nimMessage : msgList) { - PersonAccountAttribute person = ImAccountParser.parsePerson(nimMessage.getFrom()).orElse(null); + PersonAccountAttribute person = ImAccountParser + .parsePerson(nimMessage.getFrom()).orElse(null); GroupMessage message = new GroupMessage(); messages.add(message); message.setTid(group.getTid()); From faf9f051d81295716923db7be06e97be6949c2cf Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 09:38:47 +0800 Subject: [PATCH 096/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E4=BA=91?= =?UTF-8?q?=E4=BF=A1msgid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/center/api/vo/PersonAccountAttribute.java | 11 +++++++++++ .../im/group/message/GroupMessageSyncHandler.java | 12 ++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java index 38be41d..27ff894 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java @@ -20,6 +20,9 @@ import java.util.Objects; @NoArgsConstructor public class PersonAccountAttribute { + private static final PersonAccountAttribute ROBOT = + new PersonAccountAttribute("0", 0L, 0L, AppTypeEnum.NONE); + /** * 接收消息的personId */ @@ -42,6 +45,10 @@ public class PersonAccountAttribute { @NotNull(message = "appType不能为空") private AppTypeEnum appType; + public static PersonAccountAttribute robot() { + return ROBOT; + } + public static PersonAccountAttribute cmp(Long personId, Long ouId) { return PersonAccountAttribute.builder() .personId(String.valueOf(personId)) @@ -67,6 +74,10 @@ public class PersonAccountAttribute { return ouId == null ? 0L : ouId; } + public boolean isRobot() { + return this == ROBOT; + } + @Override public boolean equals(Object o) { if (!(o instanceof PersonAccountAttribute)) return false; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index af47082..a9499f1 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -2,7 +2,6 @@ package cn.axzo.im.group.message; import cn.axzo.basics.common.constant.enums.CodeDefinition; import cn.axzo.im.center.api.vo.PersonAccountAttribute; -import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.NimFromClientType; import cn.axzo.im.center.common.enums.NimMessageType; import cn.axzo.im.center.common.enums.YesOrNo; @@ -89,15 +88,16 @@ class GroupMessageSyncHandler implements Runnable { ArrayList messages = new ArrayList<>(); for (NimGroupMessage nimMessage : msgList) { PersonAccountAttribute person = ImAccountParser - .parsePerson(nimMessage.getFrom()).orElse(null); + .parsePerson(nimMessage.getFrom()) + .orElse(PersonAccountAttribute.robot()); GroupMessage message = new GroupMessage(); messages.add(message); message.setTid(group.getTid()); message.setFromAccount(nimMessage.getFrom()); - message.setFromPersonId(person == null ? 0L : Long.parseLong(person.getPersonId())); - message.setFromPersonOuId(person == null ? 0L : person.getOuId()); - message.setFromPersonAppType(person == null ? AppTypeEnum.NONE : person.getAppType()); - message.setIsFromRobot(YesOrNo.valueOf(person == null)); + message.setFromPersonId(Long.parseLong(person.getPersonId())); + message.setFromPersonOuId(person.getOuId()); + message.setFromPersonAppType(person.getAppType()); + message.setIsFromRobot(person.isRobot() ? YesOrNo.YES : YesOrNo.NO); message.setMessageId(nimMessage.getMsgid()); message.setMessageType(CodeDefinition.findByCode( NimMessageType.class, nimMessage.getType()).orElse(null)); From f7cd95c0d23eb51c0ac439cac9d95184e8e46eaf Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 09:39:54 +0800 Subject: [PATCH 097/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E4=BA=91?= =?UTF-8?q?=E4=BF=A1msgid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index a9499f1..97d8162 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import static cn.axzo.im.center.api.vo.PersonAccountAttribute.robot; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; @@ -89,7 +90,7 @@ class GroupMessageSyncHandler implements Runnable { for (NimGroupMessage nimMessage : msgList) { PersonAccountAttribute person = ImAccountParser .parsePerson(nimMessage.getFrom()) - .orElse(PersonAccountAttribute.robot()); + .orElse(robot()); GroupMessage message = new GroupMessage(); messages.add(message); message.setTid(group.getTid()); From 9c37b403c4b7923db63b886f46b6f4d6a578b3d4 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 09:43:52 +0800 Subject: [PATCH 098/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E4=BA=91?= =?UTF-8?q?=E4=BF=A1msgid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/utils/ImAccountParser.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java b/im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java index 4251ed3..b2321b8 100644 --- a/im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java +++ b/im-center-server/src/main/java/cn/axzo/im/utils/ImAccountParser.java @@ -2,6 +2,7 @@ package cn.axzo.im.utils; import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.common.enums.AppTypeEnum; +import org.apache.commons.lang3.math.NumberUtils; import java.util.Optional; import java.util.regex.Matcher; @@ -24,9 +25,9 @@ public class ImAccountParser { PersonAccountAttribute person = new PersonAccountAttribute(); person.setPersonId(personId); - person.setOuId(ouId != null ? Long.parseLong(ouId) : null); + person.setOuId(NumberUtils.isDigits(ouId) ? Long.parseLong(ouId) : null); person.setAppType(appType); return Optional.of(person); } -} +} \ No newline at end of file From b7ea4769d6a9a3e22f6fec2b68beb92165b7a813 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 10:11:51 +0800 Subject: [PATCH 099/201] =?UTF-8?q?REQ-3345:=20=E8=AE=BE=E7=BD=AE=E7=BE=A4?= =?UTF-8?q?=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index d1cb8cf..79a0638 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -37,7 +37,7 @@ public class GroupSupport implements GroupLogger { group.setAvatar(request.getAvatar()); group.setMemberCount((long) request.getOwnerAndMembers().size()); Long memberLimit = request.getMemberLimit(); - group.setMemberLimit(memberLimit == null ? 0L : memberLimit); + group.setMemberLimit(memberLimit == null ? 499L : memberLimit); group.setOwnerAccount(owner); group.setOwnerPersonId(request.getOwner().personIdAsLong()); group.setCreatePersonId(request.getOwner().personIdAsLong()); From 0ee1c985e4224bd39a8e0b0189a294de8f48dc47 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 10:14:51 +0800 Subject: [PATCH 100/201] =?UTF-8?q?REQ-3345:=20=E8=AE=BE=E7=BD=AE=E7=BE=A4?= =?UTF-8?q?=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java index 163335b..f690d5e 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java @@ -52,7 +52,7 @@ public class GroupCreateRequest { private Set members; /** - * 群成员上限 + * 群成员上限, 不传默认为 499 */ private Long memberLimit; From e9afd8ed383adfd408cb9600bf307223c5197cba Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 10:16:24 +0800 Subject: [PATCH 101/201] =?UTF-8?q?REQ-3345:=20=E8=AE=BE=E7=BD=AE=E7=BE=A4?= =?UTF-8?q?=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/GroupProps.java | 20 +++++++++++++++++++ .../java/cn/axzo/im/group/GroupSupport.java | 3 ++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java new file mode 100644 index 0000000..74a64e7 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java @@ -0,0 +1,20 @@ +package cn.axzo.im.group; + +import lombok.Data; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.context.annotation.Configuration; + +/** + * @author yanglin + */ +@Setter +@RefreshScope +@Configuration +@ConfigurationProperties(prefix = "im-center.group") +public class GroupProps { + + public int defaultMemberLimit = 499; + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index 79a0638..d3e7012 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -26,6 +26,7 @@ public class GroupSupport implements GroupLogger { private static final String INTRODUCE_MESSAGE = "邀请您加入群聊"; private final ChatGroupService chatGroupService; + private final GroupProps groupProps; Group buildNewGroup(GroupCreateRequest request, ImAccounts imAccounts) { String owner = imAccounts.findAccount(request.getOwner()).orElse(null); @@ -37,7 +38,7 @@ public class GroupSupport implements GroupLogger { group.setAvatar(request.getAvatar()); group.setMemberCount((long) request.getOwnerAndMembers().size()); Long memberLimit = request.getMemberLimit(); - group.setMemberLimit(memberLimit == null ? 499L : memberLimit); + group.setMemberLimit(memberLimit == null ? groupProps.defaultMemberLimit : memberLimit); group.setOwnerAccount(owner); group.setOwnerPersonId(request.getOwner().personIdAsLong()); group.setCreatePersonId(request.getOwner().personIdAsLong()); From 949806bf7efee189f6ba04176bfca950b82c720b Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 10:16:58 +0800 Subject: [PATCH 102/201] =?UTF-8?q?REQ-3345:=20=E8=AE=BE=E7=BD=AE=E7=BE=A4?= =?UTF-8?q?=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java | 1 - 1 file changed, 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java index 74a64e7..7c05bf3 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java @@ -1,6 +1,5 @@ package cn.axzo.im.group; -import lombok.Data; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.context.config.annotation.RefreshScope; From 3ea5f37f245dab0cfa8aabe01ba40061a0d1c49e Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 10:45:27 +0800 Subject: [PATCH 103/201] =?UTF-8?q?REQ-3345:=20=E8=AE=BE=E7=BD=AE=E7=BE=A4?= =?UTF-8?q?=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/GroupProps.java | 8 +++++++- .../im/group/message/GroupMessageSyncJob.java | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java index 7c05bf3..d5904b3 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java @@ -1,5 +1,6 @@ package cn.axzo.im.group; +import com.alibaba.fastjson.JSON; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.context.config.annotation.RefreshScope; @@ -11,9 +12,14 @@ import org.springframework.context.annotation.Configuration; @Setter @RefreshScope @Configuration -@ConfigurationProperties(prefix = "im-center.group") +@ConfigurationProperties(prefix = "im-group") public class GroupProps { public int defaultMemberLimit = 499; + public int fetchGroupMessageTps = 20; + @Override + public String toString() { + return JSON.toJSONString(this); + } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 3e702c2..04da135 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -9,6 +9,7 @@ import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.dao.repository.GroupMessageDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMessage; +import cn.axzo.im.group.GroupProps; import cn.axzo.im.utils.RecordCursor; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.xxl.job.core.biz.model.ReturnT; @@ -17,6 +18,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.joda.time.DateTime; +import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Service; import java.util.Collection; @@ -25,7 +27,7 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; -import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.Executors; /** * @author yanglin @@ -33,13 +35,14 @@ import java.util.concurrent.ForkJoinPool; @Slf4j @Service @RequiredArgsConstructor -public class GroupMessageSyncJob { +public class GroupMessageSyncJob implements InitializingBean { - private final int tps = 10; - private final ExecutorService executor = new ForkJoinPool(tps); + private int tps; + private ExecutorService executor; private final GroupDao groupDao; private final GroupMessageDao groupMessageDao; private final NimClient nimClient; + private final GroupProps groupProps; private volatile boolean isRunning = false; @@ -119,4 +122,10 @@ public class GroupMessageSyncJob { return nimClient.getGroupMessages(request); } + @Override + public void afterPropertiesSet() { + tps = groupProps.fetchGroupMessageTps; + executor = Executors.newFixedThreadPool(tps + 1); + } + } \ No newline at end of file From 023a07b8846c9f6a2189622846ce8a9bc75c18bb Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 10:46:34 +0800 Subject: [PATCH 104/201] =?UTF-8?q?REQ-3345:=20=E8=AE=BE=E7=BD=AE=E7=BE=A4?= =?UTF-8?q?=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncJob.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 04da135..749f7fc 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -37,13 +37,13 @@ import java.util.concurrent.Executors; @RequiredArgsConstructor public class GroupMessageSyncJob implements InitializingBean { - private int tps; - private ExecutorService executor; private final GroupDao groupDao; private final GroupMessageDao groupMessageDao; private final NimClient nimClient; private final GroupProps groupProps; + private int tps; + private ExecutorService executor; private volatile boolean isRunning = false; @SuppressWarnings("unused") From 2f57d4c0e0202176790bf22d6ac4c7b68df5f14c Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 10:47:36 +0800 Subject: [PATCH 105/201] =?UTF-8?q?REQ-3345:=20=E8=AE=BE=E7=BD=AE=E7=BE=A4?= =?UTF-8?q?=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/message/GroupMessageSyncJob.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 749f7fc..b8103fb 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -12,6 +12,7 @@ import cn.axzo.im.entity.GroupMessage; import cn.axzo.im.group.GroupProps; import cn.axzo.im.utils.RecordCursor; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.taobao.api.internal.util.NamedThreadFactory; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.annotation.XxlJob; import lombok.RequiredArgsConstructor; @@ -125,7 +126,8 @@ public class GroupMessageSyncJob implements InitializingBean { @Override public void afterPropertiesSet() { tps = groupProps.fetchGroupMessageTps; - executor = Executors.newFixedThreadPool(tps + 1); + executor = Executors.newFixedThreadPool( + tps + 1, new NamedThreadFactory(GroupMessageSyncJob.class.getName())); } } \ No newline at end of file From bfd737faf19c9e289f22ca88d6d6cc0aaef4c9c5 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 10:51:34 +0800 Subject: [PATCH 106/201] =?UTF-8?q?REQ-3345:=20=E8=AE=BE=E7=BD=AE=E7=BE=A4?= =?UTF-8?q?=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java | 2 +- .../main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java index d5904b3..993a9b2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java @@ -16,7 +16,7 @@ import org.springframework.context.annotation.Configuration; public class GroupProps { public int defaultMemberLimit = 499; - public int fetchGroupMessageTps = 20; + public int syncMessageType = 20; @Override public String toString() { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index b8103fb..3386a0d 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -125,7 +125,7 @@ public class GroupMessageSyncJob implements InitializingBean { @Override public void afterPropertiesSet() { - tps = groupProps.fetchGroupMessageTps; + tps = groupProps.syncMessageType; executor = Executors.newFixedThreadPool( tps + 1, new NamedThreadFactory(GroupMessageSyncJob.class.getName())); } From f18d4a025ab09d1c8e6fc286ba634f79f2019250 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 10:51:54 +0800 Subject: [PATCH 107/201] =?UTF-8?q?REQ-3345:=20=E8=AE=BE=E7=BD=AE=E7=BE=A4?= =?UTF-8?q?=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java | 2 +- .../main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java index 993a9b2..77ad054 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java @@ -16,7 +16,7 @@ import org.springframework.context.annotation.Configuration; public class GroupProps { public int defaultMemberLimit = 499; - public int syncMessageType = 20; + public int syncMessageTps = 20; @Override public String toString() { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 3386a0d..3193f68 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -125,7 +125,7 @@ public class GroupMessageSyncJob implements InitializingBean { @Override public void afterPropertiesSet() { - tps = groupProps.syncMessageType; + tps = groupProps.syncMessageTps; executor = Executors.newFixedThreadPool( tps + 1, new NamedThreadFactory(GroupMessageSyncJob.class.getName())); } From 22c31ef7bb1c476167587f8e885cd3c22758ecc3 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 10:58:24 +0800 Subject: [PATCH 108/201] =?UTF-8?q?REQ-3345:=20=E8=AE=BE=E7=BD=AE=E7=BE=A4?= =?UTF-8?q?=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupProps.java | 6 ++++-- .../src/main/java/cn/axzo/im/group/GroupSupport.java | 3 ++- .../java/cn/axzo/im/group/message/GroupMessageSyncJob.java | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java index 77ad054..e026657 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java @@ -1,6 +1,7 @@ package cn.axzo.im.group; import com.alibaba.fastjson.JSON; +import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.context.config.annotation.RefreshScope; @@ -10,13 +11,14 @@ import org.springframework.context.annotation.Configuration; * @author yanglin */ @Setter +@Getter @RefreshScope @Configuration @ConfigurationProperties(prefix = "im-group") public class GroupProps { - public int defaultMemberLimit = 499; - public int syncMessageTps = 20; + private int defaultMemberLimit = 499; + private int syncMessageTps = 20; @Override public String toString() { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index d3e7012..b7929bd 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -38,7 +38,8 @@ public class GroupSupport implements GroupLogger { group.setAvatar(request.getAvatar()); group.setMemberCount((long) request.getOwnerAndMembers().size()); Long memberLimit = request.getMemberLimit(); - group.setMemberLimit(memberLimit == null ? groupProps.defaultMemberLimit : memberLimit); + group.setMemberLimit(memberLimit == null + ? groupProps.getDefaultMemberLimit() : memberLimit); group.setOwnerAccount(owner); group.setOwnerPersonId(request.getOwner().personIdAsLong()); group.setCreatePersonId(request.getOwner().personIdAsLong()); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 3193f68..6f42d88 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -125,7 +125,7 @@ public class GroupMessageSyncJob implements InitializingBean { @Override public void afterPropertiesSet() { - tps = groupProps.syncMessageTps; + tps = groupProps.getSyncMessageTps(); executor = Executors.newFixedThreadPool( tps + 1, new NamedThreadFactory(GroupMessageSyncJob.class.getName())); } From d47208ed1e23f59a6ee5629590a3a22c38daa4cf Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 11:21:47 +0800 Subject: [PATCH 109/201] =?UTF-8?q?REQ-3345:=20=E5=A4=84=E7=90=86=E7=BE=A4?= =?UTF-8?q?=E7=9A=84=E4=B8=9A=E5=8A=A1=E6=89=A9=E5=B1=95=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupSupport.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index b7929bd..32c5f0a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -15,6 +15,9 @@ import lombok.extern.slf4j.Slf4j; import org.slf4j.helpers.MessageFormatter; import org.springframework.stereotype.Component; +import java.util.Collections; +import java.util.Map; + /** * @author yanglin */ @@ -61,7 +64,10 @@ public class GroupSupport implements GroupLogger { nimRequest.setIcon(request.getAvatar()); nimRequest.addCustom(Group.CUSTOM_GROUP_TYPE, request.getGroupType()); nimRequest.addCustom(Group.CUSTOM_BIZ_CODE, request.getBizCode()); - nimRequest.addCustom(Group.CUSTOM_BIZ_GROUP_INFO, request.getBizGroupInfo()); + Map bizGroupInfo = request.getBizGroupInfo(); + if (bizGroupInfo == null) + bizGroupInfo = Collections.emptyMap(); + nimRequest.addCustom(Group.CUSTOM_BIZ_GROUP_INFO, bizGroupInfo); return nimRequest; } From 88c1d86612682832bf244a13f208dbc457b77a12 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 11:39:10 +0800 Subject: [PATCH 110/201] =?UTF-8?q?REQ-3345:=20=E5=A4=84=E7=90=86=E7=BE=A4?= =?UTF-8?q?=E7=9A=84=E4=B8=9A=E5=8A=A1=E6=89=A9=E5=B1=95=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../center/api/vo/mq/GroupChangedMessage.java | 19 +++++++++++++++ .../im/center/common/enums/GroupType.java | 2 +- .../cn/axzo/im/event/inner/EventTypeEnum.java | 2 ++ .../cn/axzo/im/group/GroupBroadcaster.java | 24 ++++++++++++------- .../java/cn/axzo/im/group/GroupManager.java | 15 ++++++++---- 5 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupChangedMessage.java diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupChangedMessage.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupChangedMessage.java new file mode 100644 index 0000000..ac42f8d --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/mq/GroupChangedMessage.java @@ -0,0 +1,19 @@ +package cn.axzo.im.center.api.vo.mq; + +import cn.axzo.im.center.api.vo.group.GroupInfo; +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupChangedMessage extends MqMessage { + + /** + * 群信息 + */ + private GroupInfo group; + +} diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupType.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupType.java index a021eed..7dcb688 100644 --- a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupType.java +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupType.java @@ -10,7 +10,7 @@ import lombok.RequiredArgsConstructor; @Getter @RequiredArgsConstructor public enum GroupType implements CodeDefinition { - NONE("随意"), + NONE("未指定"), VISA("变洽签"), WORKSPACE("项目群"), WORKSPACE_OU("项目单位群"), diff --git a/im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java b/im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java index 3e5ee66..a4e52e3 100644 --- a/im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java +++ b/im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java @@ -14,6 +14,8 @@ public enum EventTypeEnum { MESSAGE_HISTORY_CREATED("message-history", "message-history-created", "发送记录创建"), MESSAGE_HISTORY_UPDATED("message-history", "message-history-updated", "发送记录修改"), MESSAGE_CHAT_GROUP_CREATE("chat-group", "chat-group-create", "群聊创建[项目]"), + GROUP_CREATED("group", "group-created", "创建群聊"), + GROUP_DISMISSED("group", "group-dismissed", "群解散"), GROUP_ADD_MEMBERS("group", "group-add-members", "添加群聊成员"), GROUP_REMOVE_MEMBERS("group", "group-remove-members", "移除群聊成员"), UPDATE_AVATAR("profile", "update-avatar", "头像更新"), diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java index e6dc02a..55ef367 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java @@ -4,6 +4,7 @@ import cn.axzo.basics.common.BeanMapper; import cn.axzo.framework.rocketmq.Event; import cn.axzo.im.center.api.vo.group.GroupInfo; import cn.axzo.im.center.api.vo.group.GroupMemberInfo; +import cn.axzo.im.center.api.vo.mq.GroupChangedMessage; import cn.axzo.im.center.api.vo.mq.GroupMembersChangeMessage; import cn.axzo.im.config.MqProducer; import cn.axzo.im.dao.repository.GroupDao; @@ -25,15 +26,22 @@ class GroupBroadcaster { private final MqProducer mqProducer; private final GroupDao groupDao; - void fireMembersAdded(Group group, Collection accounts) { - fireMembersChanged(group, accounts, EventTypeEnum.GROUP_ADD_MEMBERS); + void fireGroupChanged(Group group, EventTypeEnum eventType) { + GroupChangedMessage message = new GroupChangedMessage(); + message.setGroup(BeanMapper.copyBean(group, GroupInfo.class)); + Event event = Event.builder() + .targetId(group.getTid() + "") + .targetType(eventType.getModel()) + .eventCode(eventType.getEventCode()) + .shardingKey(group.getTid() + "") + .data(message) + .build(); + mqProducer.send(event); } - void fireMembersRemoved(Group group, Collection accounts) { - fireMembersChanged(group, accounts, EventTypeEnum.GROUP_REMOVE_MEMBERS); - } - - private void fireMembersChanged(Group group, Collection accounts, EventTypeEnum eventType) { + void fireMembersChanged(Group group, + Collection accounts, + EventTypeEnum eventType) { if (accounts.isEmpty()) return; Group effectiveGroup = groupDao.getById(group.getId()); for (GroupMember account : accounts) { @@ -44,7 +52,7 @@ class GroupBroadcaster { .targetId(group.getTid() + "") .targetType(eventType.getModel()) .eventCode(eventType.getEventCode()) - .shardingKey(group.getId() + "") + .shardingKey(group.getTid() + "") .data(message) .build(); mqProducer.send(event); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 628c6b2..47e9274 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -21,6 +21,7 @@ import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMember; +import cn.axzo.im.event.inner.EventTypeEnum; import cn.axzo.im.group.member.GroupMemberSyncer; import cn.axzo.im.service.AccountService; import cn.axzo.im.service.domain.ImAccounts; @@ -77,8 +78,9 @@ public class GroupManager { BizAssertions.assertTrue(nimResponse.isSuccess(), "创建群失败: {}", nimResponse.getDesc()); groupDao.updateTid(group.getId(), nimResponse.getTid()); group = groupDao.getById(group.getId()); + groupBroadcaster.fireGroupChanged(group, EventTypeEnum.GROUP_CREATED); groupMemberSyncer.syncMembers(group); - groupBroadcaster.fireMembersAdded(group, groupMemberDao.getByTid(nimResponse.getTid())); + groupBroadcaster.fireMembersChanged(group, groupMemberDao.getByTid(nimResponse.getTid()), EventTypeEnum.GROUP_ADD_MEMBERS); GroupCreateResponse response = new GroupCreateResponse(); response.setTid(nimResponse.getTid()); response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( @@ -97,6 +99,8 @@ public class GroupManager { if (!nimResponse.isGroupNotFoundError()) BizAssertions.assertTrue(nimResponse.isSuccess(), "解散群失败: {}", nimResponse.getDesc()); groupDao.setDismissed(group.getTid()); + group = groupDao.getById(group.getId()); + groupBroadcaster.fireGroupChanged(group, EventTypeEnum.GROUP_DISMISSED); } @Transactional @@ -128,8 +132,10 @@ public class GroupManager { BizAssertions.assertTrue(nimResponse.isSuccess(), "添加群成员失败: {}", nimResponse.getDesc()); // sync members 2 groupMemberSyncer.syncMembers(group); - groupBroadcaster.fireMembersAdded(group, groupMemberDao - .getByPersons(group.getTid(), toAddMembers)); + groupBroadcaster.fireMembersChanged( + group, + groupMemberDao.getByPersons(group.getTid(), toAddMembers), + EventTypeEnum.GROUP_ADD_MEMBERS); GroupAddMembersResponse response = new GroupAddMembersResponse(); response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( groupSupport, "添加群成员", group, request.getMembers())); @@ -158,7 +164,8 @@ public class GroupManager { log.info("移除群成员, request={}, response={}", nimRequest, nimResponse); groupMemberSyncer.syncMembers(group); // 不比较直接发消息 - groupBroadcaster.fireMembersRemoved(group, toRemoveMembers); + groupBroadcaster.fireMembersChanged( + group, toRemoveMembers, EventTypeEnum.GROUP_REMOVE_MEMBERS); } @NotNull From 7bd2ca0d07f93001c6f3d85e088aeb278df97574 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 11:44:39 +0800 Subject: [PATCH 111/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/center/api/enums/MqEventType.java | 6 +-- .../cn/axzo/im/group/GroupBroadcaster.java | 6 +-- .../java/cn/axzo/im/group/GroupManager.java | 12 +++--- .../ChatGroupChangeOwnerEventHandler.java | 14 +++---- .../chatgroup/ChatGroupEventHandler.java | 6 +-- ...anizationalNodeUserChangeEventHandler.java | 38 +++++++++---------- ...PersonProfileAvatarUpdateEventHandler.java | 4 +- .../im/service/impl/ChatGroupServiceImpl.java | 3 +- .../impl/MessageHistoryServiceImpl.java | 4 +- 9 files changed, 47 insertions(+), 46 deletions(-) rename im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java => im-center-api/src/main/java/cn/axzo/im/center/api/enums/MqEventType.java (93%) diff --git a/im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java b/im-center-api/src/main/java/cn/axzo/im/center/api/enums/MqEventType.java similarity index 93% rename from im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java rename to im-center-api/src/main/java/cn/axzo/im/center/api/enums/MqEventType.java index a4e52e3..1469d24 100644 --- a/im-center-server/src/main/java/cn/axzo/im/event/inner/EventTypeEnum.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/enums/MqEventType.java @@ -1,4 +1,4 @@ -package cn.axzo.im.event.inner; +package cn.axzo.im.center.api.enums; import cn.axzo.framework.rocketmq.Event; import lombok.Getter; @@ -9,7 +9,7 @@ import lombok.Getter; * @Created by lilong */ @Getter -public enum EventTypeEnum { +public enum MqEventType { MESSAGE_HISTORY_CREATED("message-history", "message-history-created", "发送记录创建"), MESSAGE_HISTORY_UPDATED("message-history", "message-history-updated", "发送记录修改"), @@ -27,7 +27,7 @@ public enum EventTypeEnum { SAAS_ROLE_USER_RELATION_UPSERT("saas-role-user-relation", "saas-role-user-relation-upsert", "更新用户角色信息"), ; - EventTypeEnum(String model, String name, String desc) { + MqEventType(String model, String name, String desc) { this.eventCode = Event.EventCode.builder() .module(model) .name(name) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java index 55ef367..c5886c7 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java @@ -2,6 +2,7 @@ package cn.axzo.im.group; import cn.axzo.basics.common.BeanMapper; import cn.axzo.framework.rocketmq.Event; +import cn.axzo.im.center.api.enums.MqEventType; import cn.axzo.im.center.api.vo.group.GroupInfo; import cn.axzo.im.center.api.vo.group.GroupMemberInfo; import cn.axzo.im.center.api.vo.mq.GroupChangedMessage; @@ -10,7 +11,6 @@ import cn.axzo.im.config.MqProducer; import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMember; -import cn.axzo.im.event.inner.EventTypeEnum; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -26,7 +26,7 @@ class GroupBroadcaster { private final MqProducer mqProducer; private final GroupDao groupDao; - void fireGroupChanged(Group group, EventTypeEnum eventType) { + void fireGroupChanged(Group group, MqEventType eventType) { GroupChangedMessage message = new GroupChangedMessage(); message.setGroup(BeanMapper.copyBean(group, GroupInfo.class)); Event event = Event.builder() @@ -41,7 +41,7 @@ class GroupBroadcaster { void fireMembersChanged(Group group, Collection accounts, - EventTypeEnum eventType) { + MqEventType eventType) { if (accounts.isEmpty()) return; Group effectiveGroup = groupDao.getById(group.getId()); for (GroupMember account : accounts) { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 47e9274..e38b9a3 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -1,6 +1,7 @@ package cn.axzo.im.group; import cn.axzo.basics.common.exception.ServiceException; +import cn.axzo.im.center.api.enums.MqEventType; import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; @@ -21,7 +22,6 @@ import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMember; -import cn.axzo.im.event.inner.EventTypeEnum; import cn.axzo.im.group.member.GroupMemberSyncer; import cn.axzo.im.service.AccountService; import cn.axzo.im.service.domain.ImAccounts; @@ -78,9 +78,9 @@ public class GroupManager { BizAssertions.assertTrue(nimResponse.isSuccess(), "创建群失败: {}", nimResponse.getDesc()); groupDao.updateTid(group.getId(), nimResponse.getTid()); group = groupDao.getById(group.getId()); - groupBroadcaster.fireGroupChanged(group, EventTypeEnum.GROUP_CREATED); + groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_CREATED); groupMemberSyncer.syncMembers(group); - groupBroadcaster.fireMembersChanged(group, groupMemberDao.getByTid(nimResponse.getTid()), EventTypeEnum.GROUP_ADD_MEMBERS); + groupBroadcaster.fireMembersChanged(group, groupMemberDao.getByTid(nimResponse.getTid()), MqEventType.GROUP_ADD_MEMBERS); GroupCreateResponse response = new GroupCreateResponse(); response.setTid(nimResponse.getTid()); response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( @@ -100,7 +100,7 @@ public class GroupManager { BizAssertions.assertTrue(nimResponse.isSuccess(), "解散群失败: {}", nimResponse.getDesc()); groupDao.setDismissed(group.getTid()); group = groupDao.getById(group.getId()); - groupBroadcaster.fireGroupChanged(group, EventTypeEnum.GROUP_DISMISSED); + groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_DISMISSED); } @Transactional @@ -135,7 +135,7 @@ public class GroupManager { groupBroadcaster.fireMembersChanged( group, groupMemberDao.getByPersons(group.getTid(), toAddMembers), - EventTypeEnum.GROUP_ADD_MEMBERS); + MqEventType.GROUP_ADD_MEMBERS); GroupAddMembersResponse response = new GroupAddMembersResponse(); response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( groupSupport, "添加群成员", group, request.getMembers())); @@ -165,7 +165,7 @@ public class GroupManager { groupMemberSyncer.syncMembers(group); // 不比较直接发消息 groupBroadcaster.fireMembersChanged( - group, toRemoveMembers, EventTypeEnum.GROUP_REMOVE_MEMBERS); + group, toRemoveMembers, MqEventType.GROUP_REMOVE_MEMBERS); } @NotNull diff --git a/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/ChatGroupChangeOwnerEventHandler.java b/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/ChatGroupChangeOwnerEventHandler.java index 8a2f68c..f6f44ab 100644 --- a/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/ChatGroupChangeOwnerEventHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/ChatGroupChangeOwnerEventHandler.java @@ -5,12 +5,12 @@ import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.im.center.api.enums.MqEventType; import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupGenericSearchReq; import cn.axzo.im.center.api.vo.req.chatgroup.UserAddChatGroupReq; import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.ChatGroupUserDataSourceEnum; import cn.axzo.im.entity.ChatGroup; -import cn.axzo.im.event.inner.EventTypeEnum; import cn.axzo.im.event.payload.SaasRoleUserRelationUpsertPayload; import cn.axzo.im.gateway.TyrApiGateway; import cn.axzo.im.service.ChatGroupService; @@ -55,8 +55,8 @@ public class ChatGroupChangeOwnerEventHandler implements EventHandler, Initializ @Override public void onEvent(Event event, EventConsumer.Context context) { - if (!EventTypeEnum.SAAS_ROLE_USER_RELATION_REMOVED.getName().equalsIgnoreCase(event.getEventCode().getName()) - && !EventTypeEnum.SAAS_ROLE_USER_RELATION_UPSERT.getName().equalsIgnoreCase(event.getEventCode().getName())) { + if (!MqEventType.SAAS_ROLE_USER_RELATION_REMOVED.getName().equalsIgnoreCase(event.getEventCode().getName()) + && !MqEventType.SAAS_ROLE_USER_RELATION_UPSERT.getName().equalsIgnoreCase(event.getEventCode().getName())) { return; } @@ -64,13 +64,13 @@ public class ChatGroupChangeOwnerEventHandler implements EventHandler, Initializ long start = System.currentTimeMillis(); try { //角色删除 - if (EventTypeEnum.SAAS_ROLE_USER_RELATION_REMOVED.getName().equalsIgnoreCase(event.getEventCode().getName())) { + if (MqEventType.SAAS_ROLE_USER_RELATION_REMOVED.getName().equalsIgnoreCase(event.getEventCode().getName())) { this.handleMqMessageRoleRemove(event); log.info("ChatGroupChangeOwnerEventHandler-handle-roleRemove mq event, event={},used={}ms", JSON.toJSONString(event), System.currentTimeMillis() - start); return; } //角色变更 - if (EventTypeEnum.SAAS_ROLE_USER_RELATION_UPSERT.getName().equalsIgnoreCase(event.getEventCode().getName())) { + if (MqEventType.SAAS_ROLE_USER_RELATION_UPSERT.getName().equalsIgnoreCase(event.getEventCode().getName())) { this.handleMqMessageRoleUpsert(event); log.info("ChatGroupChangeOwnerEventHandler-handle-upsert mq event, event={},used={}ms", JSON.toJSONString(event), System.currentTimeMillis() - start); } @@ -213,8 +213,8 @@ public class ChatGroupChangeOwnerEventHandler implements EventHandler, Initializ @Override public void afterPropertiesSet() { - Event.EventCode removedEventCode = new Event.EventCode(EventTypeEnum.SAAS_ROLE_USER_RELATION_REMOVED.getModel(), EventTypeEnum.SAAS_ROLE_USER_RELATION_REMOVED.getName()); - Event.EventCode upsertEventCode = new Event.EventCode(EventTypeEnum.SAAS_ROLE_USER_RELATION_UPSERT.getModel(), EventTypeEnum.SAAS_ROLE_USER_RELATION_UPSERT.getName()); + Event.EventCode removedEventCode = new Event.EventCode(MqEventType.SAAS_ROLE_USER_RELATION_REMOVED.getModel(), MqEventType.SAAS_ROLE_USER_RELATION_REMOVED.getName()); + Event.EventCode upsertEventCode = new Event.EventCode(MqEventType.SAAS_ROLE_USER_RELATION_UPSERT.getModel(), MqEventType.SAAS_ROLE_USER_RELATION_UPSERT.getName()); eventConsumer.registerHandler(removedEventCode, this); eventConsumer.registerHandler(upsertEventCode, this); } diff --git a/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/ChatGroupEventHandler.java b/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/ChatGroupEventHandler.java index 99bcf97..eb9b932 100644 --- a/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/ChatGroupEventHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/ChatGroupEventHandler.java @@ -4,10 +4,10 @@ import cn.axzo.basics.profiles.dto.basic.PersonProfileDto; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.im.center.api.enums.MqEventType; import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupCreateReq; import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.ChatGroupUserDataSourceEnum; -import cn.axzo.im.event.inner.EventTypeEnum; import cn.axzo.im.event.payload.ChatGroupCreatePayload; import cn.axzo.im.gateway.ProfilesApiGateway; import cn.axzo.im.service.ChatGroupService; @@ -52,7 +52,7 @@ public class ChatGroupEventHandler implements EventHandler, InitializingBean { @Override public void onEvent(Event event, EventConsumer.Context context) { - if (!EventTypeEnum.MESSAGE_CHAT_GROUP_CREATE.getName().equalsIgnoreCase(event.getEventCode().getName())) { + if (!MqEventType.MESSAGE_CHAT_GROUP_CREATE.getName().equalsIgnoreCase(event.getEventCode().getName())) { return; } @@ -140,7 +140,7 @@ public class ChatGroupEventHandler implements EventHandler, InitializingBean { @Override public void afterPropertiesSet() { - Event.EventCode eventCode = new Event.EventCode(EventTypeEnum.MESSAGE_CHAT_GROUP_CREATE.getModel(), EventTypeEnum.MESSAGE_CHAT_GROUP_CREATE.getName()); + Event.EventCode eventCode = new Event.EventCode(MqEventType.MESSAGE_CHAT_GROUP_CREATE.getModel(), MqEventType.MESSAGE_CHAT_GROUP_CREATE.getName()); eventConsumer.registerHandler(eventCode, this); } } diff --git a/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/OrganizationalNodeUserChangeEventHandler.java b/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/OrganizationalNodeUserChangeEventHandler.java index 6100da6..94ab7ba 100644 --- a/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/OrganizationalNodeUserChangeEventHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/OrganizationalNodeUserChangeEventHandler.java @@ -4,6 +4,7 @@ import cn.axzo.apollo.core.service.ServiceException; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.im.center.api.enums.MqEventType; import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupCreateReq; import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupGenericSearchReq; import cn.axzo.im.center.common.enums.AppTypeEnum; @@ -13,7 +14,6 @@ import cn.axzo.im.channel.netease.dto.ChatGroupQueryResponse; import cn.axzo.im.config.JobCodeProperties; import cn.axzo.im.entity.ChatGroup; import cn.axzo.im.entity.dto.OrganizationalNodeUserDTO; -import cn.axzo.im.event.inner.EventTypeEnum; import cn.axzo.im.event.payload.OrganizationalNodeUser; import cn.axzo.im.event.payload.OrganizationalNodeUserPayload; import cn.axzo.im.event.payload.OrganizationalNodeUserUpsertedPayload; @@ -77,10 +77,10 @@ public class OrganizationalNodeUserChangeEventHandler implements EventHandler, I @Override public void onEvent(Event event, EventConsumer.Context context) { - if (!EventTypeEnum.NODE_USER_CREATE.getName().equalsIgnoreCase(event.getEventCode().getName()) - && !EventTypeEnum.NODE_USER_UPDATE.getName().equalsIgnoreCase(event.getEventCode().getName()) - && !EventTypeEnum.NODE_USER_DELETE.getName().equalsIgnoreCase(event.getEventCode().getName()) - && !EventTypeEnum.NODE_USER_UPSERTED.getName().equalsIgnoreCase(event.getEventCode().getName())) { + if (!MqEventType.NODE_USER_CREATE.getName().equalsIgnoreCase(event.getEventCode().getName()) + && !MqEventType.NODE_USER_UPDATE.getName().equalsIgnoreCase(event.getEventCode().getName()) + && !MqEventType.NODE_USER_DELETE.getName().equalsIgnoreCase(event.getEventCode().getName()) + && !MqEventType.NODE_USER_UPSERTED.getName().equalsIgnoreCase(event.getEventCode().getName())) { return; } log.info("im-organizationalNodeUserChange-start mq,eventModule:{},eventName:{}, event:{}", event.getEventCode().getModule(), event.getEventCode().getName(), JSON.toJSONString(event)); @@ -114,8 +114,8 @@ public class OrganizationalNodeUserChangeEventHandler implements EventHandler, I private OrgNodeUserPayLoadBean buildPayload(Event event) { - if (EventTypeEnum.NODE_USER_CREATE.getName().equalsIgnoreCase(event.getEventCode().getName()) - || EventTypeEnum.NODE_USER_UPDATE.getName().equalsIgnoreCase(event.getEventCode().getName())) { + if (MqEventType.NODE_USER_CREATE.getName().equalsIgnoreCase(event.getEventCode().getName()) + || MqEventType.NODE_USER_UPDATE.getName().equalsIgnoreCase(event.getEventCode().getName())) { //解析数据 OrganizationalNodeUserPayload payload = event.normalizedData(OrganizationalNodeUserPayload.class); OrgNodeUserPayLoad newNodeUser = this.buildPayload(payload.getId()); @@ -123,7 +123,7 @@ public class OrganizationalNodeUserChangeEventHandler implements EventHandler, I .build(); } - if (EventTypeEnum.NODE_USER_DELETE.getName().equalsIgnoreCase(event.getEventCode().getName())) { + if (MqEventType.NODE_USER_DELETE.getName().equalsIgnoreCase(event.getEventCode().getName())) { //解析数据 OrganizationalNodeUserPayload payload = event.normalizedData(OrganizationalNodeUserPayload.class); OrgNodeUserPayLoad newNodeUser = this.buildDeletePayload(payload); @@ -131,7 +131,7 @@ public class OrganizationalNodeUserChangeEventHandler implements EventHandler, I .build(); } - if (EventTypeEnum.NODE_USER_UPSERTED.getName().equalsIgnoreCase(event.getEventCode().getName())) { + if (MqEventType.NODE_USER_UPSERTED.getName().equalsIgnoreCase(event.getEventCode().getName())) { //解析数据 OrganizationalNodeUserUpsertedPayload payload = event.normalizedData(OrganizationalNodeUserUpsertedPayload.class); if (Objects.isNull(payload.getOldValue()) || Objects.isNull(payload.getNewValue())) { @@ -157,7 +157,7 @@ public class OrganizationalNodeUserChangeEventHandler implements EventHandler, I .nodeId(newNodeUserVO.getOrganizationalNodeId()) .jobId(newNodeUserVO.getOrganizationalJobId()) .personId(newNodeUserVO.getPersonId()) - .tag(EventTypeEnum.NODE_USER_UPDATE.getName()) + .tag(MqEventType.NODE_USER_UPDATE.getName()) .build(); } @@ -172,7 +172,7 @@ public class OrganizationalNodeUserChangeEventHandler implements EventHandler, I .nodeId(payload.getOrganizationalNodeId()) .jobId(payload.getOrganizationalJobId()) .personId(payload.getPersonId()) - .tag(EventTypeEnum.NODE_USER_DELETE.getName()) + .tag(MqEventType.NODE_USER_DELETE.getName()) .build(); } @@ -188,7 +188,7 @@ public class OrganizationalNodeUserChangeEventHandler implements EventHandler, I .nodeId(oldValue.getOrganizationalNodeId()) .jobId(oldValue.getOrganizationalJobId()) .personId(oldValue.getPersonId()) - .tag(EventTypeEnum.NODE_USER_UPDATE.getName()) + .tag(MqEventType.NODE_USER_UPDATE.getName()) .build(); } @@ -361,17 +361,17 @@ public class OrganizationalNodeUserChangeEventHandler implements EventHandler, I log.info("doEnterOrExitChatGroup,tag:{},groupId:{},currentImAccount:{},owner:{},containJobCode:{}", tag, chatGroup.getId(), currentImAccount, owner, containJobCode); } //orgNodeUser新增人,并且当前群不包含人 - if (tag.equals(EventTypeEnum.NODE_USER_CREATE.getName()) && containJobCode) { + if (tag.equals(MqEventType.NODE_USER_CREATE.getName()) && containJobCode) { //拉人进群 return this.chatGroupService.userAddChatGroup(chatGroup.getId(), chatGroup.getTid(), owner, Sets.newHashSet(currentImAccount), chatGroup.getName(), ChatGroupUserDataSourceEnum.USER_CHANGE, 0); } //orgNodeUser删除人 并且当前成员不包含人 - if (tag.equals(EventTypeEnum.NODE_USER_DELETE.getName()) && members.contains(currentImAccount)) { + if (tag.equals(MqEventType.NODE_USER_DELETE.getName()) && members.contains(currentImAccount)) { //踢出群 return this.chatGroupService.kickChatGroup(chatGroup.getId(), chatGroup.getTid(), owner,currentImAccount); } //以下orgNodeUser更新 - if (!tag.equals(EventTypeEnum.NODE_USER_UPDATE.getName())) { + if (!tag.equals(MqEventType.NODE_USER_UPDATE.getName())) { return false; } @@ -407,10 +407,10 @@ public class OrganizationalNodeUserChangeEventHandler implements EventHandler, I @Override public void afterPropertiesSet() { - Event.EventCode nodeUserCreateEventCode = new Event.EventCode(EventTypeEnum.NODE_USER_CREATE.getModel(), EventTypeEnum.NODE_USER_CREATE.getName()); - Event.EventCode nodeUserUpdateEventCode = new Event.EventCode(EventTypeEnum.NODE_USER_UPDATE.getModel(), EventTypeEnum.NODE_USER_UPDATE.getName()); - Event.EventCode nodeUserDeleteEventCode = new Event.EventCode(EventTypeEnum.NODE_USER_DELETE.getModel(), EventTypeEnum.NODE_USER_DELETE.getName()); - Event.EventCode nodeUserUpsertedEventCode = new Event.EventCode(EventTypeEnum.NODE_USER_UPSERTED.getModel(), EventTypeEnum.NODE_USER_UPSERTED.getName()); + Event.EventCode nodeUserCreateEventCode = new Event.EventCode(MqEventType.NODE_USER_CREATE.getModel(), MqEventType.NODE_USER_CREATE.getName()); + Event.EventCode nodeUserUpdateEventCode = new Event.EventCode(MqEventType.NODE_USER_UPDATE.getModel(), MqEventType.NODE_USER_UPDATE.getName()); + Event.EventCode nodeUserDeleteEventCode = new Event.EventCode(MqEventType.NODE_USER_DELETE.getModel(), MqEventType.NODE_USER_DELETE.getName()); + Event.EventCode nodeUserUpsertedEventCode = new Event.EventCode(MqEventType.NODE_USER_UPSERTED.getModel(), MqEventType.NODE_USER_UPSERTED.getName()); eventConsumer.registerHandler(nodeUserCreateEventCode, this); eventConsumer.registerHandler(nodeUserUpdateEventCode, this); diff --git a/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/PersonProfileAvatarUpdateEventHandler.java b/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/PersonProfileAvatarUpdateEventHandler.java index 19a47df..3584e8c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/PersonProfileAvatarUpdateEventHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/handler/chatgroup/PersonProfileAvatarUpdateEventHandler.java @@ -7,10 +7,10 @@ import cn.axzo.basics.profiles.dto.mq.ProfileMQBaseEntity; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventHandler; +import cn.axzo.im.center.api.enums.MqEventType; import cn.axzo.im.channel.netease.dto.NimGetAccountInfoResponse; import cn.axzo.im.entity.AccountRegister; import cn.axzo.im.entity.bo.AccountQueryParam; -import cn.axzo.im.event.inner.EventTypeEnum; import cn.axzo.im.service.AccountService; import cn.azxo.framework.common.model.CommonResponse; import com.alibaba.fastjson.JSON; @@ -90,7 +90,7 @@ public class PersonProfileAvatarUpdateEventHandler implements EventHandler, Init @Override public void afterPropertiesSet() { - Event.EventCode eventCode = new Event.EventCode(EventTypeEnum.UPDATE_AVATAR.getModel(), EventTypeEnum.UPDATE_AVATAR.getName()); + Event.EventCode eventCode = new Event.EventCode(MqEventType.UPDATE_AVATAR.getModel(), MqEventType.UPDATE_AVATAR.getName()); eventConsumer.registerHandler(eventCode, this); } } diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java index 94292de..c6480a6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java @@ -91,7 +91,8 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; -import static cn.axzo.im.event.inner.EventTypeEnum.MESSAGE_CHAT_GROUP_CREATE; +import static cn.axzo.im.center.api.enums.MqEventType.MESSAGE_CHAT_GROUP_CREATE; + /** * @author xudawei@axzo.cn diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageHistoryServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageHistoryServiceImpl.java index 78d4a66..2bc68f6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageHistoryServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageHistoryServiceImpl.java @@ -48,9 +48,9 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.im.center.api.enums.MqEventType.MESSAGE_HISTORY_CREATED; +import static cn.axzo.im.center.api.enums.MqEventType.MESSAGE_HISTORY_UPDATED; import static cn.axzo.im.config.BizResultCode.ACQUIRE_RATE_LIMITER_FAIL; -import static cn.axzo.im.event.inner.EventTypeEnum.MESSAGE_HISTORY_CREATED; -import static cn.axzo.im.event.inner.EventTypeEnum.MESSAGE_HISTORY_UPDATED; import static java.util.stream.Collectors.toList; @Slf4j From 4bc6ec2f8a85173deddbf956634cb926c4c9fc4e Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 11:47:31 +0800 Subject: [PATCH 112/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index e38b9a3..7079bcf 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -80,7 +80,9 @@ public class GroupManager { group = groupDao.getById(group.getId()); groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_CREATED); groupMemberSyncer.syncMembers(group); - groupBroadcaster.fireMembersChanged(group, groupMemberDao.getByTid(nimResponse.getTid()), MqEventType.GROUP_ADD_MEMBERS); + groupBroadcaster.fireMembersChanged(group, + groupMemberDao.getByTid(nimResponse.getTid()), + MqEventType.GROUP_ADD_MEMBERS); GroupCreateResponse response = new GroupCreateResponse(); response.setTid(nimResponse.getTid()); response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( @@ -132,8 +134,7 @@ public class GroupManager { BizAssertions.assertTrue(nimResponse.isSuccess(), "添加群成员失败: {}", nimResponse.getDesc()); // sync members 2 groupMemberSyncer.syncMembers(group); - groupBroadcaster.fireMembersChanged( - group, + groupBroadcaster.fireMembersChanged(group, groupMemberDao.getByPersons(group.getTid(), toAddMembers), MqEventType.GROUP_ADD_MEMBERS); GroupAddMembersResponse response = new GroupAddMembersResponse(); @@ -164,8 +165,8 @@ public class GroupManager { log.info("移除群成员, request={}, response={}", nimRequest, nimResponse); groupMemberSyncer.syncMembers(group); // 不比较直接发消息 - groupBroadcaster.fireMembersChanged( - group, toRemoveMembers, MqEventType.GROUP_REMOVE_MEMBERS); + groupBroadcaster.fireMembersChanged(group, + toRemoveMembers, MqEventType.GROUP_REMOVE_MEMBERS); } @NotNull From 4d09ce2ee3ea90d0cbf4115700a6eaed6d0f294f Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 16:45:05 +0800 Subject: [PATCH 113/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/channel/netease/NimChannelService.java | 9 +++ .../java/cn/axzo/im/group/GroupManager.java | 6 ++ .../java/cn/axzo/im/group/GroupSupport.java | 1 + .../im/group/member/GroupMemberSyncer.java | 3 + .../im/group/message/GroupMessageSyncJob.java | 2 +- .../support/GroupManipulateRateLimiter.java | 58 +++++++++++++++++++ .../im/group/{ => support}/GroupProps.java | 10 +++- .../im/service/impl/ChatGroupServiceImpl.java | 2 +- 8 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/support/GroupManipulateRateLimiter.java rename im-center-server/src/main/java/cn/axzo/im/group/{ => support}/GroupProps.java (69%) diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java index b04a51a..276e62d 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java @@ -27,6 +27,7 @@ import cn.axzo.im.channel.netease.dto.RegisterResponse; import cn.axzo.im.channel.netease.dto.RegisterUpdateRequest; import cn.axzo.im.channel.netease.dto.UserAddChatGroupRequest; import cn.axzo.im.channel.netease.dto.UserAddChatGroupResponse; +import cn.axzo.im.group.support.GroupManipulateRateLimiter; import cn.axzo.im.utils.ImProperties; import cn.hutool.core.util.ObjectUtil; import cn.hutool.http.HttpRequest; @@ -133,6 +134,9 @@ public class NimChannelService implements IMChannelProvider { @Resource private ImProperties props; + @Resource + private GroupManipulateRateLimiter rateLimiter; + @Override public String getProviderAppKey() { return appKeyUtil.getAppKey(); @@ -395,6 +399,7 @@ public class NimChannelService implements IMChannelProvider { Map authHeaderMap = buildAuthHeader(getProviderAppKey(), getProviderAppSecret()); log.warn("chatGroupCreate-请求网易云信,URL:{},Header:{},请求参数:{}", CHAT_GROUP_CREATE, JSONUtil.toJsonStr(authHeaderMap), JSONUtil.toJsonStr(paramMap)); + rateLimiter.requireCreateGroup(); HttpResponse response = HttpRequest.post(CHAT_GROUP_CREATE).addHeaders(authHeaderMap) .form(paramMap).timeout(5000).execute(); String result = response.body(); @@ -452,6 +457,7 @@ public class NimChannelService implements IMChannelProvider { Map authHeaderMap = buildAuthHeader(getProviderAppKey(), getProviderAppSecret()); log.warn("userAddChatGroup-请求网易云信,URL:{},Header:{},请求参数:{}", USER_ADD_CHAT_GROUP, JSONUtil.toJsonStr(authHeaderMap), JSONUtil.toJsonStr(paramMap)); + rateLimiter.requireAddMember(); HttpResponse response = HttpRequest.post(USER_ADD_CHAT_GROUP).addHeaders(authHeaderMap) .form(paramMap).timeout(5000).execute(); String result = response.body(); @@ -484,6 +490,7 @@ public class NimChannelService implements IMChannelProvider { Map authHeaderMap = buildAuthHeader(getProviderAppKey(), getProviderAppSecret()); log.warn("kickChatGroup-请求网易云信,URL:{},Header:{},请求参数:{}", KICK_CHAT_GROUP, JSONUtil.toJsonStr(authHeaderMap), JSONUtil.toJsonStr(paramMap)); + rateLimiter.requireRemoveMember(); HttpResponse response = HttpRequest.post(KICK_CHAT_GROUP).addHeaders(authHeaderMap) .form(paramMap).timeout(5000).execute(); String result = response.body(); @@ -540,6 +547,7 @@ public class NimChannelService implements IMChannelProvider { Map authHeaderMap = buildAuthHeader(getProviderAppKey(), getProviderAppSecret()); log.warn("chatGroupQuery-请求网易云信,URL:{},Header:{},请求参数:{}", CHAT_GROUP_QUERY, JSONUtil.toJsonStr(authHeaderMap), JSONUtil.toJsonStr(paramMap)); + rateLimiter.requireGetGroupInfo(); HttpResponse response = HttpRequest.post(CHAT_GROUP_QUERY).addHeaders(authHeaderMap) .form(paramMap).timeout(5000).execute(); String result = response.body(); @@ -580,6 +588,7 @@ public class NimChannelService implements IMChannelProvider { Map authHeaderMap = buildAuthHeader(getProviderAppKey(), getProviderAppSecret()); log.warn("changeOwner-请求网易云信,URL:{},Header:{},请求参数:{}", CHANGE_OWNER, JSONUtil.toJsonStr(authHeaderMap), JSONUtil.toJsonStr(paramMap)); + rateLimiter.requireChangeOwner(); HttpResponse response = HttpRequest.post(CHANGE_OWNER).addHeaders(authHeaderMap) .form(paramMap).timeout(5000).execute(); String result = response.body(); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 7079bcf..2680f4d 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -23,6 +23,7 @@ import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMember; import cn.axzo.im.group.member.GroupMemberSyncer; +import cn.axzo.im.group.support.GroupManipulateRateLimiter; import cn.axzo.im.service.AccountService; import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.BizAssertions; @@ -55,6 +56,7 @@ public class GroupManager { private final AccountService accountService; private final GroupBroadcaster groupBroadcaster; private final GroupMemberSyncer groupMemberSyncer; + private final GroupManipulateRateLimiter rateLimiter; @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { @@ -73,6 +75,7 @@ public class GroupManager { } NimGroupCreateRequest nimRequest = groupSupport .buildNimCreateGroupRequest(request, imAccounts); + rateLimiter.requireCreateGroup(); NimGroupCreateResponse nimResponse = nimClient.createGroup(nimRequest); log.info("创建群, request={}, response={}", nimRequest, nimResponse); BizAssertions.assertTrue(nimResponse.isSuccess(), "创建群失败: {}", nimResponse.getDesc()); @@ -96,6 +99,7 @@ public class GroupManager { if (group.isDismissed()) return; NimGroupDismissRequest nimRequest = groupSupport .buildNimDismissGroupRequest(group.getOwnerAccount(), group); + rateLimiter.requireDismissGroup(); NimGroupDismissResponse nimResponse = nimClient.dismissGroup(nimRequest); log.info("解散群, request={}, response={}", nimRequest, nimResponse); if (!nimResponse.isGroupNotFoundError()) @@ -129,6 +133,7 @@ public class GroupManager { NimGroupAddMembersRequest nimRequest = groupSupport .buildAddMembersRequest(group, group.getOwnerAccount(), imAccounts); // add members + rateLimiter.requireAddMember(); NimGroupAddMembersResponse nimResponse = nimClient.addGroupMembers(nimRequest); log.info("添加群成员, request={}, response={}", nimRequest, nimResponse); BizAssertions.assertTrue(nimResponse.isSuccess(), "添加群成员失败: {}", nimResponse.getDesc()); @@ -160,6 +165,7 @@ public class GroupManager { return; NimGroupRemoveMembersRequest nimRequest = groupSupport .buildRemoveMembersRequest(group, group.getOwnerAccount(), imAccounts); + rateLimiter.requireRemoveMember(); // 不判断NIM响应状态, 因为前端可能已经调用app sdk移除过成员了(支持重复移除) NimGroupRemoveMembersResponse nimResponse = nimClient.removeGroupMembers(nimRequest); log.info("移除群成员, request={}, response={}", nimRequest, nimResponse); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index 32c5f0a..cf19205 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -7,6 +7,7 @@ import cn.axzo.im.channel.netease.dto.NimGroupCreateRequest; import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersRequest; import cn.axzo.im.entity.Group; +import cn.axzo.im.group.support.GroupProps; import cn.axzo.im.service.ChatGroupService; import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.BizAssertions; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index f87af88..c7f14d6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -13,6 +13,7 @@ import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMember; +import cn.axzo.im.group.support.GroupManipulateRateLimiter; import cn.axzo.im.utils.BizAssertions; import cn.axzo.im.utils.ImAccountParser; import lombok.RequiredArgsConstructor; @@ -35,6 +36,7 @@ public class GroupMemberSyncer { private final GroupMemberDao groupMemberDao; private final GroupDao groupDao; private final NimClient nimClient; + private final GroupManipulateRateLimiter rateLimiter; public void syncMembers(Group group) { NimGroupInfo groupInfo = fetchGroupInfo(group).orElse(null); @@ -50,6 +52,7 @@ public class GroupMemberSyncer { NimGroupGetInfoRequest nimRequest = new NimGroupGetInfoRequest(); nimRequest.setTid(group.getTid()); long start = System.currentTimeMillis(); + rateLimiter.requireGetGroupInfo(); NimGroupGetInfoResponse nimResponse = nimClient.getGroupInfo(nimRequest); log.info("获取群信息, request={}, response={}, timeUsed={}", nimRequest, nimResponse, System.currentTimeMillis() - start); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 6f42d88..8726f62 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -9,7 +9,7 @@ import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.dao.repository.GroupMessageDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMessage; -import cn.axzo.im.group.GroupProps; +import cn.axzo.im.group.support.GroupProps; import cn.axzo.im.utils.RecordCursor; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.taobao.api.internal.util.NamedThreadFactory; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupManipulateRateLimiter.java b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupManipulateRateLimiter.java new file mode 100644 index 0000000..1cfc047 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupManipulateRateLimiter.java @@ -0,0 +1,58 @@ +package cn.axzo.im.group.support; + +import com.google.common.util.concurrent.RateLimiter; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Component; + +/** + * @author yanglin + */ +@Component +@RequiredArgsConstructor +public class GroupManipulateRateLimiter implements InitializingBean { + + private final GroupProps groupProps; + + private RateLimiter createGroupLimiter; + private RateLimiter dismissGroupLimiter; + private RateLimiter addMemberLimiter; + private RateLimiter removeMemberLimiter; + private RateLimiter getGroupInfoLimiter; + private RateLimiter changeOwnerLimiter; + + public void requireCreateGroup() { + createGroupLimiter.acquire(); + } + + public void requireDismissGroup() { + dismissGroupLimiter.acquire(); + } + + public void requireAddMember() { + addMemberLimiter.acquire(); + } + + public void requireRemoveMember() { + removeMemberLimiter.acquire(); + } + + public void requireGetGroupInfo() { + getGroupInfoLimiter.acquire(); + } + + public void requireChangeOwner() { + changeOwnerLimiter.acquire(); + } + + @Override + public void afterPropertiesSet() { + createGroupLimiter = RateLimiter.create(groupProps.getCreateGroupTps()); + dismissGroupLimiter = RateLimiter.create(groupProps.getDismissGroupTps()); + addMemberLimiter = RateLimiter.create(groupProps.getAddMemberTps()); + removeMemberLimiter = RateLimiter.create(groupProps.getRemoveMemberTps()); + getGroupInfoLimiter = RateLimiter.create(groupProps.getGetGroupInfoTps()); + changeOwnerLimiter = RateLimiter.create(groupProps.getChangeOwnerTps()); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java similarity index 69% rename from im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java rename to im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java index e026657..c629224 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupProps.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java @@ -1,4 +1,4 @@ -package cn.axzo.im.group; +package cn.axzo.im.group.support; import com.alibaba.fastjson.JSON; import lombok.Getter; @@ -18,10 +18,18 @@ import org.springframework.context.annotation.Configuration; public class GroupProps { private int defaultMemberLimit = 499; + private int syncMessageTps = 20; + private int createGroupTps = 10; + private int dismissGroupTps = 10; + private int addMemberTps = 10; + private int removeMemberTps = 10; + private int getGroupInfoTps = 10; + private int changeOwnerTps = 10; @Override public String toString() { return JSON.toJSONString(this); } + } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java index c6480a6..05a28da 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java @@ -48,6 +48,7 @@ import cn.axzo.im.config.MqProducer; import cn.axzo.im.dao.mapper.ChatGroupMapper; import cn.axzo.im.entity.ChatGroup; import cn.axzo.im.entity.Group; +import cn.axzo.im.entity.dto.OrganizationalNodeUserDTO; import cn.axzo.im.event.payload.ChatGroupCreatePayload; import cn.axzo.im.gateway.OrganizationalNodeUserApiGateway; import cn.axzo.im.gateway.ProfilesApiGateway; @@ -62,7 +63,6 @@ import cn.axzo.im.service.OperateLogService; import cn.axzo.im.utils.BizAssertions; import cn.axzo.im.utils.DateFormatUtil; import cn.axzo.im.utils.JobCodeUtils; -import cn.axzo.im.entity.dto.OrganizationalNodeUserDTO; import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO; import cn.hutool.core.bean.BeanUtil; From 7937ee8b571847a6a7a26e1943f2bd8c73df5a5f Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 16:48:05 +0800 Subject: [PATCH 114/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java | 4 ++++ .../src/main/java/cn/axzo/im/service/domain/ImAccounts.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java index 27ff894..c490e93 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java @@ -71,6 +71,10 @@ public class PersonAccountAttribute { } public Long ouIdOrDefault() { + return getOuIdOrDefault(ouId); + } + + public static Long getOuIdOrDefault(Long ouId) { return ouId == null ? 0L : ouId; } diff --git a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java index ad24833..24f60ba 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java @@ -72,7 +72,7 @@ public class ImAccounts { private static boolean isAccountMatchPerson(PersonAccountAttribute person, AccountRegister account) { return person.getPersonId().equals(account.getAccountId()) && person.getAppType().getCode().equals(account.getAppType()) - && Objects.equals(person.getOuId(), account.getOuId()); + && Objects.equals(person.ouIdOrDefault(), PersonAccountAttribute.getOuIdOrDefault(account.getOuId())); } } \ No newline at end of file From 6f85a266794b23ea60f3735a521f1cd3933c8110 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 17:09:05 +0800 Subject: [PATCH 115/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{MergedGroupSupport.java => LegacyGroupSupport.java} | 2 +- .../cn/axzo/im/service/impl/MessageTaskServiceImpl.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) rename im-center-server/src/main/java/cn/axzo/im/group/{MergedGroupSupport.java => LegacyGroupSupport.java} (98%) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/MergedGroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/LegacyGroupSupport.java similarity index 98% rename from im-center-server/src/main/java/cn/axzo/im/group/MergedGroupSupport.java rename to im-center-server/src/main/java/cn/axzo/im/group/LegacyGroupSupport.java index 674a635..6dfc7d6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/MergedGroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/LegacyGroupSupport.java @@ -22,7 +22,7 @@ import static java.util.stream.Collectors.toList; */ @Component @RequiredArgsConstructor -public class MergedGroupSupport { +public class LegacyGroupSupport { private final GroupDao groupDao; private final ChatGroupMapper chatGroupMapper; diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java index 2b40d9c..44a1bbe 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java @@ -13,7 +13,7 @@ import cn.axzo.im.entity.AccountRegister; import cn.axzo.im.entity.MessageHistory; import cn.axzo.im.entity.MessageTask; import cn.axzo.im.enums.MessageHistoryStatus; -import cn.axzo.im.group.MergedGroupSupport; +import cn.axzo.im.group.LegacyGroupSupport; import cn.axzo.im.push.NimPushService; import cn.axzo.im.push.PushPeer; import cn.axzo.im.service.AccountRegisterService; @@ -79,7 +79,7 @@ public class MessageTaskServiceImpl extends ServiceImpl result = new HashSet<>(); - result.addAll(mergedGroupSupport.getGroupAccounts(imAccounts)); - result.addAll(mergedGroupSupport.getGroupCatAccounts(imAccounts)); + result.addAll(legacyGroupSupport.getGroupAccounts(imAccounts)); + result.addAll(legacyGroupSupport.getGroupCatAccounts(imAccounts)); return result; } From 598523e43f89595d723dbb264b3967d19426a0b2 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 17:22:32 +0800 Subject: [PATCH 116/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-center-server/src/main/java/cn/axzo/im/entity/Group.java | 5 ++--- .../src/main/java/cn/axzo/im/group/GroupManager.java | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/Group.java b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java index f964d6e..28c229e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/Group.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java @@ -42,9 +42,8 @@ public class Group { @TableField(typeHandler = FastjsonTypeHandler.class) private RecordExt recordExt; - public boolean isMemberLimitReached(int memberCount) { - if (memberLimit <= 0) return false; - return memberCount > memberLimit; + public boolean addMoreMembers(int memberCount) { + return memberLimit <= 0 || memberCount <= memberLimit; } public boolean isDismissed() { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 2680f4d..d38eeee 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -65,7 +65,7 @@ public class GroupManager { String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); Group group = groupSupport.buildNewGroup(request, imAccounts); - BizAssertions.assertFalse(group.isMemberLimitReached( + BizAssertions.assertTrue(group.addMoreMembers( request.getOwnerAndMembers().size()), "无法创建群, 群成员数量超过上限" + group.getMemberLimit()); try { groupDao.save(group); @@ -122,7 +122,7 @@ public class GroupManager { .collect(toSet()); if (toAddMembers.isEmpty()) return new GroupAddMembersResponse(); - if (group.isMemberLimitReached(preMembers.size() + toAddMembers.size())) + if (!group.addMoreMembers(preMembers.size() + toAddMembers.size())) throw new ServiceException("群聊人数上限" + group.getMemberLimit() + "人, 请删除部分已选人员"); ImAccounts imAccounts = accountService.getOrCreateImAccounts(toAddMembers); if (imAccounts.isAccountEmpty()) { From 5c7dd410d93bbdc822a66b594b34214519a69c5d Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 17:25:05 +0800 Subject: [PATCH 117/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupSupport.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index cf19205..343b6cc 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -42,8 +42,9 @@ public class GroupSupport implements GroupLogger { group.setAvatar(request.getAvatar()); group.setMemberCount((long) request.getOwnerAndMembers().size()); Long memberLimit = request.getMemberLimit(); - group.setMemberLimit(memberLimit == null - ? groupProps.getDefaultMemberLimit() : memberLimit); + if (memberLimit == null) + memberLimit = (long)groupProps.getDefaultMemberLimit(); + group.setMemberLimit(memberLimit); group.setOwnerAccount(owner); group.setOwnerPersonId(request.getOwner().personIdAsLong()); group.setCreatePersonId(request.getOwner().personIdAsLong()); From 20197be1ef06b05214b40e8add05350438aa2316 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 17:28:27 +0800 Subject: [PATCH 118/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/group/message/GroupMessageSyncHandler.java | 14 +++++++------- .../axzo/im/group/message/timeline/Timeline.java | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 97d8162..8d45970 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -46,22 +46,22 @@ class GroupMessageSyncHandler implements Runnable { Timeline timeline = new Timeline(maxMs + 1, System.currentTimeMillis()); // don't change long limit = 100L; - TimeNode head = timeline.head(); - while (head != null) { - NimGroupGetMessagesResponse response = fetchMessages(head, limit); + TimeNode current = timeline.head(); + while (current != null) { + NimGroupGetMessagesResponse response = fetchMessages(current, limit); BizAssertions.assertTrue(response.isSuccess(), "fetch group messages failed"); List msgList = response.getMsgs(); if (CollectionUtils.isEmpty(msgList)) { - head = timeline.consume(); + current = timeline.advance(); continue; } // response.size 不可靠 - if (msgList.size() >= limit && head.isSplittable()) { - head = timeline.split(); + if (msgList.size() >= limit && current.isSplittable()) { + current = timeline.split(); continue; } saveMessages(asGroupMessages(msgList)); - head = timeline.consume(); + current = timeline.advance(); } } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java index eb88669..bb07941 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/timeline/Timeline.java @@ -38,7 +38,7 @@ public class Timeline { return head(); } - public TimeNode consume() { + public TimeNode advance() { TimeNode node = head(); BizAssertions.assertNotNull(node, "timeline is empty"); nodes.removeFirst(); From 2860e1c1f7c602347bcbae8d984c90df80d8da19 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 17:51:44 +0800 Subject: [PATCH 119/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/LegacyGroupSupport.java | 11 +++++++++-- .../axzo/im/service/impl/MessageTaskServiceImpl.java | 6 +----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/LegacyGroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/LegacyGroupSupport.java index 6dfc7d6..02f5fbc 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/LegacyGroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/LegacyGroupSupport.java @@ -4,6 +4,7 @@ import cn.axzo.im.dao.mapper.ChatGroupMapper; import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.entity.ChatGroup; import cn.axzo.im.entity.Group; +import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.math.NumberUtils; @@ -27,7 +28,13 @@ public class LegacyGroupSupport { private final GroupDao groupDao; private final ChatGroupMapper chatGroupMapper; - public List getGroupAccounts(Set groupIds) { + public Set getMergedAccounts(Set groupIds) { + Set accounts = Sets.newHashSet(getGroupAccounts(groupIds)); + accounts.addAll(getGroupCatAccounts(groupIds)); + return accounts; + } + + private List getGroupAccounts(Set groupIds) { if (CollectionUtils.isEmpty(groupIds)) return Collections.emptyList(); if (parseLongs(groupIds).isEmpty()) @@ -40,7 +47,7 @@ public class LegacyGroupSupport { .collect(toList()); } - public List getGroupCatAccounts(Set groupIds) { + private List getGroupCatAccounts(Set groupIds) { if (CollectionUtils.isEmpty(groupIds)) return Collections.emptyList(); return chatGroupMapper.selectList( diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java index 44a1bbe..f4d1843 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java @@ -48,7 +48,6 @@ import org.springframework.util.CollectionUtils; import java.util.Collections; import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -413,10 +412,7 @@ public class MessageTaskServiceImpl extends ServiceImpl result = new HashSet<>(); - result.addAll(legacyGroupSupport.getGroupAccounts(imAccounts)); - result.addAll(legacyGroupSupport.getGroupCatAccounts(imAccounts)); - return result; + return legacyGroupSupport.getMergedAccounts(imAccounts); } private String resolveBody(MessageTask.ReceivePerson receivePerson, From 58c560ee03b0eabcbec3fb6591c4f8a837493d66 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 6 Feb 2025 17:58:41 +0800 Subject: [PATCH 120/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/center/api/enums/MqEventType.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/enums/MqEventType.java b/im-center-api/src/main/java/cn/axzo/im/center/api/enums/MqEventType.java index 1469d24..a53e162 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/enums/MqEventType.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/enums/MqEventType.java @@ -37,8 +37,8 @@ public enum MqEventType { this.desc = desc; } - private String model; - private String name; - private String desc; - private Event.EventCode eventCode; + private final String model; + private final String name; + private final String desc; + private final Event.EventCode eventCode; } From 3c64e82a5c6246b222e4e503d6ea3760aaf5e36a Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 09:36:43 +0800 Subject: [PATCH 121/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E5=91=8A?= =?UTF-8?q?=E8=AD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/GroupSupport.java | 7 +------ .../cn/axzo/im/service/ChatGroupService.java | 18 +++++++++++------- .../im/service/impl/ChatGroupServiceImpl.java | 9 +++++++++ 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index 343b6cc..e9212c6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -13,7 +13,6 @@ import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.BizAssertions; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.slf4j.helpers.MessageFormatter; import org.springframework.stereotype.Component; import java.util.Collections; @@ -102,11 +101,7 @@ public class GroupSupport implements GroupLogger { } public void log(String message, Object... args) { - try { - chatGroupService.sendDingRobot(MessageFormatter.arrayFormat(message, args).getMessage()); - } catch (Exception e) { - log.warn("发送钉钉机器人消息失败", e); - } + chatGroupService.log(message, args); } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java b/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java index 354cc44..119b641 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java @@ -18,6 +18,7 @@ import cn.axzo.im.center.api.vo.resp.HistoryMsgQueryResp; import cn.axzo.im.center.common.enums.ChatGroupUserDataSourceEnum; import cn.axzo.im.entity.ChatGroup; import cn.axzo.im.entity.dto.OrganizationalNodeUserDTO; +import cn.axzo.im.group.GroupLogger; import cn.hutool.core.lang.Pair; import com.baomidou.mybatisplus.extension.service.IService; @@ -29,7 +30,7 @@ import java.util.Set; * @date 2024/11/05 * @desc 群聊 */ -public interface ChatGroupService extends IService { +public interface ChatGroupService extends IService, GroupLogger { /** * 创建群聊 @@ -79,9 +80,10 @@ public interface ChatGroupService extends IService { /** * 拉人进群 - * @param tid 群Id - * @param owner 群主 - * @param members im账号集合 + * + * @param tid 群Id + * @param owner 群主 + * @param members im账号集合 * @param groupName 群名称 */ boolean userAddChatGroup(Long chatGroupId, String tid, String owner, Set members, String groupName, ChatGroupUserDataSourceEnum dataSource, Integer executeCount); @@ -93,15 +95,17 @@ public interface ChatGroupService extends IService { /** * 踢出群 - * @param tid 群Id - * @param owner 群主 + * + * @param tid 群Id + * @param owner 群主 * @param imAccount im账号 */ boolean kickChatGroup(Long chatGroupId, String tid, String owner, String imAccount); /** * 更改群主 - * @param chatGroupId 群聊Id + * + * @param chatGroupId 群聊Id * @param oldAccIdOwner 原群主账号 * @param newAccIdOwner 新群主账号 */ diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java index 05a28da..beda881 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java @@ -77,6 +77,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.compress.utils.Lists; import org.apache.commons.lang3.BooleanUtils; +import org.slf4j.helpers.MessageFormatter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; @@ -766,6 +767,14 @@ public class ChatGroupServiceImpl extends ServiceImpl Date: Fri, 7 Feb 2025 13:50:06 +0800 Subject: [PATCH 122/201] =?UTF-8?q?REQ-3345:=20=E5=8F=91=E9=80=81=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=97=B6=E9=87=8D=E6=96=B0=E6=9F=A5=E8=AF=A2=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/GroupBroadcaster.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java index c5886c7..4ba1f3c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java @@ -27,13 +27,14 @@ class GroupBroadcaster { private final GroupDao groupDao; void fireGroupChanged(Group group, MqEventType eventType) { + Group effectiveGroup = groupDao.getById(group.getId()); GroupChangedMessage message = new GroupChangedMessage(); - message.setGroup(BeanMapper.copyBean(group, GroupInfo.class)); + message.setGroup(BeanMapper.copyBean(effectiveGroup, GroupInfo.class)); Event event = Event.builder() - .targetId(group.getTid() + "") + .targetId(effectiveGroup.getTid() + "") .targetType(eventType.getModel()) .eventCode(eventType.getEventCode()) - .shardingKey(group.getTid() + "") + .shardingKey(effectiveGroup.getTid() + "") .data(message) .build(); mqProducer.send(event); @@ -49,10 +50,10 @@ class GroupBroadcaster { message.setGroup(BeanMapper.copyBean(effectiveGroup, GroupInfo.class)); message.setMember(BeanMapper.copyBean(account, GroupMemberInfo.class)); Event event = Event.builder() - .targetId(group.getTid() + "") + .targetId(effectiveGroup.getTid() + "") .targetType(eventType.getModel()) .eventCode(eventType.getEventCode()) - .shardingKey(group.getTid() + "") + .shardingKey(effectiveGroup.getTid() + "") .data(message) .build(); mqProducer.send(event); From c27fbb079f1f74b46e74c31c172e81a0dc6f181a Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 14:00:08 +0800 Subject: [PATCH 123/201] =?UTF-8?q?REQ-3345:=20=E5=8F=91=E9=80=81=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=97=B6=E9=87=8D=E6=96=B0=E6=9F=A5=E8=AF=A2=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/group/member/GroupMemberSyncer.java | 22 ++++++++----------- .../message/GroupMessageSyncHandler.java | 2 +- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index c7f14d6..dba0113 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -1,7 +1,6 @@ package cn.axzo.im.group.member; import cn.axzo.im.center.api.vo.PersonAccountAttribute; -import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.GroupMemberType; import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.channel.netease.client.NimClient; @@ -25,6 +24,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import static cn.axzo.im.center.api.vo.PersonAccountAttribute.robot; + /** * @author yanglin */ @@ -66,24 +67,19 @@ public class GroupMemberSyncer { private List parseGroupMembers(Group group, NimGroupInfo groupInfo) { ArrayList accounts = new ArrayList<>(); for (NimGroupMemberInfo member : groupInfo.getOwnerAndMembers()) { - PersonAccountAttribute person = ImAccountParser.parsePerson(member.getAccid()).orElse(null); + PersonAccountAttribute person = ImAccountParser + .parsePerson(member.getAccid()) + .orElse(robot()); GroupMember account = new GroupMember(); accounts.add(account); account.setTid(group.getTid()); account.setImAccount(member.getAccid()); account.setMemberType(groupInfo.getOwner().equals(member) ? GroupMemberType.OWNER : GroupMemberType.MEMBER); - if (person == null) { - account.setPersonId(0L); - account.setPersonOuId(0L); - account.setAppType(AppTypeEnum.NONE); - account.setIsRobot(YesOrNo.YES); - } else { - account.setPersonId(Long.valueOf(person.getPersonId())); - account.setPersonOuId(person.ouIdOrDefault()); - account.setAppType(person.getAppType()); - account.setIsRobot(YesOrNo.NO); - } + account.setPersonId(person.personIdAsLong()); + account.setPersonOuId(person.ouIdOrDefault()); + account.setAppType(person.getAppType()); + account.setIsRobot(person.isRobot() ? YesOrNo.YES : YesOrNo.NO); } return accounts; } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java index 8d45970..d10786b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncHandler.java @@ -95,7 +95,7 @@ class GroupMessageSyncHandler implements Runnable { messages.add(message); message.setTid(group.getTid()); message.setFromAccount(nimMessage.getFrom()); - message.setFromPersonId(Long.parseLong(person.getPersonId())); + message.setFromPersonId(person.personIdAsLong()); message.setFromPersonOuId(person.getOuId()); message.setFromPersonAppType(person.getAppType()); message.setIsFromRobot(person.isRobot() ? YesOrNo.YES : YesOrNo.NO); From f406ae33a46c9465c063dd73109c858b9da80115 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 14:07:10 +0800 Subject: [PATCH 124/201] =?UTF-8?q?REQ-3345:=20=E4=BF=9D=E7=95=99=E7=BE=A4?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/entity/GroupMember.java | 2 ++ .../main/java/cn/axzo/im/group/member/GroupMemberSyncer.java | 1 + 2 files changed, 3 insertions(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java index 0a11855..761b25a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java @@ -2,6 +2,7 @@ package cn.axzo.im.entity; import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.GroupMemberType; +import cn.axzo.im.center.common.enums.GroupType; import cn.axzo.im.center.common.enums.YesOrNo; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Getter; @@ -18,6 +19,7 @@ import java.util.Date; public class GroupMember { private Long id; private Long tid; + private GroupType groupType; private String imAccount; private Long personId; private Long personOuId; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index dba0113..e5cdaaa 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -74,6 +74,7 @@ public class GroupMemberSyncer { accounts.add(account); account.setTid(group.getTid()); account.setImAccount(member.getAccid()); + account.setGroupType(group.getType()); account.setMemberType(groupInfo.getOwner().equals(member) ? GroupMemberType.OWNER : GroupMemberType.MEMBER); account.setPersonId(person.personIdAsLong()); From 90c537b45bb0a6ff0737764cfb9f2fcf17ca7a62 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 14:10:57 +0800 Subject: [PATCH 125/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E7=BE=A4?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/member/GroupMemberSyncer.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index e5cdaaa..cf2cdf6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -19,6 +19,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; +import org.springframework.transaction.support.TransactionTemplate; import java.util.ArrayList; import java.util.List; @@ -38,15 +39,18 @@ public class GroupMemberSyncer { private final GroupDao groupDao; private final NimClient nimClient; private final GroupManipulateRateLimiter rateLimiter; + private final TransactionTemplate transactionTemplate; public void syncMembers(Group group) { NimGroupInfo groupInfo = fetchGroupInfo(group).orElse(null); if (groupInfo == null) return; - groupMemberDao.deleteAccounts(group.getTid()); List accounts = parseGroupMembers(group, groupInfo); - if (CollectionUtils.isNotEmpty(accounts)) - groupMemberDao.saveBatch(accounts); - groupDao.updateMembersCount(group.getTid(), accounts.size()); + transactionTemplate.executeWithoutResult(unused -> { + groupMemberDao.deleteAccounts(group.getTid()); + if (CollectionUtils.isNotEmpty(accounts)) + groupMemberDao.saveBatch(accounts); + groupDao.updateMembersCount(group.getTid(), accounts.size()); + }); } private Optional fetchGroupInfo(Group group) { From eb1deb440de6c9aee9f367ebe533917c54183c61 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 14:41:06 +0800 Subject: [PATCH 126/201] =?UTF-8?q?REQ-3345:=20=E4=BF=9D=E5=AD=98=E7=BE=A4?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E6=89=A9=E5=B1=95=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/center/api/vo/group/GroupInfo.java | 5 +++++ .../cn/axzo/im/center/api/vo/req/GroupCreateRequest.java | 5 +++++ .../src/main/java/cn/axzo/im/entity/Group.java | 2 ++ .../src/main/java/cn/axzo/im/group/GroupSupport.java | 9 ++------- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupInfo.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupInfo.java index 1e99f96..bbfc78d 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupInfo.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/group/GroupInfo.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.Setter; import java.util.Date; +import java.util.Map; /** * @author yanglin @@ -29,6 +30,10 @@ public class GroupInfo { * 群类型. VISA: 变洽签, WORKSPACE: 项目群, WORKSPACE_OU: 项目单位群, WORKSPACE_TEAM: 项目班组群 */ private GroupType type; + /** + * 群聊业务扩展信息 + */ + private Map bizGroupInfo; /** * 群头像 */ diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java index f690d5e..28f9635 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java @@ -11,6 +11,7 @@ import lombok.Setter; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; +import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -66,6 +67,10 @@ public class GroupCreateRequest { */ private Map bizGroupInfo; + public Map bizGroupInfoOrEmpty() { + return bizGroupInfo == null ? Collections.emptyMap() : bizGroupInfo; + } + @JsonIgnore @JSONField(serialize = false, deserialize = false) public Set getOwnerAndMembers() { Set ownerAndMembers = new HashSet<>(members); diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/Group.java b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java index 28c229e..a75e594 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/Group.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java @@ -10,6 +10,7 @@ import lombok.Getter; import lombok.Setter; import java.util.Date; +import java.util.Map; /** * @author yanglin @@ -28,6 +29,7 @@ public class Group { private String name; private String bizCode; private GroupType type; + private Map bizGroupInfo; private String avatar; private Long memberCount; private Long memberLimit; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index e9212c6..d96740b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -15,9 +15,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.util.Collections; -import java.util.Map; - /** * @author yanglin */ @@ -38,6 +35,7 @@ public class GroupSupport implements GroupLogger { group.setName(request.getName()); group.setBizCode(request.getBizCode()); group.setType(request.getGroupType()); + group.setBizGroupInfo(request.bizGroupInfoOrEmpty()); group.setAvatar(request.getAvatar()); group.setMemberCount((long) request.getOwnerAndMembers().size()); Long memberLimit = request.getMemberLimit(); @@ -65,10 +63,7 @@ public class GroupSupport implements GroupLogger { nimRequest.setIcon(request.getAvatar()); nimRequest.addCustom(Group.CUSTOM_GROUP_TYPE, request.getGroupType()); nimRequest.addCustom(Group.CUSTOM_BIZ_CODE, request.getBizCode()); - Map bizGroupInfo = request.getBizGroupInfo(); - if (bizGroupInfo == null) - bizGroupInfo = Collections.emptyMap(); - nimRequest.addCustom(Group.CUSTOM_BIZ_GROUP_INFO, bizGroupInfo); + nimRequest.addCustom(Group.CUSTOM_BIZ_GROUP_INFO, request.bizGroupInfoOrEmpty()); return nimRequest; } From 9b218c517182b65509ee9a324f6f8e54fa5a2ab1 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 14:43:13 +0800 Subject: [PATCH 127/201] =?UTF-8?q?REQ-3345:=20=E4=BF=9D=E5=AD=98=E7=BE=A4?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E6=89=A9=E5=B1=95=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- im-center-server/src/main/java/cn/axzo/im/entity/Group.java | 1 + 1 file changed, 1 insertion(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/Group.java b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java index a75e594..c4bb718 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/Group.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/Group.java @@ -29,6 +29,7 @@ public class Group { private String name; private String bizCode; private GroupType type; + @TableField(typeHandler = FastjsonTypeHandler.class) private Map bizGroupInfo; private String avatar; private Long memberCount; From 134b8e2d50a2f6716c2c6e5eff861d95eadca584 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 15:43:48 +0800 Subject: [PATCH 128/201] =?UTF-8?q?REQ-3345:=20=E4=BF=9D=E5=AD=98=E7=BE=A4?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E6=89=A9=E5=B1=95=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index d38eeee..7ae459b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -81,8 +81,9 @@ public class GroupManager { BizAssertions.assertTrue(nimResponse.isSuccess(), "创建群失败: {}", nimResponse.getDesc()); groupDao.updateTid(group.getId(), nimResponse.getTid()); group = groupDao.getById(group.getId()); - groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_CREATED); groupMemberSyncer.syncMembers(group); + // 同步完成员后再发消息 + groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_CREATED); groupBroadcaster.fireMembersChanged(group, groupMemberDao.getByTid(nimResponse.getTid()), MqEventType.GROUP_ADD_MEMBERS); From a5845bc10620ca3cfd6bab9900fbf3c046f4d0c2 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 15:47:18 +0800 Subject: [PATCH 129/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E7=BE=A4?= =?UTF-8?q?=E6=88=90=E5=91=98=E6=97=B6=E8=BF=9B=E8=A1=8C=E7=89=A9=E7=90=86?= =?UTF-8?q?=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java | 6 ++++++ .../main/java/cn/axzo/im/dao/repository/GroupMemberDao.java | 4 +--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java index 61477c6..c7293f4 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java @@ -2,9 +2,15 @@ package cn.axzo.im.dao.mapper; import cn.axzo.im.entity.GroupMember; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Param; /** * @author yanglin */ public interface GroupMapperMapper extends BaseMapper { + + @Delete("DELETE FROM im_group_member WHERE tid = #{tid}") + void deleteAccounts(@Param("tid") Long tid); + } diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java index 4042ceb..c9b70ce 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java @@ -21,9 +21,7 @@ import static java.util.stream.Collectors.toSet; public class GroupMemberDao extends ServiceImpl { public void deleteAccounts(Long tid) { - lambdaUpdate() - .eq(GroupMember::getTid, tid) - .remove(); + getBaseMapper().deleteAccounts(tid); } public Set getGroupPersons(Long tid) { From 0bf040d5d8374d6b3b3a98db43ac48712c0bfafd Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 16:04:49 +0800 Subject: [PATCH 130/201] =?UTF-8?q?REQ-3345:=20=E8=AE=B0=E5=BD=95=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/dao/mapper/GroupLogMapper.java | 10 ++++++ .../axzo/im/dao/repository/GroupLogDao.java | 13 +++++++ .../main/java/cn/axzo/im/entity/GroupLog.java | 36 +++++++++++++++++++ .../java/cn/axzo/im/group/GroupLogger.java | 8 ----- .../java/cn/axzo/im/group/GroupManager.java | 9 +++-- .../cn/axzo/im/group/GroupNotification.java | 8 +++++ .../java/cn/axzo/im/group/GroupSupport.java | 19 +++++++--- .../cn/axzo/im/service/ChatGroupService.java | 4 +-- .../cn/axzo/im/service/domain/ImAccounts.java | 6 ++-- .../im/service/impl/ChatGroupServiceImpl.java | 2 +- 10 files changed, 95 insertions(+), 20 deletions(-) create mode 100644 im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupLogMapper.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupLogDao.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/entity/GroupLog.java delete mode 100644 im-center-server/src/main/java/cn/axzo/im/group/GroupLogger.java create mode 100644 im-center-server/src/main/java/cn/axzo/im/group/GroupNotification.java diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupLogMapper.java b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupLogMapper.java new file mode 100644 index 0000000..9ea4c01 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupLogMapper.java @@ -0,0 +1,10 @@ +package cn.axzo.im.dao.mapper; + +import cn.axzo.im.entity.GroupLog; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @author yanglin + */ +public interface GroupLogMapper extends BaseMapper { +} diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupLogDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupLogDao.java new file mode 100644 index 0000000..6c47b01 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupLogDao.java @@ -0,0 +1,13 @@ +package cn.axzo.im.dao.repository; + +import cn.axzo.im.dao.mapper.GroupLogMapper; +import cn.axzo.im.entity.GroupLog; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Repository; + +/** + * @author yanglin + */ +@Repository("groupLogDao") +public class GroupLogDao extends ServiceImpl { +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupLog.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupLog.java new file mode 100644 index 0000000..c4214f2 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupLog.java @@ -0,0 +1,36 @@ +package cn.axzo.im.entity; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * @author yanglin + */ +@Setter +@Getter +@TableName(value = "im_group_log", autoResultMap = true) +public class GroupLog { + private Long id; + private String context; + private Long tid; + @TableField(typeHandler = FastjsonTypeHandler.class) + private JSONObject content; + @TableField(typeHandler = FastjsonTypeHandler.class) + private Object request; + @TableField(typeHandler = FastjsonTypeHandler.class) + private RecordExt recordExt; + private Long isDelete; + private Date createAt; + private Date updateAt; + + @Setter + @Getter + public static class RecordExt { + } +} diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupLogger.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupLogger.java deleted file mode 100644 index bc0a9d1..0000000 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupLogger.java +++ /dev/null @@ -1,8 +0,0 @@ -package cn.axzo.im.group; - -/** - * @author yanglin - */ -public interface GroupLogger { - void log(String message, Object... args); -} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 7ae459b..a8dc7ae 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -61,6 +61,7 @@ public class GroupManager { @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { BizAssertions.assertTrue(request.getOwnerAndMembers().size() > 1, "群成员数量(含群主)不能少于2"); + groupSupport.log(0L, "create-group:preparing", request); ImAccounts imAccounts = accountService.getOrCreateImAccounts(request.getOwnerAndMembers()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); @@ -81,6 +82,7 @@ public class GroupManager { BizAssertions.assertTrue(nimResponse.isSuccess(), "创建群失败: {}", nimResponse.getDesc()); groupDao.updateTid(group.getId(), nimResponse.getTid()); group = groupDao.getById(group.getId()); + groupSupport.log(group.getTid(), "create-group", request); groupMemberSyncer.syncMembers(group); // 同步完成员后再发消息 groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_CREATED); @@ -97,6 +99,7 @@ public class GroupManager { @Transactional public void dismissGroup(GroupDismissRequest request) { Group group = getGroupForUpdateOrThrow(request.getTid()); + groupSupport.log(group.getTid(), "dismiss-group", request); if (group.isDismissed()) return; NimGroupDismissRequest nimRequest = groupSupport .buildNimDismissGroupRequest(group.getOwnerAccount(), group); @@ -114,6 +117,7 @@ public class GroupManager { public GroupAddMembersResponse addMembers(GroupAddMembersRequest request) { Group group = getGroupForUpdateOrThrow(request.getTid()); BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); + groupSupport.log(group.getTid(), "add-members", request); // sync members 1 groupMemberSyncer.syncMembers(group); // prepare add members @@ -127,7 +131,7 @@ public class GroupManager { throw new ServiceException("群聊人数上限" + group.getMemberLimit() + "人, 请删除部分已选人员"); ImAccounts imAccounts = accountService.getOrCreateImAccounts(toAddMembers); if (imAccounts.isAccountEmpty()) { - groupSupport.log("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + groupSupport.sendNotification("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); return new GroupAddMembersResponse(); } @@ -153,9 +157,10 @@ public class GroupManager { public void removeMembers(GroupRemoveMembersRequest request) { Group group = getGroupForUpdateOrThrow(request.getTid()); BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); + groupSupport.log(group.getTid(), "remove-members", request); ImAccounts imAccounts = accountService.getAccountsByPersons(request.getMembers()); if (imAccounts.isAccountEmpty()) { - groupSupport.log("移除群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + groupSupport.sendNotification("移除群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); return; } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupNotification.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupNotification.java new file mode 100644 index 0000000..a86394e --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupNotification.java @@ -0,0 +1,8 @@ +package cn.axzo.im.group; + +/** + * @author yanglin + */ +public interface GroupNotification { + void sendNotification(String message, Object... args); +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index d96740b..e0786f2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -6,7 +6,9 @@ import cn.axzo.im.channel.netease.dto.NimGroupAddMembersRequest; import cn.axzo.im.channel.netease.dto.NimGroupCreateRequest; import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; import cn.axzo.im.channel.netease.dto.NimGroupRemoveMembersRequest; +import cn.axzo.im.dao.repository.GroupLogDao; import cn.axzo.im.entity.Group; +import cn.axzo.im.entity.GroupLog; import cn.axzo.im.group.support.GroupProps; import cn.axzo.im.service.ChatGroupService; import cn.axzo.im.service.domain.ImAccounts; @@ -21,12 +23,13 @@ import org.springframework.stereotype.Component; @Slf4j @Component @RequiredArgsConstructor -public class GroupSupport implements GroupLogger { +public class GroupSupport implements GroupNotification { private static final String INTRODUCE_MESSAGE = "邀请您加入群聊"; private final ChatGroupService chatGroupService; private final GroupProps groupProps; + private final GroupLogDao groupLogDao; Group buildNewGroup(GroupCreateRequest request, ImAccounts imAccounts) { String owner = imAccounts.findAccount(request.getOwner()).orElse(null); @@ -40,7 +43,7 @@ public class GroupSupport implements GroupLogger { group.setMemberCount((long) request.getOwnerAndMembers().size()); Long memberLimit = request.getMemberLimit(); if (memberLimit == null) - memberLimit = (long)groupProps.getDefaultMemberLimit(); + memberLimit = (long) groupProps.getDefaultMemberLimit(); group.setMemberLimit(memberLimit); group.setOwnerAccount(owner); group.setOwnerPersonId(request.getOwner().personIdAsLong()); @@ -95,8 +98,16 @@ public class GroupSupport implements GroupLogger { return nimRequest; } - public void log(String message, Object... args) { - chatGroupService.log(message, args); + public void log(Long tid, String context, Object request) { + GroupLog log = new GroupLog(); + log.setTid(tid == null ? 0 : tid); + log.setContext(context); + log.setRequest(request); + groupLogDao.save(log); + } + + public void sendNotification(String message, Object... args) { + chatGroupService.sendNotification(message, args); } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java b/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java index 119b641..62b947b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java @@ -18,7 +18,7 @@ import cn.axzo.im.center.api.vo.resp.HistoryMsgQueryResp; import cn.axzo.im.center.common.enums.ChatGroupUserDataSourceEnum; import cn.axzo.im.entity.ChatGroup; import cn.axzo.im.entity.dto.OrganizationalNodeUserDTO; -import cn.axzo.im.group.GroupLogger; +import cn.axzo.im.group.GroupNotification; import cn.hutool.core.lang.Pair; import com.baomidou.mybatisplus.extension.service.IService; @@ -30,7 +30,7 @@ import java.util.Set; * @date 2024/11/05 * @desc 群聊 */ -public interface ChatGroupService extends IService, GroupLogger { +public interface ChatGroupService extends IService, GroupNotification { /** * 创建群聊 diff --git a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java index 24f60ba..824260b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java @@ -4,7 +4,7 @@ import cn.axzo.framework.jackson.utility.JSON; import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.entity.AccountRegister; import cn.axzo.im.entity.Group; -import cn.axzo.im.group.GroupLogger; +import cn.axzo.im.group.GroupNotification; import lombok.RequiredArgsConstructor; import lombok.Setter; import org.apache.commons.collections.CollectionUtils; @@ -32,7 +32,7 @@ public class ImAccounts { } public Set getAccountNotFoundPersons( - GroupLogger logger, String operation, + GroupNotification logger, String operation, Group group, Set persons) { if (CollectionUtils.isEmpty(persons)) return Collections.emptySet(); @@ -40,7 +40,7 @@ public class ImAccounts { .filter(person -> !findAccount(person).isPresent()) .collect(toSet()); if (!notFound.isEmpty()) - logger.log("{}[{},{}], IM账号不存在列表: {}", operation, + logger.sendNotification("{}[{},{}], IM账号不存在列表: {}", operation, group.getTid(), group.getName(), JSON.toJSONString(notFound)); return notFound; diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java index beda881..c0b9dbc 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java @@ -768,7 +768,7 @@ public class ChatGroupServiceImpl extends ServiceImpl Date: Fri, 7 Feb 2025 16:28:53 +0800 Subject: [PATCH 131/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E6=B6=88=E6=81=AF=E4=BD=93=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/channel/netease/dto/MessageBody.java | 4 ++- .../axzo/im/group/GroupMessageController.java | 21 +++++++++++++-- .../UpdatableMessageQueryService.java | 11 ++++++++ .../updatable/domain/UpdatableMessages.java | 27 +++++++++++++++++++ 4 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 im-center-server/src/main/java/cn/axzo/im/updatable/domain/UpdatableMessages.java diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java index 3d99e33..ee53db4 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java @@ -33,7 +33,9 @@ public class MessageBody { private String msgContent; /** - * 消息通知结构体 + * @see cn.axzo.im.group.GroupMessageController 有引用 + * + * 消息通知结构体, 名称不能随便调整 */ private String msgBody; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java index 544d0a3..80325b4 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java @@ -8,11 +8,15 @@ import cn.axzo.im.center.api.vo.req.GroupMessagePageQueryRequest; import cn.axzo.im.center.api.vo.resp.GroupMessagePageQueryResponse; import cn.axzo.im.dao.repository.GroupMessageDao; import cn.axzo.im.entity.GroupMessage; -import cn.axzo.im.gateway.domain.OrgCollection; +import cn.axzo.im.entity.UpdatableMessage; import cn.axzo.im.gateway.OrgGateway; +import cn.axzo.im.gateway.domain.OrgCollection; +import cn.axzo.im.updatable.UpdatableMessageQueryService; +import cn.axzo.im.updatable.domain.UpdatableMessages; import com.baomidou.mybatisplus.core.metadata.IPage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.RestController; import java.util.List; @@ -30,6 +34,7 @@ public class GroupMessageController implements GroupMessageApi { private final GroupMessageDao groupMessageDao; private final OrgGateway orgGateway; + private final UpdatableMessageQueryService updatableMessageQueryService; @Override public ApiPageResult pageQuery(GroupMessagePageQueryRequest request) { @@ -39,15 +44,27 @@ public class GroupMessageController implements GroupMessageApi { .page(request.toPage()); List messages = BeanMapper.copyList( page.getRecords(), GroupMessagePageQueryResponse.class); + UpdatableMessages updatableMessages = UpdatableMessages.wrap( + updatableMessageQueryService.getUpdatableMessagesByNimIds( + messages.stream() + .map(GroupMessagePageQueryResponse::getMessageId) + .collect(toList()))); OrgCollection units = OrgCollection.wrap(orgGateway.getUnits(messages.stream() .map(GroupMessagePageQueryResponse::getFromPersonOuId) .filter(Objects::nonNull) .filter(ouId -> ouId > 0) .distinct() .collect(toList()))); - for (GroupMessagePageQueryResponse message : messages) + for (GroupMessagePageQueryResponse message : messages) { units.findUnit(message.getFromPersonOuId()) .ifPresent(unit -> message.setUnitName(unit.getName())); + String msgBody = message.getBody().getString("msgBody"); + UpdatableMessage updatableMessage = updatableMessages + .findByNimMessageId(message.getMessageId()) + .orElse(null); + if (StringUtils.isNotBlank(msgBody) && updatableMessage != null) + message.getBody().put("msgBody", updatableMessage.getBizBody().toJSONString()); + } PageResp pageResp = PageResp.list( page.getCurrent(), page.getSize(), diff --git a/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageQueryService.java b/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageQueryService.java index c389804..3c52d41 100644 --- a/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageQueryService.java +++ b/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageQueryService.java @@ -11,8 +11,11 @@ import cn.axzo.im.utils.BizAssertions; import cn.axzo.im.utils.ImProperties; import com.alibaba.fastjson.JSONObject; import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Component; +import java.util.Collection; +import java.util.Collections; import java.util.List; /** @@ -26,6 +29,14 @@ public class UpdatableMessageQueryService { private final ImProperties props; private final UpdateSupport updateSupport; + public List getUpdatableMessagesByNimIds(Collection nimIds) { + if (CollectionUtils.isEmpty(nimIds)) + return Collections.emptyList(); + return updatableMessageDao.lambdaQuery() + .in(UpdatableMessage::getNimMessageId, nimIds) + .list(); + } + public GetMessageDetailResponse getMessageDetails(GetMessageDetailRequest request) { BizAssertions.assertTrue(request.getBizMessageIds().size() <= 100, "消息ID数量不能超过100"); List messages = updatableMessageDao.lambdaQuery() diff --git a/im-center-server/src/main/java/cn/axzo/im/updatable/domain/UpdatableMessages.java b/im-center-server/src/main/java/cn/axzo/im/updatable/domain/UpdatableMessages.java new file mode 100644 index 0000000..1e5669c --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/updatable/domain/UpdatableMessages.java @@ -0,0 +1,27 @@ +package cn.axzo.im.updatable.domain; + +import cn.axzo.im.entity.UpdatableMessage; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; + +import java.util.List; +import java.util.Optional; + +/** + * @author yanglin + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class UpdatableMessages { + + private final List messages; + + public static UpdatableMessages wrap(List messages) { + return new UpdatableMessages(messages); + } + + public Optional findByNimMessageId(String nimMessageId) { + return messages.stream() + .filter(m -> m.getNimMessageId().equals(nimMessageId)) + .findFirst(); + } +} From 438ba768c83b1a4307f177c2f53a74bb6a5f32d1 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 16:39:56 +0800 Subject: [PATCH 132/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E6=B6=88=E6=81=AF=E4=BD=93=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/GroupMessageController.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java index 80325b4..3312040 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java @@ -16,7 +16,6 @@ import cn.axzo.im.updatable.domain.UpdatableMessages; import com.baomidou.mybatisplus.core.metadata.IPage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.RestController; import java.util.List; @@ -58,12 +57,9 @@ public class GroupMessageController implements GroupMessageApi { for (GroupMessagePageQueryResponse message : messages) { units.findUnit(message.getFromPersonOuId()) .ifPresent(unit -> message.setUnitName(unit.getName())); - String msgBody = message.getBody().getString("msgBody"); - UpdatableMessage updatableMessage = updatableMessages + updatableMessages .findByNimMessageId(message.getMessageId()) - .orElse(null); - if (StringUtils.isNotBlank(msgBody) && updatableMessage != null) - message.getBody().put("msgBody", updatableMessage.getBizBody().toJSONString()); + .ifPresent(updatableMessage -> updateMsgBody(message, updatableMessage)); } PageResp pageResp = PageResp.list( page.getCurrent(), @@ -73,4 +69,8 @@ public class GroupMessageController implements GroupMessageApi { return ApiPageResult.ok(pageResp); } + private void updateMsgBody(GroupMessagePageQueryResponse message, UpdatableMessage updatableMessage) { + message.getBody().put("msgBody", updatableMessage.getBizBody().toJSONString()); + } + } From 7aef40923d74831c9f5bc63799627da961fd25b5 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 16:42:02 +0800 Subject: [PATCH 133/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E6=B6=88=E6=81=AF=E4=BD=93=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupMessageController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java index 3312040..3348426 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java @@ -6,6 +6,7 @@ import cn.axzo.framework.domain.web.result.ApiPageResult; import cn.axzo.im.center.api.feign.GroupMessageApi; import cn.axzo.im.center.api.vo.req.GroupMessagePageQueryRequest; import cn.axzo.im.center.api.vo.resp.GroupMessagePageQueryResponse; +import cn.axzo.im.center.common.enums.NimMessageType; import cn.axzo.im.dao.repository.GroupMessageDao; import cn.axzo.im.entity.GroupMessage; import cn.axzo.im.entity.UpdatableMessage; @@ -46,6 +47,7 @@ public class GroupMessageController implements GroupMessageApi { UpdatableMessages updatableMessages = UpdatableMessages.wrap( updatableMessageQueryService.getUpdatableMessagesByNimIds( messages.stream() + .filter(message -> message.getMessageType() == NimMessageType.CUSTOM) .map(GroupMessagePageQueryResponse::getMessageId) .collect(toList()))); OrgCollection units = OrgCollection.wrap(orgGateway.getUnits(messages.stream() From 69673099356e24692cef895cbb3c5a5552d029e9 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 16:45:34 +0800 Subject: [PATCH 134/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E6=B6=88=E6=81=AF=E4=BD=93=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/group/GroupMessageController.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java index 3348426..44e2fa4 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java @@ -7,6 +7,7 @@ import cn.axzo.im.center.api.feign.GroupMessageApi; import cn.axzo.im.center.api.vo.req.GroupMessagePageQueryRequest; import cn.axzo.im.center.api.vo.resp.GroupMessagePageQueryResponse; import cn.axzo.im.center.common.enums.NimMessageType; +import cn.axzo.im.channel.netease.dto.MessageBody; import cn.axzo.im.dao.repository.GroupMessageDao; import cn.axzo.im.entity.GroupMessage; import cn.axzo.im.entity.UpdatableMessage; @@ -71,6 +72,9 @@ public class GroupMessageController implements GroupMessageApi { return ApiPageResult.ok(pageResp); } + /** + * @see MessageBody#getMsgBody() + */ private void updateMsgBody(GroupMessagePageQueryResponse message, UpdatableMessage updatableMessage) { message.getBody().put("msgBody", updatableMessage.getBizBody().toJSONString()); } From 3e7243386c12368bce864e242503e670b2c99ab5 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 17:11:35 +0800 Subject: [PATCH 135/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E6=B6=88=E6=81=AF=E4=BD=93=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/center/api/vo/resp/GroupMessagePageQueryResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java index 307d253..7ae641a 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java @@ -58,7 +58,7 @@ public class GroupMessagePageQueryResponse { /** * 发送时间 */ - private Date sendTime; + private Long sendTime; /** * 消息体. 具体格式根据messageType来定, 字段参考云信文档的body部分: https://doc.yunxin.163.com/messaging/server-apis/DE0MTk0OTY?platform=server#%E5%8E%86%E5%8F%B2%E6%B6%88%E6%81%AF%E6%9F%A5%E8%AF%A2%E8%BF%94%E5%9B%9E%E7%9A%84%E6%B6%88%E6%81%AF%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E */ From 45943bba97dab82f06b504ff07daa1b33c0da9e2 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 17:30:38 +0800 Subject: [PATCH 136/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/center/api/vo/resp/UpdatableMessageSendResult.java | 3 ++- .../java/cn/axzo/im/updatable/UpdatableMessageManager.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/UpdatableMessageSendResult.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/UpdatableMessageSendResult.java index 5ca6951..0ad7654 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/UpdatableMessageSendResult.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/UpdatableMessageSendResult.java @@ -11,5 +11,6 @@ import lombok.Setter; @Getter public class UpdatableMessageSendResult { private String bizMessageId; - private PersonAccountAttribute account; + private PersonAccountAttribute person; + private String imAccount; } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageManager.java b/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageManager.java index 35ad06f..dd5b68b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageManager.java @@ -108,7 +108,7 @@ public class UpdatableMessageManager { UpdatableMessageSendResult sendResult = new UpdatableMessageSendResult(); sendResults.add(sendResult); sendResult.setBizMessageId(message.bizMessageId()); - sendResult.setAccount(message.parsePersonAccount()); + sendResult.setPerson(message.parsePersonAccount()); } for (String imAccount : imReceiveAccounts) { UpdatableMessage message = messageFactory.get(); @@ -125,7 +125,7 @@ public class UpdatableMessageManager { UpdatableMessageSendResult sendResult = new UpdatableMessageSendResult(); sendResults.add(sendResult); sendResult.setBizMessageId(message.bizMessageId()); - sendResult.setAccount(null); + sendResult.setImAccount(imAccount); } collector.finish(); return sendResults; From 44ca936d1c08cff32a0c58a62d7b65bac4a71495 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 18:18:40 +0800 Subject: [PATCH 137/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=A4=B4=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resp/GroupMessagePageQueryResponse.java | 10 +++++++ .../im/gateway/domain/PersonProfiles.java | 27 +++++++++++++++++++ .../axzo/im/group/GroupMessageController.java | 18 +++++++++++-- 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 im-center-server/src/main/java/cn/axzo/im/gateway/domain/PersonProfiles.java diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java index 7ae641a..a7d1c7a 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupMessagePageQueryResponse.java @@ -69,6 +69,16 @@ public class GroupMessagePageQueryResponse { */ private String unitName; + /** + * 发送者名称 + */ + private String fromPersonName; + + /** + * 发送者头像 + */ + private String fromPersonAvatar; + /** * 客户端id */ diff --git a/im-center-server/src/main/java/cn/axzo/im/gateway/domain/PersonProfiles.java b/im-center-server/src/main/java/cn/axzo/im/gateway/domain/PersonProfiles.java new file mode 100644 index 0000000..6cb291d --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/gateway/domain/PersonProfiles.java @@ -0,0 +1,27 @@ +package cn.axzo.im.gateway.domain; + +import cn.axzo.basics.profiles.dto.basic.PersonProfileDto; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; + +import java.util.List; +import java.util.Optional; + +/** + * @author yanglin + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class PersonProfiles { + + private final List profiles; + + public static PersonProfiles wrap(List profiles) { + return new PersonProfiles(profiles); + } + + public Optional findByUserId(Long personId) { + return profiles.stream() + .filter(p -> p.getId().equals(personId)) + .findFirst(); + } +} diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java index 44e2fa4..9798274 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java @@ -12,7 +12,9 @@ import cn.axzo.im.dao.repository.GroupMessageDao; import cn.axzo.im.entity.GroupMessage; import cn.axzo.im.entity.UpdatableMessage; import cn.axzo.im.gateway.OrgGateway; +import cn.axzo.im.gateway.ProfilesApiGateway; import cn.axzo.im.gateway.domain.OrgCollection; +import cn.axzo.im.gateway.domain.PersonProfiles; import cn.axzo.im.updatable.UpdatableMessageQueryService; import cn.axzo.im.updatable.domain.UpdatableMessages; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -36,6 +38,7 @@ public class GroupMessageController implements GroupMessageApi { private final GroupMessageDao groupMessageDao; private final OrgGateway orgGateway; private final UpdatableMessageQueryService updatableMessageQueryService; + private final ProfilesApiGateway profilesApiGateway; @Override public ApiPageResult pageQuery(GroupMessagePageQueryRequest request) { @@ -51,6 +54,13 @@ public class GroupMessageController implements GroupMessageApi { .filter(message -> message.getMessageType() == NimMessageType.CUSTOM) .map(GroupMessagePageQueryResponse::getMessageId) .collect(toList()))); + PersonProfiles personProfiles = PersonProfiles.wrap( + profilesApiGateway.getPersonProfilesByIds(messages.stream() + .map(GroupMessagePageQueryResponse::getFromPersonId) + .filter(Objects::nonNull) + .filter(personId -> personId > 0) + .distinct() + .collect(toList()))); OrgCollection units = OrgCollection.wrap(orgGateway.getUnits(messages.stream() .map(GroupMessagePageQueryResponse::getFromPersonOuId) .filter(Objects::nonNull) @@ -60,9 +70,13 @@ public class GroupMessageController implements GroupMessageApi { for (GroupMessagePageQueryResponse message : messages) { units.findUnit(message.getFromPersonOuId()) .ifPresent(unit -> message.setUnitName(unit.getName())); - updatableMessages - .findByNimMessageId(message.getMessageId()) + updatableMessages.findByNimMessageId(message.getMessageId()) .ifPresent(updatableMessage -> updateMsgBody(message, updatableMessage)); + personProfiles.findByUserId(message.getFromPersonId()) + .ifPresent(profile -> { + message.setFromPersonName(profile.getRealName()); + message.setFromPersonAvatar(profile.getAvatarUrl()); + }); } PageResp pageResp = PageResp.list( page.getCurrent(), From 237443c3b532b5ce7b10ccecb993b46af20f1ba4 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 18:28:44 +0800 Subject: [PATCH 138/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=A4=B4=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/channel/netease/dto/MessageBody.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java index ee53db4..2356145 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java @@ -33,7 +33,7 @@ public class MessageBody { private String msgContent; /** - * @see cn.axzo.im.group.GroupMessageController 有引用 + * @see cn.axzo.im.group.GroupMessageController 有字符串引用 * * 消息通知结构体, 名称不能随便调整 */ From 525f69e04a8198a5823bde87b146ff0e692a11cc Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 7 Feb 2025 18:30:51 +0800 Subject: [PATCH 139/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=A4=B4=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/gateway/domain/{OrgCollection.java => OrgUnits.java} | 6 +++--- .../main/java/cn/axzo/im/group/GroupMessageController.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename im-center-server/src/main/java/cn/axzo/im/gateway/domain/{OrgCollection.java => OrgUnits.java} (77%) diff --git a/im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgCollection.java b/im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgUnits.java similarity index 77% rename from im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgCollection.java rename to im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgUnits.java index 45841b4..bd157b9 100644 --- a/im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgCollection.java +++ b/im-center-server/src/main/java/cn/axzo/im/gateway/domain/OrgUnits.java @@ -11,12 +11,12 @@ import java.util.Optional; * @author yanglin */ @RequiredArgsConstructor(access = AccessLevel.PRIVATE) -public class OrgCollection { +public class OrgUnits { private final Collection units; - public static OrgCollection wrap(Collection units) { - return new OrgCollection(units); + public static OrgUnits wrap(Collection units) { + return new OrgUnits(units); } public Optional findUnit(Long ouId) { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java index 9798274..efa5525 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java @@ -13,7 +13,7 @@ import cn.axzo.im.entity.GroupMessage; import cn.axzo.im.entity.UpdatableMessage; import cn.axzo.im.gateway.OrgGateway; import cn.axzo.im.gateway.ProfilesApiGateway; -import cn.axzo.im.gateway.domain.OrgCollection; +import cn.axzo.im.gateway.domain.OrgUnits; import cn.axzo.im.gateway.domain.PersonProfiles; import cn.axzo.im.updatable.UpdatableMessageQueryService; import cn.axzo.im.updatable.domain.UpdatableMessages; @@ -61,7 +61,7 @@ public class GroupMessageController implements GroupMessageApi { .filter(personId -> personId > 0) .distinct() .collect(toList()))); - OrgCollection units = OrgCollection.wrap(orgGateway.getUnits(messages.stream() + OrgUnits units = OrgUnits.wrap(orgGateway.getUnits(messages.stream() .map(GroupMessagePageQueryResponse::getFromPersonOuId) .filter(Objects::nonNull) .filter(ouId -> ouId > 0) From 514e54230c13a0e65ae49db4e04366dad10c49d2 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 09:10:30 +0800 Subject: [PATCH 140/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=A4=B4=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 4 ++-- .../src/main/java/cn/axzo/im/group/GroupNotification.java | 2 +- .../src/main/java/cn/axzo/im/group/GroupSupport.java | 4 ++-- .../src/main/java/cn/axzo/im/service/domain/ImAccounts.java | 4 ++-- .../java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index a8dc7ae..fb3d199 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -131,7 +131,7 @@ public class GroupManager { throw new ServiceException("群聊人数上限" + group.getMemberLimit() + "人, 请删除部分已选人员"); ImAccounts imAccounts = accountService.getOrCreateImAccounts(toAddMembers); if (imAccounts.isAccountEmpty()) { - groupSupport.sendNotification("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + groupSupport.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); return new GroupAddMembersResponse(); } @@ -160,7 +160,7 @@ public class GroupManager { groupSupport.log(group.getTid(), "remove-members", request); ImAccounts imAccounts = accountService.getAccountsByPersons(request.getMembers()); if (imAccounts.isAccountEmpty()) { - groupSupport.sendNotification("移除群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + groupSupport.send("移除群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); return; } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupNotification.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupNotification.java index a86394e..a8ba601 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupNotification.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupNotification.java @@ -4,5 +4,5 @@ package cn.axzo.im.group; * @author yanglin */ public interface GroupNotification { - void sendNotification(String message, Object... args); + void send(String message, Object... args); } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index e0786f2..f63c0eb 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -106,8 +106,8 @@ public class GroupSupport implements GroupNotification { groupLogDao.save(log); } - public void sendNotification(String message, Object... args) { - chatGroupService.sendNotification(message, args); + public void send(String message, Object... args) { + chatGroupService.send(message, args); } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java index 824260b..70be619 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java @@ -32,7 +32,7 @@ public class ImAccounts { } public Set getAccountNotFoundPersons( - GroupNotification logger, String operation, + GroupNotification notification, String operation, Group group, Set persons) { if (CollectionUtils.isEmpty(persons)) return Collections.emptySet(); @@ -40,7 +40,7 @@ public class ImAccounts { .filter(person -> !findAccount(person).isPresent()) .collect(toSet()); if (!notFound.isEmpty()) - logger.sendNotification("{}[{},{}], IM账号不存在列表: {}", operation, + notification.send("{}[{},{}], IM账号不存在列表: {}", operation, group.getTid(), group.getName(), JSON.toJSONString(notFound)); return notFound; diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java index c0b9dbc..192ea5f 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/ChatGroupServiceImpl.java @@ -768,7 +768,7 @@ public class ChatGroupServiceImpl extends ServiceImpl Date: Sat, 8 Feb 2025 09:17:13 +0800 Subject: [PATCH 141/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=A4=B4=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/channel/netease/dto/MessageBody.java | 3 ++- .../cn/axzo/im/group/{ => controller}/GroupController.java | 3 ++- .../axzo/im/group/{ => controller}/GroupMessageController.java | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) rename im-center-server/src/main/java/cn/axzo/im/group/{ => controller}/GroupController.java (97%) rename im-center-server/src/main/java/cn/axzo/im/group/{ => controller}/GroupMessageController.java (99%) diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java index 2356145..08769dc 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/MessageBody.java @@ -1,5 +1,6 @@ package cn.axzo.im.channel.netease.dto; +import cn.axzo.im.group.controller.GroupMessageController; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import lombok.Data; @@ -33,7 +34,7 @@ public class MessageBody { private String msgContent; /** - * @see cn.axzo.im.group.GroupMessageController 有字符串引用 + * @see GroupMessageController 有字符串引用 * * 消息通知结构体, 名称不能随便调整 */ diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java similarity index 97% rename from im-center-server/src/main/java/cn/axzo/im/group/GroupController.java rename to im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java index edc68f1..f26f2e9 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java @@ -1,4 +1,4 @@ -package cn.axzo.im.group; +package cn.axzo.im.group.controller; import cn.axzo.basics.common.BeanMapper; import cn.axzo.framework.domain.web.result.ApiResult; @@ -15,6 +15,7 @@ import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; import cn.axzo.im.center.api.vo.resp.GroupGetMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupGetOwnerResponse; import cn.axzo.im.entity.GroupMember; +import cn.axzo.im.group.GroupManager; import cn.axzo.im.group.member.GroupMemberQueryService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupMessageController.java similarity index 99% rename from im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java rename to im-center-server/src/main/java/cn/axzo/im/group/controller/GroupMessageController.java index efa5525..d1f2fca 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupMessageController.java @@ -1,4 +1,4 @@ -package cn.axzo.im.group; +package cn.axzo.im.group.controller; import cn.axzo.basics.common.BeanMapper; import cn.axzo.framework.domain.page.PageResp; From 1d140f63d6e887ff7bf5d6e43dfec3a3b38b39c0 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 09:22:40 +0800 Subject: [PATCH 142/201] =?UTF-8?q?REQ-3345:=20=E8=BF=94=E5=9B=9E=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=A4=B4=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/channel/netease/NimChannelService.java | 4 ++-- .../src/main/java/cn/axzo/im/group/GroupManager.java | 4 ++-- .../main/java/cn/axzo/im/group/member/GroupMemberSyncer.java | 4 ++-- ...{GroupManipulateRateLimiter.java => GroupRateLimiter.java} | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename im-center-server/src/main/java/cn/axzo/im/group/support/{GroupManipulateRateLimiter.java => GroupRateLimiter.java} (95%) diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java index 276e62d..03aa06d 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/NimChannelService.java @@ -27,7 +27,7 @@ import cn.axzo.im.channel.netease.dto.RegisterResponse; import cn.axzo.im.channel.netease.dto.RegisterUpdateRequest; import cn.axzo.im.channel.netease.dto.UserAddChatGroupRequest; import cn.axzo.im.channel.netease.dto.UserAddChatGroupResponse; -import cn.axzo.im.group.support.GroupManipulateRateLimiter; +import cn.axzo.im.group.support.GroupRateLimiter; import cn.axzo.im.utils.ImProperties; import cn.hutool.core.util.ObjectUtil; import cn.hutool.http.HttpRequest; @@ -135,7 +135,7 @@ public class NimChannelService implements IMChannelProvider { private ImProperties props; @Resource - private GroupManipulateRateLimiter rateLimiter; + private GroupRateLimiter rateLimiter; @Override public String getProviderAppKey() { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index fb3d199..8e2b454 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -23,7 +23,7 @@ import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMember; import cn.axzo.im.group.member.GroupMemberSyncer; -import cn.axzo.im.group.support.GroupManipulateRateLimiter; +import cn.axzo.im.group.support.GroupRateLimiter; import cn.axzo.im.service.AccountService; import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.BizAssertions; @@ -56,7 +56,7 @@ public class GroupManager { private final AccountService accountService; private final GroupBroadcaster groupBroadcaster; private final GroupMemberSyncer groupMemberSyncer; - private final GroupManipulateRateLimiter rateLimiter; + private final GroupRateLimiter rateLimiter; @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index cf2cdf6..bfd07ff 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -12,7 +12,7 @@ import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMember; -import cn.axzo.im.group.support.GroupManipulateRateLimiter; +import cn.axzo.im.group.support.GroupRateLimiter; import cn.axzo.im.utils.BizAssertions; import cn.axzo.im.utils.ImAccountParser; import lombok.RequiredArgsConstructor; @@ -38,7 +38,7 @@ public class GroupMemberSyncer { private final GroupMemberDao groupMemberDao; private final GroupDao groupDao; private final NimClient nimClient; - private final GroupManipulateRateLimiter rateLimiter; + private final GroupRateLimiter rateLimiter; private final TransactionTemplate transactionTemplate; public void syncMembers(Group group) { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupManipulateRateLimiter.java b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java similarity index 95% rename from im-center-server/src/main/java/cn/axzo/im/group/support/GroupManipulateRateLimiter.java rename to im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java index 1cfc047..84366fd 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupManipulateRateLimiter.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java @@ -10,7 +10,7 @@ import org.springframework.stereotype.Component; */ @Component @RequiredArgsConstructor -public class GroupManipulateRateLimiter implements InitializingBean { +public class GroupRateLimiter implements InitializingBean { private final GroupProps groupProps; From 30975d114b0b5fcce90c1679e4e7b83d14a4db27 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 09:30:52 +0800 Subject: [PATCH 143/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/GroupManager.java | 10 +++-- .../java/cn/axzo/im/group/GroupSupport.java | 8 +--- .../im/group/support/GroupRateLimiter.java | 45 ++++++++++++++----- .../cn/axzo/im/service/ChatGroupService.java | 4 +- .../cn/axzo/im/service/domain/ImAccounts.java | 4 +- .../Notification.java} | 4 +- 6 files changed, 46 insertions(+), 29 deletions(-) rename im-center-server/src/main/java/cn/axzo/im/{group/GroupNotification.java => utils/Notification.java} (53%) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 8e2b454..56ef5f4 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -27,6 +27,7 @@ import cn.axzo.im.group.support.GroupRateLimiter; import cn.axzo.im.service.AccountService; import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.BizAssertions; +import cn.axzo.im.utils.Notification; import com.alibaba.fastjson.JSON; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -57,6 +58,7 @@ public class GroupManager { private final GroupBroadcaster groupBroadcaster; private final GroupMemberSyncer groupMemberSyncer; private final GroupRateLimiter rateLimiter; + private final Notification notification; @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { @@ -92,7 +94,7 @@ public class GroupManager { GroupCreateResponse response = new GroupCreateResponse(); response.setTid(nimResponse.getTid()); response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( - groupSupport, "创建群", group, request.getMembers())); + notification, "创建群", group, request.getMembers())); return response; } @@ -131,7 +133,7 @@ public class GroupManager { throw new ServiceException("群聊人数上限" + group.getMemberLimit() + "人, 请删除部分已选人员"); ImAccounts imAccounts = accountService.getOrCreateImAccounts(toAddMembers); if (imAccounts.isAccountEmpty()) { - groupSupport.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + notification.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); return new GroupAddMembersResponse(); } @@ -149,7 +151,7 @@ public class GroupManager { MqEventType.GROUP_ADD_MEMBERS); GroupAddMembersResponse response = new GroupAddMembersResponse(); response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( - groupSupport, "添加群成员", group, request.getMembers())); + notification, "添加群成员", group, request.getMembers())); return response; } @@ -160,7 +162,7 @@ public class GroupManager { groupSupport.log(group.getTid(), "remove-members", request); ImAccounts imAccounts = accountService.getAccountsByPersons(request.getMembers()); if (imAccounts.isAccountEmpty()) { - groupSupport.send("移除群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + notification.send("移除群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); return; } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index f63c0eb..7940ed5 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -10,7 +10,6 @@ import cn.axzo.im.dao.repository.GroupLogDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupLog; import cn.axzo.im.group.support.GroupProps; -import cn.axzo.im.service.ChatGroupService; import cn.axzo.im.service.domain.ImAccounts; import cn.axzo.im.utils.BizAssertions; import lombok.RequiredArgsConstructor; @@ -23,11 +22,10 @@ import org.springframework.stereotype.Component; @Slf4j @Component @RequiredArgsConstructor -public class GroupSupport implements GroupNotification { +public class GroupSupport { private static final String INTRODUCE_MESSAGE = "邀请您加入群聊"; - private final ChatGroupService chatGroupService; private final GroupProps groupProps; private final GroupLogDao groupLogDao; @@ -106,8 +104,4 @@ public class GroupSupport implements GroupNotification { groupLogDao.save(log); } - public void send(String message, Object... args) { - chatGroupService.send(message, args); - } - } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java index 84366fd..d9cf667 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java @@ -1,5 +1,6 @@ package cn.axzo.im.group.support; +import cn.axzo.im.utils.Notification; import com.google.common.util.concurrent.RateLimiter; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.InitializingBean; @@ -13,13 +14,14 @@ import org.springframework.stereotype.Component; public class GroupRateLimiter implements InitializingBean { private final GroupProps groupProps; + private final Notification notification; - private RateLimiter createGroupLimiter; - private RateLimiter dismissGroupLimiter; - private RateLimiter addMemberLimiter; - private RateLimiter removeMemberLimiter; - private RateLimiter getGroupInfoLimiter; - private RateLimiter changeOwnerLimiter; + private Limiter createGroupLimiter; + private Limiter dismissGroupLimiter; + private Limiter addMemberLimiter; + private Limiter removeMemberLimiter; + private Limiter getGroupInfoLimiter; + private Limiter changeOwnerLimiter; public void requireCreateGroup() { createGroupLimiter.acquire(); @@ -47,12 +49,31 @@ public class GroupRateLimiter implements InitializingBean { @Override public void afterPropertiesSet() { - createGroupLimiter = RateLimiter.create(groupProps.getCreateGroupTps()); - dismissGroupLimiter = RateLimiter.create(groupProps.getDismissGroupTps()); - addMemberLimiter = RateLimiter.create(groupProps.getAddMemberTps()); - removeMemberLimiter = RateLimiter.create(groupProps.getRemoveMemberTps()); - getGroupInfoLimiter = RateLimiter.create(groupProps.getGetGroupInfoTps()); - changeOwnerLimiter = RateLimiter.create(groupProps.getChangeOwnerTps()); + createGroupLimiter = new Limiter("create-group", groupProps.getCreateGroupTps()); + dismissGroupLimiter = new Limiter("dismiss-group", groupProps.getDismissGroupTps()); + addMemberLimiter = new Limiter("group-add-member", groupProps.getAddMemberTps()); + removeMemberLimiter = new Limiter("group-remove-member", groupProps.getRemoveMemberTps()); + getGroupInfoLimiter = new Limiter("group-get-group-info", groupProps.getGetGroupInfoTps()); + changeOwnerLimiter = new Limiter("group-change-owner", groupProps.getChangeOwnerTps()); } + private class Limiter { + + final RateLimiter rateLimiter; + final String name; + + Limiter(String name, int tps) { + this.rateLimiter = RateLimiter.create(tps); + this.name = name; + } + + public void acquire() { + long beginMs = System.currentTimeMillis(); + rateLimiter.acquire(); + long deltaMs = System.currentTimeMillis() - beginMs; + if (deltaMs > 1000) + notification.send("{} wait too long to acquire rate limiter: {}ms", name, deltaMs); + } + + } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java b/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java index 62b947b..155ae98 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/ChatGroupService.java @@ -18,7 +18,7 @@ import cn.axzo.im.center.api.vo.resp.HistoryMsgQueryResp; import cn.axzo.im.center.common.enums.ChatGroupUserDataSourceEnum; import cn.axzo.im.entity.ChatGroup; import cn.axzo.im.entity.dto.OrganizationalNodeUserDTO; -import cn.axzo.im.group.GroupNotification; +import cn.axzo.im.utils.Notification; import cn.hutool.core.lang.Pair; import com.baomidou.mybatisplus.extension.service.IService; @@ -30,7 +30,7 @@ import java.util.Set; * @date 2024/11/05 * @desc 群聊 */ -public interface ChatGroupService extends IService, GroupNotification { +public interface ChatGroupService extends IService, Notification { /** * 创建群聊 diff --git a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java index 70be619..b52ef2d 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java @@ -4,7 +4,7 @@ import cn.axzo.framework.jackson.utility.JSON; import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.entity.AccountRegister; import cn.axzo.im.entity.Group; -import cn.axzo.im.group.GroupNotification; +import cn.axzo.im.utils.Notification; import lombok.RequiredArgsConstructor; import lombok.Setter; import org.apache.commons.collections.CollectionUtils; @@ -32,7 +32,7 @@ public class ImAccounts { } public Set getAccountNotFoundPersons( - GroupNotification notification, String operation, + Notification notification, String operation, Group group, Set persons) { if (CollectionUtils.isEmpty(persons)) return Collections.emptySet(); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupNotification.java b/im-center-server/src/main/java/cn/axzo/im/utils/Notification.java similarity index 53% rename from im-center-server/src/main/java/cn/axzo/im/group/GroupNotification.java rename to im-center-server/src/main/java/cn/axzo/im/utils/Notification.java index a8ba601..58fe930 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupNotification.java +++ b/im-center-server/src/main/java/cn/axzo/im/utils/Notification.java @@ -1,8 +1,8 @@ -package cn.axzo.im.group; +package cn.axzo.im.utils; /** * @author yanglin */ -public interface GroupNotification { +public interface Notification { void send(String message, Object... args); } \ No newline at end of file From 8483b955b2635f35e8ef98e9e3a8dd5291f8d2a0 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 09:35:43 +0800 Subject: [PATCH 144/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/gateway/DingDingMsgApiGateway.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/gateway/DingDingMsgApiGateway.java b/im-center-server/src/main/java/cn/axzo/im/gateway/DingDingMsgApiGateway.java index 80cdc07..2716f4b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/gateway/DingDingMsgApiGateway.java +++ b/im-center-server/src/main/java/cn/axzo/im/gateway/DingDingMsgApiGateway.java @@ -9,6 +9,12 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + @Service("dingDingMsgApiGateway") @Slf4j @RequiredArgsConstructor @@ -16,10 +22,22 @@ public class DingDingMsgApiGateway { private final DingDingMsgApi dingDingMsgApi; + private final ExecutorService executor = new ThreadPoolExecutor(2, 2, + 0L, TimeUnit.MILLISECONDS, + new ArrayBlockingQueue<>(10)); + + public void sendMsg(DingTalkMsgTypeEnum msgType, String title, String text, String dingDingScene) { + try { + executor.execute(() -> sendMsgImpl(msgType, title, text, dingDingScene)); + } catch (Exception e) { + log.warn("DingDingMsgApiGateway-sendMsg Exception, msgType:{}, title:{}, text:{}, dingDingScene:{}", msgType, title, text, dingDingScene, e); + } + } + /** * 发送消息 */ - public void sendMsg(DingTalkMsgTypeEnum msgType, String title, String text, String dingDingScene) { + private void sendMsgImpl(DingTalkMsgTypeEnum msgType, String title, String text, String dingDingScene) { DingDingSendRebootGroupMsgReq req = new DingDingSendRebootGroupMsgReq(); req.setMsgType(msgType); req.setDingDingJson(new SampleMarkdown(title, text).toJson()); From 97e99dcb3f95d8715f9db920242bba2cabc401d2 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 09:41:48 +0800 Subject: [PATCH 145/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/support/GroupRateLimiter.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java index d9cf667..d4fc7fb 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java @@ -68,11 +68,9 @@ public class GroupRateLimiter implements InitializingBean { } public void acquire() { - long beginMs = System.currentTimeMillis(); - rateLimiter.acquire(); - long deltaMs = System.currentTimeMillis() - beginMs; - if (deltaMs > 1000) - notification.send("{} wait too long to acquire rate limiter: {}ms", name, deltaMs); + double seconds = rateLimiter.acquire(); + if (seconds > 1) + notification.send("{} wait too long to acquire rate limiter: {} seconds", name, seconds); } } From bbe15e20196ef26e0cfa006e04fd07951637608e Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 09:50:39 +0800 Subject: [PATCH 146/201] =?UTF-8?q?REQ-3345:=20=E5=90=8C=E6=AD=A5=E7=BE=A4?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E7=9A=84job=E4=BD=BF=E7=94=A8=E5=88=86?= =?UTF-8?q?=E7=89=87=E6=89=A7=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/message/GroupMessageSyncJob.java | 8 ++++++-- .../main/java/cn/axzo/im/group/support/GroupProps.java | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 8726f62..97eba8f 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -15,6 +15,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.taobao.api.internal.util.NamedThreadFactory; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.annotation.XxlJob; +import com.xxl.job.core.util.ShardingUtil; +import com.xxl.job.core.util.ShardingUtil.ShardingVO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; @@ -59,7 +61,7 @@ public class GroupMessageSyncJob implements InitializingBean { } try { log.info("start sync group messages..."); - syncImpl(); + syncImpl(ShardingUtil.getShardingVo()); log.info("sync group messages finished"); } finally { isRunning = false; @@ -67,7 +69,7 @@ public class GroupMessageSyncJob implements InitializingBean { return ReturnT.SUCCESS; } - private void syncImpl() throws Exception { + private void syncImpl(ShardingVO sharding) throws Exception { CountDownLatch completed = new CountDownLatch(1); MessageSyncController controller = new MessageSyncController(tps, completed::countDown); Date twoDayAgo = new DateTime(new Date()).minusDays(2).toDate(); @@ -80,6 +82,8 @@ public class GroupMessageSyncJob implements InitializingBean { .gt(Group::getDismissedAt, twoDayAgo)))); for (List groups : cursor) { for (Group group : groups) { + if (group.getTid() % sharding.getTotal() != sharding.getIndex()) + continue; controller.submitGroup(group); executor.execute(new GroupMessageSyncHandler(this, controller, group) { @Override diff --git a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java index c629224..ba8e863 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java @@ -19,7 +19,7 @@ public class GroupProps { private int defaultMemberLimit = 499; - private int syncMessageTps = 20; + private int syncMessageTps = 10; private int createGroupTps = 10; private int dismissGroupTps = 10; private int addMemberTps = 10; From c930eb93bb029870a8873aa127d6f6645b655875 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 09:52:28 +0800 Subject: [PATCH 147/201] =?UTF-8?q?Revert=20"REQ-3345:=20=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=BE=A4=E4=BF=A1=E6=81=AF=E7=9A=84job=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=88=86=E7=89=87=E6=89=A7=E8=A1=8C"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit bbe15e20196ef26e0cfa006e04fd07951637608e. --- .../cn/axzo/im/group/message/GroupMessageSyncJob.java | 8 ++------ .../main/java/cn/axzo/im/group/support/GroupProps.java | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java index 97eba8f..8726f62 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/message/GroupMessageSyncJob.java @@ -15,8 +15,6 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.taobao.api.internal.util.NamedThreadFactory; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.annotation.XxlJob; -import com.xxl.job.core.util.ShardingUtil; -import com.xxl.job.core.util.ShardingUtil.ShardingVO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; @@ -61,7 +59,7 @@ public class GroupMessageSyncJob implements InitializingBean { } try { log.info("start sync group messages..."); - syncImpl(ShardingUtil.getShardingVo()); + syncImpl(); log.info("sync group messages finished"); } finally { isRunning = false; @@ -69,7 +67,7 @@ public class GroupMessageSyncJob implements InitializingBean { return ReturnT.SUCCESS; } - private void syncImpl(ShardingVO sharding) throws Exception { + private void syncImpl() throws Exception { CountDownLatch completed = new CountDownLatch(1); MessageSyncController controller = new MessageSyncController(tps, completed::countDown); Date twoDayAgo = new DateTime(new Date()).minusDays(2).toDate(); @@ -82,8 +80,6 @@ public class GroupMessageSyncJob implements InitializingBean { .gt(Group::getDismissedAt, twoDayAgo)))); for (List groups : cursor) { for (Group group : groups) { - if (group.getTid() % sharding.getTotal() != sharding.getIndex()) - continue; controller.submitGroup(group); executor.execute(new GroupMessageSyncHandler(this, controller, group) { @Override diff --git a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java index ba8e863..c629224 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java @@ -19,7 +19,7 @@ public class GroupProps { private int defaultMemberLimit = 499; - private int syncMessageTps = 10; + private int syncMessageTps = 20; private int createGroupTps = 10; private int dismissGroupTps = 10; private int addMemberTps = 10; From c69aee2377b6570f8e07ecba07b947540cf8d760 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 10:04:06 +0800 Subject: [PATCH 148/201] =?UTF-8?q?REQ-3345:=20=E7=BE=A4=E6=88=90=E5=91=98?= =?UTF-8?q?=E6=95=B0=E9=87=8F=E4=B8=8D=E8=83=BD=E7=AD=89=E4=BA=8E0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/dao/repository/GroupMemberDao.java | 6 +++--- .../src/main/java/cn/axzo/im/group/GroupManager.java | 12 ++++++++---- .../im/group/member/GroupMemberQueryService.java | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java index c9b70ce..223fbc5 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java @@ -25,7 +25,7 @@ public class GroupMemberDao extends ServiceImpl } public Set getGroupPersons(Long tid) { - return getByTid(tid).stream() + return getMembersByTid(tid).stream() .map(account -> { PersonAccountAttribute person = new PersonAccountAttribute(); person.setPersonId(account.getPersonId() + ""); @@ -36,13 +36,13 @@ public class GroupMemberDao extends ServiceImpl .collect(toSet()); } - public List getByTid(Long tid) { + public List getMembersByTid(Long tid) { return lambdaQuery() .eq(GroupMember::getTid, tid) .list(); } - public List getByPersons( + public List getMembersByPersons( Long tid, Collection persons) { if (CollectionUtils.isEmpty(persons)) return Collections.emptyList(); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 56ef5f4..e072a10 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -89,7 +89,7 @@ public class GroupManager { // 同步完成员后再发消息 groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_CREATED); groupBroadcaster.fireMembersChanged(group, - groupMemberDao.getByTid(nimResponse.getTid()), + groupMemberDao.getMembersByTid(nimResponse.getTid()), MqEventType.GROUP_ADD_MEMBERS); GroupCreateResponse response = new GroupCreateResponse(); response.setTid(nimResponse.getTid()); @@ -147,7 +147,7 @@ public class GroupManager { // sync members 2 groupMemberSyncer.syncMembers(group); groupBroadcaster.fireMembersChanged(group, - groupMemberDao.getByPersons(group.getTid(), toAddMembers), + groupMemberDao.getMembersByPersons(group.getTid(), toAddMembers), MqEventType.GROUP_ADD_MEMBERS); GroupAddMembersResponse response = new GroupAddMembersResponse(); response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( @@ -166,11 +166,15 @@ public class GroupManager { group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); return; } - // 获取人员之前不能做同步, 因为app可能已经通过sdk移除过成员了 - List toRemoveMembers = groupMemberDao.getByPersons( + groupMemberSyncer.syncMembers(group); + List toRemoveMembers = groupMemberDao.getMembersByPersons( group.getTid(), request.getMembers()); if (CollectionUtils.isEmpty(toRemoveMembers)) return; + List groupMembers = groupMemberDao + .getMembersByTid(group.getTid()); + BizAssertions.assertTrue( + groupMembers.size() - toRemoveMembers.size() >= 1, "无法移除, 群聊人数不能少于1人"); NimGroupRemoveMembersRequest nimRequest = groupSupport .buildRemoveMembersRequest(group, group.getOwnerAccount(), imAccounts); rateLimiter.requireRemoveMember(); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java index 180070f..94bb887 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java @@ -20,7 +20,7 @@ public class GroupMemberQueryService { private final GroupMemberDao groupMemberDao; public List getMembers(Long tid) { - return groupMemberDao.getByTid(tid); + return groupMemberDao.getMembersByTid(tid); } public GroupMember getOwner(Long tid) { From 0d001d71ee614ad4074111b9aeb9744fc9743d80 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 10:10:06 +0800 Subject: [PATCH 149/201] =?UTF-8?q?REQ-3345:=20=E7=BE=A4=E6=88=90=E5=91=98?= =?UTF-8?q?=E6=95=B0=E9=87=8F=E4=B8=8D=E8=83=BD=E7=AD=89=E4=BA=8E0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index e072a10..6bd199c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -178,11 +178,10 @@ public class GroupManager { NimGroupRemoveMembersRequest nimRequest = groupSupport .buildRemoveMembersRequest(group, group.getOwnerAccount(), imAccounts); rateLimiter.requireRemoveMember(); - // 不判断NIM响应状态, 因为前端可能已经调用app sdk移除过成员了(支持重复移除) NimGroupRemoveMembersResponse nimResponse = nimClient.removeGroupMembers(nimRequest); log.info("移除群成员, request={}, response={}", nimRequest, nimResponse); + BizAssertions.assertTrue(nimResponse.isSuccess(), "移除群成员失败: {}", nimResponse.getDesc()); groupMemberSyncer.syncMembers(group); - // 不比较直接发消息 groupBroadcaster.fireMembersChanged(group, toRemoveMembers, MqEventType.GROUP_REMOVE_MEMBERS); } From 12103aeaf46f47f362011f2758ea0d53f8536314 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 14:32:39 +0800 Subject: [PATCH 150/201] =?UTF-8?q?REQ-3345:=20=E7=A7=BB=E9=99=A4=E7=BE=A4?= =?UTF-8?q?=E6=88=90=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/center/api/feign/GroupApi.java | 9 ++++ .../api/vo/req/GroupGetInfoRequest.java | 18 ++++++++ .../api/vo/req/GroupRemoveMembersRequest.java | 5 ++ .../api/vo/resp/GroupGetInfoResponse.java | 20 ++++++++ .../center/common/enums/GroupMemberType.java | 6 +-- .../im/channel/netease/dto/NimGroupInfo.java | 7 ++- .../java/cn/axzo/im/config/MqProducer.java | 1 + .../axzo/im/controller/PrivateController.java | 14 +++++- .../axzo/im/dao/mapper/GroupMapperMapper.java | 6 --- .../im/dao/repository/GroupMemberDao.java | 35 ++++++++++---- .../cn/axzo/im/entity/AccountRegister.java | 7 +++ .../java/cn/axzo/im/entity/GroupMember.java | 9 ++++ .../cn/axzo/im/group/GroupBroadcaster.java | 6 +-- .../java/cn/axzo/im/group/GroupManager.java | 46 +++++++++++-------- .../im/group/controller/GroupController.java | 21 +++++++-- .../group/member/GroupMemberQueryService.java | 33 ------------- .../im/group/member/GroupMemberSyncer.java | 37 ++++++++++----- .../cn/axzo/im/service/domain/ImAccounts.java | 4 ++ 18 files changed, 196 insertions(+), 88 deletions(-) create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetInfoRequest.java create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetInfoResponse.java delete mode 100644 im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java index e5950b9..789ccd0 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java @@ -1,14 +1,17 @@ package cn.axzo.im.center.api.feign; import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.im.center.api.vo.group.GroupInfo; import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.req.GroupGetInfoRequest; import cn.axzo.im.center.api.vo.req.GroupGetMembersRequest; import cn.axzo.im.center.api.vo.req.GroupGetOwnerRequest; import cn.axzo.im.center.api.vo.req.GroupRemoveMembersRequest; import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; +import cn.axzo.im.center.api.vo.resp.GroupGetInfoResponse; import cn.axzo.im.center.api.vo.resp.GroupGetMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupGetOwnerResponse; import org.springframework.cloud.openfeign.FeignClient; @@ -58,4 +61,10 @@ public interface GroupApi { @PostMapping("/api/im/group/getOwner") ApiResult getOwner(@RequestBody @Validated GroupGetOwnerRequest request); + /** + * 获取群信息 + */ + @PostMapping("/api/im/group/getGroupInfo") + ApiResult getGroupInfo(@RequestBody @Validated GroupGetInfoRequest request); + } \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetInfoRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetInfoRequest.java new file mode 100644 index 0000000..1c26437 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupGetInfoRequest.java @@ -0,0 +1,18 @@ +package cn.axzo.im.center.api.vo.req; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotNull; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupGetInfoRequest { + + @NotNull(message = "群ID不能为空") + private Long tid; + +} diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupRemoveMembersRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupRemoveMembersRequest.java index 62dc102..cb9e9ef 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupRemoveMembersRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupRemoveMembersRequest.java @@ -1,6 +1,7 @@ package cn.axzo.im.center.api.vo.req; import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import com.alibaba.fastjson.JSON; import lombok.Getter; import lombok.Setter; @@ -24,4 +25,8 @@ public class GroupRemoveMembersRequest { @NotEmpty(message = "群成员不能为空") private Set members; + @Override + public String toString() { + return JSON.toJSONString(this); + } } \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetInfoResponse.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetInfoResponse.java new file mode 100644 index 0000000..9d221a1 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/GroupGetInfoResponse.java @@ -0,0 +1,20 @@ +package cn.axzo.im.center.api.vo.resp; + +import cn.axzo.im.center.api.vo.group.GroupInfo; +import com.alibaba.fastjson.JSON; +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class GroupGetInfoResponse { + private GroupInfo group; + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupMemberType.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupMemberType.java index f3cd724..c4ca67b 100644 --- a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupMemberType.java +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/GroupMemberType.java @@ -7,9 +7,9 @@ import cn.axzo.basics.common.constant.enums.CodeDefinition; */ public enum GroupMemberType implements CodeDefinition { - MEMBER, - OWNER - ; + OWNER, + ADMIN, + MEMBER; @Override public String getCode() { diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java index f6b063b..3ccc96b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java @@ -15,12 +15,17 @@ import java.util.Set; public class NimGroupInfo { private NimGroupMemberInfo owner; + private Set admins; private Set members; @JSONField(serialize = false, deserialize = false) public Set getOwnerAndMembers() { - HashSet ownerAndMembers = new HashSet<>(members); + HashSet ownerAndMembers = new HashSet<>(); ownerAndMembers.add(owner); + if (admins != null) + ownerAndMembers.addAll(admins); + if (members != null) + ownerAndMembers.addAll(members); return ownerAndMembers; } diff --git a/im-center-server/src/main/java/cn/axzo/im/config/MqProducer.java b/im-center-server/src/main/java/cn/axzo/im/config/MqProducer.java index 5c7ebd1..f40c6fe 100644 --- a/im-center-server/src/main/java/cn/axzo/im/config/MqProducer.java +++ b/im-center-server/src/main/java/cn/axzo/im/config/MqProducer.java @@ -31,6 +31,7 @@ public class MqProducer { } //生产消息 eventProducer.send(event); + log.info("send mq:{}", JSON.toJSONString(event)); } public void sendBatch(List events){ diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java index 7fa6641..0326593 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java @@ -10,7 +10,10 @@ import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; import cn.axzo.im.channel.netease.dto.NimQueryEventRequest; import cn.axzo.im.channel.netease.dto.NimQueryMessageRequest; import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; +import cn.axzo.im.dao.repository.GroupDao; +import cn.axzo.im.entity.Group; import cn.axzo.im.group.GroupManager; +import cn.axzo.im.group.member.GroupMemberSyncer; import cn.axzo.im.group.message.GroupMessageSyncJob; import cn.axzo.im.job.CreateMessageHistoryJob; import cn.axzo.im.job.ExpungeImTaskJob; @@ -40,7 +43,8 @@ public class PrivateController { private final MessageController messageController; private final ExpungeImTaskJob expungeImTaskJob; private final GroupManager groupManager; - private final GroupMessageSyncJob groupMessageSyncService; + private final GroupDao groupDao; + private final GroupMemberSyncer groupMemberSyncer; @PostMapping("/private/revoke") public Object revoke(@Valid @RequestBody NimRevokeMessageRequest request) { @@ -111,4 +115,12 @@ public class PrivateController { return CommonResponse.success(nimClient.getGroupInfo(request)); } + @PostMapping("/private/group/syncGroupMembers") + public Object syncGroupMembers(@RequestParam("tid") Long tid) { + Group group = groupDao.findByTid(tid, false).orElse(null); + if (group == null) return "group not found"; + groupMemberSyncer.syncMembers(group); + return CommonResponse.success("done"); + } + } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java index c7293f4..61477c6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/GroupMapperMapper.java @@ -2,15 +2,9 @@ package cn.axzo.im.dao.mapper; import cn.axzo.im.entity.GroupMember; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import org.apache.ibatis.annotations.Delete; -import org.apache.ibatis.annotations.Param; /** * @author yanglin */ public interface GroupMapperMapper extends BaseMapper { - - @Delete("DELETE FROM im_group_member WHERE tid = #{tid}") - void deleteAccounts(@Param("tid") Long tid); - } diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java index 223fbc5..05136a5 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java @@ -1,6 +1,7 @@ package cn.axzo.im.dao.repository; import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.common.enums.GroupMemberType; import cn.axzo.im.dao.mapper.GroupMapperMapper; import cn.axzo.im.entity.GroupMember; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -21,18 +22,14 @@ import static java.util.stream.Collectors.toSet; public class GroupMemberDao extends ServiceImpl { public void deleteAccounts(Long tid) { - getBaseMapper().deleteAccounts(tid); + lambdaUpdate() + .eq(GroupMember::getTid, tid) + .remove(); } public Set getGroupPersons(Long tid) { return getMembersByTid(tid).stream() - .map(account -> { - PersonAccountAttribute person = new PersonAccountAttribute(); - person.setPersonId(account.getPersonId() + ""); - person.setOuId(account.getPersonOuId()); - person.setAppType(account.getAppType()); - return person; - }) + .map(GroupMember::asPerson) .collect(toSet()); } @@ -42,6 +39,22 @@ public class GroupMemberDao extends ServiceImpl .list(); } + public void deleteByPersons(Long tid, Collection persons) { + if (CollectionUtils.isEmpty(persons)) + return; + lambdaUpdate() + .eq(GroupMember::getTid, tid) + .nested(wrapper -> { + for (PersonAccountAttribute person : persons) { + wrapper.or() + .eq(GroupMember::getPersonId, Long.parseLong(person.getPersonId())) + .eq(GroupMember::getPersonOuId, person.ouIdOrDefault()) + .eq(GroupMember::getAppType, person.getAppType()); + } + }) + .remove(); + } + public List getMembersByPersons( Long tid, Collection persons) { if (CollectionUtils.isEmpty(persons)) @@ -59,4 +72,10 @@ public class GroupMemberDao extends ServiceImpl .list(); } + public GroupMember getOwner(Long tid) { + return lambdaQuery() + .eq(GroupMember::getTid, tid) + .eq(GroupMember::getMemberType, GroupMemberType.OWNER) + .one(); + } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/AccountRegister.java b/im-center-server/src/main/java/cn/axzo/im/entity/AccountRegister.java index 006c6f4..1cb5896 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/AccountRegister.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/AccountRegister.java @@ -1,6 +1,7 @@ package cn.axzo.im.entity; import cn.axzo.im.center.common.enums.AppTypeEnum; +import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -100,4 +101,10 @@ public class AccountRegister implements Serializable { @TableField private Date updateAt; + + @Override + public String toString() { + return JSON.toJSONString(this); + } + } diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java index 761b25a..8e12144 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java @@ -1,5 +1,6 @@ package cn.axzo.im.entity; +import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.GroupMemberType; import cn.axzo.im.center.common.enums.GroupType; @@ -29,4 +30,12 @@ public class GroupMember { private Long isDelete; private Date createAt; private Date updateAt; + + public PersonAccountAttribute asPerson() { + PersonAccountAttribute person = new PersonAccountAttribute(); + person.setPersonId(personId + ""); + person.setOuId(personOuId); + person.setAppType(appType); + return person; + } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java index 4ba1f3c..bdb26b8 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupBroadcaster.java @@ -41,11 +41,11 @@ class GroupBroadcaster { } void fireMembersChanged(Group group, - Collection accounts, + Collection members, MqEventType eventType) { - if (accounts.isEmpty()) return; + if (members.isEmpty()) return; Group effectiveGroup = groupDao.getById(group.getId()); - for (GroupMember account : accounts) { + for (GroupMember account : members) { GroupMembersChangeMessage message = new GroupMembersChangeMessage(); message.setGroup(BeanMapper.copyBean(effectiveGroup, GroupInfo.class)); message.setMember(BeanMapper.copyBean(account, GroupMemberInfo.class)); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 6bd199c..74c1f56 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -31,7 +31,7 @@ import cn.axzo.im.utils.Notification; import com.alibaba.fastjson.JSON; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -118,20 +118,20 @@ public class GroupManager { @Transactional public GroupAddMembersResponse addMembers(GroupAddMembersRequest request) { Group group = getGroupForUpdateOrThrow(request.getTid()); - BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); + BizAssertions.assertFalse(group.isDismissed(), "群已经解散"); groupSupport.log(group.getTid(), "add-members", request); // sync members 1 groupMemberSyncer.syncMembers(group); // prepare add members - Set preMembers = groupMemberDao.getGroupPersons(group.getTid()); - Set toAddMembers = request.getMembers().stream() - .filter(member -> !preMembers.contains(member)) + Set prePersons = groupMemberDao.getGroupPersons(group.getTid()); + Set addPersons = request.getMembers().stream() + .filter(member -> !prePersons.contains(member)) .collect(toSet()); - if (toAddMembers.isEmpty()) + if (addPersons.isEmpty()) return new GroupAddMembersResponse(); - if (!group.addMoreMembers(preMembers.size() + toAddMembers.size())) - throw new ServiceException("群聊人数上限" + group.getMemberLimit() + "人, 请删除部分已选人员"); - ImAccounts imAccounts = accountService.getOrCreateImAccounts(toAddMembers); + BizAssertions.assertTrue(group.addMoreMembers(prePersons.size() + addPersons.size()), + "群聊人数上限{}人, 请删除部分已选人员", group.getMemberLimit()); + ImAccounts imAccounts = accountService.getOrCreateImAccounts(addPersons); if (imAccounts.isAccountEmpty()) { notification.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); @@ -147,7 +147,7 @@ public class GroupManager { // sync members 2 groupMemberSyncer.syncMembers(group); groupBroadcaster.fireMembersChanged(group, - groupMemberDao.getMembersByPersons(group.getTid(), toAddMembers), + groupMemberDao.getMembersByPersons(group.getTid(), addPersons), MqEventType.GROUP_ADD_MEMBERS); GroupAddMembersResponse response = new GroupAddMembersResponse(); response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( @@ -158,7 +158,7 @@ public class GroupManager { @Transactional public void removeMembers(GroupRemoveMembersRequest request) { Group group = getGroupForUpdateOrThrow(request.getTid()); - BizAssertions.assertFalse(group.isDismissed(), "群已经解散: {}", group.getTid()); + BizAssertions.assertFalse(group.isDismissed(), "群已经解散"); groupSupport.log(group.getTid(), "remove-members", request); ImAccounts imAccounts = accountService.getAccountsByPersons(request.getMembers()); if (imAccounts.isAccountEmpty()) { @@ -166,24 +166,34 @@ public class GroupManager { group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); return; } + // sync members 1 groupMemberSyncer.syncMembers(group); - List toRemoveMembers = groupMemberDao.getMembersByPersons( - group.getTid(), request.getMembers()); - if (CollectionUtils.isEmpty(toRemoveMembers)) + Set groupPersons = groupMemberDao + .getGroupPersons(group.getTid()); + Set removePersons = request.getMembers().stream() + .filter(groupPersons::contains) + .collect(toSet()); + if (CollectionUtils.isEmpty(removePersons)) { + log.info("移除群成员, 成员不在群中, request={}", request); return; - List groupMembers = groupMemberDao - .getMembersByTid(group.getTid()); + } BizAssertions.assertTrue( - groupMembers.size() - toRemoveMembers.size() >= 1, "无法移除, 群聊人数不能少于1人"); + groupPersons.size() - removePersons.size() >= 1, "无法移除, 群聊人数不能少于1人"); + PersonAccountAttribute owner = groupMemberDao.getOwner(request.getTid()).asPerson(); + BizAssertions.assertFalse(removePersons.contains(owner), "不能移除群主"); NimGroupRemoveMembersRequest nimRequest = groupSupport .buildRemoveMembersRequest(group, group.getOwnerAccount(), imAccounts); rateLimiter.requireRemoveMember(); NimGroupRemoveMembersResponse nimResponse = nimClient.removeGroupMembers(nimRequest); log.info("移除群成员, request={}, response={}", nimRequest, nimResponse); BizAssertions.assertTrue(nimResponse.isSuccess(), "移除群成员失败: {}", nimResponse.getDesc()); + // 同步前进行查询, 不然查询不到了 + List removeMembers = groupMemberDao + .getMembersByPersons(group.getTid(), removePersons); + // sync members 2 groupMemberSyncer.syncMembers(group); groupBroadcaster.fireMembersChanged(group, - toRemoveMembers, MqEventType.GROUP_REMOVE_MEMBERS); + removeMembers, MqEventType.GROUP_REMOVE_MEMBERS); } @NotNull diff --git a/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java index f26f2e9..4c30a14 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java @@ -3,20 +3,25 @@ package cn.axzo.im.group.controller; import cn.axzo.basics.common.BeanMapper; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.im.center.api.feign.GroupApi; +import cn.axzo.im.center.api.vo.group.GroupInfo; import cn.axzo.im.center.api.vo.group.GroupMemberInfo; import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.req.GroupGetInfoRequest; import cn.axzo.im.center.api.vo.req.GroupGetMembersRequest; import cn.axzo.im.center.api.vo.req.GroupGetOwnerRequest; import cn.axzo.im.center.api.vo.req.GroupRemoveMembersRequest; import cn.axzo.im.center.api.vo.resp.GroupAddMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupCreateResponse; +import cn.axzo.im.center.api.vo.resp.GroupGetInfoResponse; import cn.axzo.im.center.api.vo.resp.GroupGetMembersResponse; import cn.axzo.im.center.api.vo.resp.GroupGetOwnerResponse; +import cn.axzo.im.dao.repository.GroupDao; +import cn.axzo.im.dao.repository.GroupMemberDao; +import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMember; import cn.axzo.im.group.GroupManager; -import cn.axzo.im.group.member.GroupMemberQueryService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RestController; @@ -31,8 +36,9 @@ import java.util.List; @RequiredArgsConstructor public class GroupController implements GroupApi { + private final GroupDao groupDao; private final GroupManager groupManager; - private final GroupMemberQueryService groupMemberQueryService; + private final GroupMemberDao groupMemberDao; @Override public ApiResult createGroup(GroupCreateRequest request) { @@ -58,7 +64,7 @@ public class GroupController implements GroupApi { @Override public ApiResult getMembers(GroupGetMembersRequest request) { - List members = groupMemberQueryService.getMembers(request.getTid()); + List members = groupMemberDao.getMembersByTid(request.getTid()); GroupGetMembersResponse response = new GroupGetMembersResponse(); response.setMembers(BeanMapper.copyList(members, GroupMemberInfo.class)); return ApiResult.ok(response); @@ -66,10 +72,17 @@ public class GroupController implements GroupApi { @Override public ApiResult getOwner(GroupGetOwnerRequest request) { - GroupMember owner = groupMemberQueryService.getOwner(request.getTid()); + GroupMember owner = groupMemberDao.getOwner(request.getTid()); GroupGetOwnerResponse response = new GroupGetOwnerResponse(); response.setOwner(BeanMapper.copyBean(owner, GroupMemberInfo.class)); return ApiResult.ok(response); } + @Override + public ApiResult getGroupInfo(GroupGetInfoRequest request) { + Group group = groupDao.findByTid(request.getTid(), false).orElse(null); + GroupGetInfoResponse response = new GroupGetInfoResponse(); + response.setGroup(BeanMapper.copyBean(group, GroupInfo.class)); + return ApiResult.ok(response); + } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java deleted file mode 100644 index 94bb887..0000000 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberQueryService.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.axzo.im.group.member; - -import cn.axzo.im.center.common.enums.GroupMemberType; -import cn.axzo.im.dao.repository.GroupMemberDao; -import cn.axzo.im.entity.GroupMember; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.util.List; - -/** - * @author yanglin - */ -@Slf4j -@Component -@RequiredArgsConstructor -public class GroupMemberQueryService { - - private final GroupMemberDao groupMemberDao; - - public List getMembers(Long tid) { - return groupMemberDao.getMembersByTid(tid); - } - - public GroupMember getOwner(Long tid) { - return groupMemberDao.lambdaQuery() - .eq(GroupMember::getTid, tid) - .eq(GroupMember::getMemberType, GroupMemberType.OWNER) - .one(); - } - -} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index bfd07ff..e59de95 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -15,17 +15,20 @@ import cn.axzo.im.entity.GroupMember; import cn.axzo.im.group.support.GroupRateLimiter; import cn.axzo.im.utils.BizAssertions; import cn.axzo.im.utils.ImAccountParser; +import com.google.common.collect.Sets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; import org.springframework.transaction.support.TransactionTemplate; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.Set; import static cn.axzo.im.center.api.vo.PersonAccountAttribute.robot; +import static java.util.stream.Collectors.toSet; /** * @author yanglin @@ -44,12 +47,19 @@ public class GroupMemberSyncer { public void syncMembers(Group group) { NimGroupInfo groupInfo = fetchGroupInfo(group).orElse(null); if (groupInfo == null) return; - List accounts = parseGroupMembers(group, groupInfo); transactionTemplate.executeWithoutResult(unused -> { - groupMemberDao.deleteAccounts(group.getTid()); - if (CollectionUtils.isNotEmpty(accounts)) - groupMemberDao.saveBatch(accounts); - groupDao.updateMembersCount(group.getTid(), accounts.size()); + List newMembers = parseGroupMembers(group, groupInfo); + List oldMembers = groupMemberDao.getMembersByTid(group.getTid()); + Set newPersons = newMembers.stream().map(GroupMember::asPerson).collect(toSet()); + Set oldPersons = oldMembers.stream().map(GroupMember::asPerson).collect(toSet()); + + Sets.SetView removedPersons = Sets.difference(oldPersons, newPersons); + groupMemberDao.deleteByPersons(group.getTid(), removedPersons); + Sets.SetView addedPersons = Sets.difference(newPersons, oldPersons); + newMembers.removeIf(newMember -> !addedPersons.contains(newMember.asPerson())); + if (!newMembers.isEmpty()) + groupMemberDao.saveBatch(newMembers); + groupDao.updateMembersCount(group.getTid(), newMembers.size()); }); } @@ -69,24 +79,29 @@ public class GroupMemberSyncer { } private List parseGroupMembers(Group group, NimGroupInfo groupInfo) { - ArrayList accounts = new ArrayList<>(); + ArrayList members = new ArrayList<>(); + Set admins = groupInfo.getAdmins(); + if (admins == null) + admins = Collections.emptySet(); for (NimGroupMemberInfo member : groupInfo.getOwnerAndMembers()) { PersonAccountAttribute person = ImAccountParser .parsePerson(member.getAccid()) .orElse(robot()); GroupMember account = new GroupMember(); - accounts.add(account); + members.add(account); account.setTid(group.getTid()); account.setImAccount(member.getAccid()); account.setGroupType(group.getType()); - account.setMemberType(groupInfo.getOwner().equals(member) - ? GroupMemberType.OWNER : GroupMemberType.MEMBER); + account.setMemberType( + groupInfo.getOwner().equals(member) + ? GroupMemberType.OWNER + : (admins.contains(member) ? GroupMemberType.ADMIN : GroupMemberType.MEMBER)); account.setPersonId(person.personIdAsLong()); account.setPersonOuId(person.ouIdOrDefault()); account.setAppType(person.getAppType()); account.setIsRobot(person.isRobot() ? YesOrNo.YES : YesOrNo.NO); } - return accounts; + return members; } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java index b52ef2d..e48ff0b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java @@ -75,4 +75,8 @@ public class ImAccounts { && Objects.equals(person.ouIdOrDefault(), PersonAccountAttribute.getOuIdOrDefault(account.getOuId())); } + @Override + public String toString() { + return JSON.toJSONString(imAccounts); + } } \ No newline at end of file From 8e3ae7e2cd7a373e6ae911bab4826b7d580015b5 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 14:51:10 +0800 Subject: [PATCH 151/201] =?UTF-8?q?REQ-3345:=20=E7=A7=BB=E9=99=A4=E7=BE=A4?= =?UTF-8?q?=E6=88=90=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/GroupManager.java | 23 +++++++++++++++---- .../cn/axzo/im/service/domain/ImAccounts.java | 19 --------------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 74c1f56..1e86dc6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -37,6 +37,7 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import javax.validation.constraints.NotNull; +import java.util.Collections; import java.util.List; import java.util.Set; @@ -93,8 +94,8 @@ public class GroupManager { MqEventType.GROUP_ADD_MEMBERS); GroupCreateResponse response = new GroupCreateResponse(); response.setTid(nimResponse.getTid()); - response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( - notification, "创建群", group, request.getMembers())); + response.setAccountsNotFound(getAccountNotFoundPersons( + notification, "创建群", imAccounts, group, request.getMembers())); return response; } @@ -150,8 +151,8 @@ public class GroupManager { groupMemberDao.getMembersByPersons(group.getTid(), addPersons), MqEventType.GROUP_ADD_MEMBERS); GroupAddMembersResponse response = new GroupAddMembersResponse(); - response.setAccountsNotFound(imAccounts.getAccountNotFoundPersons( - notification, "添加群成员", group, request.getMembers())); + response.setAccountsNotFound(getAccountNotFoundPersons( + notification, "添加群成员", imAccounts, group, request.getMembers())); return response; } @@ -203,4 +204,18 @@ public class GroupManager { return group; } + public Set getAccountNotFoundPersons( + Notification notification, String operation, + ImAccounts accounts, Group group, Set persons) { + if (org.apache.commons.collections.CollectionUtils.isEmpty(persons)) + return Collections.emptySet(); + Set notFound = persons.stream() + .filter(person -> !accounts.findAccount(person).isPresent()) + .collect(toSet()); + if (!notFound.isEmpty()) + notification.send("{}[{},{}], IM账号不存在列表: {}", operation, + group.getTid(), group.getName(), + cn.axzo.framework.jackson.utility.JSON.toJSONString(notFound)); + return notFound; + } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java index e48ff0b..24d2b96 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/domain/ImAccounts.java @@ -3,13 +3,9 @@ package cn.axzo.im.service.domain; import cn.axzo.framework.jackson.utility.JSON; import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.entity.AccountRegister; -import cn.axzo.im.entity.Group; -import cn.axzo.im.utils.Notification; import lombok.RequiredArgsConstructor; import lombok.Setter; -import org.apache.commons.collections.CollectionUtils; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -31,21 +27,6 @@ public class ImAccounts { return imAccounts.isEmpty(); } - public Set getAccountNotFoundPersons( - Notification notification, String operation, - Group group, Set persons) { - if (CollectionUtils.isEmpty(persons)) - return Collections.emptySet(); - Set notFound = persons.stream() - .filter(person -> !findAccount(person).isPresent()) - .collect(toSet()); - if (!notFound.isEmpty()) - notification.send("{}[{},{}], IM账号不存在列表: {}", operation, - group.getTid(), group.getName(), - JSON.toJSONString(notFound)); - return notFound; - } - public Set filterAccounts(Predicate filter) { return getAccounts().stream() .filter(filter) From 6dd5b385301b1ed37af4021a82beef7e3158fd06 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 14:52:08 +0800 Subject: [PATCH 152/201] =?UTF-8?q?REQ-3345:=20=E7=A7=BB=E9=99=A4=E7=BE=A4?= =?UTF-8?q?=E6=88=90=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 1e86dc6..db6c825 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -95,7 +95,7 @@ public class GroupManager { GroupCreateResponse response = new GroupCreateResponse(); response.setTid(nimResponse.getTid()); response.setAccountsNotFound(getAccountNotFoundPersons( - notification, "创建群", imAccounts, group, request.getMembers())); + "创建群", imAccounts, group, request.getMembers())); return response; } @@ -152,7 +152,7 @@ public class GroupManager { MqEventType.GROUP_ADD_MEMBERS); GroupAddMembersResponse response = new GroupAddMembersResponse(); response.setAccountsNotFound(getAccountNotFoundPersons( - notification, "添加群成员", imAccounts, group, request.getMembers())); + "添加群成员", imAccounts, group, request.getMembers())); return response; } @@ -205,15 +205,15 @@ public class GroupManager { } public Set getAccountNotFoundPersons( - Notification notification, String operation, - ImAccounts accounts, Group group, Set persons) { + String operation, ImAccounts accounts, Group group, + Set persons) { if (org.apache.commons.collections.CollectionUtils.isEmpty(persons)) return Collections.emptySet(); Set notFound = persons.stream() .filter(person -> !accounts.findAccount(person).isPresent()) .collect(toSet()); if (!notFound.isEmpty()) - notification.send("{}[{},{}], IM账号不存在列表: {}", operation, + this.notification.send("{}[{},{}], IM账号不存在列表: {}", operation, group.getTid(), group.getName(), cn.axzo.framework.jackson.utility.JSON.toJSONString(notFound)); return notFound; From 0d42fd82ff38e7eb50c4cc6195eb28906224abbc Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 15:35:01 +0800 Subject: [PATCH 153/201] =?UTF-8?q?REQ-3345:=20=E7=A7=BB=E9=99=A4=E7=BE=A4?= =?UTF-8?q?=E6=88=90=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/member/GroupMemberSyncer.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index e59de95..ae127ff 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -28,6 +28,7 @@ import java.util.Optional; import java.util.Set; import static cn.axzo.im.center.api.vo.PersonAccountAttribute.robot; +import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; /** @@ -56,9 +57,11 @@ public class GroupMemberSyncer { Sets.SetView removedPersons = Sets.difference(oldPersons, newPersons); groupMemberDao.deleteByPersons(group.getTid(), removedPersons); Sets.SetView addedPersons = Sets.difference(newPersons, oldPersons); - newMembers.removeIf(newMember -> !addedPersons.contains(newMember.asPerson())); - if (!newMembers.isEmpty()) - groupMemberDao.saveBatch(newMembers); + List addedMembers = newMembers.stream() + .filter(newMember -> addedPersons.contains(newMember.asPerson())) + .collect(toList()); + if (!addedMembers.isEmpty()) + groupMemberDao.saveBatch(addedMembers); groupDao.updateMembersCount(group.getTid(), newMembers.size()); }); } From 449c172641f3fec21dff31865529813858b4e1a0 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 15:36:05 +0800 Subject: [PATCH 154/201] =?UTF-8?q?REQ-3345:=20=E7=A7=BB=E9=99=A4=E7=BE=A4?= =?UTF-8?q?=E6=88=90=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/member/GroupMemberSyncer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index ae127ff..c056b05 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -57,11 +57,11 @@ public class GroupMemberSyncer { Sets.SetView removedPersons = Sets.difference(oldPersons, newPersons); groupMemberDao.deleteByPersons(group.getTid(), removedPersons); Sets.SetView addedPersons = Sets.difference(newPersons, oldPersons); - List addedMembers = newMembers.stream() + List addMembers = newMembers.stream() .filter(newMember -> addedPersons.contains(newMember.asPerson())) .collect(toList()); - if (!addedMembers.isEmpty()) - groupMemberDao.saveBatch(addedMembers); + if (!addMembers.isEmpty()) + groupMemberDao.saveBatch(addMembers); groupDao.updateMembersCount(group.getTid(), newMembers.size()); }); } From ba374b92cad1a0b3f5015e79d14f60aea0740fbf Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 15:39:52 +0800 Subject: [PATCH 155/201] =?UTF-8?q?REQ-3345:=20=E7=A7=BB=E9=99=A4=E7=BE=A4?= =?UTF-8?q?=E6=88=90=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index db6c825..2cf015c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -87,7 +87,7 @@ public class GroupManager { group = groupDao.getById(group.getId()); groupSupport.log(group.getTid(), "create-group", request); groupMemberSyncer.syncMembers(group); - // 同步完成员后再发消息 + // 同步完成员后再发消息, 因为接收方可能会查询群成员 groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_CREATED); groupBroadcaster.fireMembersChanged(group, groupMemberDao.getMembersByTid(nimResponse.getTid()), From 332fc19dd09caa546876785c853b2508fc4995e5 Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 15:50:50 +0800 Subject: [PATCH 156/201] =?UTF-8?q?REQ-3345:=20=E7=A7=BB=E9=99=A4=E7=BE=A4?= =?UTF-8?q?=E6=88=90=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../im/channel/netease/dto/NimGroupInfo.java | 18 +++++++----------- .../im/group/member/GroupMemberSyncer.java | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java index 3ccc96b..b0d16d6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java +++ b/im-center-server/src/main/java/cn/axzo/im/channel/netease/dto/NimGroupInfo.java @@ -19,18 +19,14 @@ public class NimGroupInfo { private Set members; @JSONField(serialize = false, deserialize = false) - public Set getOwnerAndMembers() { - HashSet ownerAndMembers = new HashSet<>(); - ownerAndMembers.add(owner); + public Set getPeople() { + HashSet people = new HashSet<>(); + people.add(owner); if (admins != null) - ownerAndMembers.addAll(admins); - if (members != null) - ownerAndMembers.addAll(members); - return ownerAndMembers; - } - - public int memberCount() { - return getOwnerAndMembers().size(); + people.addAll(admins); + if (this.members != null) + people.addAll(this.members); + return people; } } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index c056b05..ab04890 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -86,7 +86,7 @@ public class GroupMemberSyncer { Set admins = groupInfo.getAdmins(); if (admins == null) admins = Collections.emptySet(); - for (NimGroupMemberInfo member : groupInfo.getOwnerAndMembers()) { + for (NimGroupMemberInfo member : groupInfo.getPeople()) { PersonAccountAttribute person = ImAccountParser .parsePerson(member.getAccid()) .orElse(robot()); From 95125c4aae42dc56fdbc6f57a098571564b45a3e Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 16:19:27 +0800 Subject: [PATCH 157/201] =?UTF-8?q?REQ-3345:=20=E7=A7=BB=E9=99=A4=E7=BE=A4?= =?UTF-8?q?=E6=88=90=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/center/api/vo/req/GroupCreateRequest.java | 2 +- .../src/main/java/cn/axzo/im/group/GroupManager.java | 6 +++--- .../src/main/java/cn/axzo/im/group/GroupSupport.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java index 28f9635..bda3e7b 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupCreateRequest.java @@ -72,7 +72,7 @@ public class GroupCreateRequest { } @JsonIgnore @JSONField(serialize = false, deserialize = false) - public Set getOwnerAndMembers() { + public Set getPeople() { Set ownerAndMembers = new HashSet<>(members); ownerAndMembers.add(owner); return ownerAndMembers; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 2cf015c..845916f 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -63,14 +63,14 @@ public class GroupManager { @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { - BizAssertions.assertTrue(request.getOwnerAndMembers().size() > 1, "群成员数量(含群主)不能少于2"); + BizAssertions.assertTrue(request.getPeople().size() > 1, "群成员数量(含群主)不能少于2"); groupSupport.log(0L, "create-group:preparing", request); - ImAccounts imAccounts = accountService.getOrCreateImAccounts(request.getOwnerAndMembers()); + ImAccounts imAccounts = accountService.getOrCreateImAccounts(request.getPeople()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); Group group = groupSupport.buildNewGroup(request, imAccounts); BizAssertions.assertTrue(group.addMoreMembers( - request.getOwnerAndMembers().size()), "无法创建群, 群成员数量超过上限" + group.getMemberLimit()); + request.getPeople().size()), "无法创建群, 群成员数量超过上限" + group.getMemberLimit()); try { groupDao.save(group); } catch (DuplicateKeyException e) { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index 7940ed5..7570f67 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -38,7 +38,7 @@ public class GroupSupport { group.setType(request.getGroupType()); group.setBizGroupInfo(request.bizGroupInfoOrEmpty()); group.setAvatar(request.getAvatar()); - group.setMemberCount((long) request.getOwnerAndMembers().size()); + group.setMemberCount((long) request.getPeople().size()); Long memberLimit = request.getMemberLimit(); if (memberLimit == null) memberLimit = (long) groupProps.getDefaultMemberLimit(); From 13f2f3de17687aee6dacd7d296e6f1722d70adab Mon Sep 17 00:00:00 2001 From: yanglin Date: Sat, 8 Feb 2025 18:40:34 +0800 Subject: [PATCH 158/201] REQ-3345: fix bugs --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 845916f..2d093d9 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -152,7 +152,7 @@ public class GroupManager { MqEventType.GROUP_ADD_MEMBERS); GroupAddMembersResponse response = new GroupAddMembersResponse(); response.setAccountsNotFound(getAccountNotFoundPersons( - "添加群成员", imAccounts, group, request.getMembers())); + "添加群成员", imAccounts, group, addPersons)); return response; } From c177d51b2a119b52cccc1cf07021e64d8df475c4 Mon Sep 17 00:00:00 2001 From: yanglin Date: Mon, 10 Feb 2025 09:17:06 +0800 Subject: [PATCH 159/201] REQ-3345: fix bugs --- .../java/cn/axzo/im/dao/repository/GroupMemberDao.java | 8 ++++---- .../src/main/java/cn/axzo/im/group/GroupManager.java | 10 +++++----- .../cn/axzo/im/group/controller/GroupController.java | 2 +- .../cn/axzo/im/group/member/GroupMemberSyncer.java | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java index 05136a5..dbbc4e7 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java @@ -27,13 +27,13 @@ public class GroupMemberDao extends ServiceImpl .remove(); } - public Set getGroupPersons(Long tid) { - return getMembersByTid(tid).stream() + public Set getAsPersons(Long tid) { + return getByTid(tid).stream() .map(GroupMember::asPerson) .collect(toSet()); } - public List getMembersByTid(Long tid) { + public List getByTid(Long tid) { return lambdaQuery() .eq(GroupMember::getTid, tid) .list(); @@ -55,7 +55,7 @@ public class GroupMemberDao extends ServiceImpl .remove(); } - public List getMembersByPersons( + public List getByPersons( Long tid, Collection persons) { if (CollectionUtils.isEmpty(persons)) return Collections.emptyList(); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 2d093d9..2de4d40 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -90,7 +90,7 @@ public class GroupManager { // 同步完成员后再发消息, 因为接收方可能会查询群成员 groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_CREATED); groupBroadcaster.fireMembersChanged(group, - groupMemberDao.getMembersByTid(nimResponse.getTid()), + groupMemberDao.getByTid(nimResponse.getTid()), MqEventType.GROUP_ADD_MEMBERS); GroupCreateResponse response = new GroupCreateResponse(); response.setTid(nimResponse.getTid()); @@ -124,7 +124,7 @@ public class GroupManager { // sync members 1 groupMemberSyncer.syncMembers(group); // prepare add members - Set prePersons = groupMemberDao.getGroupPersons(group.getTid()); + Set prePersons = groupMemberDao.getAsPersons(group.getTid()); Set addPersons = request.getMembers().stream() .filter(member -> !prePersons.contains(member)) .collect(toSet()); @@ -148,7 +148,7 @@ public class GroupManager { // sync members 2 groupMemberSyncer.syncMembers(group); groupBroadcaster.fireMembersChanged(group, - groupMemberDao.getMembersByPersons(group.getTid(), addPersons), + groupMemberDao.getByPersons(group.getTid(), addPersons), MqEventType.GROUP_ADD_MEMBERS); GroupAddMembersResponse response = new GroupAddMembersResponse(); response.setAccountsNotFound(getAccountNotFoundPersons( @@ -170,7 +170,7 @@ public class GroupManager { // sync members 1 groupMemberSyncer.syncMembers(group); Set groupPersons = groupMemberDao - .getGroupPersons(group.getTid()); + .getAsPersons(group.getTid()); Set removePersons = request.getMembers().stream() .filter(groupPersons::contains) .collect(toSet()); @@ -190,7 +190,7 @@ public class GroupManager { BizAssertions.assertTrue(nimResponse.isSuccess(), "移除群成员失败: {}", nimResponse.getDesc()); // 同步前进行查询, 不然查询不到了 List removeMembers = groupMemberDao - .getMembersByPersons(group.getTid(), removePersons); + .getByPersons(group.getTid(), removePersons); // sync members 2 groupMemberSyncer.syncMembers(group); groupBroadcaster.fireMembersChanged(group, diff --git a/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java index 4c30a14..d6e70f0 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java @@ -64,7 +64,7 @@ public class GroupController implements GroupApi { @Override public ApiResult getMembers(GroupGetMembersRequest request) { - List members = groupMemberDao.getMembersByTid(request.getTid()); + List members = groupMemberDao.getByTid(request.getTid()); GroupGetMembersResponse response = new GroupGetMembersResponse(); response.setMembers(BeanMapper.copyList(members, GroupMemberInfo.class)); return ApiResult.ok(response); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java index ab04890..7793c7a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java @@ -50,7 +50,7 @@ public class GroupMemberSyncer { if (groupInfo == null) return; transactionTemplate.executeWithoutResult(unused -> { List newMembers = parseGroupMembers(group, groupInfo); - List oldMembers = groupMemberDao.getMembersByTid(group.getTid()); + List oldMembers = groupMemberDao.getByTid(group.getTid()); Set newPersons = newMembers.stream().map(GroupMember::asPerson).collect(toSet()); Set oldPersons = oldMembers.stream().map(GroupMember::asPerson).collect(toSet()); From f8af4fba2e2c2c23aa0bdf649f6c07f79113b7bb Mon Sep 17 00:00:00 2001 From: yanglin Date: Mon, 10 Feb 2025 09:17:55 +0800 Subject: [PATCH 160/201] REQ-3345: fix bugs --- .../src/main/java/cn/axzo/im/controller/PrivateController.java | 3 +-- .../src/main/java/cn/axzo/im/group/GroupManager.java | 1 - .../java/cn/axzo/im/group/{member => }/GroupMemberSyncer.java | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) rename im-center-server/src/main/java/cn/axzo/im/group/{member => }/GroupMemberSyncer.java (99%) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java index 0326593..2dabd65 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java @@ -13,8 +13,7 @@ import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.entity.Group; import cn.axzo.im.group.GroupManager; -import cn.axzo.im.group.member.GroupMemberSyncer; -import cn.axzo.im.group.message.GroupMessageSyncJob; +import cn.axzo.im.group.GroupMemberSyncer; import cn.axzo.im.job.CreateMessageHistoryJob; import cn.axzo.im.job.ExpungeImTaskJob; import cn.axzo.im.job.RevokeAllMessagesJob; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 2de4d40..2159f69 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -22,7 +22,6 @@ import cn.axzo.im.dao.repository.GroupDao; import cn.axzo.im.dao.repository.GroupMemberDao; import cn.axzo.im.entity.Group; import cn.axzo.im.entity.GroupMember; -import cn.axzo.im.group.member.GroupMemberSyncer; import cn.axzo.im.group.support.GroupRateLimiter; import cn.axzo.im.service.AccountService; import cn.axzo.im.service.domain.ImAccounts; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberSyncer.java similarity index 99% rename from im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java rename to im-center-server/src/main/java/cn/axzo/im/group/GroupMemberSyncer.java index 7793c7a..48c39e2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/member/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberSyncer.java @@ -1,4 +1,4 @@ -package cn.axzo.im.group.member; +package cn.axzo.im.group; import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.common.enums.GroupMemberType; From ebcb1b391607af103cc7c41fc55fc7b03212c599 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 14 Feb 2025 10:00:22 +0800 Subject: [PATCH 161/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupSupport.java | 2 +- .../src/main/java/cn/axzo/im/group/support/GroupProps.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index 7570f67..39b9592 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -41,7 +41,7 @@ public class GroupSupport { group.setMemberCount((long) request.getPeople().size()); Long memberLimit = request.getMemberLimit(); if (memberLimit == null) - memberLimit = (long) groupProps.getDefaultMemberLimit(); + memberLimit = groupProps.getDefaultMemberLimit(); group.setMemberLimit(memberLimit); group.setOwnerAccount(owner); group.setOwnerPersonId(request.getOwner().personIdAsLong()); diff --git a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java index c629224..eee64c2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java @@ -17,7 +17,7 @@ import org.springframework.context.annotation.Configuration; @ConfigurationProperties(prefix = "im-group") public class GroupProps { - private int defaultMemberLimit = 499; + private long defaultMemberLimit = 499; private int syncMessageTps = 20; private int createGroupTps = 10; From 1974e3952dbf77a700e60f8bff304f8005a7f453 Mon Sep 17 00:00:00 2001 From: yanglin Date: Mon, 17 Feb 2025 17:52:44 +0800 Subject: [PATCH 162/201] =?UTF-8?q?REQ-3345:=20=E8=A7=A3=E6=95=A3=E7=9A=84?= =?UTF-8?q?=E7=BE=A4=E5=8F=AF=E4=BB=A5=E9=87=8D=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/dao/repository/GroupDao.java | 9 +++++++++ .../main/java/cn/axzo/im/group/GroupManager.java | 13 +++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java index 5945663..a795556 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java @@ -1,5 +1,6 @@ package cn.axzo.im.dao.repository; +import cn.axzo.im.center.common.enums.GroupType; import cn.axzo.im.center.common.enums.YesOrNo; import cn.axzo.im.dao.mapper.GroupMapper; import cn.axzo.im.entity.Group; @@ -45,4 +46,12 @@ public class GroupDao extends ServiceImpl { .update(); } + public Optional findByBizCode(String bizCode, GroupType groupType, boolean forUpdate) { + return lambdaQuery() + .eq(Group::getBizCode, bizCode) + .eq(Group::getType, groupType) + .last(forUpdate, "FOR UPDATE") + .oneOpt(); + } + } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 2159f69..ac9e7ff 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -1,6 +1,5 @@ package cn.axzo.im.group; -import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.im.center.api.enums.MqEventType; import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; @@ -31,7 +30,6 @@ import com.alibaba.fastjson.JSON; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; -import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -64,18 +62,17 @@ public class GroupManager { public GroupCreateResponse createGroup(GroupCreateRequest request) { BizAssertions.assertTrue(request.getPeople().size() > 1, "群成员数量(含群主)不能少于2"); groupSupport.log(0L, "create-group:preparing", request); + Group savedGroup = groupDao.findByBizCode(request.getBizCode(), request.getGroupType(), true) + .orElse(null); + BizAssertions.assertNull(savedGroup == null || savedGroup.isDismissed(), + String.format("群已经存在: %s", request.getName())); ImAccounts imAccounts = accountService.getOrCreateImAccounts(request.getPeople()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); Group group = groupSupport.buildNewGroup(request, imAccounts); BizAssertions.assertTrue(group.addMoreMembers( request.getPeople().size()), "无法创建群, 群成员数量超过上限" + group.getMemberLimit()); - try { - groupDao.save(group); - } catch (DuplicateKeyException e) { - log.warn("重复创建群, request={}", request, e); - throw new ServiceException(403, String.format("群已经存在: %s", request.getName())); - } + groupDao.save(group); NimGroupCreateRequest nimRequest = groupSupport .buildNimCreateGroupRequest(request, imAccounts); rateLimiter.requireCreateGroup(); From f5c3b8d4b1d25d2854b1578d7aa7dcef755db44c Mon Sep 17 00:00:00 2001 From: yanglin Date: Mon, 17 Feb 2025 18:21:08 +0800 Subject: [PATCH 163/201] =?UTF-8?q?REQ-3345:=20=E8=A7=A3=E6=95=A3=E7=9A=84?= =?UTF-8?q?=E7=BE=A4=E5=8F=AF=E4=BB=A5=E9=87=8D=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index ac9e7ff..0bb3380 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -64,7 +64,7 @@ public class GroupManager { groupSupport.log(0L, "create-group:preparing", request); Group savedGroup = groupDao.findByBizCode(request.getBizCode(), request.getGroupType(), true) .orElse(null); - BizAssertions.assertNull(savedGroup == null || savedGroup.isDismissed(), + BizAssertions.assertTrue(savedGroup == null || savedGroup.isDismissed(), String.format("群已经存在: %s", request.getName())); ImAccounts imAccounts = accountService.getOrCreateImAccounts(request.getPeople()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); From bf304c82926e9a8c167405c18bddac26d61cb104 Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 18 Feb 2025 14:41:49 +0800 Subject: [PATCH 164/201] =?UTF-8?q?REQ-3345:=20=E8=A7=A3=E5=86=B3=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E4=B8=8D=E5=88=B0=E8=B4=A6=E5=8F=B7=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/GroupManager.java | 102 +++++++++--------- 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 0bb3380..02679a2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -32,6 +32,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionTemplate; import javax.validation.constraints.NotNull; import java.util.Collections; @@ -57,8 +58,8 @@ public class GroupManager { private final GroupMemberSyncer groupMemberSyncer; private final GroupRateLimiter rateLimiter; private final Notification notification; + private final TransactionTemplate transactionTemplate; - @Transactional public GroupCreateResponse createGroup(GroupCreateRequest request) { BizAssertions.assertTrue(request.getPeople().size() > 1, "群成员数量(含群主)不能少于2"); groupSupport.log(0L, "create-group:preparing", request); @@ -67,32 +68,34 @@ public class GroupManager { BizAssertions.assertTrue(savedGroup == null || savedGroup.isDismissed(), String.format("群已经存在: %s", request.getName())); ImAccounts imAccounts = accountService.getOrCreateImAccounts(request.getPeople()); - String owner = imAccounts.findAccount(request.getOwner()).orElse(null); - BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); - Group group = groupSupport.buildNewGroup(request, imAccounts); - BizAssertions.assertTrue(group.addMoreMembers( - request.getPeople().size()), "无法创建群, 群成员数量超过上限" + group.getMemberLimit()); - groupDao.save(group); - NimGroupCreateRequest nimRequest = groupSupport - .buildNimCreateGroupRequest(request, imAccounts); - rateLimiter.requireCreateGroup(); - NimGroupCreateResponse nimResponse = nimClient.createGroup(nimRequest); - log.info("创建群, request={}, response={}", nimRequest, nimResponse); - BizAssertions.assertTrue(nimResponse.isSuccess(), "创建群失败: {}", nimResponse.getDesc()); - groupDao.updateTid(group.getId(), nimResponse.getTid()); - group = groupDao.getById(group.getId()); - groupSupport.log(group.getTid(), "create-group", request); - groupMemberSyncer.syncMembers(group); - // 同步完成员后再发消息, 因为接收方可能会查询群成员 - groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_CREATED); - groupBroadcaster.fireMembersChanged(group, - groupMemberDao.getByTid(nimResponse.getTid()), - MqEventType.GROUP_ADD_MEMBERS); - GroupCreateResponse response = new GroupCreateResponse(); - response.setTid(nimResponse.getTid()); - response.setAccountsNotFound(getAccountNotFoundPersons( - "创建群", imAccounts, group, request.getMembers())); - return response; + return transactionTemplate.execute(unused -> { + String owner = imAccounts.findAccount(request.getOwner()).orElse(null); + BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); + Group group = groupSupport.buildNewGroup(request, imAccounts); + BizAssertions.assertTrue(group.addMoreMembers( + request.getPeople().size()), "无法创建群, 群成员数量超过上限" + group.getMemberLimit()); + groupDao.save(group); + NimGroupCreateRequest nimRequest = groupSupport + .buildNimCreateGroupRequest(request, imAccounts); + rateLimiter.requireCreateGroup(); + NimGroupCreateResponse nimResponse = nimClient.createGroup(nimRequest); + log.info("创建群, request={}, response={}", nimRequest, nimResponse); + BizAssertions.assertTrue(nimResponse.isSuccess(), "创建群失败: {}", nimResponse.getDesc()); + groupDao.updateTid(group.getId(), nimResponse.getTid()); + group = groupDao.getById(group.getId()); + groupSupport.log(group.getTid(), "create-group", request); + groupMemberSyncer.syncMembers(group); + // 同步完成员后再发消息, 因为接收方可能会查询群成员 + groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_CREATED); + groupBroadcaster.fireMembersChanged(group, + groupMemberDao.getByTid(nimResponse.getTid()), + MqEventType.GROUP_ADD_MEMBERS); + GroupCreateResponse response = new GroupCreateResponse(); + response.setTid(nimResponse.getTid()); + response.setAccountsNotFound(getAccountNotFoundPersons( + "创建群", imAccounts, group, request.getMembers())); + return response; + }); } @Transactional @@ -112,7 +115,6 @@ public class GroupManager { groupBroadcaster.fireGroupChanged(group, MqEventType.GROUP_DISMISSED); } - @Transactional public GroupAddMembersResponse addMembers(GroupAddMembersRequest request) { Group group = getGroupForUpdateOrThrow(request.getTid()); BizAssertions.assertFalse(group.isDismissed(), "群已经解散"); @@ -129,27 +131,29 @@ public class GroupManager { BizAssertions.assertTrue(group.addMoreMembers(prePersons.size() + addPersons.size()), "群聊人数上限{}人, 请删除部分已选人员", group.getMemberLimit()); ImAccounts imAccounts = accountService.getOrCreateImAccounts(addPersons); - if (imAccounts.isAccountEmpty()) { - notification.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", - group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); - return new GroupAddMembersResponse(); - } - NimGroupAddMembersRequest nimRequest = groupSupport - .buildAddMembersRequest(group, group.getOwnerAccount(), imAccounts); - // add members - rateLimiter.requireAddMember(); - NimGroupAddMembersResponse nimResponse = nimClient.addGroupMembers(nimRequest); - log.info("添加群成员, request={}, response={}", nimRequest, nimResponse); - BizAssertions.assertTrue(nimResponse.isSuccess(), "添加群成员失败: {}", nimResponse.getDesc()); - // sync members 2 - groupMemberSyncer.syncMembers(group); - groupBroadcaster.fireMembersChanged(group, - groupMemberDao.getByPersons(group.getTid(), addPersons), - MqEventType.GROUP_ADD_MEMBERS); - GroupAddMembersResponse response = new GroupAddMembersResponse(); - response.setAccountsNotFound(getAccountNotFoundPersons( - "添加群成员", imAccounts, group, addPersons)); - return response; + return transactionTemplate.execute(unused -> { + if (imAccounts.isAccountEmpty()) { + notification.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); + return new GroupAddMembersResponse(); + } + NimGroupAddMembersRequest nimRequest = groupSupport + .buildAddMembersRequest(group, group.getOwnerAccount(), imAccounts); + // add members + rateLimiter.requireAddMember(); + NimGroupAddMembersResponse nimResponse = nimClient.addGroupMembers(nimRequest); + log.info("添加群成员, request={}, response={}", nimRequest, nimResponse); + BizAssertions.assertTrue(nimResponse.isSuccess(), "添加群成员失败: {}", nimResponse.getDesc()); + // sync members 2 + groupMemberSyncer.syncMembers(group); + groupBroadcaster.fireMembersChanged(group, + groupMemberDao.getByPersons(group.getTid(), addPersons), + MqEventType.GROUP_ADD_MEMBERS); + GroupAddMembersResponse response = new GroupAddMembersResponse(); + response.setAccountsNotFound(getAccountNotFoundPersons( + "添加群成员", imAccounts, group, addPersons)); + return response; + }); } @Transactional From d4af3adae34236cf100aef111dc4624992e5c2a4 Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 18 Feb 2025 16:10:39 +0800 Subject: [PATCH 165/201] =?UTF-8?q?REQ-3345:=20=E8=A7=A3=E5=86=B3=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E4=B8=8D=E5=88=B0=E8=B4=A6=E5=8F=B7=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 02679a2..8adbeb6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -68,9 +68,9 @@ public class GroupManager { BizAssertions.assertTrue(savedGroup == null || savedGroup.isDismissed(), String.format("群已经存在: %s", request.getName())); ImAccounts imAccounts = accountService.getOrCreateImAccounts(request.getPeople()); + String owner = imAccounts.findAccount(request.getOwner()).orElse(null); + BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); return transactionTemplate.execute(unused -> { - String owner = imAccounts.findAccount(request.getOwner()).orElse(null); - BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); Group group = groupSupport.buildNewGroup(request, imAccounts); BizAssertions.assertTrue(group.addMoreMembers( request.getPeople().size()), "无法创建群, 群成员数量超过上限" + group.getMemberLimit()); From 88ab9bcc65291a35aeca83f90079d2b3b8e24491 Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 18 Feb 2025 16:16:43 +0800 Subject: [PATCH 166/201] =?UTF-8?q?REQ-3345:=20=E8=A7=A3=E5=86=B3=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E4=B8=8D=E5=88=B0=E8=B4=A6=E5=8F=B7=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/GroupManager.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 8adbeb6..4657b7b 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -116,7 +116,8 @@ public class GroupManager { } public GroupAddMembersResponse addMembers(GroupAddMembersRequest request) { - Group group = getGroupForUpdateOrThrow(request.getTid()); + Group group = groupDao.findByTid(request.getTid(), false).orElse(null); + //noinspection DataFlowIssue BizAssertions.assertFalse(group.isDismissed(), "群已经解散"); groupSupport.log(group.getTid(), "add-members", request); // sync members 1 @@ -128,19 +129,20 @@ public class GroupManager { .collect(toSet()); if (addPersons.isEmpty()) return new GroupAddMembersResponse(); + ImAccounts imAccounts = accountService.getOrCreateImAccounts(addPersons); BizAssertions.assertTrue(group.addMoreMembers(prePersons.size() + addPersons.size()), "群聊人数上限{}人, 请删除部分已选人员", group.getMemberLimit()); - ImAccounts imAccounts = accountService.getOrCreateImAccounts(addPersons); + if (imAccounts.isAccountEmpty()) { + notification.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); + return new GroupAddMembersResponse(); + } + NimGroupAddMembersRequest nimRequest = groupSupport + .buildAddMembersRequest(group, group.getOwnerAccount(), imAccounts); + // add members + rateLimiter.requireAddMember(); return transactionTemplate.execute(unused -> { - if (imAccounts.isAccountEmpty()) { - notification.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", - group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); - return new GroupAddMembersResponse(); - } - NimGroupAddMembersRequest nimRequest = groupSupport - .buildAddMembersRequest(group, group.getOwnerAccount(), imAccounts); - // add members - rateLimiter.requireAddMember(); + getGroupForUpdateOrThrow(group.getTid()); NimGroupAddMembersResponse nimResponse = nimClient.addGroupMembers(nimRequest); log.info("添加群成员, request={}, response={}", nimRequest, nimResponse); BizAssertions.assertTrue(nimResponse.isSuccess(), "添加群成员失败: {}", nimResponse.getDesc()); From 3e30c85a5c6ba49599a4851cf93e086383e100fb Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 18 Feb 2025 16:26:04 +0800 Subject: [PATCH 167/201] =?UTF-8?q?Revert=20"REQ-3345:=20=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E6=9F=A5=E8=AF=A2=E4=B8=8D=E5=88=B0=E8=B4=A6=E5=8F=B7?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 88ab9bcc65291a35aeca83f90079d2b3b8e24491. --- .../java/cn/axzo/im/group/GroupManager.java | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 4657b7b..8adbeb6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -116,8 +116,7 @@ public class GroupManager { } public GroupAddMembersResponse addMembers(GroupAddMembersRequest request) { - Group group = groupDao.findByTid(request.getTid(), false).orElse(null); - //noinspection DataFlowIssue + Group group = getGroupForUpdateOrThrow(request.getTid()); BizAssertions.assertFalse(group.isDismissed(), "群已经解散"); groupSupport.log(group.getTid(), "add-members", request); // sync members 1 @@ -129,20 +128,19 @@ public class GroupManager { .collect(toSet()); if (addPersons.isEmpty()) return new GroupAddMembersResponse(); - ImAccounts imAccounts = accountService.getOrCreateImAccounts(addPersons); BizAssertions.assertTrue(group.addMoreMembers(prePersons.size() + addPersons.size()), "群聊人数上限{}人, 请删除部分已选人员", group.getMemberLimit()); - if (imAccounts.isAccountEmpty()) { - notification.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", - group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); - return new GroupAddMembersResponse(); - } - NimGroupAddMembersRequest nimRequest = groupSupport - .buildAddMembersRequest(group, group.getOwnerAccount(), imAccounts); - // add members - rateLimiter.requireAddMember(); + ImAccounts imAccounts = accountService.getOrCreateImAccounts(addPersons); return transactionTemplate.execute(unused -> { - getGroupForUpdateOrThrow(group.getTid()); + if (imAccounts.isAccountEmpty()) { + notification.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", + group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); + return new GroupAddMembersResponse(); + } + NimGroupAddMembersRequest nimRequest = groupSupport + .buildAddMembersRequest(group, group.getOwnerAccount(), imAccounts); + // add members + rateLimiter.requireAddMember(); NimGroupAddMembersResponse nimResponse = nimClient.addGroupMembers(nimRequest); log.info("添加群成员, request={}, response={}", nimRequest, nimResponse); BizAssertions.assertTrue(nimResponse.isSuccess(), "添加群成员失败: {}", nimResponse.getDesc()); From 72a8ee121ea24009885e02d3b2504aa422b4c3d6 Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 18 Feb 2025 16:27:48 +0800 Subject: [PATCH 168/201] =?UTF-8?q?REQ-3345:=20=E8=A7=A3=E5=86=B3=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E4=B8=8D=E5=88=B0=E8=B4=A6=E5=8F=B7=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/GroupManager.java | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 8adbeb6..cea3375 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -116,22 +116,24 @@ public class GroupManager { } public GroupAddMembersResponse addMembers(GroupAddMembersRequest request) { - Group group = getGroupForUpdateOrThrow(request.getTid()); - BizAssertions.assertFalse(group.isDismissed(), "群已经解散"); - groupSupport.log(group.getTid(), "add-members", request); - // sync members 1 - groupMemberSyncer.syncMembers(group); - // prepare add members - Set prePersons = groupMemberDao.getAsPersons(group.getTid()); - Set addPersons = request.getMembers().stream() - .filter(member -> !prePersons.contains(member)) - .collect(toSet()); - if (addPersons.isEmpty()) - return new GroupAddMembersResponse(); - BizAssertions.assertTrue(group.addMoreMembers(prePersons.size() + addPersons.size()), - "群聊人数上限{}人, 请删除部分已选人员", group.getMemberLimit()); - ImAccounts imAccounts = accountService.getOrCreateImAccounts(addPersons); + // DON'T delete this line + accountService.getOrCreateImAccounts(request.getMembers()); return transactionTemplate.execute(unused -> { + Group group = getGroupForUpdateOrThrow(request.getTid()); + BizAssertions.assertFalse(group.isDismissed(), "群已经解散"); + groupSupport.log(group.getTid(), "add-members", request); + // sync members 1 + groupMemberSyncer.syncMembers(group); + // prepare add members + Set prePersons = groupMemberDao.getAsPersons(group.getTid()); + Set addPersons = request.getMembers().stream() + .filter(member -> !prePersons.contains(member)) + .collect(toSet()); + if (addPersons.isEmpty()) + return new GroupAddMembersResponse(); + BizAssertions.assertTrue(group.addMoreMembers(prePersons.size() + addPersons.size()), + "群聊人数上限{}人, 请删除部分已选人员", group.getMemberLimit()); + ImAccounts imAccounts = accountService.getOrCreateImAccounts(addPersons); if (imAccounts.isAccountEmpty()) { notification.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); From 86a2e2fdbecb6b67a7a1cdfd9a88842ccca5fbf5 Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 18 Feb 2025 16:35:00 +0800 Subject: [PATCH 169/201] =?UTF-8?q?REQ-3345:=20=E8=A7=A3=E5=86=B3=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E4=B8=8D=E5=88=B0=E8=B4=A6=E5=8F=B7=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/GroupManager.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index cea3375..cfce088 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -63,14 +63,16 @@ public class GroupManager { public GroupCreateResponse createGroup(GroupCreateRequest request) { BizAssertions.assertTrue(request.getPeople().size() > 1, "群成员数量(含群主)不能少于2"); groupSupport.log(0L, "create-group:preparing", request); - Group savedGroup = groupDao.findByBizCode(request.getBizCode(), request.getGroupType(), true) - .orElse(null); - BizAssertions.assertTrue(savedGroup == null || savedGroup.isDismissed(), - String.format("群已经存在: %s", request.getName())); - ImAccounts imAccounts = accountService.getOrCreateImAccounts(request.getPeople()); - String owner = imAccounts.findAccount(request.getOwner()).orElse(null); - BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); + // DON'T delete this line + accountService.getOrCreateImAccounts(request.getPeople()); return transactionTemplate.execute(unused -> { + Group savedGroup = groupDao.findByBizCode(request.getBizCode(), request.getGroupType(), true) + .orElse(null); + BizAssertions.assertTrue(savedGroup == null || savedGroup.isDismissed(), + String.format("群已经存在: %s", request.getName())); + ImAccounts imAccounts = accountService.getOrCreateImAccounts(request.getPeople()); + String owner = imAccounts.findAccount(request.getOwner()).orElse(null); + BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); Group group = groupSupport.buildNewGroup(request, imAccounts); BizAssertions.assertTrue(group.addMoreMembers( request.getPeople().size()), "无法创建群, 群成员数量超过上限" + group.getMemberLimit()); @@ -120,8 +122,8 @@ public class GroupManager { accountService.getOrCreateImAccounts(request.getMembers()); return transactionTemplate.execute(unused -> { Group group = getGroupForUpdateOrThrow(request.getTid()); - BizAssertions.assertFalse(group.isDismissed(), "群已经解散"); groupSupport.log(group.getTid(), "add-members", request); + BizAssertions.assertFalse(group.isDismissed(), "群已经解散"); // sync members 1 groupMemberSyncer.syncMembers(group); // prepare add members From e1cb4c61ce38998f5122b57f46e3c1bc58eee59a Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 18 Feb 2025 16:37:27 +0800 Subject: [PATCH 170/201] =?UTF-8?q?REQ-3345:=20=E8=A7=A3=E5=86=B3=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E4=B8=8D=E5=88=B0=E8=B4=A6=E5=8F=B7=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 8 ++++---- .../src/main/java/cn/axzo/im/service/AccountService.java | 8 +++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index cfce088..740ad92 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -64,13 +64,13 @@ public class GroupManager { BizAssertions.assertTrue(request.getPeople().size() > 1, "群成员数量(含群主)不能少于2"); groupSupport.log(0L, "create-group:preparing", request); // DON'T delete this line - accountService.getOrCreateImAccounts(request.getPeople()); + accountService.maybeCreateImAccounts(request.getPeople()); return transactionTemplate.execute(unused -> { Group savedGroup = groupDao.findByBizCode(request.getBizCode(), request.getGroupType(), true) .orElse(null); BizAssertions.assertTrue(savedGroup == null || savedGroup.isDismissed(), String.format("群已经存在: %s", request.getName())); - ImAccounts imAccounts = accountService.getOrCreateImAccounts(request.getPeople()); + ImAccounts imAccounts = accountService.getAccountsByPersons(request.getPeople()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); Group group = groupSupport.buildNewGroup(request, imAccounts); @@ -119,7 +119,7 @@ public class GroupManager { public GroupAddMembersResponse addMembers(GroupAddMembersRequest request) { // DON'T delete this line - accountService.getOrCreateImAccounts(request.getMembers()); + accountService.maybeCreateImAccounts(request.getMembers()); return transactionTemplate.execute(unused -> { Group group = getGroupForUpdateOrThrow(request.getTid()); groupSupport.log(group.getTid(), "add-members", request); @@ -135,7 +135,7 @@ public class GroupManager { return new GroupAddMembersResponse(); BizAssertions.assertTrue(group.addMoreMembers(prePersons.size() + addPersons.size()), "群聊人数上限{}人, 请删除部分已选人员", group.getMemberLimit()); - ImAccounts imAccounts = accountService.getOrCreateImAccounts(addPersons); + ImAccounts imAccounts = accountService.getAccountsByPersons(addPersons); if (imAccounts.isAccountEmpty()) { notification.send("添加群成员[{},{}], 有效群成员IM账号列表为空. 请求成员信息: {}", group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); diff --git a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java index 88b3f2c..51d9901 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/AccountService.java @@ -393,12 +393,10 @@ public class AccountService { /** * 无法保证所有账号创建成功,可能的原因是因为人员的信息不全,或者是人员信息不正确 */ - public ImAccounts getOrCreateImAccounts(Set persons) { + public void maybeCreateImAccounts(Set persons) { ImAccounts imAccounts = getAccountsByPersons(persons); - if (imAccounts.getAccountSize() == persons.size()) - return imAccounts; - registerAccountIfAbsent(persons); - return getAccountsByPersons(persons); + if (imAccounts.getAccountSize() != persons.size()) + registerAccountIfAbsent(persons); } public void registerAccountIfAbsent(Collection persons) { From 20890e850238f9c940ff413826a5dead5eebd90c Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 10:16:49 +0800 Subject: [PATCH 171/201] =?UTF-8?q?REQ-3345:=20=E4=BF=AE=E5=A4=8D=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/entity/GroupMember.java | 2 +- .../src/main/java/cn/axzo/im/group/GroupMemberSyncer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java index 8e12144..135106c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java @@ -20,7 +20,7 @@ import java.util.Date; public class GroupMember { private Long id; private Long tid; - private GroupType groupType; + private GroupType type; private String imAccount; private Long personId; private Long personOuId; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberSyncer.java index 48c39e2..12860a1 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberSyncer.java @@ -94,7 +94,7 @@ public class GroupMemberSyncer { members.add(account); account.setTid(group.getTid()); account.setImAccount(member.getAccid()); - account.setGroupType(group.getType()); + account.setType(group.getType()); account.setMemberType( groupInfo.getOwner().equals(member) ? GroupMemberType.OWNER From 58d558a6076123859ab652572fb68ffdd78c1a5c Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 10:32:32 +0800 Subject: [PATCH 172/201] =?UTF-8?q?REQ-3345:=20=E4=BF=AE=E5=A4=8D=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/entity/GroupMember.java | 2 +- .../src/main/java/cn/axzo/im/group/GroupMemberSyncer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java index 135106c..8e12144 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/GroupMember.java @@ -20,7 +20,7 @@ import java.util.Date; public class GroupMember { private Long id; private Long tid; - private GroupType type; + private GroupType groupType; private String imAccount; private Long personId; private Long personOuId; diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberSyncer.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberSyncer.java index 12860a1..48c39e2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberSyncer.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupMemberSyncer.java @@ -94,7 +94,7 @@ public class GroupMemberSyncer { members.add(account); account.setTid(group.getTid()); account.setImAccount(member.getAccid()); - account.setType(group.getType()); + account.setGroupType(group.getType()); account.setMemberType( groupInfo.getOwner().equals(member) ? GroupMemberType.OWNER From 26ba842af72da99f869e6a02e6592627714e9e7c Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 10:41:11 +0800 Subject: [PATCH 173/201] =?UTF-8?q?REQ-3345:=20=E7=9B=B4=E6=8E=A5=E8=A7=A3?= =?UTF-8?q?=E6=95=A3=E7=BE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/controller/PrivateController.java | 13 +++++++++++++ .../channel/netease/client/NimClientTest.java | 17 +++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java index 2dabd65..5d22cd6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java @@ -6,7 +6,9 @@ import cn.axzo.im.center.api.vo.req.GroupDismissRequest; import cn.axzo.im.center.api.vo.req.GroupRemoveMembersRequest; import cn.axzo.im.center.api.vo.req.SendMessageParam; import cn.axzo.im.channel.netease.client.NimClient; +import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; +import cn.axzo.im.channel.netease.dto.NimGroupGetInfoResponse; import cn.axzo.im.channel.netease.dto.NimQueryEventRequest; import cn.axzo.im.channel.netease.dto.NimQueryMessageRequest; import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; @@ -97,6 +99,17 @@ public class PrivateController { return CommonResponse.success(); } + @PostMapping("/private/group/dismissGroupDirectly") + public Object dismissGroupDirectly(@Valid @RequestBody GroupDismissRequest request) { + NimGroupGetInfoRequest req1 = new NimGroupGetInfoRequest(); + req1.setTid(34202637051L); + NimGroupGetInfoResponse res1 = nimClient.getGroupInfo(req1); + NimGroupDismissRequest req2 = new NimGroupDismissRequest(); + req2.setOwner(res1.getTinfo().getOwner().getAccid()); + req2.setTid(34202637051L); + return CommonResponse.success(nimClient.dismissGroup(req2)); + } + @PostMapping("/private/group/addMembers") public Object addMembers(@Valid @RequestBody GroupAddMembersRequest request) { groupManager.addMembers(request); diff --git a/im-center-server/src/test/java/cn/axzo/im/channel/netease/client/NimClientTest.java b/im-center-server/src/test/java/cn/axzo/im/channel/netease/client/NimClientTest.java index ffc15ae..6d5b67a 100644 --- a/im-center-server/src/test/java/cn/axzo/im/channel/netease/client/NimClientTest.java +++ b/im-center-server/src/test/java/cn/axzo/im/channel/netease/client/NimClientTest.java @@ -1,6 +1,10 @@ package cn.axzo.im.channel.netease.client; import cn.axzo.im.Application; +import cn.axzo.im.channel.netease.dto.NimGroupDismissRequest; +import cn.axzo.im.channel.netease.dto.NimGroupDismissResponse; +import cn.axzo.im.channel.netease.dto.NimGroupGetInfoRequest; +import cn.axzo.im.channel.netease.dto.NimGroupGetInfoResponse; import cn.axzo.im.channel.netease.dto.NimRevokeMessageRequest; import lombok.RequiredArgsConstructor; import org.junit.jupiter.api.Test; @@ -18,12 +22,13 @@ class NimClientTest { @Test void revoke() { - NimRevokeMessageRequest request = new NimRevokeMessageRequest(); - request.setMessageId("13017220665628"); - request.setFrom("eac6c28d888c4cca87683e5c75a34ec4"); - request.setTo("master177117_cmp_20350"); - NimClient.NimCodeResponse revoke = nimClient.revoke(request); - System.out.println(); + NimGroupGetInfoRequest req1 = new NimGroupGetInfoRequest(); + req1.setTid(34202637051L); + NimGroupGetInfoResponse res1 = nimClient.getGroupInfo(req1); + NimGroupDismissRequest req2 = new NimGroupDismissRequest(); + req2.setOwner(res1.getTinfo().getOwner().getAccid()); + req2.setTid(34202637051L); + NimGroupDismissResponse res2 = nimClient.dismissGroup(req2); } } \ No newline at end of file From 743563393d334efc717fa3c9cf72489fd2acddfd Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 10:41:38 +0800 Subject: [PATCH 174/201] =?UTF-8?q?REQ-3345:=20=E7=9B=B4=E6=8E=A5=E8=A7=A3?= =?UTF-8?q?=E6=95=A3=E7=BE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/controller/PrivateController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java index 5d22cd6..34ea056 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/PrivateController.java @@ -102,11 +102,11 @@ public class PrivateController { @PostMapping("/private/group/dismissGroupDirectly") public Object dismissGroupDirectly(@Valid @RequestBody GroupDismissRequest request) { NimGroupGetInfoRequest req1 = new NimGroupGetInfoRequest(); - req1.setTid(34202637051L); + req1.setTid(request.getTid()); NimGroupGetInfoResponse res1 = nimClient.getGroupInfo(req1); NimGroupDismissRequest req2 = new NimGroupDismissRequest(); req2.setOwner(res1.getTinfo().getOwner().getAccid()); - req2.setTid(34202637051L); + req2.setTid(request.getTid()); return CommonResponse.success(nimClient.dismissGroup(req2)); } From 747eed944dd4cefd8e28cb21d37fcfd244705427 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 10:52:54 +0800 Subject: [PATCH 175/201] =?UTF-8?q?REQ-3345:=20=E7=9B=B4=E6=8E=A5=E8=A7=A3?= =?UTF-8?q?=E6=95=A3=E7=BE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/controller/MessageController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index f5b5d19..960dba4 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -237,6 +237,7 @@ public class MessageController implements MessageApi { @Override public ApiResult sendChatMessage(SendChatMessageRequest request) { + log.info("sendChatMessage, request={}", request); PersonAccountAttribute sender = request.getSender(); BizAssertions.assertNotNull(sender.getAppType(), "发送人appType不能为空"); String sendImAccount = accountService.registerAccountIfAbsent( From 74726858e798382a42881be7d8a9078bfc50117d Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 11:00:13 +0800 Subject: [PATCH 176/201] =?UTF-8?q?REQ-3345:=20=E7=9B=B4=E6=8E=A5=E8=A7=A3?= =?UTF-8?q?=E6=95=A3=E7=BE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 740ad92..e15ab95 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -68,8 +68,7 @@ public class GroupManager { return transactionTemplate.execute(unused -> { Group savedGroup = groupDao.findByBizCode(request.getBizCode(), request.getGroupType(), true) .orElse(null); - BizAssertions.assertTrue(savedGroup == null || savedGroup.isDismissed(), - String.format("群已经存在: %s", request.getName())); + BizAssertions.assertTrue(savedGroup == null, String.format("群已经存在: %s", request.getName())); ImAccounts imAccounts = accountService.getAccountsByPersons(request.getPeople()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); From dc53d3fd7caf7d844d90637cd59b39bec2710185 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 11:00:30 +0800 Subject: [PATCH 177/201] =?UTF-8?q?Revert=20"REQ-3345:=20=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E8=A7=A3=E6=95=A3=E7=BE=A4"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 74726858e798382a42881be7d8a9078bfc50117d. --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index e15ab95..740ad92 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -68,7 +68,8 @@ public class GroupManager { return transactionTemplate.execute(unused -> { Group savedGroup = groupDao.findByBizCode(request.getBizCode(), request.getGroupType(), true) .orElse(null); - BizAssertions.assertTrue(savedGroup == null, String.format("群已经存在: %s", request.getName())); + BizAssertions.assertTrue(savedGroup == null || savedGroup.isDismissed(), + String.format("群已经存在: %s", request.getName())); ImAccounts imAccounts = accountService.getAccountsByPersons(request.getPeople()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); From 953dcd243815262fb24da338a7fa2ea3315086c7 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 11:35:25 +0800 Subject: [PATCH 178/201] =?UTF-8?q?REQ-3345:=20=E7=9B=B4=E6=8E=A5=E8=A7=A3?= =?UTF-8?q?=E6=95=A3=E7=BE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/dao/repository/GroupDao.java | 1 + .../src/main/java/cn/axzo/im/group/GroupManager.java | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java index a795556..81044c6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java @@ -50,6 +50,7 @@ public class GroupDao extends ServiceImpl { return lambdaQuery() .eq(Group::getBizCode, bizCode) .eq(Group::getType, groupType) + .ne(Group::getIsDismissed, YesOrNo.NO) .last(forUpdate, "FOR UPDATE") .oneOpt(); } diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 740ad92..0b48def 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -66,10 +66,10 @@ public class GroupManager { // DON'T delete this line accountService.maybeCreateImAccounts(request.getPeople()); return transactionTemplate.execute(unused -> { - Group savedGroup = groupDao.findByBizCode(request.getBizCode(), request.getGroupType(), true) + Group savedGroup = groupDao + .findByBizCode(request.getBizCode(), request.getGroupType(), true) .orElse(null); - BizAssertions.assertTrue(savedGroup == null || savedGroup.isDismissed(), - String.format("群已经存在: %s", request.getName())); + BizAssertions.assertTrue(savedGroup == null, String.format("群已经存在: %s", request.getName())); ImAccounts imAccounts = accountService.getAccountsByPersons(request.getPeople()); String owner = imAccounts.findAccount(request.getOwner()).orElse(null); BizAssertions.assertNotNull(owner, "群主没有IM账号, 无法创建群. {}", request.getOwner()); From 34e1e416f6cf188a93e7a5ec1c917cffc29d294c Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 12:04:19 +0800 Subject: [PATCH 179/201] =?UTF-8?q?REQ-3345:=20=E7=9B=B4=E6=8E=A5=E8=A7=A3?= =?UTF-8?q?=E6=95=A3=E7=BE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/dao/repository/GroupDao.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java index 81044c6..cf591d3 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupDao.java @@ -50,7 +50,7 @@ public class GroupDao extends ServiceImpl { return lambdaQuery() .eq(Group::getBizCode, bizCode) .eq(Group::getType, groupType) - .ne(Group::getIsDismissed, YesOrNo.NO) + .eq(Group::getIsDismissed, YesOrNo.NO) .last(forUpdate, "FOR UPDATE") .oneOpt(); } From 98b33c3290d9d21eddac5481ae05f8e56b537a22 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 15:56:09 +0800 Subject: [PATCH 180/201] =?UTF-8?q?REQ-3345:=20=E5=B0=91=E5=AD=98=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E6=97=A0=E7=94=A8=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java index c490e93..818fe6b 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java @@ -1,6 +1,8 @@ package cn.axzo.im.center.api.vo; import cn.axzo.im.center.common.enums.AppTypeEnum; +import com.alibaba.fastjson.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -78,6 +80,7 @@ public class PersonAccountAttribute { return ouId == null ? 0L : ouId; } + @JsonIgnore @JSONField(serialize = false) public boolean isRobot() { return this == ROBOT; } From 9ef5dadd76b0bc47a69cff6a0ee01e9c663cbb3b Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 16:06:09 +0800 Subject: [PATCH 181/201] =?UTF-8?q?REQ-3345:=20=E7=BE=A4=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/group/controller/GroupMessageController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupMessageController.java b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupMessageController.java index d1f2fca..87900ef 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupMessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupMessageController.java @@ -42,9 +42,9 @@ public class GroupMessageController implements GroupMessageApi { @Override public ApiPageResult pageQuery(GroupMessagePageQueryRequest request) { - @SuppressWarnings("unchecked") IPage page = groupMessageDao.lambdaQuery() - .orderByDesc(GroupMessage::getTid, GroupMessage::getSendTime) + .eq(GroupMessage::getTid, request.getTid()) + .orderByDesc(GroupMessage::getSendTime) .page(request.toPage()); List messages = BeanMapper.copyList( page.getRecords(), GroupMessagePageQueryResponse.class); From ea8b2f623db32c749d1eef66241392e24e2fe898 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 16:13:33 +0800 Subject: [PATCH 182/201] =?UTF-8?q?REQ-3345:=20=E7=BE=A4=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/im/group/support/GroupProps.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java index eee64c2..e771a12 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java @@ -20,12 +20,12 @@ public class GroupProps { private long defaultMemberLimit = 499; private int syncMessageTps = 20; - private int createGroupTps = 10; - private int dismissGroupTps = 10; - private int addMemberTps = 10; - private int removeMemberTps = 10; - private int getGroupInfoTps = 10; - private int changeOwnerTps = 10; + private int createGroupTps = 15; + private int dismissGroupTps = 15; + private int addMemberTps = 15; + private int removeMemberTps = 15; + private int getGroupInfoTps = 15; + private int changeOwnerTps = 15; @Override public String toString() { From 7e6966865f0b62052c47a0ad7affe6361a49813d Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 19 Feb 2025 16:16:00 +0800 Subject: [PATCH 183/201] =?UTF-8?q?REQ-3345:=20=E7=BE=A4=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/support/GroupProps.java | 1 + .../main/java/cn/axzo/im/group/support/GroupRateLimiter.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java index e771a12..530992e 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupProps.java @@ -26,6 +26,7 @@ public class GroupProps { private int removeMemberTps = 15; private int getGroupInfoTps = 15; private int changeOwnerTps = 15; + private double tpsTooLowWarnWaitSeconds = 1.5; @Override public String toString() { diff --git a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java index d4fc7fb..8681727 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/support/GroupRateLimiter.java @@ -69,7 +69,7 @@ public class GroupRateLimiter implements InitializingBean { public void acquire() { double seconds = rateLimiter.acquire(); - if (seconds > 1) + if (seconds > groupProps.getTpsTooLowWarnWaitSeconds()) notification.send("{} wait too long to acquire rate limiter: {} seconds", name, seconds); } From 2e01f785e24ee20f8f0d8cfb2ae6bd08adf7f894 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 20 Feb 2025 16:05:16 +0800 Subject: [PATCH 184/201] =?UTF-8?q?REQ-3345:=20=E7=BE=A4=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/im/controller/MessageController.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index 960dba4..05eac95 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -205,6 +205,7 @@ public class MessageController implements MessageApi { List receivePersons = new ArrayList<>(requestReceivePersons); if (CollectionUtils.isNotEmpty(request.getImReceiveAccounts())) { for (String account : request.getImReceiveAccounts()) { + ensureImAccountNotBlank(account); receivePersons.add(MessageTask.ReceivePerson.builder() .imAccount(account) .build()); @@ -255,6 +256,7 @@ public class MessageController implements MessageApi { List receivePersons = new ArrayList<>(requestReceivePersons); if (CollectionUtils.isNotEmpty(request.getImReceiveAccounts())) { for (String account : request.getImReceiveAccounts()) { + ensureImAccountNotBlank(account); receivePersons.add(MessageTask.ReceivePerson.builder() .imAccount(account) .build()); @@ -274,6 +276,11 @@ public class MessageController implements MessageApi { return ApiResult.ok(messageTask.getId()); } + private void ensureImAccountNotBlank(String imAccount) { + BizAssertions.assertTrue(StringUtils.isNotBlank(imAccount), "接收人IM账号不能为空"); + BizAssertions.assertFalse("null".equalsIgnoreCase(imAccount), "接收人IM账号不能为空"); + } + @Override public ApiResult updateMessage(UpdateMessageRequest request) { log.info("updateMessage, request={}", request); From f67c3a1fcb6bae0a0b4bd9e9890b62829ec89bc4 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 21 Feb 2025 17:38:51 +0800 Subject: [PATCH 185/201] =?UTF-8?q?REQ-3345:=20=E9=82=80=E8=AF=B7=E4=BA=BA?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/center/api/vo/req/GroupAddMembersRequest.java | 6 ++++++ .../main/java/cn/axzo/im/dao/repository/GroupMemberDao.java | 6 ++++++ .../src/main/java/cn/axzo/im/group/GroupManager.java | 6 +++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java index 6f4a330..7eb6fbc 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java @@ -20,6 +20,12 @@ public class GroupAddMembersRequest { @NotNull(message = "群ID不能为空") private Long tid; + /** + * 邀请者 + */ + @NotNull(message = "inviter不能为空") + private PersonAccountAttribute inviter; + /** * 群成员, 不包含群主. members数量不能超过199 */ diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java index dbbc4e7..704cf32 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java @@ -11,6 +11,7 @@ import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.Set; import static java.util.stream.Collectors.toSet; @@ -55,6 +56,11 @@ public class GroupMemberDao extends ServiceImpl .remove(); } + public Optional findByPerson(Long tid, PersonAccountAttribute person) { + List members = getByPersons(tid, Collections.singletonList(person)); + return CollectionUtils.isEmpty(members) ? Optional.empty() : Optional.of(members.get(0)); + } + public List getByPersons( Long tid, Collection persons) { if (CollectionUtils.isEmpty(persons)) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 0b48def..0a07816 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -141,8 +141,12 @@ public class GroupManager { group.getTid(), group.getName(), JSON.toJSONString(request.getMembers())); return new GroupAddMembersResponse(); } + GroupMember inviter = groupMemberDao + .findByPerson(group.getTid(), request.getInviter()) + .orElse(null); + BizAssertions.assertNotNull(inviter, "邀请者不在群中"); NimGroupAddMembersRequest nimRequest = groupSupport - .buildAddMembersRequest(group, group.getOwnerAccount(), imAccounts); + .buildAddMembersRequest(group, inviter.getImAccount(), imAccounts); // add members rateLimiter.requireAddMember(); NimGroupAddMembersResponse nimResponse = nimClient.addGroupMembers(nimRequest); From 897356a5dcdf7dcbb31c0fb0d65dab49905cc24e Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 21 Feb 2025 17:39:27 +0800 Subject: [PATCH 186/201] =?UTF-8?q?REQ-3345:=20=E9=82=80=E8=AF=B7=E4=BA=BA?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 0a07816..6ecae5a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -145,6 +145,7 @@ public class GroupManager { .findByPerson(group.getTid(), request.getInviter()) .orElse(null); BizAssertions.assertNotNull(inviter, "邀请者不在群中"); + //noinspection DataFlowIssue NimGroupAddMembersRequest nimRequest = groupSupport .buildAddMembersRequest(group, inviter.getImAccount(), imAccounts); // add members From c94daaf136f34922e1d849ae5b5bb683d645c9c4 Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 21 Feb 2025 17:44:53 +0800 Subject: [PATCH 187/201] =?UTF-8?q?REQ-3345:=20=E9=82=80=E8=AF=B7=E4=BA=BA?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/group/GroupSupport.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java index 39b9592..4c28479 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupSupport.java @@ -76,11 +76,11 @@ public class GroupSupport { } NimGroupAddMembersRequest buildAddMembersRequest( - Group group, String owner, ImAccounts accounts) { + Group group, String inviter, ImAccounts accounts) { BizAssertions.assertNotEmpty(accounts.getAccounts(), "有效群成员IM账号列表为空"); NimGroupAddMembersRequest nimRequest = new NimGroupAddMembersRequest(); nimRequest.setTid(group.getTid()); - nimRequest.setOwner(owner); + nimRequest.setOwner(inviter); nimRequest.setMsg(INTRODUCE_MESSAGE); nimRequest.addMembers(accounts.getAccounts()); return nimRequest; From bcfe415252c50a293ad83edd98f0c463354eba6b Mon Sep 17 00:00:00 2001 From: yanglin Date: Fri, 21 Feb 2025 18:34:09 +0800 Subject: [PATCH 188/201] =?UTF-8?q?REQ-3345:=20=E9=82=80=E8=AF=B7=E4=BA=BA?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/center/api/vo/req/GroupAddMembersRequest.java | 2 +- .../java/cn/axzo/im/dao/repository/GroupMemberDao.java | 7 +++++++ .../src/main/java/cn/axzo/im/group/GroupManager.java | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java index 7eb6fbc..bdf5408 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupAddMembersRequest.java @@ -24,7 +24,7 @@ public class GroupAddMembersRequest { * 邀请者 */ @NotNull(message = "inviter不能为空") - private PersonAccountAttribute inviter; + private String inviter; /** * 群成员, 不包含群主. members数量不能超过199 diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java index 704cf32..e44928d 100644 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/GroupMemberDao.java @@ -22,6 +22,13 @@ import static java.util.stream.Collectors.toSet; @Repository("groupMemberDao") public class GroupMemberDao extends ServiceImpl { + public Optional findByAccount(Long tid, String imAccount) { + return lambdaQuery() + .eq(GroupMember::getTid, tid) + .eq(GroupMember::getImAccount, imAccount) + .oneOpt(); + } + public void deleteAccounts(Long tid) { lambdaUpdate() .eq(GroupMember::getTid, tid) diff --git a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java index 6ecae5a..89f8167 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/GroupManager.java @@ -142,7 +142,7 @@ public class GroupManager { return new GroupAddMembersResponse(); } GroupMember inviter = groupMemberDao - .findByPerson(group.getTid(), request.getInviter()) + .findByAccount(group.getTid(), request.getInviter()) .orElse(null); BizAssertions.assertNotNull(inviter, "邀请者不在群中"); //noinspection DataFlowIssue From 0b15bcd3a2730f4257ced91e9718629de1b0dfe8 Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 25 Feb 2025 17:01:13 +0800 Subject: [PATCH 189/201] =?UTF-8?q?REQ-3345:=20=E8=B0=83=E6=95=B4=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E6=B6=88=E6=81=AF=E7=9A=84=E4=BC=98=E5=85=88=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/center/api/feign/SendPriority.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/SendPriority.java b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/SendPriority.java index d37221b..aafde62 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/SendPriority.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/SendPriority.java @@ -11,8 +11,8 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class SendPriority { + public static final SendPriority CHAT_MESSAGE = create(900); public static final SendPriority TEMPLATE_MESSAGE = create(1000); - public static final SendPriority CHAT_MESSAGE = create(1500); public static final SendPriority SYSTEM_CUSTOM_MESSAGE = create(5000); public static final SendPriority UPDATE_MESSAGE = create(5500); public static final SendPriority UPDATE_MESSAGE_RETRY = create(5510); // lower priority than UPDATE_MESSAGE From 8be8cc4daea1bbb6edd351a5cff896c1a02dc37d Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 25 Feb 2025 17:09:47 +0800 Subject: [PATCH 190/201] =?UTF-8?q?REQ-3345:=20=E5=8D=B3=E5=88=BB=E7=94=9F?= =?UTF-8?q?=E6=88=90=E8=81=8A=E5=A4=A9=E6=B6=88=E6=81=AF=E7=9A=84history?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/controller/MessageController.java | 35 +++++++++++-------- .../java/cn/axzo/im/entity/MessageTask.java | 2 ++ .../axzo/im/job/CreateMessageHistoryJob.java | 3 ++ .../service/impl/MessageTaskServiceImpl.java | 1 + 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index 05eac95..b275915 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -39,7 +39,6 @@ import cn.axzo.im.service.MessageTaskService; import cn.axzo.im.service.RobotMsgTemplateService; import cn.axzo.im.updatable.UpdatableMessageManager; import cn.axzo.im.updatable.UpdatableMessageQueryService; -import cn.axzo.im.updatable.UpdateSupport; import cn.axzo.im.utils.BizAssertions; import cn.axzo.pokonyan.exception.Aassert; import com.alibaba.fastjson.JSON; @@ -56,6 +55,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionTemplate; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @@ -99,9 +99,9 @@ public class MessageController implements MessageApi { @Autowired private UpdatableMessageManager updatableMessageManager; @Autowired - private UpdateSupport updateSupport; - @Autowired private UpdatableMessageQueryService updatableMessageQueryService; + @Autowired + private TransactionTemplate transactionTemplate; @Override @@ -247,6 +247,7 @@ public class MessageController implements MessageApi { MessageTask.BizData bizData = MessageTask.BizData.builder() .messageBody(JSON.toJSONString(request.getMessageBody())) .isSenderRobot(false) + .isChatMessage(true) .senderPersonId(request.determineSenderPersonId()) .nimMessageType(request.getMessageType()) .build(); @@ -262,17 +263,23 @@ public class MessageController implements MessageApi { .build()); } } - MessageTask messageTask = messageTaskService.create(MessageTask.builder() - .bizId(request.getBizId()) - .sendImAccount(sendImAccount) - .receivePersons(receivePersons) - .status(MessageTaskStatus.PENDING) - .bizData(bizData) - .planStartTime(now) - .createAt(now) - .sendPriority(SendPriority.CHAT_MESSAGE.getPriority()) - .apiChannel(ApiChannel.COMMON_MESSAGE) - .build()); + MessageTask messageTask = transactionTemplate.execute(unused -> { + MessageTask task = messageTaskService.create(MessageTask.builder() + .bizId(request.getBizId()) + .sendImAccount(sendImAccount) + .receivePersons(receivePersons) + .status(MessageTaskStatus.PENDING) + .bizData(bizData) + .planStartTime(now) + .createAt(now) + .sendPriority(SendPriority.CHAT_MESSAGE.getPriority()) + .apiChannel(ApiChannel.COMMON_MESSAGE) + .build()); + task = messageTaskService.getById(task.getId()); + messageTaskService.createMessageHistory(task); + return task; + }); + //noinspection DataFlowIssue return ApiResult.ok(messageTask.getId()); } diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java index 3e8e70f..20a8333 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java @@ -170,6 +170,8 @@ public class MessageTask { private NimMessageType nimMessageType; + private boolean isChatMessage; + public boolean determineIsSenderRobot() { return isSenderRobot != null && isSenderRobot; } diff --git a/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java b/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java index 885755d..a8e8367 100644 --- a/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java @@ -59,6 +59,9 @@ public class CreateMessageHistoryJob extends IJobHandler { Page page = messageTaskService.page(req); if (CollectionUtils.isNotEmpty(page.getRecords())) { page.getRecords().forEach(messageTask -> { + MessageTask.BizData bizData = messageTask.getBizData(); + if (bizData != null && bizData.isChatMessage()) + return; count.set(count.get() + 1); try { messageTaskService.createMessageHistory(messageTask); diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java index f4d1843..173f74f 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java @@ -45,6 +45,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; +import java.io.Serializable; import java.util.Collections; import java.util.Date; import java.util.HashMap; From b83036941330c712c91a657992425974a0cffa2d Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 25 Feb 2025 17:31:27 +0800 Subject: [PATCH 191/201] =?UTF-8?q?REQ-3345:=20=E5=8D=B3=E5=88=BB=E7=94=9F?= =?UTF-8?q?=E6=88=90=E8=81=8A=E5=A4=A9=E6=B6=88=E6=81=AF=E7=9A=84history?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/controller/MessageController.java | 2 +- .../src/main/java/cn/axzo/im/entity/MessageTask.java | 2 +- .../src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index b275915..acdfb12 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -247,7 +247,7 @@ public class MessageController implements MessageApi { MessageTask.BizData bizData = MessageTask.BizData.builder() .messageBody(JSON.toJSONString(request.getMessageBody())) .isSenderRobot(false) - .isChatMessage(true) + .historyCreated(true) .senderPersonId(request.determineSenderPersonId()) .nimMessageType(request.getMessageType()) .build(); diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java index 20a8333..0cc8094 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java @@ -170,7 +170,7 @@ public class MessageTask { private NimMessageType nimMessageType; - private boolean isChatMessage; + private boolean historyCreated; public boolean determineIsSenderRobot() { return isSenderRobot != null && isSenderRobot; diff --git a/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java b/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java index a8e8367..2591e81 100644 --- a/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java @@ -60,7 +60,7 @@ public class CreateMessageHistoryJob extends IJobHandler { if (CollectionUtils.isNotEmpty(page.getRecords())) { page.getRecords().forEach(messageTask -> { MessageTask.BizData bizData = messageTask.getBizData(); - if (bizData != null && bizData.isChatMessage()) + if (bizData != null && bizData.isHistoryCreated()) return; count.set(count.get() + 1); try { From 638a6fd8fbde881807cf9ed0665078c647c7f4ff Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 25 Feb 2025 17:57:30 +0800 Subject: [PATCH 192/201] =?UTF-8?q?REQ-3345:=20=E5=A6=82=E6=9E=9C=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E6=B6=88=E6=81=AF=E5=8F=AA=E6=9C=89=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/vo/req/SendChatMessageRequest.java | 5 +++ .../axzo/im/controller/MessageController.java | 40 ++++++++++++++----- .../cn/axzo/im/entity/HistoryRecordExt.java | 1 + .../java/cn/axzo/im/entity/MessageTask.java | 2 +- .../axzo/im/job/CreateMessageHistoryJob.java | 3 -- .../send/handler/CommonSendBatchHandler.java | 21 ++++++---- .../im/send/handler/CommonSendOneHandler.java | 20 ++++++---- .../axzo/im/service/MessageTaskService.java | 2 +- .../service/impl/MessageTaskServiceImpl.java | 30 +++++++++----- 9 files changed, 84 insertions(+), 40 deletions(-) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java index 4ab93f7..abbde16 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java @@ -32,6 +32,11 @@ public class SendChatMessageRequest extends SendMessageRequest { @NotEmpty(message = "消息体不能为空") private Map messageBody; + /** + * 尝试同步发送 + */ + private boolean trySyncSend; + /** * 发送文本消息 * diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index acdfb12..bdd7fb0 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -27,16 +27,20 @@ import cn.axzo.im.center.api.vo.resp.MessageUpdateResponse; import cn.axzo.im.center.api.vo.resp.UpdatableMessageSendResult; import cn.axzo.im.center.api.vo.resp.UserAccountResp; import cn.axzo.im.center.common.enums.AppTypeEnum; +import cn.axzo.im.channel.netease.dto.MessageDispatchResponse; import cn.axzo.im.entity.AccountRegister; +import cn.axzo.im.entity.MessageHistory; import cn.axzo.im.entity.MessageTask; import cn.axzo.im.enums.MessageHistoryStatus; import cn.axzo.im.enums.MessageTaskStatus; +import cn.axzo.im.send.handler.CommonSendOneHandler; import cn.axzo.im.service.AccountRegisterService; import cn.axzo.im.service.AccountService; import cn.axzo.im.service.CustomMessageService; import cn.axzo.im.service.MessageHistoryService; import cn.axzo.im.service.MessageTaskService; import cn.axzo.im.service.RobotMsgTemplateService; +import cn.axzo.im.service.impl.MessageHistoryServiceImpl; import cn.axzo.im.updatable.UpdatableMessageManager; import cn.axzo.im.updatable.UpdatableMessageQueryService; import cn.axzo.im.utils.BizAssertions; @@ -72,7 +76,7 @@ import static cn.axzo.im.config.BizResultCode.SEND_IM_ACCOUNT_NOT_FOUND; import static cn.axzo.im.config.BizResultCode.SEND_PERSSON_ERROR; /** - * IM消息派发相关 + * IM消息派发相关 * * @author zuoqinbo * @version V1.0 @@ -93,7 +97,7 @@ public class MessageController implements MessageApi { @Autowired private AccountRegisterService accountRegisterService; @Autowired - private MessageHistoryService messageHistoryService; + private MessageHistoryServiceImpl messageHistoryService; @Autowired private CustomMessageService customMessageService; @Autowired @@ -102,6 +106,8 @@ public class MessageController implements MessageApi { private UpdatableMessageQueryService updatableMessageQueryService; @Autowired private TransactionTemplate transactionTemplate; + @Autowired + private CommonSendOneHandler commonSendOneHandler; @Override @@ -116,7 +122,7 @@ public class MessageController implements MessageApi { return ApiResult.ok(messageRespList); } - @ExceptionHandler({ RequestNotPermitted.class }) + @ExceptionHandler({RequestNotPermitted.class}) @ResponseStatus(HttpStatus.TOO_MANY_REQUESTS) public ApiResult handleRequestNotPermitted() { return ApiResult.err("服务器资源繁忙,请求被拒绝!"); @@ -126,6 +132,7 @@ public class MessageController implements MessageApi { /** * 发送消息时只是存储在messageTask中,通过xxlJob或者mq异步去处理 * 因为:1、为了提高接口响应性能。2、第三方接口有限流控制,防止被限流后阻塞业务 + * * @param sendMessageParam 发送消息请求参数 * @return */ @@ -244,10 +251,14 @@ public class MessageController implements MessageApi { String sendImAccount = accountService.registerAccountIfAbsent( sender.getPersonId(), sender.getOuId(), sender.getAppType()); BizAssertions.assertNotNull(sendImAccount, "创建账号失败"); + boolean syncSend = request.isTrySyncSend() + && CollectionUtils.isEmpty(request.receivePersonsOrEmpty()) + && request.getImReceiveAccounts() != null + && request.getImReceiveAccounts().size() == 1; MessageTask.BizData bizData = MessageTask.BizData.builder() .messageBody(JSON.toJSONString(request.getMessageBody())) .isSenderRobot(false) - .historyCreated(true) + .syncSend(syncSend) .senderPersonId(request.determineSenderPersonId()) .nimMessageType(request.getMessageType()) .build(); @@ -263,7 +274,7 @@ public class MessageController implements MessageApi { .build()); } } - MessageTask messageTask = transactionTemplate.execute(unused -> { + Long taskId = transactionTemplate.execute(unused -> { MessageTask task = messageTaskService.create(MessageTask.builder() .bizId(request.getBizId()) .sendImAccount(sendImAccount) @@ -275,12 +286,21 @@ public class MessageController implements MessageApi { .sendPriority(SendPriority.CHAT_MESSAGE.getPriority()) .apiChannel(ApiChannel.COMMON_MESSAGE) .build()); - task = messageTaskService.getById(task.getId()); - messageTaskService.createMessageHistory(task); - return task; + if (syncSend) { + task = messageTaskService.getById(task.getId()); + List historyIds = messageTaskService.createMessageHistory(task); + MessageHistory history = messageHistoryService.getById(historyIds.get(0)); + MessageDispatchResponse response = commonSendOneHandler.send(history); + if (response.isSuccess()) { + messageHistoryService.setSendSuccess(history, response.getMsgid(), null); + } else { + log.warn("sendChatMessage, send failed, historyId={}, taskId={}, bizId={}, failReason={}", + history.getId(), history.getImMessageTaskId(), history.getBizId(), response.getDesc()); + } + } + return task.getId(); }); - //noinspection DataFlowIssue - return ApiResult.ok(messageTask.getId()); + return ApiResult.ok(taskId); } private void ensureImAccountNotBlank(String imAccount) { diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/HistoryRecordExt.java b/im-center-server/src/main/java/cn/axzo/im/entity/HistoryRecordExt.java index 621c8f8..0119c8a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/HistoryRecordExt.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/HistoryRecordExt.java @@ -37,4 +37,5 @@ public class HistoryRecordExt { private Long workspaceId; private Integer nimMessageType; + private boolean syncSend; } \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java index 0cc8094..c3b00fd 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java @@ -170,7 +170,7 @@ public class MessageTask { private NimMessageType nimMessageType; - private boolean historyCreated; + private boolean syncSend; public boolean determineIsSenderRobot() { return isSenderRobot != null && isSenderRobot; diff --git a/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java b/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java index 2591e81..885755d 100644 --- a/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java @@ -59,9 +59,6 @@ public class CreateMessageHistoryJob extends IJobHandler { Page page = messageTaskService.page(req); if (CollectionUtils.isNotEmpty(page.getRecords())) { page.getRecords().forEach(messageTask -> { - MessageTask.BizData bizData = messageTask.getBizData(); - if (bizData != null && bizData.isHistoryCreated()) - return; count.set(count.get() + 1); try { messageTaskService.createMessageHistory(messageTask); diff --git a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java index 6cb65f0..ca50b59 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendBatchHandler.java @@ -13,6 +13,7 @@ import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; import java.util.List; +import java.util.stream.Collectors; /** * @author yanglin @@ -27,24 +28,28 @@ public class CommonSendBatchHandler extends SendBatchHandler { @Override public void sendAndSubmitUpdate(SendExecutor> executor, List histories) { - if (CollectionUtils.isEmpty(histories)) return; + List effectiveHistories = histories.stream() + .filter(h -> !h.getOrCreateRecordExt().isSyncSend()) + .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(effectiveHistories)) + return; executor.log("batchSendMessage - request record size: {}, batchNo={}", - histories.size(), histories.get(0).determineBatchNo().orElse(null)); - MessageHistory sample = histories.get(0); + effectiveHistories.size(), effectiveHistories.get(0).determineBatchNo().orElse(null)); + MessageHistory sample = effectiveHistories.get(0); MessageBatchDispatchRequest batchRequest = new MessageBatchDispatchRequest(); batchRequest.setBody(sample.getMessageBody()); batchRequest.setFromAccid(sample.getFromAccount()); - batchRequest.setToAccids(Lists.transform(histories, MessageHistory::getToAccount)); + batchRequest.setToAccids(Lists.transform(effectiveHistories, MessageHistory::getToAccount)); batchRequest.setPayload(sample.getOrCreateRecordExt().getPayload()); batchRequest.populateOption(); - messageHistoryNimLogger.logAsync(histories, batchRequest); + messageHistoryNimLogger.logAsync(effectiveHistories, batchRequest); MessageBatchDispatchResponse response = imChannelProvider.dispatchBatchMessage(batchRequest); if (response.isRateLimited()) - executor.scheduleRetrySend(histories, null); + executor.scheduleRetrySend(effectiveHistories, null); else if (response.isSuccess()) - executor.setBatchSendSuccess(histories, response, null); + executor.setBatchSendSuccess(effectiveHistories, response, null); else - executor.setSendFail(histories, response.getDesc(), null); + executor.setSendFail(effectiveHistories, response.getDesc(), null); } @Override diff --git a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java index 285632c..daa7ddb 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java @@ -24,9 +24,21 @@ public class CommonSendOneHandler extends SendOneHandler { @Override public void sendAndSubmitUpdate(SendExecutor executor, MessageHistory history) { + if (history.getOrCreateRecordExt().isSyncSend()) + return; executor.log("sendMessage - historyId={}, taskId={}, bizId={}, batchNo={}", history.getId(), history.getImMessageTaskId(), history.getBizId(), history.determineBatchNo().orElse(null)); + MessageDispatchResponse response = send(history); + if (response.isRateLimited()) + executor.scheduleRetrySend(history, null); + else if (response.isSuccess()) + executor.submitSetSendSuccess(history, response.getMsgid()); + else + executor.submitSetSendFail(history, response.getDesc()); + } + + public MessageDispatchResponse send(MessageHistory history) { MessageDispatchRequest sendRequest = new MessageDispatchRequest(); sendRequest.setFrom(history.getFromAccount()); sendRequest.setOpe(history.isSendToGroup() ? 1 : 0); @@ -40,13 +52,7 @@ public class CommonSendOneHandler extends SendOneHandler { sendRequest.setPayload(history.getOrCreateRecordExt().getPayload()); sendRequest.populateOption(); messageHistoryNimLogger.logAsync(history, sendRequest); - MessageDispatchResponse response = imChannelProvider.dispatchMessage(sendRequest); - if (response.isRateLimited()) - executor.scheduleRetrySend(history, null); - else if (response.isSuccess()) - executor.submitSetSendSuccess(history, response.getMsgid()); - else - executor.submitSetSendFail(history, response.getDesc()); + return imChannelProvider.dispatchMessage(sendRequest); } @Override diff --git a/im-center-server/src/main/java/cn/axzo/im/service/MessageTaskService.java b/im-center-server/src/main/java/cn/axzo/im/service/MessageTaskService.java index 5faa80b..78a1e84 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/MessageTaskService.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/MessageTaskService.java @@ -22,7 +22,7 @@ public interface MessageTaskService extends IService { Page page(PageMessageTaskParam param); - void createMessageHistory(MessageTask messageTask); + List createMessageHistory(MessageTask messageTask); void update(UpdateMessageTaskParam param); diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java index 173f74f..6847869 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java @@ -45,7 +45,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; -import java.io.Serializable; +import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -105,7 +105,7 @@ public class MessageTaskServiceImpl extends ServiceImpl createMessageHistory(MessageTask messageTask) { this.update(UpdateMessageTaskParam.builder() .id(messageTask.getId()) @@ -113,12 +113,13 @@ public class MessageTaskServiceImpl extends ServiceImpl historyIds; if (bizData.isAllPerson()) { log.info("发送全员消息, taskId={}", messageTask.getId()); - doSendAll(messageTask, bizData); + historyIds = doSendAll(messageTask, bizData); } else { log.info("发送非全员消息, taskId={}", messageTask.getId()); - doSendNotAll(messageTask); + historyIds = doSendNotAll(messageTask); } this.update(UpdateMessageTaskParam.builder() @@ -126,6 +127,7 @@ public class MessageTaskServiceImpl extends ServiceImpl doSendAll(MessageTask messageTask, MessageTask.BizData bizData) { Integer pageNumber = 1; String batchNo = UUIDUtil.uuidString(); + ArrayList historyIds = new ArrayList<>(); while (true) { Page page = accountRegisterService.page(AccountRegisterService.PageAccountRegisterParam.builder() .accountType(AccountTypeEnum.USER.getCode()) @@ -159,24 +162,27 @@ public class MessageTaskServiceImpl extends ServiceImpl receivePersons = page.getRecords().stream() .map(e -> MessageTask.ReceivePerson.builder().imAccount(e.getImAccount()).build()) .collect(Collectors.toList()); - saveMessageHistory(batchNo, receivePersons, messageTask, false); + historyIds.addAll(saveMessageHistory(batchNo, receivePersons, messageTask, false)); } if (!page.hasNext()) { break; } } + return historyIds; } - private void doSendNotAll(MessageTask messageTask) { + private List doSendNotAll(MessageTask messageTask) { int totalPersonSize = messageTask.getReceivePersons().size(); String batchNo = UUIDUtil.uuidString(); // 防止sql过长 List> receivePersons = Lists.partition(messageTask.getReceivePersons(), DEFAULT_PAGE_SIZE); - receivePersons.forEach(e -> saveMessageHistory(batchNo, e, messageTask, totalPersonSize <= 2)); + return receivePersons.stream() + .flatMap(e -> saveMessageHistory(batchNo, e, messageTask, totalPersonSize <= 2).stream()) + .collect(Collectors.toList()); } - private void saveMessageHistory(String batchNo, List receivePersons, + private List saveMessageHistory(String batchNo, List receivePersons, MessageTask messageTask, boolean tryCreateAccount) { // 排除已经发送成功的记录,防止重复发送 Set existPersons = listExistPerson(receivePersons, messageTask); @@ -197,7 +203,7 @@ public class MessageTaskServiceImpl extends ServiceImpl accountRegisters = listAccountRegisters(absentReceivePersons); @@ -213,6 +219,7 @@ public class MessageTaskServiceImpl extends ServiceImpl Date: Tue, 25 Feb 2025 18:00:40 +0800 Subject: [PATCH 193/201] =?UTF-8?q?REQ-3345:=20=E5=A6=82=E6=9E=9C=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E6=B6=88=E6=81=AF=E5=8F=AA=E6=9C=89=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/im/controller/MessageController.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index bdd7fb0..129f497 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -251,17 +251,6 @@ public class MessageController implements MessageApi { String sendImAccount = accountService.registerAccountIfAbsent( sender.getPersonId(), sender.getOuId(), sender.getAppType()); BizAssertions.assertNotNull(sendImAccount, "创建账号失败"); - boolean syncSend = request.isTrySyncSend() - && CollectionUtils.isEmpty(request.receivePersonsOrEmpty()) - && request.getImReceiveAccounts() != null - && request.getImReceiveAccounts().size() == 1; - MessageTask.BizData bizData = MessageTask.BizData.builder() - .messageBody(JSON.toJSONString(request.getMessageBody())) - .isSenderRobot(false) - .syncSend(syncSend) - .senderPersonId(request.determineSenderPersonId()) - .nimMessageType(request.getMessageType()) - .build(); Date now = new Date(); List requestReceivePersons = JSONArray.parseArray( JSONObject.toJSONString(request.receivePersonsOrEmpty()), MessageTask.ReceivePerson.class); @@ -274,6 +263,15 @@ public class MessageController implements MessageApi { .build()); } } + int receiverSize = request.receivePersonsOrEmpty().size() + request.getImReceiveAccounts().size(); + boolean syncSend = request.isTrySyncSend() && receiverSize == 1; + MessageTask.BizData bizData = MessageTask.BizData.builder() + .messageBody(JSON.toJSONString(request.getMessageBody())) + .isSenderRobot(false) + .syncSend(syncSend) + .senderPersonId(request.determineSenderPersonId()) + .nimMessageType(request.getMessageType()) + .build(); Long taskId = transactionTemplate.execute(unused -> { MessageTask task = messageTaskService.create(MessageTask.builder() .bizId(request.getBizId()) From e3a4bc815a200bd73351cb85d967739e9124128d Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 25 Feb 2025 18:00:52 +0800 Subject: [PATCH 194/201] =?UTF-8?q?REQ-3345:=20=E5=A6=82=E6=9E=9C=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E6=B6=88=E6=81=AF=E5=8F=AA=E6=9C=89=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/controller/MessageController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index 129f497..84b3b9a 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -263,7 +263,7 @@ public class MessageController implements MessageApi { .build()); } } - int receiverSize = request.receivePersonsOrEmpty().size() + request.getImReceiveAccounts().size(); + int receiverSize = request.receivePersonsOrEmpty().size() + request.imReceiveAccountsOrEmpty().size(); boolean syncSend = request.isTrySyncSend() && receiverSize == 1; MessageTask.BizData bizData = MessageTask.BizData.builder() .messageBody(JSON.toJSONString(request.getMessageBody())) From 83dcef6085a3cecae99d5410073081c7c61a9c74 Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 25 Feb 2025 18:01:13 +0800 Subject: [PATCH 195/201] =?UTF-8?q?REQ-3345:=20=E5=A6=82=E6=9E=9C=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E6=B6=88=E6=81=AF=E5=8F=AA=E6=9C=89=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/controller/MessageController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index 84b3b9a..623d288 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -264,6 +264,7 @@ public class MessageController implements MessageApi { } } int receiverSize = request.receivePersonsOrEmpty().size() + request.imReceiveAccountsOrEmpty().size(); + BizAssertions.assertTrue(receiverSize >= 1, "接收人不能为空"); boolean syncSend = request.isTrySyncSend() && receiverSize == 1; MessageTask.BizData bizData = MessageTask.BizData.builder() .messageBody(JSON.toJSONString(request.getMessageBody())) From 355eefce85fb3ac3266e5b385c5015bbee0798bc Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 25 Feb 2025 18:01:42 +0800 Subject: [PATCH 196/201] =?UTF-8?q?REQ-3345:=20=E5=A6=82=E6=9E=9C=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E6=B6=88=E6=81=AF=E5=8F=AA=E6=9C=89=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/controller/MessageController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index 623d288..126a201 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -292,6 +292,8 @@ public class MessageController implements MessageApi { MessageDispatchResponse response = commonSendOneHandler.send(history); if (response.isSuccess()) { messageHistoryService.setSendSuccess(history, response.getMsgid(), null); + log.info("sendChatMessage, send success, historyId={}, taskId={}, bizId={}", + history.getId(), history.getImMessageTaskId(), history.getBizId()); } else { log.warn("sendChatMessage, send failed, historyId={}, taskId={}, bizId={}, failReason={}", history.getId(), history.getImMessageTaskId(), history.getBizId(), response.getDesc()); From 8569f32333fb0ed265c325dabd63e8a762928c2b Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 25 Feb 2025 18:04:25 +0800 Subject: [PATCH 197/201] =?UTF-8?q?REQ-3345:=20=E5=A6=82=E6=9E=9C=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E6=B6=88=E6=81=AF=E5=8F=AA=E6=9C=89=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java index abbde16..832733e 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendChatMessageRequest.java @@ -34,6 +34,7 @@ public class SendChatMessageRequest extends SendMessageRequest { /** * 尝试同步发送 + * trySyncSend=true, 接收人只有一个的情况下就会异步发送 */ private boolean trySyncSend; From 6c87f57624604504abffdd2254e49c5b387b326a Mon Sep 17 00:00:00 2001 From: yanglin Date: Tue, 25 Feb 2025 18:14:25 +0800 Subject: [PATCH 198/201] =?UTF-8?q?REQ-3345:=20=E5=A6=82=E6=9E=9C=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E6=B6=88=E6=81=AF=E5=8F=AA=E6=9C=89=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/controller/MessageController.java | 11 +---------- .../im/send/handler/CommonSendOneHandler.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index 126a201..37ca4a6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -27,7 +27,6 @@ import cn.axzo.im.center.api.vo.resp.MessageUpdateResponse; import cn.axzo.im.center.api.vo.resp.UpdatableMessageSendResult; import cn.axzo.im.center.api.vo.resp.UserAccountResp; import cn.axzo.im.center.common.enums.AppTypeEnum; -import cn.axzo.im.channel.netease.dto.MessageDispatchResponse; import cn.axzo.im.entity.AccountRegister; import cn.axzo.im.entity.MessageHistory; import cn.axzo.im.entity.MessageTask; @@ -289,15 +288,7 @@ public class MessageController implements MessageApi { task = messageTaskService.getById(task.getId()); List historyIds = messageTaskService.createMessageHistory(task); MessageHistory history = messageHistoryService.getById(historyIds.get(0)); - MessageDispatchResponse response = commonSendOneHandler.send(history); - if (response.isSuccess()) { - messageHistoryService.setSendSuccess(history, response.getMsgid(), null); - log.info("sendChatMessage, send success, historyId={}, taskId={}, bizId={}", - history.getId(), history.getImMessageTaskId(), history.getBizId()); - } else { - log.warn("sendChatMessage, send failed, historyId={}, taskId={}, bizId={}, failReason={}", - history.getId(), history.getImMessageTaskId(), history.getBizId(), response.getDesc()); - } + commonSendOneHandler.updateSyncSendState(history, commonSendOneHandler.send(history)); } return task.getId(); }); diff --git a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java index daa7ddb..dbd29f2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java +++ b/im-center-server/src/main/java/cn/axzo/im/send/handler/CommonSendOneHandler.java @@ -7,13 +7,16 @@ import cn.axzo.im.channel.netease.dto.MessageDispatchResponse; import cn.axzo.im.entity.MessageHistory; import cn.axzo.im.send.MessageHistoryNimLogger; import cn.axzo.im.send.SendExecutor; +import cn.axzo.im.service.impl.MessageHistoryServiceImpl; import cn.axzo.im.utils.ImProperties; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; /** * @author yanglin */ +@Slf4j @Component @RequiredArgsConstructor public class CommonSendOneHandler extends SendOneHandler { @@ -21,6 +24,7 @@ public class CommonSendOneHandler extends SendOneHandler { private final ImProperties props; private final IMChannelProvider imChannelProvider; private final MessageHistoryNimLogger messageHistoryNimLogger; + private final MessageHistoryServiceImpl messageHistoryService; @Override public void sendAndSubmitUpdate(SendExecutor executor, MessageHistory history) { @@ -55,6 +59,17 @@ public class CommonSendOneHandler extends SendOneHandler { return imChannelProvider.dispatchMessage(sendRequest); } + public void updateSyncSendState(MessageHistory history, MessageDispatchResponse response) { + if (response.isSuccess()) { + messageHistoryService.setSendSuccess(history, response.getMsgid(), null); + log.info("sync send success, historyId={}, taskId={}, bizId={}", + history.getId(), history.getImMessageTaskId(), history.getBizId()); + } else { + log.warn("sync send failed, historyId={}, taskId={}, bizId={}, failReason={}", + history.getId(), history.getImMessageTaskId(), history.getBizId(), response.getDesc()); + } + } + @Override ImProperties getProps() { return props; From a858c7a9feb615c991d2169b9ab3d8be2dac2c86 Mon Sep 17 00:00:00 2001 From: yanglin Date: Wed, 26 Feb 2025 20:05:57 +0800 Subject: [PATCH 199/201] =?UTF-8?q?REQ-3345:=20=E6=9F=A5=E8=AF=A2=E7=BE=A4?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/im/center/api/feign/GroupApi.java | 7 +++++ .../api/vo/req/GroupFindInfoRequest.java | 26 +++++++++++++++++++ .../im/group/controller/GroupController.java | 14 ++++++++++ 3 files changed, 47 insertions(+) create mode 100644 im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupFindInfoRequest.java diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java index 789ccd0..4478904 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/GroupApi.java @@ -5,6 +5,7 @@ import cn.axzo.im.center.api.vo.group.GroupInfo; import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.req.GroupFindInfoRequest; import cn.axzo.im.center.api.vo.req.GroupGetInfoRequest; import cn.axzo.im.center.api.vo.req.GroupGetMembersRequest; import cn.axzo.im.center.api.vo.req.GroupGetOwnerRequest; @@ -67,4 +68,10 @@ public interface GroupApi { @PostMapping("/api/im/group/getGroupInfo") ApiResult getGroupInfo(@RequestBody @Validated GroupGetInfoRequest request); + /** + * 查询群信息 + */ + @PostMapping("/api/im/group/findGroupInfo") + ApiResult findGroupInfo(@RequestBody @Validated GroupFindInfoRequest request); + } \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupFindInfoRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupFindInfoRequest.java new file mode 100644 index 0000000..435f451 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/GroupFindInfoRequest.java @@ -0,0 +1,26 @@ +package cn.axzo.im.center.api.vo.req; + +import cn.axzo.im.center.common.enums.GroupType; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @author yanglin + */ +@Setter @Getter +public class GroupFindInfoRequest { + /** + * 群类型 + */ + @NotNull(message = "群类型不能为空") + private GroupType groupType; + + /** + * 业务码 + */ + @NotBlank(message = "业务码不能为空") + private String bizCode; +} diff --git a/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java index d6e70f0..a0cacf8 100644 --- a/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java +++ b/im-center-server/src/main/java/cn/axzo/im/group/controller/GroupController.java @@ -8,6 +8,7 @@ import cn.axzo.im.center.api.vo.group.GroupMemberInfo; import cn.axzo.im.center.api.vo.req.GroupAddMembersRequest; import cn.axzo.im.center.api.vo.req.GroupCreateRequest; import cn.axzo.im.center.api.vo.req.GroupDismissRequest; +import cn.axzo.im.center.api.vo.req.GroupFindInfoRequest; import cn.axzo.im.center.api.vo.req.GroupGetInfoRequest; import cn.axzo.im.center.api.vo.req.GroupGetMembersRequest; import cn.axzo.im.center.api.vo.req.GroupGetOwnerRequest; @@ -85,4 +86,17 @@ public class GroupController implements GroupApi { response.setGroup(BeanMapper.copyBean(group, GroupInfo.class)); return ApiResult.ok(response); } + + @Override + public ApiResult findGroupInfo(GroupFindInfoRequest request) { + // @formatter:off + Group group = groupDao + .findByBizCode(request.getBizCode(), request.getGroupType(), false) + .orElse(null); + // @formatter:on + GroupGetInfoResponse response = new GroupGetInfoResponse(); + response.setGroup(BeanMapper.copyBean(group, GroupInfo.class)); + return ApiResult.ok(response); + } + } \ No newline at end of file From 33823a669504f721420ac091c27584f81c5d6294 Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 27 Feb 2025 11:19:06 +0800 Subject: [PATCH 200/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E8=AF=B7?= =?UTF-8?q?=E6=B1=82id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/entity/MessageTask.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java index c3b00fd..881e5e0 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java @@ -10,6 +10,7 @@ import cn.axzo.im.center.common.enums.NimMessageType; import cn.axzo.im.center.common.enums.TemplatedMsgType; import cn.axzo.im.config.BaseListTypeHandler; import cn.axzo.im.enums.MessageTaskStatus; +import cn.axzo.im.utils.UUIDUtil; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; @@ -122,6 +123,8 @@ public class MessageTask { @AllArgsConstructor public static class BizData { + private String requestNo = UUIDUtil.uuidString(); + private TemplatedMsgType templatedMsgType = TemplatedMsgType.TEMPLATE; private String msgTemplateId; From 66ca057b3b0ea4a29bf435e5fe181cabd2ba253e Mon Sep 17 00:00:00 2001 From: yanglin Date: Thu, 27 Feb 2025 11:30:11 +0800 Subject: [PATCH 201/201] =?UTF-8?q?REQ-3345:=20=E6=B7=BB=E5=8A=A0=E8=AF=B7?= =?UTF-8?q?=E6=B1=82id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/axzo/im/entity/MessageTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java index 881e5e0..25f7ba2 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java @@ -123,7 +123,7 @@ public class MessageTask { @AllArgsConstructor public static class BizData { - private String requestNo = UUIDUtil.uuidString(); + private final String requestNo = UUIDUtil.uuidString(); private TemplatedMsgType templatedMsgType = TemplatedMsgType.TEMPLATE;